W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
相機(jī)模塊主要工作是給相機(jī)應(yīng)用開(kāi)發(fā)者提供基本的相機(jī)API接口,用于使用相機(jī)系統(tǒng)的功能,進(jìn)行相機(jī)硬件的訪問(wèn)、操作和新功能開(kāi)發(fā)。相機(jī)的開(kāi)發(fā)流程如圖所示:
圖1 相機(jī)開(kāi)發(fā)流程
相機(jī)模塊為相機(jī)應(yīng)用開(kāi)發(fā)者提供了3個(gè)包的內(nèi)容,包括方法、枚舉、以及常量/變量,方便開(kāi)發(fā)者更容易地實(shí)現(xiàn)相機(jī)功能。詳情請(qǐng)查閱對(duì)應(yīng)開(kāi)發(fā)場(chǎng)景。
包名 | 功能 |
---|---|
ohos.media.camera.CameraKit | 相機(jī)功能入口類。獲取當(dāng)前支持的相機(jī)列表及其靜態(tài)能力信息,創(chuàng)建相機(jī)對(duì)象。 |
ohos.media.camera.device | 相機(jī)設(shè)備操作類。提供相機(jī)能力查詢、相機(jī)配置、相機(jī)幀捕獲、相機(jī)狀態(tài)回調(diào)等功能。 |
ohos.media.camera.params | 相機(jī)參數(shù)類。提供相機(jī)屬性、參數(shù)和操作結(jié)果的定義。 |
在使用相機(jī)之前,需要申請(qǐng)相機(jī)的相關(guān)權(quán)限,保證應(yīng)用擁有相機(jī)硬件及其他功能權(quán)限,應(yīng)用權(quán)限的介紹請(qǐng)參考 權(quán)限章節(jié),相機(jī)涉及權(quán)限如下表。
權(quán)限名稱 | 權(quán)限屬性值 | 是否必選 |
---|---|---|
相機(jī)權(quán)限 | ohos.permission.CAMERA | 必選 |
錄音權(quán)限 | ohos.permission.MICROPHONE | 可選(需要錄像時(shí)申請(qǐng)) |
存儲(chǔ)權(quán)限 | ohos.permission.WRITE_USER_STORAGE | 可選(需要保存圖像及視頻到設(shè)備的外部存儲(chǔ)時(shí)申請(qǐng)) |
位置權(quán)限 | ohos.permission.LOCATION | 可選(需要保存圖像及視頻位置信息時(shí)申請(qǐng)) |
CameraKit 類是相機(jī)的入口 API 類,用于獲取相機(jī)設(shè)備特性、打開(kāi)相機(jī),其接口如下表。
接口名 | 描述 |
---|---|
createCamera(String cameraId, CameraStateCallback callback, EventHandler handler) | 創(chuàng)建相機(jī)對(duì)象。 |
getCameraAbility(String cameraId) | 獲取指定邏輯相機(jī)或物理相機(jī)的靜態(tài)能力。 |
getCameraIds() | 獲取當(dāng)前邏輯相機(jī)列表。 |
getCameraInfo(String cameraId) | 獲取指定邏輯相機(jī)的信息。 |
getInstance(Context context) | 獲取CameraKit實(shí)例。 |
registerCameraDeviceCallback(CameraDeviceCallback callback, EventHandler handler) | 注冊(cè)相機(jī)使用狀態(tài)回調(diào)。 |
unregisterCameraDeviceCallback(CameraDeviceCallback callback) | 注銷相機(jī)使用狀態(tài)回調(diào)。 |
基于 HarmonyOS 實(shí)現(xiàn)一個(gè)相機(jī)應(yīng)用,無(wú)論將來(lái)想應(yīng)用到哪個(gè)或者哪些設(shè)備上,都必須先創(chuàng)建一個(gè)獨(dú)立的相機(jī)設(shè)備,然后才能繼續(xù)相機(jī)的其他操作。相機(jī)設(shè)備創(chuàng)建的建議步驟如下:
private void openCamera(){
// 獲取CameraKit對(duì)象
CameraKit cameraKit = CameraKit.getInstance(context);
if (cameraKit == null) {
// 處理cameraKit獲取失敗的情況
}
}
如果此步驟操作失敗,相機(jī)可能被占用或無(wú)法使用。如果被占用,必須等到相機(jī)釋放后才能重新獲取CameraKit對(duì)象。
try {
// 獲取當(dāng)前設(shè)備的邏輯相機(jī)列表
String[] cameraIds = cameraKit.getCameraIds();
if (cameraIds.length <= 0) {
HiLog.error("cameraIds size is 0");
}
} catch (IllegalStateException e) {
// 處理異常
}
還可以繼續(xù)查詢指定相機(jī)ID的靜態(tài)信息:
調(diào)用getDeviceLinkType(String physicalId)方法獲取物理相機(jī)連接方式;
調(diào)用getCameraInfo(String cameraId)方法查詢相機(jī)硬件朝向等信息;
調(diào)用getCameraAbility(String cameraId)方法查詢相機(jī)能力信息(比如支持的分辨率列表等)。
接口名 | 描述 |
---|---|
getDeviceLinkType(String physicalId) | 獲取物理相機(jī)連接方式。 |
getFacingType() | 獲取相機(jī)朝向信息。 |
getLogicalId() | 獲取邏輯相機(jī)ID。 |
getPhysicalIdList() | 獲取對(duì)應(yīng)的物理相機(jī)ID列表。 |
接口名 | 描述 |
---|---|
getSupportedSizes(int format) | 根據(jù)格式查詢輸出圖像的分辨率列表。 |
getSupportedSizes(Class<T> clazz) | 根據(jù) Class 類型查詢分辨率列表。 |
getParameterRange(ParameterKey.Key<T> parameter) | 獲取指定參數(shù)能夠設(shè)置的值范圍。 |
getPropertyValue(PropertyKey.Key<T> property) | 獲取指定屬性對(duì)應(yīng)的值。 |
getSupportedAeMode() | 獲取當(dāng)前相機(jī)支持的自動(dòng)曝光模式。 |
getSupportedAfMode() | 獲取當(dāng)前相機(jī)支持的自動(dòng)對(duì)焦模式。 |
getSupportedFaceDetection() | 獲取相機(jī)支持的人臉檢測(cè)類型范圍。 |
getSupportedFlashMode() | 當(dāng)前相機(jī)支持的閃光燈取值范圍。 |
getSupportedParameters() | 當(dāng)前相機(jī)支持的參數(shù)設(shè)置。 |
getSupportedProperties() | 獲取當(dāng)前相機(jī)的屬性列表。 |
getSupportedResults() | 獲取當(dāng)前相機(jī)支持的參數(shù)設(shè)置可返回的結(jié)果列表。 |
getSupportedZoom() | 獲取相機(jī)支持的變焦范圍。 |
// 創(chuàng)建相機(jī)設(shè)備
cameraKit.createCamera(cameraIds[0], cameraStateCallback, eventHandler);
第一個(gè)參數(shù) cameraId 可以是上一步獲取的邏輯相機(jī)列表中的任何一個(gè)相機(jī)ID。
第二和第三個(gè)參數(shù)負(fù)責(zé)相機(jī)創(chuàng)建和相機(jī)運(yùn)行時(shí)的數(shù)據(jù)和狀態(tài)檢測(cè),請(qǐng)務(wù)必保證在整個(gè)相機(jī)運(yùn)行周期內(nèi)有效。
private final class CameraStateCallbackImpl extends CameraStateCallback {
@Override
public void onCreated(Camera camera) {
// 創(chuàng)建相機(jī)設(shè)備
}
@Override
public void onConfigured(Camera camera) {
// 配置相機(jī)設(shè)備
}
@Override
public void onPartialConfigured(Camera camera) {
// 當(dāng)使用了 addDeferredSurfaceSize 配置了相機(jī),會(huì)接到此回調(diào)
}
@Override
public void onReleased(Camera camera) {
// 釋放相機(jī)設(shè)備
}
}
// 相機(jī)創(chuàng)建和相機(jī)運(yùn)行時(shí)的回調(diào)
CameraStateCallbackImpl cameraStateCallback = new CameraStateCallbackImpl();
if(cameraStateCallback ==null) {
HiLog.error("cameraStateCallback is null");
}
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
// 執(zhí)行回調(diào)的 EventHandler
EventHandler eventHandler = new EventHandler(EventRunner.create("CameraCb"));
if(eventHandler ==null) {
HiLog.error("eventHandler is null");
}
至此,相機(jī)設(shè)備的創(chuàng)建已經(jīng)完成。相機(jī)設(shè)備創(chuàng)建成功會(huì)在 CameraStateCallback 中觸發(fā) onCreated(Camera camera)回調(diào)。在進(jìn)入相機(jī)設(shè)備配置前,請(qǐng)確保相機(jī)設(shè)備已經(jīng)創(chuàng)建成功。否則會(huì)觸發(fā)相機(jī)設(shè)備創(chuàng)建失敗的回調(diào),并返回錯(cuò)誤碼,需要進(jìn)行錯(cuò)誤處理后,重新執(zhí)行相機(jī)設(shè)備的創(chuàng)建。
創(chuàng)建相機(jī)設(shè)備成功后,在 CameraStateCallback 中會(huì)觸發(fā) onCreated(Camera camera)回調(diào),并且?guī)Щ?Camera 對(duì)象,用于執(zhí)行相機(jī)設(shè)備的操作。
當(dāng)一個(gè)新的相機(jī)設(shè)備成功創(chuàng)建后,首先需要對(duì)相機(jī)進(jìn)行配置,調(diào)用 configure(CameraConfig) 方法實(shí)現(xiàn)配置。相機(jī)配置主要是設(shè)置預(yù)覽、拍照、錄像用到的 Surface(詳見(jiàn) ohos.agp.graphics.Surface),沒(méi)有配置過(guò) Surface,相應(yīng)的功能不能使用。
為了進(jìn)行相機(jī)幀捕獲結(jié)果的數(shù)據(jù)和狀態(tài)檢測(cè),還需要在相機(jī)配置時(shí)調(diào)用 setFrameStateCallback(FrameStateCallback, EventHandler)方法設(shè)置幀回調(diào)。
private final class CameraStateCallbackImpl extends CameraStateCallback {
@Override
public void onCreated(Camera camera) {
cameraConfigBuilder = camera.getCameraConfigBuilder();
if (cameraConfigBuilder == null) {
HiLog.error("onCreated cameraConfigBuilder is null");
return;
}
// 配置預(yù)覽的Surface
cameraConfigBuilder.addSurface(previewSurface);
// 配置拍照的Surface
cameraConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
// 配置幀結(jié)果的回調(diào)
cameraConfigBuilder.setFrameStateCallback(frameStateCallbackImpl, handler);
try {
// 相機(jī)設(shè)備配置
camera.configure(cameraConfigBuilder.build());
} catch (IllegalArgumentException e) {
HiLog.error("Argument Exception");
} catch (IllegalStateException e) {
HiLog.error("State Exception");
}
}
}
相機(jī)配置成功后,在 CameraStateCallback 中會(huì)觸發(fā) onConfigured(Camera camera)回調(diào),然后才可以執(zhí)行相機(jī)幀捕獲相關(guān)的操作。
接口名 | 描述 |
---|---|
addSurface(Surface surface) | 相機(jī)配置中增加 Surface。 |
build() | 相機(jī)配置的構(gòu)建類。 |
removeSurface(Surface surface) | 移除先前添加的 Surface。 |
setFrameStateCallback(FrameStateCallback callback, EventHandler handler) | 設(shè)置用于相機(jī)幀結(jié)果返回的 FrameStateCallback 和 Handler。 |
addDeferredSurfaceSize(Size surfaceSize, Class<T> clazz) | 添加延遲 Surface 的尺寸、類型。 |
addDeferredSurface(Surface surface) | 設(shè)置延遲的 Surface,此 Surface 的尺寸和類型必須和使用 addDeferredSurfaceSize 配置的一致。 |
Camera 操作類,包括相機(jī)預(yù)覽、錄像、拍照等功能接口。
接口名 | 描述 |
---|---|
triggerSingleCapture(FrameConfig frameConfig) | 啟動(dòng)相機(jī)幀的單幀捕獲。 |
triggerMultiCapture(List<FrameConfig> frameConfigs) | 啟動(dòng)相機(jī)幀的多幀捕獲。 |
configure(CameraConfig config) | 配置相機(jī)。 |
flushCaptures() | 停止并清除相機(jī)幀的捕獲,包括循環(huán)幀/單幀/多幀捕獲。 |
getCameraConfigBuilder() | 獲取相機(jī)配置構(gòu)造器對(duì)象。 |
getCameraId() | 獲取當(dāng)前相機(jī)的 ID。 |
getFrameConfigBuilder(int type) | 獲取指定類型的相機(jī)幀配置構(gòu)造器對(duì)象。 |
release() | 釋放相機(jī)對(duì)象及資源。 |
triggerLoopingCapture(FrameConfig frameConfig) | 啟動(dòng)或者更新相機(jī)幀的循環(huán)捕獲。 |
stopLoopingCapture() | 停止當(dāng)前相機(jī)幀的循環(huán)捕獲。 |
啟動(dòng)預(yù)覽(循環(huán)幀捕獲)
用戶一般都是先看見(jiàn)預(yù)覽畫(huà)面才執(zhí)行拍照或者其他功能,所以對(duì)于一個(gè)普通的相機(jī)應(yīng)用,預(yù)覽是必不可少的。啟動(dòng)預(yù)覽的建議步驟如下:
接口名 | 描述 | 是否必選 |
---|---|---|
addSurface(Surface surface) | 配置預(yù)覽 surface 和幀的綁定。 | 是 |
setAfMode(int afMode, Rect rect) | 配置對(duì)焦模式。 | 否 |
setAeMode(int aeMode, Rect rect) | 配置曝光模式。 | 否 |
setZoom(float value) | 配置變焦值。 | 否 |
setFlashMode(int flashMode) | 配置閃光燈模式。 | 否 |
setFaceDetection(int type, boolean isEnable) | 配置人臉檢測(cè)或者笑臉檢測(cè)。 | 否 |
setParameter(Key<T> key, T value) | 配置其他屬性(如自拍鏡像等)。 | 否 |
setMark(Object mark) | 配置一個(gè)標(biāo)簽,后續(xù)可以從 FrameConfig 中通過(guò) Object getMark() 拿到標(biāo)簽,判斷兩個(gè)是否相等,相等就說(shuō)明是同一個(gè)配置。 | 否 |
setCoordinateSurface(Surface surface) | 配置坐標(biāo)系基準(zhǔn) Surface,后續(xù)計(jì)算 Ae/Af 等區(qū)域都會(huì)基于此 Surface 為基本的中心坐標(biāo)系,不設(shè)置默認(rèn)使用添加的第一個(gè) Surface。 | 否 |
private final class CameraStateCallbackImpl extends CameraStateCallback {
@Override
public void onConfigured(Camera camera) {
// 獲取預(yù)覽配置模板
frameConfigBuilder = camera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW);
// 配置預(yù)覽 Surface
frameConfigBuilder.addSurface(previewSurface);
previewFrameConfig = frameConfigBuilder.build();
try {
// 啟動(dòng)循環(huán)幀捕獲
int triggerId = camera.triggerLoopingCapture(previewFrameConfig);
} catch (IllegalArgumentException e) {
HiLog.error("Argument Exception");
} catch (IllegalStateException e) {
HiLog.error("State Exception");
}
}
}
經(jīng)過(guò)以上的操作,相機(jī)應(yīng)用已經(jīng)可以正常進(jìn)行實(shí)時(shí)預(yù)覽了。在預(yù)覽狀態(tài)下,開(kāi)發(fā)者還可以執(zhí)行其他操作,比如:
當(dāng)預(yù)覽幀配置更改時(shí),可以通過(guò)triggerLoopingCapture(FrameConfig)方法實(shí)現(xiàn)預(yù)覽幀配置的更新;
// 預(yù)覽幀變焦值變更
frameConfigBuilder.setZoom(1.2f);
// 調(diào)用triggerLoopingCapture方法實(shí)現(xiàn)預(yù)覽幀配置更新
triggerLoopingCapture(frameConfigBuilder.build());
通過(guò)stopLoopingCapture()方法停止循環(huán)幀捕獲(停止預(yù)覽)。
// 停止預(yù)覽幀捕獲
camera.stopLoopingCapture(frameConfigBuilder.build())
實(shí)現(xiàn)拍照(單幀捕獲)
拍照功能屬于相機(jī)應(yīng)用的最重要功能之一,而且照片質(zhì)量對(duì)用戶至關(guān)重要。相機(jī)模塊基于相機(jī)復(fù)雜的邏輯,從應(yīng)用接口層到器件驅(qū)動(dòng)層都已經(jīng)默認(rèn)的做好了最適合用戶的配置,這些默認(rèn)配置盡可能地保證用戶拍出的每張照片的質(zhì)量。發(fā)起拍照的建議步驟如下:
接口名 | 描述 | 是否必選 |
---|---|---|
FrameConfig.Builder addSurface(Surface) | 實(shí)現(xiàn)拍照 Surface 和幀的綁定。 | 必選 |
FrameConfig.Builder setImageRotation(int) | 設(shè)置圖片旋轉(zhuǎn)角度。 | 可選 |
FrameConfig.Builder setLocation(Location) | 設(shè)置圖片地理位置信息。 | 可選 |
FrameConfig.Builder setParameter(Key<T>, T) | 配置其他屬性(如自拍鏡像等)。 | 可選 |
// 圖像幀數(shù)據(jù)接收處理對(duì)象
private ImageReceiver imageReceiver;
// 執(zhí)行回調(diào)的 EventHandler
private EventHandler eventHandler = new EventHandler(EventRunner.create("CameraCb"));
// 拍照支持分辨率
private Size pictureSize;
// 單幀捕獲生成圖像回調(diào) Listener
private final ImageReceiver.IImageArrivalListener imageArrivalListener = new ImageReceiver.IImageArrivalListener() {
@Override
public void onImageArrival(ImageReceiver imageReceiver) {
StringBuffer fileName = new StringBuffer("picture_");
fileName.append(UUID.randomUUID()).append(".jpg"); // 定義生成圖片文件名
File myFile = new File(dirFile, fileName.toString()); // 創(chuàng)建圖片文件
imageSaver = new ImageSaver(imageReceiver.readNextImage(), myFile); // 創(chuàng)建一個(gè)讀寫(xiě)線程任務(wù)用于保存圖片
eventHandler.postTask(imageSaver); // 執(zhí)行讀寫(xiě)線程任務(wù)生成圖片
}
};
// 保存圖片, 圖片數(shù)據(jù)讀寫(xiě),及圖像生成見(jiàn) run 方法
class ImageSaver implements Runnable {
private final Image myImage;
private final File myFile;
ImageSaver(Image image, File file) {
myImage = image;
myFile = file;
}
@Override
public void run() {
Image.Component component = myImage.getComponent(ImageFormat.ComponentType.JPEG);
byte[] bytes = new byte[component.remaining()];
component.read(bytes);
FileOutputStream output = null;
try {
output = new FileOutputStream(myFile);
output.write(bytes); // 寫(xiě)圖像數(shù)據(jù)
} catch (IOException e) {
HiLog.error("save picture occur exception!");
} finally {
myImage.release();
if (output != null) {
try {
output.close(); // 關(guān)閉流
} catch (IOException e) {
HiLog.error("image release occur exception!");
}
}
}
}
}
private void takePictureInit() {
List<Size> pictureSizes = cameraAbility.getSupportedSizes(ImageFormat.JPEG); // 獲取拍照支持分辨率列表
pictureSize = getpictureSize(pictureSizes) // 根據(jù)拍照要求選擇合適的分辨率
imageReceiver = ImageReceiver.create(Math.max(pictureSize.width, pictureSize.height),
Math.min(pictureSize.width, pictureSize.height), ImageFormat.JPEG, 5); // 創(chuàng)建 ImageReceiver 對(duì)象,注意 creat 函數(shù)中寬度要大于高度;5 為最大支持的圖像數(shù),請(qǐng)根據(jù)實(shí)際設(shè)置。
imageReceiver.setImageArrivalListener(imageArrivalListener);
}
private void capture() {
// 獲取拍照配置模板
framePictureConfigBuilder = cameraDevice.getFrameConfigBuilder(FRAME_CONFIG_PICTURE);
// 配置拍照 Surface
framePictureConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
// 配置拍照其他參數(shù)
framePictureConfigBuilder.setImageRotation(90);
try {
// 啟動(dòng)單幀捕獲(拍照)
camera.triggerSingleCapture(framePictureConfigBuilder.build());
} catch (IllegalArgumentException e) {
HiLog.error("Argument Exception");
} catch (IllegalStateException e) {
HiLog.error("State Exception");
}
}
為了捕獲到質(zhì)量更高和效果更好的圖片,還可以在幀結(jié)果中實(shí)時(shí)監(jiān)測(cè)自動(dòng)對(duì)焦和自動(dòng)曝光的狀態(tài),一般而言,在自動(dòng)對(duì)焦完成,自動(dòng)曝光收斂后的瞬間是發(fā)起單幀捕獲的最佳時(shí)機(jī)。
實(shí)現(xiàn)連拍(多幀捕獲)
連拍功能方便用戶一次拍照獲取多張照片,用于捕捉精彩瞬間。同普通拍照的實(shí)現(xiàn)流程一致,但連拍需要使用 triggerMultiCapture(List<FrameConfig> frameConfigs)方法。
啟動(dòng)錄像(循環(huán)幀捕獲)
啟動(dòng)錄像和啟動(dòng)預(yù)覽類似,但需要另外配置錄像 Surface 才能使用。
private Source source; // 音視頻源
private AudioProperty.Builder audioPropertyBuilder; // 音頻屬性
private VideoProperty.Builder videoPropertyBuilder; // 視頻屬性
private StorageProperty.Builder storagePropertyBuilder; // 音視頻存儲(chǔ)屬性
private Recorder mediaRecorder; // 錄像操作對(duì)象
private String recordName; // 音視頻文件名
private void initMediaRecorder() {
HiLog.info("initMediaRecorder begin");
videoPropertyBuilder.setRecorderBitRate(10000000); // 設(shè)置錄制比特率
int rotation = DisplayManager.getInstance().getDefaultDisplay(this).get().getRotation();
videoPropertyBuilder.setRecorderDegrees(getOrientation(rotation)); // 設(shè)置錄像方向
videoPropertyBuilder.setRecorderFps(30); // 設(shè)置錄制采樣率
videoPropertyBuilder.setRecorderHeight(Math.min(recordSize.height, recordSize.width)); // 設(shè)置錄像支持的分辨率,需保證 width > height
videoPropertyBuilder.setRecorderWidth(Math.max(recordSize.height, recordSize.width));
videoPropertyBuilder.setRecorderVideoEncoder(Recorder.VideoEncoder.H264); // 設(shè)置視頻編碼方式
videoPropertyBuilder.setRecorderRate(30); // 設(shè)置錄制幀率
source.setRecorderAudioSource(Recorder.AudioSource.MIC); // 設(shè)置錄制音頻源
source.setRecorderVideoSource(Recorder.VideoSource.SURFACE); // 設(shè)置視頻窗口
mediaRecorder.setSource(source); // 設(shè)置音視頻源
mediaRecorder.setOutputFormat(Recorder.OutputFormat.MPEG_4); // 設(shè)置音視頻輸出格式
StringBuffer fileName = new StringBuffer("record_"); // 生成隨機(jī)文件名
fileName.append(UUID.randomUUID()).append(".mp4");
recordName = fileName.toString();
File file = new File(dirFile, fileName.toString()); // 創(chuàng)建錄像文件對(duì)象
storagePropertyBuilder.setRecorderFile(file); // 設(shè)置存儲(chǔ)音視頻文件名
mediaRecorder.setStorageProperty(storagePropertyBuilder.build());
audioPropertyBuilder.setRecorderAudioEncoder(Recorder.AudioEncoder.AAC); // 設(shè)置音頻編碼格式
mediaRecorder.setAudioProperty(audioPropertyBuilder.build()); // 設(shè)置音頻屬性
mediaRecorder.setVideoProperty(videoPropertyBuilder.build()); // 設(shè)置視頻屬性
mediaRecorder.prepare(); // 準(zhǔn)備錄制
HiLog.info("initMediaRecorder end");
}
private final class CameraStateCallbackImpl extends CameraStateCallback {
@Override
public void onConfigured(Camera camera) {
// 獲取預(yù)覽配置模板
frameConfigBuilder = camera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW);
// 配置預(yù)覽Surface
frameConfigBuilder.addSurface(previewSurface);
// 配置錄像的Surface
mRecorderSurface = mediaRecorder.getVideoSurface();
cameraConfigBuilder.addSurface(mRecorderSurface);
previewFrameConfig = frameConfigBuilder.build();
try {
// 啟動(dòng)循環(huán)幀捕獲
int triggerId = camera.triggerLoopingCapture(previewFrameConfig);
} catch (IllegalArgumentException e) {
HiLog.error("Argument Exception");
} catch (IllegalStateException e) {
HiLog.error("State Exception");
}
}
}
使用完相機(jī)后,必須通過(guò) release() 來(lái)關(guān)閉相機(jī)和釋放資源,否則可能導(dǎo)致其他相機(jī)應(yīng)用無(wú)法啟動(dòng)。一旦相機(jī)被釋放,它所提供的操作就不能再被調(diào)用,否則會(huì)導(dǎo)致不可預(yù)期的結(jié)果,或是會(huì)引發(fā)狀態(tài)異常。
相機(jī)設(shè)備釋放的示例代碼如下:
private void releaseCamera() {
if (camera != null) {
// 關(guān)閉相機(jī)和釋放資源
camera.release();
camera = null;
}
// 拍照配置模板置空
framePictureConfigBuilder = null;
// 預(yù)覽配置模板置空
previewFrameConfig = null;
}
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: