diff --git a/en/application-dev/media/camera.md b/en/application-dev/media/camera.md index 06439dd049be835cdf5a96a35e2a2a42012ee6f8..25e5e573057661487895bc003c143393287b4829 100644 --- a/en/application-dev/media/camera.md +++ b/en/application-dev/media/camera.md @@ -2,7 +2,13 @@ ## When to Use -You can use the camera module to develop basic camera functions, including previewing, photographing, and video recording. +With the APIs provided by the **Camera** module, you can access and operate camera devices and develop new functions. Common operations include preview, photographing, and video recording. You can also implement flash control, exposure time control, focus mode control, zooming control, and many others. + +Before calling camera APIs, be familiar with the following concepts: + +- **Static camera capabilities**: A series of parameters used to describe inherent capabilities of a camera, such as orientation and supported resolution. +- **Physical camera**: An independent camera device. The physical camera ID is a string that uniquely identifies a physical camera. +- **Asynchronous operation**: To prevent the UI thread from being blocked, most **Camera** calls are asynchronous. Each API provides the callback and promise functions. ## How to Develop @@ -12,152 +18,298 @@ For details about the APIs, see [Camera Management](../reference/apis/js-apis-ca ### Full-Process Scenario -The full process includes creating an instance, setting parameters, managing sessions, taking photos, recording videos, and releasing resources. +The full process includes applying for permissions, creating an instance, setting parameters, managing sessions, taking photos, recording videos, and releasing resources. + +#### Applying for Permissions + +You must apply for the permission for your application to access the camera device and other functions. The following table lists camera-related permissions. + +| Permission| Attribute Value | +| -------- | ------------------------------ | +| Camera| ohos.permission.CAMERA | +| Call recording| ohos.permission.MICROPHONE | +| Storage| ohos.permission.WRITE_MEDIA | +| Read| ohos.permission.READ_MEDIA | +| Location| ohos.permission.MEDIA_LOCATION | -The method for creating an XComponent is also provided. For details, see [XComponent Creation](#xcomponent-creation). +The code snippet is as follows: -For details about the APIs used to save images, see [Image Processing](../reference/apis/js-apis-image.md). +```typescript +const PERMISSIONS: Array = [ + 'ohos.permission.CAMERA', + 'ohos.permission.MICROPHONE', + 'ohos.permission.MEDIA_LOCATION', + 'ohos.permission.READ_MEDIA', + 'ohos.permission.WRITE_MEDIA' +] + +function applyPermission() { + console.info('[permission] get permission'); + globalThis.abilityContext.requestPermissionFromUser(PERMISSIONS) + } +``` #### Creating an Instance -```js +You must create an independent **CameraManager** instance before performing camera operations. If this operation fails, the camera may be occupied or unusable. If the camera is occupied, wait until it is released. You can call **getSupportedCameras()** to obtain the list of cameras supported by the current device. The list stores all camera IDs of the current device. If the list is not empty, each ID in the list can be used to create an independent camera instance. If the list is empty, no camera is available for the current device and subsequent operations cannot be performed. The camera has preview, shooting, video recording, and metadata streams. You can use **getSupportedOutputCapability()** to obtain the output stream capabilities of the camera and configure them in the **profile** field in **CameraOutputCapability**. The procedure for creating a **CameraManager** instance is as follows: + +```typescript import camera from '@ohos.multimedia.camera' import image from '@ohos.multimedia.image' import media from '@ohos.multimedia.media' -import featureAbility from '@ohos.ability.featureAbility' // Create a CameraManager object. -let cameraManager -await camera.getCameraManager(globalThis.Context, (err, manager) => { - if (err) { - console.error('Failed to get the CameraManager instance ${err.message}'); - return; - } - console.log('Callback returned with the CameraManager instance'); - cameraManager = manager -}) - -// Register a callback to listen for camera status changes and obtain the updated camera status information. -cameraManager.on('cameraStatus', (cameraStatusInfo) => { - console.log('camera : ' + cameraStatusInfo.camera.cameraId); - console.log('status: ' + cameraStatusInfo.status); -}) +context: any = getContext(this) +let cameraManager = await camera.getCameraManager(this.context) +if (!cameraManager) { + console.error('Failed to get the CameraManager instance'); +} // Obtain the camera list. -let cameraArray -await cameraManager.getCameras((err, cameras) => { - if (err) { - console.error('Failed to get the cameras. ${err.message}'); - return; - } - console.log('Callback returned with an array of supported cameras: ' + cameras.length); - cameraArray = cameras -}) +let cameraArray = await cameraManager.getSupportedCameras() +if (!cameraArray) { + console.error('Failed to get the cameras'); +} -for(let cameraIndex = 0; cameraIndex < cameraArray.length; cameraIndex++) { - console.log('cameraId : ' + cameraArray[cameraIndex].cameraId) // Obtain the camera ID. - console.log('cameraPosition : ' + cameraArray[cameraIndex].cameraPosition) // Obtain the camera position. - console.log('cameraType : ' + cameraArray[cameraIndex].cameraType) // Obtain the camera type. - console.log('connectionType : ' + cameraArray[cameraIndex].connectionType) // Obtain the camera connection type. +for (let index = 0; index < cameraArray.length; index++) { + console.log('cameraId : ' + cameraArray[index].cameraId) // Obtain the camera ID. + console.log('cameraPosition : ' + cameraArray[index].cameraPosition) // Obtain the camera position. + console.log('cameraType : ' + cameraArray[index].cameraType) // Obtain the camera type. + console.log('connectionType : ' + cameraArray[index].connectionType) // Obtain the camera connection type. } // Create a camera input stream. -let cameraInput -await cameraManager.createCameraInput(cameraArray[0].cameraId).then((input) => { - console.log('Promise returned with the CameraInput instance'); - cameraInput = input -}) +let cameraInput = await cameraManager.createCameraInput(cameraArray[0]) + +// Obtain the output stream capabilities supported by the camera. +let cameraOutputCap = await cameraManager.getSupportedOutputCapability(cameraArray[0]); +if (!cameraOutputCap) { + console.error("outputCapability outputCapability == null || undefined") +} else { + console.info("outputCapability: " + JSON.stringify(cameraOutputCap)); +} -// Create a preview output stream. -let previewOutput -camera.createPreviewOutput((globalThis.surfaceId), (err, output) => { - if (err) { - console.error('Failed to create the PreviewOutput instance. ${err.message}'); - return; - } - console.log('Callback returned with previewOutput instance'); - previewOutput = output -}); +let previewProfilesArray = cameraOutputCap.GetPreviewProfiles(); +if (!previewProfilesArray) { + console.error("createOutput previewProfilesArray == null || undefined") +} + +let photoProfilesArray = cameraOutputCap.GetPhotoProfiles(); +if (!photoProfilesArray) { + console.error("createOutput photoProfilesArray == null || undefined") +} + +let videoProfilesArray = cameraOutputCap.GetVideoProfiles(); +if (!videoProfilesArray) { + console.error("createOutput videoProfilesArray == null || undefined") +} + +let metadataObjectTypesArray = cameraOutputCap.GetSupportedMetadataObjectType(); +if (!metadataObjectTypesArray) { + console.error("createOutput metadataObjectTypesArray == null || undefined") +} + +// Create a preview stream. For details about the surfaceId parameter, see the XComponent section. The preview stream is the surface provided by the XComponent. +let previewOutput = await cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId) +if (!previewOutput) { + console.error("Failed to create the PreviewOutput instance.") +} -// Create an ImageReceiver object and set image parameters. +// Create an ImageReceiver object and set photo parameters. The resolution is set based on the photographing resolutions supported by the current device, which are obtained by photoProfilesArray. let imageReceiver = await image.createImageReceiver(1920, 1080, 4, 8) // Obtain the surface ID for displaying the photos. let photoSurfaceId = await imageReceiver.getReceivingSurfaceId() // Create a photographing output stream. -let photoOutput -camera.createPhotoOutput((photoSurfaceId), (err, output) => { - if (err) { - console.error('Failed to create the PhotoOutput instance. ${err.message}'); - return; - } - console.log('Callback returned with the PhotoOutput instance.'); - photoOutput = output -}); +let photoOutput = await cameraManager.createPhotoOutput(photoProfilesArray[0], photoSurfaceId) +if (!photoOutput) { + console.error('Failed to create the PhotoOutput instance.'); + return; +} // Define video recording parameters. -let videoProfile = { - audioBitrate : 48000, - audioChannels : 2, - audioCodec : 'audio/mp4a-latm', - audioSampleRate : 48000, - fileFormat : 'mp4', - videoBitrate : 48000, - videoCodec : 'video/mp4v-es', - videoFrameWidth : 640, - videoFrameHeight : 480, - videoFrameRate : 30 -} let videoConfig = { - audioSourceType : 1, - videoSourceType : 0, - profile : videoProfile, - url : 'file:///data/media/01.mp4', - orientationHint : 0, - location : { latitude : 30, longitude : 130 }, + audioSourceType: 1, + videoSourceType: 1, + profile: { + audioBitrate: 48000, + audioChannels: 2, + audioCodec: 'audio/mp4v-es', + audioSampleRate: 48000, + durationTime: 1000, + fileFormat: 'mp4', + videoBitrate: 48000, + videoCodec: 'video/mp4v-es', + videoFrameWidth: 640, + videoFrameHeight: 480, + videoFrameRate: 30 + }, + url: 'file:///data/media/01.mp4', + orientationHint: 0, + maxSize: 100, + maxDuration: 500, + rotation: 0 } // Create a video recording output stream. let videoRecorder -await media.createVideoRecorder().then((recorder) => { +media.createVideoRecorder().then((recorder) => { console.log('createVideoRecorder called') videoRecorder = recorder }) // Set video recording parameters. -await videoRecorder.prepare(videoConfig) +videoRecorder.prepare(videoConfig) // Obtain the surface ID for video recording. -await videoRecorder.getInputSurface().then((id) => { +let videoSurfaceId +videoRecorder.getInputSurface().then((id) => { console.log('getInputSurface called') videoSurfaceId = id }) -``` -For details about how to create a video recorder, see [Video Recording Development](./video-recorder.md). -```js + // Create a VideoOutput object. -let videoOutput -camera.createVideoOutput((surfaceId), (err, output) => { - if (err) { - console.error('Failed to create the VideoOutput instance. ${err.message}'); - return; +let videoOutput = await cameraManager.createVideoOutput(videoProfilesArray[0], videoSurfaceId) +if (!videoOutput) { + console.error('Failed to create the videoOutput instance.'); + return; +} +``` +Surfaces must be created in advance for the preview, shooting, and video recording stream. The preview stream is the surface provided by the **XComponent**, the shooting stream is the surface provided by **ImageReceiver**, and the video recording stream is the surface provided by **VideoRecorder**. + +**XComponent** + +```typescript +mXComponentController: XComponentController = new XComponentController // Create an XComponentController. + +build() { + Flex() { + XComponent({ // Create an XComponent. + id: '', + type: 'surface', + libraryname: '', + controller: this.mXComponentController + }) + .onload(() => { // Set the onload callback. + // Set the surface width and height (1920 x 1080). For details about how to set the preview size, see the preview resolutions supported by the current device, which are obtained by previewProfilesArray. + this.mXComponentController.setXComponentSurfaceSize({surfaceWidth:1920,surfaceHeight:1080}) + // Obtain the surface ID. + globalThis.surfaceId = mXComponentController.getXComponentSurfaceId() + }) + .width('1920px') // Set the width of the XComponent. + .height('1080px') // Set the height of the XComponent. } - console.log('Callback returned with the VideoOutput instance'); - videoOutput = output -}); +} +``` + +**ImageReceiver** + +```typescript +function getImageReceiverSurfaceId() { + let receiver = image.createImageReceiver(640, 480, 4, 8) + console.log(TAG + 'before ImageReceiver check') + if (receiver !== undefined) { + console.log('ImageReceiver is ok') + surfaceId1 = receiver.getReceivingSurfaceId() + console.log('ImageReceived id: ' + JSON.stringify(surfaceId1)) + } else { + console.log('ImageReceiver is not ok') + } + } +``` + +**VideoRecorder** + +```typescript +function getVideoRecorderSurface() { + await getFd('CameraManager.mp4'); + mVideoConfig.url = mFdPath; + media.createVideoRecorder((err, recorder) => { + console.info('Entering create video receiver') + mVideoRecorder = recorder + console.info('videoRecorder is :' + JSON.stringify(mVideoRecorder)) + console.info('videoRecorder.prepare called.') + mVideoRecorder.prepare(mVideoConfig, (err) => { + console.info('videoRecorder.prepare success.') + mVideoRecorder.getInputSurface((err, id) => { + console.info('getInputSurface called') + mVideoSurface = id + console.info('getInputSurface surfaceId: ' + JSON.stringify(mVideoSurface)) + }) + }) + }) + } +``` + +#### Managing Sessions + +##### Creating a Session + +```typescript +// Create a session. +let captureSession = await camera.createCaptureSession() +if (!captureSession) { + console.error('Failed to create the CaptureSession instance.'); + return; +} +console.log('Callback returned with the CaptureSession instance.' + session); + +// Start configuration for the session. +await captureSession.beginConfig() + +// Add the camera input stream to the session. +await captureSession.addInput(cameraInput) + +// Add the preview input stream to the session. +await captureSession.addOutput(previewOutput) + +// Add the photographing output stream to the session. +await captureSession.addOutput(photoOutput) + +// Commit the session configuration. +await captureSession.commitConfig() + +// Start the session. +await captureSession.start().then(() => { + console.log('Promise returned to indicate the session start success.'); +}) +``` +##### Switching a Session + +```typescript +// Stop the session. +await captureSession.stop() + +// Start configuration for the session. +await captureSession.beginConfig() + +// Remove the photographing output stream from the session. +await captureSession.removeOutput(photoOutput) + +// Add a video recording output stream to the session. +await captureSession.addOutput(videoOutput) + +// Commit the session configuration. +await captureSession.commitConfig() + +// Start the session. +await captureSession.start().then(() => { + console.log('Promise returned to indicate the session start success.'); +}) ``` #### Setting Parameters -```js +```typescript // Check whether the camera has flash. -let flashStatus -await cameraInput.hasFlash().then((status) => { - console.log('Promise returned with the flash light support status:' + status); - flashStatus = status -}) -if(flashStatus) { +let flashStatus = await captureSession.hasFlash() +if (!flashStatus) { + console.error('Failed to check whether the device has the flash mode.'); +} +console.log('Promise returned with the flash light support status:' + flashStatus); + +if (flashStatus) { // Check whether the auto flash mode is supported. let flashModeStatus - cameraInput.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO, (err, status) => { + captureSession.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO, async (err, status) => { if (err) { console.error('Failed to check whether the flash mode is supported. ${err.message}'); return; @@ -167,7 +319,7 @@ if(flashStatus) { }) if(flashModeStatus) { // Set the flash mode to auto. - cameraInput.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO, (err) => { + captureSession.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO, async (err) => { if (err) { console.error('Failed to set the flash mode ${err.message}'); return; @@ -179,7 +331,7 @@ if(flashStatus) { // Check whether the continuous auto focus is supported. let focusModeStatus -cameraInput.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, (err, status) => { +captureSession.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, async (err, status) => { if (err) { console.error('Failed to check whether the focus mode is supported. ${err.message}'); return; @@ -187,9 +339,9 @@ cameraInput.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, (e console.log('Callback returned with the focus mode support status: ' + status); focusModeStatus = status }) -if(focusModeStatus) { +if (focusModeStatus) { // Set the focus mode to continuous auto focus. - cameraInput.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, (err) => { + captureSession.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, async (err) => { if (err) { console.error('Failed to set the focus mode ${err.message}'); return; @@ -199,18 +351,14 @@ if(focusModeStatus) { } // Obtain the zoom ratio range supported by the camera. -let zoomRatioRange -cameraInput.getZoomRatioRange((err, range) => { - if (err) { - console.error('Failed to get the zoom ratio range. ${err.message}'); - return; - } - console.log('Callback returned with zoom ratio range: ' + range.length); - zoomRatioRange = range -}) +let zoomRatioRange = await captureSession.getZoomRatioRange() +if (!zoomRatioRange) { + console.error('Failed to get the zoom ratio range.'); + return; +} // Set a zoom ratio. -cameraInput.setZoomRatio(zoomRatioRange[0], (err) => { +captureSession.setZoomRatio(zoomRatioRange[0], async (err) => { if (err) { console.error('Failed to set the zoom ratio value ${err.message}'); return; @@ -219,139 +367,15 @@ cameraInput.setZoomRatio(zoomRatioRange[0], (err) => { }) ``` -#### Managing Sessions - -##### Creating a Session - -```js -// Create a Context object. -let context = featureAbility.getContext() - -// Create a session. -let captureSession -await camera.createCaptureSession((context), (err, session) => { - if (err) { - console.error('Failed to create the CaptureSession instance. ${err.message}'); - return; - } - console.log('Callback returned with the CaptureSession instance.' + session); - captureSession = session -}); - -// Start configuration for the session. -await captureSession.beginConfig((err) => { - if (err) { - console.error('Failed to start the configuration. ${err.message}'); - return; - } - console.log('Callback invoked to indicate the begin config success.'); -}); - -// Add the camera input stream to the session. -await captureSession.addInput(cameraInput, (err) => { - if (err) { - console.error('Failed to add the CameraInput instance. ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the CameraInput instance is added.'); -}); - -// Add the preview input stream to the session. -await captureSession.addOutput(previewOutput, (err) => { - if (err) { - console.error('Failed to add the PreviewOutput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the PreviewOutput instance is added.'); -}); - -// Add the photographing output stream to the session. -await captureSession.addOutput(photoOutput, (err) => { - if (err) { - console.error('Failed to add the PhotoOutput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the PhotoOutput instance is added.'); -}); - -// Commit the session configuration. -await captureSession.commitConfig((err) => { - if (err) { - console.error('Failed to commit the configuration. ${err.message}'); - return; - } - console.log('Callback invoked to indicate the commit config success.'); -}); - -// Start the session. -await captureSession.start().then(() => { - console.log('Promise returned to indicate the session start success.'); -}) -``` - -##### Switching a Session - -```js -// Stop the session. -await captureSession.stop((err) => { - if (err) { - console.error('Failed to stop the session ${err.message}'); - return; - } - console.log('Callback invoked to indicate the session stop success.'); -}); - -// Start configuration for the session. -await captureSession.beginConfig((err) => { - if (err) { - console.error('Failed to start the configuration. ${err.message}'); - return; - } - console.log('Callback invoked to indicate the begin config success.'); -}); - -// Remove the photographing output stream from the session. -await captureSession.removeOutput(photoOutput, (err) => { - if (err) { - console.error('Failed to remove the PhotoOutput instance. ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the PhotoOutput instance is removed.'); -}); - -// Add a video recording output stream to the session. -await captureSession.addOutput(videoOutput, (err) => { - if (err) { - console.error('Failed to add the VideoOutput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the VideoOutput instance is added.'); -}); - -// Commit the session configuration. -await captureSession.commitConfig((err) => { - if (err) { - console.error('Failed to commit the configuration. ${err.message}'); - return; - } - console.log('Callback invoked to indicate the commit config success.'); -}); - -// Start the session. -await captureSession.start().then(() => { - console.log('Promise returned to indicate the session start success.'); -}) -``` - #### Taking Photos -```js +```typescript let settings = { quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // Set the image quality to high. rotation: camera.ImageRotation.ROTATION_0 // Set the image rotation angle to 0. } // Use the current photographing settings to take photos. -photoOutput.capture(settings, (err) => { +photoOutput.capture(settings, async (err) => { if (err) { console.error('Failed to capture the photo ${err.message}'); return; @@ -362,9 +386,9 @@ photoOutput.capture(settings, (err) => { #### Recording Videos -```js +```typescript // Start the video recording output stream. -videoOutput.start((err) => { +videoOutput.start(async (err) => { if (err) { console.error('Failed to start the video output ${err.message}'); return; @@ -373,17 +397,17 @@ videoOutput.start((err) => { }); // Start video recording. -await videoRecorder.start().then(() => { +videoRecorder.start().then(() => { console.info('videoRecorder start success'); } // Stop video recording. -await videoRecorder.stop().then(() => { +videoRecorder.stop().then(() => { console.info('stop success'); } // Stop the video recording output stream. -await videoOutput.stop((err) => { +videoOutput.stop((err) => { if (err) { console.error('Failed to stop the video output ${err.message}'); return; @@ -392,81 +416,34 @@ await videoOutput.stop((err) => { }); ``` +For details about the APIs used for saving photos, see [Image Processing](image.md#using-imagereceiver). + #### Releasing Resources -```js +```typescript // Stop the session. -await captureSession.stop((err) => { - if (err) { - console.error('Failed to stop the session ${err.message}'); - return; - } - console.log('Callback invoked to indicate the session stop success.'); -}); +captureSession.stop() + // Release the camera input stream. -await cameraInput.release((err) => { - if (err) { - console.error('Failed to release the CameraInput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the CameraInput instance is released successfully.'); -}); +cameraInput.release() + // Release the preview output stream. -await previewOutput.release((err) => { - if (err) { - console.error('Failed to release the PreviewOutput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the PreviewOutput instance is released successfully.'); -}); +previewOutput.release() + // Release the photographing output stream. -await photoOutput.release((err) => { - if (err) { - console.error('Failed to release the PhotoOutput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the PhotoOutput instance is released successfully.'); -}); +photoOutput.release() + // Release the video recording output stream. -await videoOutput.release((err) => { - if (err) { - console.error('Failed to release the VideoOutput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the VideoOutput instance is released successfully.'); -}); +videoOutput.release() + // Release the session. -await captureSession.release((err) => { - if (err) { - console.error('Failed to release the CaptureSession instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the CaptureSession instance is released successfully.'); -}); -``` +captureSession.release() -#### XComponent Creation -The surface ID must be obtained for image preview. +// Set the session to null. +captureSession = null +``` -```js -mXComponentController: XComponentController = new XComponentController // Create an XComponentController. +## Process Flowchart -build() { - Flex() { - XComponent({ // Create an XComponent. - id: '', - type: 'surface', - libraryname: '', - controller: this.mXComponentController - }) - .onload(() => { // Set the onload callback. - // Set the width and height of the surface to 1920 and 1080, respectively. - this.mXComponentController.setXComponentSurfaceSize({surfaceWidth:1920,surfaceHeight:1080}) - // Obtain the surface ID. - globalThis.surfaceId = mXComponentController.getXComponentSurfaceId() - }) - .width('1920px') // Set the width of the XComponent. - .height('1080px') // Set the height of the XComponent. - } -} -``` +The following figure shows the process of using the camera. +![camera_framework process](figures/camera_framework_process.jpg) diff --git a/en/application-dev/media/figures/camera_framework_process.jpg b/en/application-dev/media/figures/camera_framework_process.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1207a9a4adb5d5886f9427b07f0ec7d717fc5bf8 Binary files /dev/null and b/en/application-dev/media/figures/camera_framework_process.jpg differ