鴻蒙OS 相機(jī)設(shè)備開發(fā)指導(dǎo)

2020-09-18 14:24 更新

相機(jī)開發(fā)流程

相機(jī)模塊主要工作是給相機(jī)應(yīng)用開發(fā)者提供基本的相機(jī)API接口,用于使用相機(jī)系統(tǒng)的功能,進(jìn)行相機(jī)硬件的訪問、操作和新功能開發(fā)。相機(jī)的開發(fā)流程如圖所示:

圖1 相機(jī)開發(fā)流程 點(diǎn)擊放大

接口說明

相機(jī)模塊為相機(jī)應(yīng)用開發(fā)者提供了3個(gè)包的內(nèi)容,包括方法、枚舉、以及常量/變量,方便開發(fā)者更容易地實(shí)現(xiàn)相機(jī)功能。詳情請查閱對應(yīng)開發(fā)場景。

包名 功能
ohos.media.camera.CameraKit 相機(jī)功能入口類。獲取當(dāng)前支持的相機(jī)列表及其靜態(tài)能力信息,創(chuàng)建相機(jī)對象。
ohos.media.camera.device 相機(jī)設(shè)備操作類。提供相機(jī)能力查詢、相機(jī)配置、相機(jī)幀捕獲、相機(jī)狀態(tài)回調(diào)等功能。
ohos.media.camera.params 相機(jī)參數(shù)類。提供相機(jī)屬性、參數(shù)和操作結(jié)果的定義。

相機(jī)權(quán)限申請

在使用相機(jī)之前,需要申請相機(jī)的相關(guān)權(quán)限,保證應(yīng)用擁有相機(jī)硬件及其他功能權(quán)限,應(yīng)用權(quán)限的介紹請參考 權(quán)限章節(jié),相機(jī)涉及權(quán)限如下表。

權(quán)限名稱 權(quán)限屬性值 是否必選
相機(jī)權(quán)限 ohos.permission.CAMERA 必選
錄音權(quán)限 ohos.permission.MICROPHONE 可選(需要錄像時(shí)申請)
存儲權(quán)限 ohos.permission.WRITE_USER_STORAGE 可選(需要保存圖像及視頻到設(shè)備的外部存儲時(shí)申請)
位置權(quán)限 ohos.permission.LOCATION 可選(需要保存圖像及視頻位置信息時(shí)申請)

相機(jī)設(shè)備創(chuàng)建

CameraKit 類是相機(jī)的入口 API 類,用于獲取相機(jī)設(shè)備特性、打開相機(jī),其接口如下表。

接口名 描述
createCamera(String cameraId, CameraStateCallback callback, EventHandler handler) 創(chuàng)建相機(jī)對象。
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) 注冊相機(jī)使用狀態(tài)回調(diào)。
unregisterCameraDeviceCallback(CameraDeviceCallback callback) 注銷相機(jī)使用狀態(tài)回調(diào)。

基于 HarmonyOS 實(shí)現(xiàn)一個(gè)相機(jī)應(yīng)用,無論將來想應(yīng)用到哪個(gè)或者哪些設(shè)備上,都必須先創(chuàng)建一個(gè)獨(dú)立的相機(jī)設(shè)備,然后才能繼續(xù)相機(jī)的其他操作。相機(jī)設(shè)備創(chuàng)建的建議步驟如下:

  1. 通過 CameraKit.getInstance(Context context) 方法獲取唯一的 CameraKit 對象是創(chuàng)建新的相機(jī)應(yīng)用的第一步操作。

   private void openCamera(){
       // 獲取CameraKit對象
       CameraKit cameraKit = CameraKit.getInstance(context);
       if (cameraKit == null) {
           // 處理cameraKit獲取失敗的情況 
       }
   }

如果此步驟操作失敗,相機(jī)可能被占用或無法使用。如果被占用,必須等到相機(jī)釋放后才能重新獲取CameraKit對象。

  1. 通過getCameraIds()方法,獲取當(dāng)前使用的設(shè)備支持的邏輯相機(jī)列表。邏輯相機(jī)列表中存儲了當(dāng)前設(shè)備擁有的所有邏輯相機(jī)ID,如果列表不為空,則列表中的每個(gè)ID都支持獨(dú)立創(chuàng)建相機(jī)對象;否則,說明正在使用的設(shè)備無可用的相機(jī),不能繼續(xù)后續(xù)的操作。

   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() 獲取對應(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) 獲取指定屬性對應(yīng)的值。
getSupportedAeMode() 獲取當(dāng)前相機(jī)支持的自動(dòng)曝光模式。
getSupportedAfMode() 獲取當(dāng)前相機(jī)支持的自動(dòng)對焦模式。
getSupportedFaceDetection() 獲取相機(jī)支持的人臉檢測類型范圍。
getSupportedFlashMode() 當(dāng)前相機(jī)支持的閃光燈取值范圍。
getSupportedParameters() 當(dāng)前相機(jī)支持的參數(shù)設(shè)置。
getSupportedProperties() 獲取當(dāng)前相機(jī)的屬性列表。
getSupportedResults() 獲取當(dāng)前相機(jī)支持的參數(shù)設(shè)置可返回的結(jié)果列表。
getSupportedZoom() 獲取相機(jī)支持的變焦范圍。

  1. 通過createCamera(String cameraId, CameraStateCallback callback, EventHandler handler)方法,創(chuàng)建相機(jī)對象,此步驟執(zhí)行成功意味著相機(jī)系統(tǒng)的硬件已經(jīng)完成了上電。

   // 創(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)檢測,請務(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ī),會接到此回調(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)建成功會在 CameraStateCallback 中觸發(fā) onCreated(Camera camera)回調(diào)。在進(jìn)入相機(jī)設(shè)備配置前,請確保相機(jī)設(shè)備已經(jīng)創(chuàng)建成功。否則會觸發(fā)相機(jī)設(shè)備創(chuàng)建失敗的回調(diào),并返回錯(cuò)誤碼,需要進(jìn)行錯(cuò)誤處理后,重新執(zhí)行相機(jī)設(shè)備的創(chuàng)建。

相機(jī)設(shè)備配置

創(chuàng)建相機(jī)設(shè)備成功后,在 CameraStateCallback 中會觸發(fā) onCreated(Camera camera)回調(diào),并且?guī)Щ?Camera 對象,用于執(zhí)行相機(jī)設(shè)備的操作。

當(dāng)一個(gè)新的相機(jī)設(shè)備成功創(chuàng)建后,首先需要對相機(jī)進(jìn)行配置,調(diào)用 configure(CameraConfig) 方法實(shí)現(xiàn)配置。相機(jī)配置主要是設(shè)置預(yù)覽、拍照、錄像用到的 Surface(詳見 ohos.agp.graphics.Surface),沒有配置過 Surface,相應(yīng)的功能不能使用。

為了進(jìn)行相機(jī)幀捕獲結(jié)果的數(shù)據(jù)和狀態(tài)檢測,還需要在相機(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 中會觸發(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 配置的一致。

相機(jī)幀捕獲

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)造器對象。
getCameraId() 獲取當(dāng)前相機(jī)的 ID。
getFrameConfigBuilder(int type) 獲取指定類型的相機(jī)幀配置構(gòu)造器對象。
release() 釋放相機(jī)對象及資源。
triggerLoopingCapture(FrameConfig frameConfig) 啟動(dòng)或者更新相機(jī)幀的循環(huán)捕獲。
stopLoopingCapture() 停止當(dāng)前相機(jī)幀的循環(huán)捕獲。

啟動(dòng)預(yù)覽(循環(huán)幀捕獲)

用戶一般都是先看見預(yù)覽畫面才執(zhí)行拍照或者其他功能,所以對于一個(gè)普通的相機(jī)應(yīng)用,預(yù)覽是必不可少的。啟動(dòng)預(yù)覽的建議步驟如下:

  1. 通過getFrameConfigBuilder(FRAME_CONFIG_PREVIEW)方法獲取預(yù)覽配置模板,常用幀配置項(xiàng)見下表,更多的幀配置項(xiàng)以及詳細(xì)使用方法請參考 API 接口說明的 FrameConfig.Builder 部分。

接口名 描述 是否必選
addSurface(Surface surface) 配置預(yù)覽 surface 和幀的綁定。
setAfMode(int afMode, Rect rect) 配置對焦模式。
setAeMode(int aeMode, Rect rect) 配置曝光模式。
setZoom(float value) 配置變焦值。
setFlashMode(int flashMode) 配置閃光燈模式。
setFaceDetection(int type, boolean isEnable) 配置人臉檢測或者笑臉檢測。
setParameter(Key<T> key, T value) 配置其他屬性(如自拍鏡像等)。
setMark(Object mark) 配置一個(gè)標(biāo)簽,后續(xù)可以從 FrameConfig 中通過 Object getMark() 拿到標(biāo)簽,判斷兩個(gè)是否相等,相等就說明是同一個(gè)配置。
setCoordinateSurface(Surface surface) 配置坐標(biāo)系基準(zhǔn) Surface,后續(xù)計(jì)算 Ae/Af 等區(qū)域都會基于此 Surface 為基本的中心坐標(biāo)系,不設(shè)置默認(rèn)使用添加的第一個(gè) Surface。

  1. 通過 triggerLoopingCapture(FrameConfig)方法實(shí)現(xiàn)循環(huán)幀捕獲(如預(yù)覽/錄像)。

   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)過以上的操作,相機(jī)應(yīng)用已經(jīng)可以正常進(jìn)行實(shí)時(shí)預(yù)覽了。在預(yù)覽狀態(tài)下,開發(fā)者還可以執(zhí)行其他操作,比如:

當(dāng)預(yù)覽幀配置更改時(shí),可以通過triggerLoopingCapture(FrameConfig)方法實(shí)現(xiàn)預(yù)覽幀配置的更新;

   // 預(yù)覽幀變焦值變更
   frameConfigBuilder.setZoom(1.2f);
   // 調(diào)用triggerLoopingCapture方法實(shí)現(xiàn)預(yù)覽幀配置更新
   triggerLoopingCapture(frameConfigBuilder.build());

通過stopLoopingCapture()方法停止循環(huán)幀捕獲(停止預(yù)覽)。

   // 停止預(yù)覽幀捕獲
   camera.stopLoopingCapture(frameConfigBuilder.build())

實(shí)現(xiàn)拍照(單幀捕獲)

拍照功能屬于相機(jī)應(yīng)用的最重要功能之一,而且照片質(zhì)量對用戶至關(guān)重要。相機(jī)模塊基于相機(jī)復(fù)雜的邏輯,從應(yīng)用接口層到器件驅(qū)動(dòng)層都已經(jīng)默認(rèn)的做好了最適合用戶的配置,這些默認(rèn)配置盡可能地保證用戶拍出的每張照片的質(zhì)量。發(fā)起拍照的建議步驟如下:

  1. 通過getFrameConfigBuilder(FRAME_CONFIG_PICTURE)方法獲取拍照配置模板,并且設(shè)置拍照幀配置,如下表:

接口名 描述 是否必選
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) 配置其他屬性(如自拍鏡像等)。 可選

  1. 拍照前準(zhǔn)備圖像幀數(shù)據(jù)的接收實(shí)現(xiàn)。

   // 圖像幀數(shù)據(jù)接收處理對象       
   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è)讀寫線程任務(wù)用于保存圖片
           eventHandler.postTask(imageSaver); // 執(zhí)行讀寫線程任務(wù)生成圖片
       }
   };

    
   // 保存圖片, 圖片數(shù)據(jù)讀寫,及圖像生成見 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); // 寫圖像數(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 對象,注意 creat 函數(shù)中寬度要大于高度;5 為最大支持的圖像數(shù),請根據(jù)實(shí)際設(shè)置。
       imageReceiver.setImageArrivalListener(imageArrivalListener);
   }

  1. 通過 triggerSingleCapture(FrameConfig)方法實(shí)現(xiàn)單幀捕獲(如拍照)。

   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)測自動(dòng)對焦和自動(dòng)曝光的狀態(tài),一般而言,在自動(dòng)對焦完成,自動(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 才能使用。

  1. 錄像前需要進(jìn)行音視頻模塊的配置。

   private Source source; // 音視頻源
   private AudioProperty.Builder audioPropertyBuilder; // 音頻屬性
   private VideoProperty.Builder videoPropertyBuilder; // 視頻屬性
   private StorageProperty.Builder storagePropertyBuilder; // 音視頻存儲屬性
   private Recorder mediaRecorder; // 錄像操作對象
   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)建錄像文件對象
       storagePropertyBuilder.setRecorderFile(file); // 設(shè)置存儲音視頻文件名
       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");
   }

  1. 配置錄像幀,啟動(dòng)錄像。

   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");
           }
       }
   }

  1. 通過 camera.stopLoopingCapture()方法停止循環(huán)幀捕獲(錄像)。

相機(jī)設(shè)備釋放

使用完相機(jī)后,必須通過 release() 來關(guān)閉相機(jī)和釋放資源,否則可能導(dǎo)致其他相機(jī)應(yīng)用無法啟動(dòng)。一旦相機(jī)被釋放,它所提供的操作就不能再被調(diào)用,否則會導(dǎo)致不可預(yù)期的結(jié)果,或是會引發(fā)狀態(tài)異常。

相機(jī)設(shè)備釋放的示例代碼如下:

private void releaseCamera() {
    if (camera != null) {
        // 關(guān)閉相機(jī)和釋放資源
        camera.release();
        camera = null;
    }
    // 拍照配置模板置空
    framePictureConfigBuilder = null;
    // 預(yù)覽配置模板置空
    previewFrameConfig = null;
}
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號