From 45454c59f0ab314370fc6a93ece8dfc6cbdb6a17 Mon Sep 17 00:00:00 2001 From: gaohui Date: Fri, 24 Sep 2021 16:54:46 +0800 Subject: [PATCH 1/2] Bug fix Camera Signed-off-by: gaohui --- media/Camera/README_zh.md | 17 +- .../ohos/samples/camera/TakePhotoAbility.java | 237 +-------------- .../samples/camera/VideoRecordAbility.java | 280 +---------------- .../samples/camera/slice/TakePhotoSlice.java | 241 +++++++++++++++ .../camera/slice/VideoRecordSlice.java | 286 ++++++++++++++++++ 5 files changed, 548 insertions(+), 513 deletions(-) create mode 100644 media/Camera/entry/src/main/java/ohos/samples/camera/slice/TakePhotoSlice.java create mode 100644 media/Camera/entry/src/main/java/ohos/samples/camera/slice/VideoRecordSlice.java diff --git a/media/Camera/README_zh.md b/media/Camera/README_zh.md index 7dcbf3c6b9..6e11c975e0 100644 --- a/media/Camera/README_zh.md +++ b/media/Camera/README_zh.md @@ -1,6 +1,17 @@ # 相机 -- 相机模块支持相机业务的开发,开发者可以通过已开放的接口实现相机硬件的访问、操作和新功能开发,最常见的操作如:预览、拍照、连拍和录像等。 +### 简介 - 开发者也可以通过合适的接口或者接口组合实现闪光灯控制、曝光时间控制、手动对焦和自动对焦控制、变焦控制、人脸识别以及更多的功能。 -- 相机模块目前只能支持真机运行调试,不能支持模拟器。 \ No newline at end of file +相机模块支持相机业务的开发,开发者可以通过已开放的接口实现相机硬件的访问、操作和新功能开发,最常见的操作如:预览、拍照、连拍和录像等。 + +开发者也可以通过合适的接口或者接口组合实现闪光灯控制、曝光时间控制、手动对焦和自动对焦控制、变焦控制、人脸识别以及更多的功能。 + +### 使用说明 + +1.点击“Take Photo”,开启拍照功能; + +2.点击“Video Record”,开启录像功能。 + +### 约束与限制 + +本示例仅支持在大型系统上运行。 diff --git a/media/Camera/entry/src/main/java/ohos/samples/camera/TakePhotoAbility.java b/media/Camera/entry/src/main/java/ohos/samples/camera/TakePhotoAbility.java index 7020281a07..a14683f7c2 100644 --- a/media/Camera/entry/src/main/java/ohos/samples/camera/TakePhotoAbility.java +++ b/media/Camera/entry/src/main/java/ohos/samples/camera/TakePhotoAbility.java @@ -15,247 +15,18 @@ package ohos.samples.camera; -import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PICTURE; -import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PREVIEW; - import ohos.aafwk.ability.Ability; import ohos.aafwk.content.Intent; -import ohos.agp.components.Component; -import ohos.agp.components.ComponentContainer; -import ohos.agp.components.DirectionalLayout; -import ohos.agp.components.Image; -import ohos.agp.components.surfaceprovider.SurfaceProvider; -import ohos.agp.graphics.Surface; -import ohos.agp.graphics.SurfaceOps; -import ohos.agp.window.dialog.ToastDialog; -import ohos.app.Context; -import ohos.eventhandler.EventHandler; -import ohos.eventhandler.EventRunner; -import ohos.hiviewdfx.HiLog; -import ohos.hiviewdfx.HiLogLabel; -import ohos.media.camera.CameraKit; -import ohos.media.camera.device.Camera; -import ohos.media.camera.device.CameraConfig; -import ohos.media.camera.device.CameraInfo; -import ohos.media.camera.device.CameraStateCallback; -import ohos.media.camera.device.FrameConfig; -import ohos.media.image.ImageReceiver; -import ohos.media.image.common.ImageFormat; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import ohos.samples.camera.slice.TakePhotoSlice; /** * TakePhotoAbility */ public class TakePhotoAbility extends Ability { - private static final String TAG = TakePhotoAbility.class.getSimpleName(); - - private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD000F00, TAG); - - private static final int SCREEN_WIDTH = 1080; - - private static final int SCREEN_HEIGHT = 1920; - - private static final int IMAGE_RCV_CAPACITY = 9; - - private SurfaceProvider surfaceProvider; - - private ImageReceiver imageReceiver; - - private boolean isFrontCamera; - - private Surface previewSurface; - - private Camera cameraDevice; - - private Component buttonGroupLayout; - - private ComponentContainer surfaceContainer; - - private final EventHandler eventHandler = new EventHandler(EventRunner.current()) { - }; - - @Override - public void onStart(Intent intent) { - super.onStart(intent); - super.setUIContent(ResourceTable.Layout_main_camera_slice); - - initComponents(); - initSurface(); - } - - 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); - if (surfaceProvider.getSurfaceOps().isPresent()) { - surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceCallBack()); - } - surfaceContainer.addComponent(surfaceProvider); - } - - private void initComponents() { - buttonGroupLayout = findComponentById(ResourceTable.Id_directionalLayout); - surfaceContainer = (ComponentContainer) findComponentById(ResourceTable.Id_surface_container); - Image takePhotoImage = (Image) findComponentById(ResourceTable.Id_tack_picture_btn); - Image exitImage = (Image) findComponentById(ResourceTable.Id_exit); - Image switchCameraImage = (Image) findComponentById(ResourceTable.Id_switch_camera_btn); - exitImage.setClickedListener(component -> terminateAbility()); - takePhotoImage.setClickedListener(this::takeSingleCapture); - takePhotoImage.setLongClickedListener(this::takeMultiCapture); - switchCameraImage.setClickedListener(this::switchCamera); - } - - private void openCamera() { - imageReceiver = ImageReceiver.create(SCREEN_WIDTH, SCREEN_HEIGHT, ImageFormat.JPEG, IMAGE_RCV_CAPACITY); - imageReceiver.setImageArrivalListener(this::saveImage); - CameraKit cameraKit = CameraKit.getInstance(getApplicationContext()); - String[] cameraList = cameraKit.getCameraIds(); - String cameraId = ""; - for (String logicalCameraId : cameraList) { - int faceType = cameraKit.getCameraInfo(logicalCameraId).getFacingType(); - switch (faceType) { - case CameraInfo.FacingType.CAMERA_FACING_FRONT: - if (isFrontCamera) { - cameraId = logicalCameraId; - } - break; - case CameraInfo.FacingType.CAMERA_FACING_BACK: - if (!isFrontCamera) { - cameraId = logicalCameraId; - } - break; - case CameraInfo.FacingType.CAMERA_FACING_OTHERS: - default: - break; - } - } - if (cameraId != null && !cameraId.isEmpty()) { - CameraStateCallbackImpl cameraStateCallback = new CameraStateCallbackImpl(); - cameraKit.createCamera(cameraId, cameraStateCallback, eventHandler); - } - } - - private void saveImage(ImageReceiver receiver) { - File saveFile = new File(getFilesDir(), "IMG_" + System.currentTimeMillis() + ".jpg"); - ohos.media.image.Image image = receiver.readNextImage(); - ohos.media.image.Image.Component component = image.getComponent(ImageFormat.ComponentType.JPEG); - byte[] bytes = new byte[component.remaining()]; - component.read(bytes); - try (FileOutputStream output = new FileOutputStream(saveFile)) { - output.write(bytes); - output.flush(); - String msg = "Take photo succeed"; - showTips(this, msg); - } catch (IOException e) { - HiLog.error(LABEL_LOG, "%{public}s", "saveImage IOException"); - } - } - - private void takeSingleCapture(Component component) { - if (cameraDevice == null || imageReceiver == null) { - return; - } - FrameConfig.Builder framePictureConfigBuilder = cameraDevice.getFrameConfigBuilder(FRAME_CONFIG_PICTURE); - framePictureConfigBuilder.addSurface(imageReceiver.getRecevingSurface()); - FrameConfig pictureFrameConfig = framePictureConfigBuilder.build(); - cameraDevice.triggerSingleCapture(pictureFrameConfig); - } - - private void takeMultiCapture(Component component) { - FrameConfig.Builder framePictureConfigBuilder = cameraDevice.getFrameConfigBuilder(FRAME_CONFIG_PICTURE); - framePictureConfigBuilder.addSurface(imageReceiver.getRecevingSurface()); - List frameConfigs = new ArrayList<>(); - FrameConfig firstFrameConfig = framePictureConfigBuilder.build(); - frameConfigs.add(firstFrameConfig); - FrameConfig secondFrameConfig = framePictureConfigBuilder.build(); - frameConfigs.add(secondFrameConfig); - cameraDevice.triggerMultiCapture(frameConfigs); - } - - private void switchCamera(Component component) { - isFrontCamera = !isFrontCamera; - if (cameraDevice != null) { - cameraDevice.release(); - } - updateComponentVisible(false); - openCamera(); - } - - private class CameraStateCallbackImpl extends CameraStateCallback { - CameraStateCallbackImpl() { - } - - @Override - public void onCreated(Camera camera) { - if (surfaceProvider.getSurfaceOps().isPresent()) { - previewSurface = surfaceProvider.getSurfaceOps().get().getSurface(); - } - if (previewSurface == null) { - HiLog.error(LABEL_LOG, "%{public}s", "Create camera filed, preview surface is null"); - return; - } - CameraConfig.Builder cameraConfigBuilder = camera.getCameraConfigBuilder(); - cameraConfigBuilder.addSurface(previewSurface); - cameraConfigBuilder.addSurface(imageReceiver.getRecevingSurface()); - camera.configure(cameraConfigBuilder.build()); - cameraDevice = camera; - updateComponentVisible(true); - } - - @Override - public void onConfigured(Camera camera) { - FrameConfig.Builder framePreviewConfigBuilder = camera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW); - framePreviewConfigBuilder.addSurface(previewSurface); - camera.triggerLoopingCapture(framePreviewConfigBuilder.build()); - } - } - - private void updateComponentVisible(boolean isVisible) { - buttonGroupLayout.setVisibility(isVisible ? Component.VISIBLE : Component.INVISIBLE); - } - - private class SurfaceCallBack implements SurfaceOps.Callback { - @Override - public void surfaceCreated(SurfaceOps callbackSurfaceOps) { - if (callbackSurfaceOps != null) { - callbackSurfaceOps.setFixedSize(SCREEN_HEIGHT, SCREEN_WIDTH); - } - eventHandler.postTask(TakePhotoAbility.this::openCamera, 200); - } - - @Override - public void surfaceChanged(SurfaceOps callbackSurfaceOps, int format, int width, int height) { - } - - @Override - public void surfaceDestroyed(SurfaceOps callbackSurfaceOps) { - } - } - - private void showTips(Context context, String msg) { - getUITaskDispatcher().asyncDispatch(() -> new ToastDialog(context).setText(msg).show()); - } - - private void releaseCamera() { - if (cameraDevice != null) { - cameraDevice.release(); - } - - if (imageReceiver != null) { - imageReceiver.release(); - } - } @Override - protected void onStop() { - releaseCamera(); + public void onStart (Intent intent) { + super.onStart(intent); + super.setMainRoute(TakePhotoSlice.class.getName()); } } diff --git a/media/Camera/entry/src/main/java/ohos/samples/camera/VideoRecordAbility.java b/media/Camera/entry/src/main/java/ohos/samples/camera/VideoRecordAbility.java index 1b4159c1d3..f5b247586b 100644 --- a/media/Camera/entry/src/main/java/ohos/samples/camera/VideoRecordAbility.java +++ b/media/Camera/entry/src/main/java/ohos/samples/camera/VideoRecordAbility.java @@ -15,291 +15,17 @@ package ohos.samples.camera; -import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PREVIEW; - import ohos.aafwk.ability.Ability; import ohos.aafwk.content.Intent; -import ohos.agp.components.Component; -import ohos.agp.components.ComponentContainer; -import ohos.agp.components.DirectionalLayout; -import ohos.agp.components.Image; -import ohos.agp.components.surfaceprovider.SurfaceProvider; -import ohos.agp.graphics.Surface; -import ohos.agp.graphics.SurfaceOps; -import ohos.agp.window.dialog.ToastDialog; -import ohos.eventhandler.EventHandler; -import ohos.eventhandler.EventRunner; -import ohos.hiviewdfx.HiLog; -import ohos.hiviewdfx.HiLogLabel; -import ohos.media.camera.CameraKit; -import ohos.media.camera.device.Camera; -import ohos.media.camera.device.CameraConfig; -import ohos.media.camera.device.CameraInfo; -import ohos.media.camera.device.CameraStateCallback; -import ohos.media.camera.device.FrameConfig; -import ohos.media.common.AudioProperty; -import ohos.media.common.Source; -import ohos.media.common.StorageProperty; -import ohos.media.common.VideoProperty; -import ohos.media.recorder.Recorder; -import ohos.multimodalinput.event.TouchEvent; - -import java.io.File; +import ohos.samples.camera.slice.VideoRecordSlice; /** * VideoRecordAbility */ public class VideoRecordAbility extends Ability { - private static final String TAG = VideoRecordAbility.class.getSimpleName(); - - private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD000F00, TAG); - - private static final int SCREEN_WIDTH = 1080; - - private static final int SCREEN_HEIGHT = 1920; - - private SurfaceProvider surfaceProvider; - - private Surface recorderSurface; - - private Surface previewSurface; - - private boolean isFrontCamera; - - private Camera cameraDevice; - - private Component buttonGroupLayout; - - private Recorder mediaRecorder; - - private ComponentContainer surfaceContainer; - private CameraConfig.Builder cameraConfigBuilder; - - private boolean isRecording; - - private final Object lock = new Object(); - - private final EventHandler eventHandler = new EventHandler(EventRunner.current()) { - }; - - @Override - public void onStart(Intent intent) { + public void onStart (Intent intent) { super.onStart(intent); - super.setUIContent(ResourceTable.Layout_main_camera_slice); - - initComponents(); - initSurface(); - } - - 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); - if (surfaceProvider.getSurfaceOps().isPresent()) { - surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceCallBack()); - } - surfaceContainer.addComponent(surfaceProvider); - } - - private void initComponents() { - buttonGroupLayout = findComponentById(ResourceTable.Id_directionalLayout); - surfaceContainer = (ComponentContainer) findComponentById(ResourceTable.Id_surface_container); - Image videoRecord = (Image) findComponentById(ResourceTable.Id_tack_picture_btn); - Image exitImage = (Image) findComponentById(ResourceTable.Id_exit); - Image switchCameraImage = (Image) findComponentById(ResourceTable.Id_switch_camera_btn); - exitImage.setClickedListener(component -> terminateAbility()); - switchCameraImage.setClickedListener(this::switchCamera); - - videoRecord.setLongClickedListener(component -> { - startRecord(); - isRecording = true; - videoRecord.setPixelMap(ResourceTable.Media_ic_camera_video_press); - }); - - videoRecord.setTouchEventListener((component, touchEvent) -> { - if (touchEvent != null && touchEvent.getAction() == TouchEvent.PRIMARY_POINT_UP && isRecording) { - stopRecord(); - isRecording = false; - videoRecord.setPixelMap(ResourceTable.Media_ic_camera_video_ready); - } - return true; - }); - } - - private void initMediaRecorder() { - mediaRecorder = new Recorder(); - VideoProperty.Builder videoPropertyBuilder = new VideoProperty.Builder(); - videoPropertyBuilder.setRecorderBitRate(10000000); - videoPropertyBuilder.setRecorderDegrees(90); - videoPropertyBuilder.setRecorderFps(30); - videoPropertyBuilder.setRecorderHeight(Math.min(1440, 720)); - videoPropertyBuilder.setRecorderWidth(Math.max(1440, 720)); - videoPropertyBuilder.setRecorderVideoEncoder(Recorder.VideoEncoder.H264); - videoPropertyBuilder.setRecorderRate(30); - - Source source = new Source(); - source.setRecorderAudioSource(Recorder.AudioSource.MIC); - source.setRecorderVideoSource(Recorder.VideoSource.SURFACE); - mediaRecorder.setSource(source); - mediaRecorder.setOutputFormat(Recorder.OutputFormat.MPEG_4); - File file = new File(getFilesDir(), "VID_" + System.currentTimeMillis() + ".mp4"); - StorageProperty.Builder storagePropertyBuilder = new StorageProperty.Builder(); - storagePropertyBuilder.setRecorderFile(file); - mediaRecorder.setStorageProperty(storagePropertyBuilder.build()); - - AudioProperty.Builder audioPropertyBuilder = new AudioProperty.Builder(); - audioPropertyBuilder.setRecorderAudioEncoder(Recorder.AudioEncoder.AAC); - mediaRecorder.setAudioProperty(audioPropertyBuilder.build()); - mediaRecorder.setVideoProperty(videoPropertyBuilder.build()); - mediaRecorder.prepare(); - } - - private void openCamera() { - CameraKit cameraKit = CameraKit.getInstance(getApplicationContext()); - String[] cameraList = cameraKit.getCameraIds(); - String cameraId = ""; - for (String logicalCameraId : cameraList) { - int faceType = cameraKit.getCameraInfo(logicalCameraId).getFacingType(); - switch (faceType) { - case CameraInfo.FacingType.CAMERA_FACING_FRONT: - if (isFrontCamera) { - cameraId = logicalCameraId; - } - break; - case CameraInfo.FacingType.CAMERA_FACING_BACK: - if (!isFrontCamera) { - cameraId = logicalCameraId; - } - break; - case CameraInfo.FacingType.CAMERA_FACING_OTHERS: - default: - break; - } - } - if (cameraId != null && !cameraId.isEmpty()) { - CameraStateCallbackImpl cameraStateCallback = new CameraStateCallbackImpl(); - cameraKit.createCamera(cameraId, cameraStateCallback, eventHandler); - } - } - - private void switchCamera(Component component) { - isFrontCamera = !isFrontCamera; - if (cameraDevice != null) { - cameraDevice.release(); - } - updateComponentVisible(false); - openCamera(); - } - - private class CameraStateCallbackImpl extends CameraStateCallback { - CameraStateCallbackImpl() { - } - - @Override - public void onCreated(Camera camera) { - if (surfaceProvider.getSurfaceOps().isPresent()) { - previewSurface = surfaceProvider.getSurfaceOps().get().getSurface(); - } - if (previewSurface == null) { - HiLog.error(LABEL_LOG, "%{public}s", "Create camera filed, preview surface is null"); - return; - } - cameraConfigBuilder = camera.getCameraConfigBuilder(); - cameraConfigBuilder.addSurface(previewSurface); - camera.configure(cameraConfigBuilder.build()); - cameraDevice = camera; - updateComponentVisible(true); - } - - @Override - public void onConfigured(Camera camera) { - FrameConfig.Builder frameConfigBuilder = camera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW); - frameConfigBuilder.addSurface(previewSurface); - if (isRecording && recorderSurface != null) { - frameConfigBuilder.addSurface(recorderSurface); - } - camera.triggerLoopingCapture(frameConfigBuilder.build()); - if (isRecording) { - eventHandler.postTask(() -> mediaRecorder.start()); - } - } - } - - private void startRecord() { - if (cameraDevice == null) { - HiLog.error(LABEL_LOG, "%{public}s", "startRecord failed, parameters is illegal"); - return; - } - synchronized (lock) { - initMediaRecorder(); - recorderSurface = mediaRecorder.getVideoSurface(); - cameraConfigBuilder = cameraDevice.getCameraConfigBuilder(); - try { - cameraConfigBuilder.addSurface(previewSurface); - if (recorderSurface != null) { - cameraConfigBuilder.addSurface(recorderSurface); - } - cameraDevice.configure(cameraConfigBuilder.build()); - } catch (IllegalStateException | IllegalArgumentException e) { - HiLog.error(LABEL_LOG, "%{public}s", "startRecord IllegalStateException | IllegalArgumentException"); - } - } - new ToastDialog(this).setText("Recording").show(); - } - - private void stopRecord() { - synchronized (lock) { - try { - eventHandler.postTask(() -> mediaRecorder.stop()); - if (cameraDevice == null || cameraDevice.getCameraConfigBuilder() == null) { - HiLog.error(LABEL_LOG, "%{public}s", "StopRecord cameraDevice or getCameraConfigBuilder is null"); - return; - } - cameraConfigBuilder = cameraDevice.getCameraConfigBuilder(); - cameraConfigBuilder.addSurface(previewSurface); - cameraConfigBuilder.removeSurface(recorderSurface); - cameraDevice.configure(cameraConfigBuilder.build()); - } catch (IllegalStateException | IllegalArgumentException exception) { - HiLog.error(LABEL_LOG, "%{public}s", "stopRecord occur exception"); - } - } - new ToastDialog(this).setText("video saved").show(); - } - - private void updateComponentVisible(boolean isVisible) { - buttonGroupLayout.setVisibility(isVisible ? Component.VISIBLE : Component.INVISIBLE); - } - - private class SurfaceCallBack implements SurfaceOps.Callback { - @Override - public void surfaceCreated(SurfaceOps callbackSurfaceOps) { - if (callbackSurfaceOps != null) { - callbackSurfaceOps.setFixedSize(SCREEN_HEIGHT, SCREEN_WIDTH); - } - eventHandler.postTask(VideoRecordAbility.this::openCamera, 200); - } - - @Override - public void surfaceChanged(SurfaceOps callbackSurfaceOps, int format, int width, int height) { - } - - @Override - public void surfaceDestroyed(SurfaceOps callbackSurfaceOps) { - } - } - - private void releaseCamera() { - if (cameraDevice != null) { - cameraDevice.release(); - } - } - - @Override - protected void onStop() { - releaseCamera(); + super.setMainRoute(VideoRecordSlice.class.getName()); } } diff --git a/media/Camera/entry/src/main/java/ohos/samples/camera/slice/TakePhotoSlice.java b/media/Camera/entry/src/main/java/ohos/samples/camera/slice/TakePhotoSlice.java new file mode 100644 index 0000000000..144b4e4ac4 --- /dev/null +++ b/media/Camera/entry/src/main/java/ohos/samples/camera/slice/TakePhotoSlice.java @@ -0,0 +1,241 @@ +package ohos.samples.camera.slice; + +import ohos.aafwk.ability.AbilitySlice; +import ohos.aafwk.content.Intent; +import ohos.agp.components.Component; +import ohos.agp.components.ComponentContainer; +import ohos.agp.components.DirectionalLayout; +import ohos.agp.components.Image; +import ohos.agp.components.surfaceprovider.SurfaceProvider; +import ohos.agp.graphics.Surface; +import ohos.agp.graphics.SurfaceOps; +import ohos.agp.window.dialog.ToastDialog; +import ohos.app.Context; +import ohos.eventhandler.EventHandler; +import ohos.eventhandler.EventRunner; +import ohos.hiviewdfx.HiLog; +import ohos.hiviewdfx.HiLogLabel; +import ohos.media.camera.CameraKit; +import ohos.media.camera.device.*; +import ohos.media.image.ImageReceiver; +import ohos.media.image.common.ImageFormat; +import ohos.samples.camera.ResourceTable; +import ohos.samples.camera.TakePhotoAbility; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PICTURE; +import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PREVIEW; + +public class TakePhotoSlice extends AbilitySlice { + private static final String TAG = TakePhotoAbility.class.getSimpleName(); + + private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD000F00, TAG); + + private static final int SCREEN_WIDTH = 1080; + + private static final int SCREEN_HEIGHT = 1920; + + private static final int IMAGE_RCV_CAPACITY = 9; + + private SurfaceProvider surfaceProvider; + + private ImageReceiver imageReceiver; + + private boolean isFrontCamera; + + private Surface previewSurface; + + private Camera cameraDevice; + + private Component buttonGroupLayout; + + private ComponentContainer surfaceContainer; + + private final EventHandler eventHandler = new EventHandler(EventRunner.current()) { + }; + + @Override + public void onStart(Intent intent) { + super.onStart(intent); + super.setUIContent(ResourceTable.Layout_main_camera_slice); + + initComponents(); + initSurface(); + } + + 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); + if (surfaceProvider.getSurfaceOps().isPresent()) { + surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceCallBack()); + } + surfaceContainer.addComponent(surfaceProvider); + } + + private void initComponents() { + buttonGroupLayout = findComponentById(ResourceTable.Id_directionalLayout); + surfaceContainer = (ComponentContainer) findComponentById(ResourceTable.Id_surface_container); + Image takePhotoImage = (Image) findComponentById(ResourceTable.Id_tack_picture_btn); + Image exitImage = (Image) findComponentById(ResourceTable.Id_exit); + Image switchCameraImage = (Image) findComponentById(ResourceTable.Id_switch_camera_btn); + exitImage.setClickedListener(component -> terminateAbility()); + takePhotoImage.setClickedListener(this::takeSingleCapture); + takePhotoImage.setLongClickedListener(this::takeMultiCapture); + switchCameraImage.setClickedListener(this::switchCamera); + } + + private void openCamera() { + imageReceiver = ImageReceiver.create(SCREEN_WIDTH, SCREEN_HEIGHT, ImageFormat.JPEG, IMAGE_RCV_CAPACITY); + imageReceiver.setImageArrivalListener(this::saveImage); + CameraKit cameraKit = CameraKit.getInstance(getApplicationContext()); + String[] cameraList = cameraKit.getCameraIds(); + String cameraId = ""; + for (String logicalCameraId : cameraList) { + int faceType = cameraKit.getCameraInfo(logicalCameraId).getFacingType(); + switch (faceType) { + case CameraInfo.FacingType.CAMERA_FACING_FRONT: + if (isFrontCamera) { + cameraId = logicalCameraId; + } + break; + case CameraInfo.FacingType.CAMERA_FACING_BACK: + if (!isFrontCamera) { + cameraId = logicalCameraId; + } + break; + case CameraInfo.FacingType.CAMERA_FACING_OTHERS: + default: + break; + } + } + if (cameraId != null && !cameraId.isEmpty()) { + CameraStateCallbackImpl cameraStateCallback = new CameraStateCallbackImpl(); + cameraKit.createCamera(cameraId, cameraStateCallback, eventHandler); + } + } + + private void saveImage(ImageReceiver receiver) { + File saveFile = new File(getFilesDir(), "IMG_" + System.currentTimeMillis() + ".jpg"); + ohos.media.image.Image image = receiver.readNextImage(); + ohos.media.image.Image.Component component = image.getComponent(ImageFormat.ComponentType.JPEG); + byte[] bytes = new byte[component.remaining()]; + component.read(bytes); + try (FileOutputStream output = new FileOutputStream(saveFile)) { + output.write(bytes); + output.flush(); + String msg = "Take photo succeed"; + showTips(this, msg); + } catch (IOException e) { + HiLog.error(LABEL_LOG, "%{public}s", "saveImage IOException"); + } + } + + private void takeSingleCapture(Component component) { + if (cameraDevice == null || imageReceiver == null) { + return; + } + FrameConfig.Builder framePictureConfigBuilder = cameraDevice.getFrameConfigBuilder(FRAME_CONFIG_PICTURE); + framePictureConfigBuilder.addSurface(imageReceiver.getRecevingSurface()); + FrameConfig pictureFrameConfig = framePictureConfigBuilder.build(); + cameraDevice.triggerSingleCapture(pictureFrameConfig); + } + + private void takeMultiCapture(Component component) { + FrameConfig.Builder framePictureConfigBuilder = cameraDevice.getFrameConfigBuilder(FRAME_CONFIG_PICTURE); + framePictureConfigBuilder.addSurface(imageReceiver.getRecevingSurface()); + List frameConfigs = new ArrayList<>(); + FrameConfig firstFrameConfig = framePictureConfigBuilder.build(); + frameConfigs.add(firstFrameConfig); + FrameConfig secondFrameConfig = framePictureConfigBuilder.build(); + frameConfigs.add(secondFrameConfig); + cameraDevice.triggerMultiCapture(frameConfigs); + } + + private void switchCamera(Component component) { + isFrontCamera = !isFrontCamera; + if (cameraDevice != null) { + cameraDevice.release(); + } + updateComponentVisible(false); + openCamera(); + } + + private class CameraStateCallbackImpl extends CameraStateCallback { + CameraStateCallbackImpl() { + } + + @Override + public void onCreated(Camera camera) { + if (surfaceProvider.getSurfaceOps().isPresent()) { + previewSurface = surfaceProvider.getSurfaceOps().get().getSurface(); + } + if (previewSurface == null) { + HiLog.error(LABEL_LOG, "%{public}s", "Create camera filed, preview surface is null"); + return; + } + CameraConfig.Builder cameraConfigBuilder = camera.getCameraConfigBuilder(); + cameraConfigBuilder.addSurface(previewSurface); + cameraConfigBuilder.addSurface(imageReceiver.getRecevingSurface()); + camera.configure(cameraConfigBuilder.build()); + cameraDevice = camera; + updateComponentVisible(true); + } + + @Override + public void onConfigured(Camera camera) { + FrameConfig.Builder framePreviewConfigBuilder = camera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW); + framePreviewConfigBuilder.addSurface(previewSurface); + camera.triggerLoopingCapture(framePreviewConfigBuilder.build()); + } + } + + private void updateComponentVisible(boolean isVisible) { + buttonGroupLayout.setVisibility(isVisible ? Component.VISIBLE : Component.INVISIBLE); + } + + private class SurfaceCallBack implements SurfaceOps.Callback { + @Override + public void surfaceCreated(SurfaceOps callbackSurfaceOps) { + if (callbackSurfaceOps != null) { + callbackSurfaceOps.setFixedSize(SCREEN_HEIGHT, SCREEN_WIDTH); + } + eventHandler.postTask(TakePhotoSlice.this::openCamera, 200); + } + + @Override + public void surfaceChanged(SurfaceOps callbackSurfaceOps, int format, int width, int height) { + } + + @Override + public void surfaceDestroyed(SurfaceOps callbackSurfaceOps) { + } + } + + private void showTips(Context context, String msg) { + getUITaskDispatcher().asyncDispatch(() -> new ToastDialog(context).setText(msg).show()); + } + + private void releaseCamera() { + if (cameraDevice != null) { + cameraDevice.release(); + } + + if (imageReceiver != null) { + imageReceiver.release(); + } + } + + @Override + protected void onStop() { + releaseCamera(); + } +} diff --git a/media/Camera/entry/src/main/java/ohos/samples/camera/slice/VideoRecordSlice.java b/media/Camera/entry/src/main/java/ohos/samples/camera/slice/VideoRecordSlice.java new file mode 100644 index 0000000000..2048c8adf7 --- /dev/null +++ b/media/Camera/entry/src/main/java/ohos/samples/camera/slice/VideoRecordSlice.java @@ -0,0 +1,286 @@ +package ohos.samples.camera.slice; + +import ohos.aafwk.ability.AbilitySlice; +import ohos.aafwk.content.Intent; +import ohos.agp.components.Component; +import ohos.agp.components.ComponentContainer; +import ohos.agp.components.DirectionalLayout; +import ohos.agp.components.Image; +import ohos.agp.components.surfaceprovider.SurfaceProvider; +import ohos.agp.graphics.Surface; +import ohos.agp.graphics.SurfaceOps; +import ohos.agp.window.dialog.ToastDialog; +import ohos.eventhandler.EventHandler; +import ohos.eventhandler.EventRunner; +import ohos.hiviewdfx.HiLog; +import ohos.hiviewdfx.HiLogLabel; +import ohos.media.camera.CameraKit; +import ohos.media.camera.device.*; +import ohos.media.common.AudioProperty; +import ohos.media.common.Source; +import ohos.media.common.StorageProperty; +import ohos.media.common.VideoProperty; +import ohos.media.recorder.Recorder; +import ohos.multimodalinput.event.TouchEvent; +import ohos.samples.camera.ResourceTable; +import ohos.samples.camera.VideoRecordAbility; + +import java.io.File; + +import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PREVIEW; + +public class VideoRecordSlice extends AbilitySlice { + private static final String TAG = VideoRecordAbility.class.getSimpleName(); + + private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD000F00, TAG); + + private static final int SCREEN_WIDTH = 1080; + + private static final int SCREEN_HEIGHT = 1920; + + private SurfaceProvider surfaceProvider; + + private Surface recorderSurface; + + private Surface previewSurface; + + private boolean isFrontCamera; + + private Camera cameraDevice; + + private Component buttonGroupLayout; + + private Recorder mediaRecorder; + + private ComponentContainer surfaceContainer; + + private CameraConfig.Builder cameraConfigBuilder; + + private boolean isRecording; + + private final Object lock = new Object(); + + private final EventHandler eventHandler = new EventHandler(EventRunner.current()) { + }; + + @Override + public void onStart(Intent intent) { + super.onStart(intent); + super.setUIContent(ResourceTable.Layout_main_camera_slice); + + initComponents(); + initSurface(); + } + + 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); + if (surfaceProvider.getSurfaceOps().isPresent()) { + surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceCallBack()); + } + surfaceContainer.addComponent(surfaceProvider); + } + + private void initComponents() { + buttonGroupLayout = findComponentById(ResourceTable.Id_directionalLayout); + surfaceContainer = (ComponentContainer) findComponentById(ResourceTable.Id_surface_container); + Image videoRecord = (Image) findComponentById(ResourceTable.Id_tack_picture_btn); + Image exitImage = (Image) findComponentById(ResourceTable.Id_exit); + Image switchCameraImage = (Image) findComponentById(ResourceTable.Id_switch_camera_btn); + exitImage.setClickedListener(component -> terminateAbility()); + switchCameraImage.setClickedListener(this::switchCamera); + + videoRecord.setLongClickedListener(component -> { + startRecord(); + isRecording = true; + videoRecord.setPixelMap(ResourceTable.Media_ic_camera_video_press); + }); + + videoRecord.setTouchEventListener((component, touchEvent) -> { + if (touchEvent != null && touchEvent.getAction() == TouchEvent.PRIMARY_POINT_UP && isRecording) { + stopRecord(); + isRecording = false; + videoRecord.setPixelMap(ResourceTable.Media_ic_camera_video_ready); + } + return true; + }); + } + + private void initMediaRecorder() { + mediaRecorder = new Recorder(); + VideoProperty.Builder videoPropertyBuilder = new VideoProperty.Builder(); + videoPropertyBuilder.setRecorderBitRate(10000000); + videoPropertyBuilder.setRecorderDegrees(90); + videoPropertyBuilder.setRecorderFps(30); + videoPropertyBuilder.setRecorderHeight(Math.min(1440, 720)); + videoPropertyBuilder.setRecorderWidth(Math.max(1440, 720)); + videoPropertyBuilder.setRecorderVideoEncoder(Recorder.VideoEncoder.H264); + videoPropertyBuilder.setRecorderRate(30); + + Source source = new Source(); + source.setRecorderAudioSource(Recorder.AudioSource.MIC); + source.setRecorderVideoSource(Recorder.VideoSource.SURFACE); + mediaRecorder.setSource(source); + mediaRecorder.setOutputFormat(Recorder.OutputFormat.MPEG_4); + File file = new File(getFilesDir(), "VID_" + System.currentTimeMillis() + ".mp4"); + StorageProperty.Builder storagePropertyBuilder = new StorageProperty.Builder(); + storagePropertyBuilder.setRecorderFile(file); + mediaRecorder.setStorageProperty(storagePropertyBuilder.build()); + + AudioProperty.Builder audioPropertyBuilder = new AudioProperty.Builder(); + audioPropertyBuilder.setRecorderAudioEncoder(Recorder.AudioEncoder.AAC); + mediaRecorder.setAudioProperty(audioPropertyBuilder.build()); + mediaRecorder.setVideoProperty(videoPropertyBuilder.build()); + mediaRecorder.prepare(); + } + + private void openCamera() { + CameraKit cameraKit = CameraKit.getInstance(getApplicationContext()); + String[] cameraList = cameraKit.getCameraIds(); + String cameraId = ""; + for (String logicalCameraId : cameraList) { + int faceType = cameraKit.getCameraInfo(logicalCameraId).getFacingType(); + switch (faceType) { + case CameraInfo.FacingType.CAMERA_FACING_FRONT: + if (isFrontCamera) { + cameraId = logicalCameraId; + } + break; + case CameraInfo.FacingType.CAMERA_FACING_BACK: + if (!isFrontCamera) { + cameraId = logicalCameraId; + } + break; + case CameraInfo.FacingType.CAMERA_FACING_OTHERS: + default: + break; + } + } + if (cameraId != null && !cameraId.isEmpty()) { + CameraStateCallbackImpl cameraStateCallback = new CameraStateCallbackImpl(); + cameraKit.createCamera(cameraId, cameraStateCallback, eventHandler); + } + } + + private void switchCamera(Component component) { + isFrontCamera = !isFrontCamera; + if (cameraDevice != null) { + cameraDevice.release(); + } + updateComponentVisible(false); + openCamera(); + } + + private class CameraStateCallbackImpl extends CameraStateCallback { + CameraStateCallbackImpl() { + } + + @Override + public void onCreated(Camera camera) { + if (surfaceProvider.getSurfaceOps().isPresent()) { + previewSurface = surfaceProvider.getSurfaceOps().get().getSurface(); + } + if (previewSurface == null) { + HiLog.error(LABEL_LOG, "%{public}s", "Create camera filed, preview surface is null"); + return; + } + cameraConfigBuilder = camera.getCameraConfigBuilder(); + cameraConfigBuilder.addSurface(previewSurface); + camera.configure(cameraConfigBuilder.build()); + cameraDevice = camera; + updateComponentVisible(true); + } + + @Override + public void onConfigured(Camera camera) { + FrameConfig.Builder frameConfigBuilder = camera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW); + frameConfigBuilder.addSurface(previewSurface); + if (isRecording && recorderSurface != null) { + frameConfigBuilder.addSurface(recorderSurface); + } + camera.triggerLoopingCapture(frameConfigBuilder.build()); + if (isRecording) { + eventHandler.postTask(() -> mediaRecorder.start()); + } + } + } + + private void startRecord() { + if (cameraDevice == null) { + HiLog.error(LABEL_LOG, "%{public}s", "startRecord failed, parameters is illegal"); + return; + } + synchronized (lock) { + initMediaRecorder(); + recorderSurface = mediaRecorder.getVideoSurface(); + cameraConfigBuilder = cameraDevice.getCameraConfigBuilder(); + try { + cameraConfigBuilder.addSurface(previewSurface); + if (recorderSurface != null) { + cameraConfigBuilder.addSurface(recorderSurface); + } + cameraDevice.configure(cameraConfigBuilder.build()); + } catch (IllegalStateException | IllegalArgumentException e) { + HiLog.error(LABEL_LOG, "%{public}s", "startRecord IllegalStateException | IllegalArgumentException"); + } + } + new ToastDialog(this).setText("Recording").show(); + } + + private void stopRecord() { + synchronized (lock) { + try { + eventHandler.postTask(() -> mediaRecorder.stop()); + if (cameraDevice == null || cameraDevice.getCameraConfigBuilder() == null) { + HiLog.error(LABEL_LOG, "%{public}s", "StopRecord cameraDevice or getCameraConfigBuilder is null"); + return; + } + cameraConfigBuilder = cameraDevice.getCameraConfigBuilder(); + cameraConfigBuilder.addSurface(previewSurface); + cameraConfigBuilder.removeSurface(recorderSurface); + cameraDevice.configure(cameraConfigBuilder.build()); + } catch (IllegalStateException | IllegalArgumentException exception) { + HiLog.error(LABEL_LOG, "%{public}s", "stopRecord occur exception"); + } + } + new ToastDialog(this).setText("video saved").show(); + } + + private void updateComponentVisible(boolean isVisible) { + buttonGroupLayout.setVisibility(isVisible ? Component.VISIBLE : Component.INVISIBLE); + } + + private class SurfaceCallBack implements SurfaceOps.Callback { + @Override + public void surfaceCreated(SurfaceOps callbackSurfaceOps) { + if (callbackSurfaceOps != null) { + callbackSurfaceOps.setFixedSize(SCREEN_HEIGHT, SCREEN_WIDTH); + } + eventHandler.postTask(VideoRecordSlice.this::openCamera, 200); + } + + @Override + public void surfaceChanged(SurfaceOps callbackSurfaceOps, int format, int width, int height) { + } + + @Override + public void surfaceDestroyed(SurfaceOps callbackSurfaceOps) { + } + } + + private void releaseCamera() { + if (cameraDevice != null) { + cameraDevice.release(); + } + } + + @Override + protected void onStop() { + releaseCamera(); + } + +} -- Gitee From 87ac5e670b95d8b1eb5476bcf073413dbcb80d5f Mon Sep 17 00:00:00 2001 From: gaohui Date: Sun, 26 Sep 2021 09:59:55 +0800 Subject: [PATCH 2/2] Bug Fix ECG Signed-off-by: gaohui --- media/Camera/README_zh.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/media/Camera/README_zh.md b/media/Camera/README_zh.md index 6e11c975e0..b14d2b322c 100644 --- a/media/Camera/README_zh.md +++ b/media/Camera/README_zh.md @@ -15,3 +15,5 @@ ### 约束与限制 本示例仅支持在大型系统上运行。 + +相机模块目前只能支持真机运行调试,不能支持模拟器。 -- Gitee