鴻蒙HarmonyOS相機的基本使用實戰(zhàn)
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
相機開發(fā)流程

相機權(quán)限申請
config.json
- "reqPermissions": [
- {"name": "ohos.permission.CAMERA" },
- { "name": "ohos.permission.WRITE_MEDIA"},
- {"name": "ohos.permission.MICROPHONE"},
- { "name": "ohos.permission.MEDIA_LOCATION"}
- ]
MainAbility
- @Override
- public void onStart(Intent intent) {
- super.onStart(intent);
- super.setMainRoute(MainAbilitySlice.class.getName());
- requestPermissions();
- }
- private void requestPermissions() {
- String[] permissions = {
- SystemPermission.CAMERA,
- SystemPermission.MICROPHONE,
- SystemPermission.MEDIA_LOCATION,
- SystemPermission.WRITE_MEDIA
- };
- List<String> permissionFiltered = Arrays.stream(permissions)
- .filter(permission -> verifySelfPermission(permission) != IBundleManager.PERMISSION_GRANTED)
- .collect(Collectors.toList());
- requestPermissionsFromUser(permissionFiltered.toArray(new String[permissionFiltered.size()]), 0);
- }
- @Override
- public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) {
- if (permissions == null || permissions.length == 0 || grantResults == null || grantResults.length == 0) {
- return;
- }
- for (int grantResult : grantResults) {
- if (grantResult != IBundleManager.PERMISSION_GRANTED) {
- terminateAbility();
- break;
- }
- }
}
相機設(shè)備創(chuàng)建
布局文件上添加按鈕:
- <Button
- ohos:id="$+id:create_camera_btn"
- ohos:height="match_content"
- ohos:width="300vp"
- ohos:text="創(chuàng)建相機并配置"
- ohos:text_size="20fp"
- ohos:text_color="#ffffff"
- ohos:background_element="#0000ff"
- ohos:layout_alignment="horizontal_center"
- ohos:top_padding="8vp"
- ohos:bottom_padding="8vp"
- ohos:left_padding="40vp"
- ohos:right_padding="40vp"
- ohos:top_margin="20vp"
- />
按鈕的邏輯代碼:
- private void createCameraBtnFunc(Component component) {
- //openCamera(); //先測試創(chuàng)建相機
- initSurface(); //創(chuàng)建surface,里面包含的openCamera()
- }
- private void openCamera(){
- System.out.println("createCameraBtnFunc start...");
- CameraKit cameraKit = CameraKit.getInstance(getContext());
- if(cameraKit == null){
- System.out.println("cameraKit create error!");
- }
- System.out.println("cameraKit create success!"+cameraKit);
- try {
- // 獲取當(dāng)前設(shè)備的邏輯相機列表
- String[] cameraIds = cameraKit.getCameraIds();
- if (cameraIds.length <= 0) {
- System.out.println("cameraIds size is 0");
- }
- System.out.println("邏輯相機ids:" + Arrays.toString(cameraIds));
- //第一個參數(shù)cameraId
- //第二和第三個參數(shù)負責(zé)相機創(chuàng)建和相機運行時的數(shù)據(jù)和狀態(tài)檢測
- cameraKit.createCamera(cameraIds[0], new CameraStateCallbackImpl(), new EventHandler(EventRunner.create("CameraCb")));
- } catch (IllegalStateException e) {
- // 處理異常
- }
- }
- private class CameraStateCallbackImpl extends CameraStateCallback {
- @Override
- public void onCreated(Camera camera) {
- //創(chuàng)建相機成功的時候回調(diào)
- }
- @Override
- public void onConfigured(Camera camera) {
- }
- }
至此,相機設(shè)備的創(chuàng)建已經(jīng)完成,執(zhí)行成功意味著相機系統(tǒng)的硬件已經(jīng)完成了上電。創(chuàng)建相機設(shè)備成功后,在CameraStateCallback中會觸發(fā)onCreated(Camera camera)回調(diào),并且?guī)Щ谻amera對象,用于執(zhí)行相機設(shè)備的操作。當(dāng)一個新的相機設(shè)備成功創(chuàng)建后,首先需要對相機進行配置,調(diào)用configure(CameraConfig)方法實現(xiàn)配置。
相機設(shè)備配置
相機配置主要是設(shè)置預(yù)覽、拍照、錄像所需要用到的Surface(ohos.agp.graphics.Surface),沒有配置過Surface,相應(yīng)的功能不能使用。為了進行相機幀捕獲結(jié)果的數(shù)據(jù)和狀態(tài)檢測,有時還需要在相機配置時調(diào)用setFrameStateCallback(FrameStateCallback, EventHandler)方法設(shè)置幀回調(diào)。相機配置成功后,在CameraStateCallback中會觸發(fā)onConfigured(Camera camera)回調(diào),然后才可以執(zhí)行相機幀捕獲相關(guān)的操作。
相機配置,布局文件上加一個布局:
- <DirectionalLayout
- ohos:id="$+id:surface_container"
- ohos:height="400vp"
- ohos:width="match_parent"/>
邏輯代碼:
- private SurfaceProvider surfaceProvider;
- private DirectionalLayout surfaceContainer; //定義在最前面
- private void initSurface() {
- getWindow().setTransparent(true);
- DirectionalLayout.LayoutConfig params = new DirectionalLayout.LayoutConfig(
- ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
- surfaceProvider = new SurfaceProvider(this);
- surfaceProvider.setLayoutConfig(params);
- surfaceProvider.pinToZTop(false);
- surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceCallBack());
- surfaceContainer.addComponent(surfaceProvider);
- }
- private class SurfaceCallBack implements SurfaceOps.Callback {
- @Override
- public void surfaceCreated(SurfaceOps callbackSurfaceOps) {
- //surfaceCreated后可以創(chuàng)建相機對象, 按鈕上點擊后執(zhí)行initSurface();
- openCamera();
- }
- @Override
- public void surfaceChanged(SurfaceOps callbackSurfaceOps, int format, int width, int height) {
- }
- @Override
- public void surfaceDestroyed(SurfaceOps callbackSurfaceOps) {
- }
- }
- //在上面的CameraStateCallbackImpl的onCreated方法中添加代碼
- private Camera cameraDevice;
- private Surface previewSurface;
- private CameraConfig.Builder cameraConfigBuilder; //放前面
- private final class CameraStateCallbackImpl extends CameraStateCallback {
- @Override
- public void onCreated(Camera camera) {
- //創(chuàng)建相機成功的時候回調(diào)
- cameraDevice = camera;
- previewSurface = surfaceProvider.getSurfaceOps().get().getSurface();
- cameraConfigBuilder = camera.getCameraConfigBuilder();
- if (cameraConfigBuilder == null) {
- System.out.println("onCreated cameraConfigBuilder is null");
- return;
- }
- // 配置預(yù)覽的Surface
- cameraConfigBuilder.addSurface(previewSurface);
- // 配置幀結(jié)果的回調(diào)
- cameraConfigBuilder.setFrameStateCallback(frameStateCallbackImpl, new EventHandler(EventRunner.create()));
- try {
- // 相機設(shè)備配置
- camera.configure(cameraConfigBuilder.build());
- } catch (IllegalArgumentException e) {
- System.out.println("Argument Exception");
- } catch (IllegalStateException e) {
- System.out.println("State Exception");
- }
- }
- }
- private FrameStateCallback frameStateCallbackImpl = new FrameStateCallback(){
- //....更具需要實現(xiàn)接口里的方法
- };
配置完成后,會回調(diào)public void onConfigured(Camera camera)方法,在這個方法里鋪貨相機拍攝的幀。
相機幀捕獲
用戶一般都是先看見預(yù)覽畫面才執(zhí)行拍照或者其他功能,所以對于一個普通的相機應(yīng)用,預(yù)覽是必不可少的。通過getFrameConfigBuilder(FRAME_CONFIG_PREVIEW)方法獲取預(yù)覽配置模板,更多的幀配置項以及詳細使用方法請參考API接口說明的FrameConfig.Builder部分。
通過triggerLoopingCapture(FrameConfig)方法實現(xiàn)循環(huán)幀捕獲實現(xiàn)預(yù)覽:
- //在CameraStateCallbackImpl的onConfigured添加代碼
- private FrameConfig.Builder frameConfigBuilder;
- private FrameConfig previewFrameConfig;
- private final class CameraStateCallbackImpl extends CameraStateCallback {
- @Override
- public void onConfigured(Camera camera) {
- //配置成功的時候回調(diào)
- // 獲取預(yù)覽配置模板
- frameConfigBuilder = camera.getFrameConfigBuilder(Camera.FrameConfigType.FRAME_CONFIG_PREVIEW);
- // 配置預(yù)覽Surface
- frameConfigBuilder.addSurface(previewSurface);
- previewFrameConfig = frameConfigBuilder.build();
- try {
- // 啟動循環(huán)幀捕獲
- int triggerId = camera.triggerLoopingCapture(previewFrameConfig);
- } catch (IllegalArgumentException e) {
- System.out.println("Argument Exception");
- } catch (IllegalStateException e) {
- System.out.println("State Exception");
- }
- }
- }
經(jīng)過以上的操作,相機應(yīng)用已經(jīng)可以正常進行實時預(yù)覽了。在預(yù)覽狀態(tài)下,開發(fā)者還可以執(zhí)行其他操作,比如:當(dāng)預(yù)覽幀配置更改時,可以通過triggerLoopingCapture(FrameConfig)方法實現(xiàn)預(yù)覽幀配置的更新。
- <Button
- ohos:id="$+id:change_camera_config_btn"
- ohos:height="match_content"
- ohos:width="300vp"
- ohos:text="改變相機焦距配置"
- ohos:text_size="20fp"
- ohos:text_color="#ffffff"
- ohos:background_element="#0000ff"
- ohos:layout_alignment="horizontal_center"
- ohos:top_padding="8vp"
- ohos:bottom_padding="8vp"
- ohos:left_padding="40vp"
- ohos:right_padding="40vp"
- ohos:top_margin="20vp"
- />
- //改變相機焦距配置
- private void changeCameraConfigBtnFunc(Component component) {
- // 預(yù)覽幀變焦值變更
- frameConfigBuilder.setZoom(1.5f);
- // 調(diào)用triggerLoopingCapture方法實現(xiàn)預(yù)覽幀配置更新
- cameraDevice.triggerLoopingCapture(frameConfigBuilder.build());
- }
通過stopLoopingCapture()方法停止循環(huán)幀捕獲(停止預(yù)覽)。
- <Button
- ohos:id="$+id:stop_camera_preview_btn"
- ohos:height="match_content"
- ohos:width="300vp"
- ohos:text="停止相機預(yù)覽"
- ohos:text_size="20fp"
- ohos:text_color="#ffffff"
- ohos:background_element="#0000ff"
- ohos:layout_alignment="horizontal_center"
- ohos:top_padding="8vp"
- ohos:bottom_padding="8vp"
- ohos:left_padding="40vp"
- ohos:right_padding="40vp"
- ohos:top_margin="20vp"
- />
- //停止相機預(yù)覽
- private void stopCameraBtnFunc(Component component) {
- // 停止預(yù)覽幀捕獲
- cameraDevice.stopLoopingCapture();
- }
到這里相機的基本用戶流程,基本搞清楚,使用相機最后一步就是釋放了。
- <Button
- ohos:id="$+id:release_camera_btn"
- ohos:height="match_content"
- ohos:width="300vp"
- ohos:text="釋放相機"
- ohos:text_size="20fp"
- ohos:text_color="#ffffff"
- ohos:background_element="#0000ff"
- ohos:layout_alignment="horizontal_center"
- ohos:top_padding="8vp"
- ohos:bottom_padding="8vp"
- ohos:left_padding="40vp"
- ohos:right_padding="40vp"
- ohos:top_margin="20vp"
- />
- private void releaseCameraBtnFunc(Component component) {
- if (cameraDevice != null) {
- // 關(guān)閉相機和釋放資源
- cameraDevice.release();
- cameraDevice = null;
- }
- // 預(yù)覽配置模板置空
- previewFrameConfig = null;
- }
最后的效果:
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)