camera.md 16.1 KB
Newer Older
W
wusongqing 已提交
1 2 3 4
# Camera Development

## When to Use

5 6 7 8 9 10 11
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.
W
wusongqing 已提交
12 13 14 15 16 17 18 19 20

## How to Develop

### Available APIs

For details about the APIs, see [Camera Management](../reference/apis/js-apis-camera.md).

### Full-Process Scenario

21 22 23 24 25 26 27 28 29 30 31 32 33
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 |
W
wusongqing 已提交
34

35
The code snippet is as follows:
W
wusongqing 已提交
36

37 38 39 40 41 42 43 44 45 46 47 48 49 50
```typescript
const PERMISSIONS: Array<string> = [
    '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)
    }
```
W
wusongqing 已提交
51 52 53

#### Creating an Instance

54 55 56
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
W
wusongqing 已提交
57 58 59 60 61
import camera from '@ohos.multimedia.camera'
import image from '@ohos.multimedia.image'
import media from '@ohos.multimedia.media'

// Create a CameraManager object.
62 63 64 65 66
context: any = getContext(this)
let cameraManager = await camera.getCameraManager(this.context)
if (!cameraManager) {
    console.error('Failed to get the CameraManager instance');
}
W
wusongqing 已提交
67 68

// Obtain the camera list.
69 70 71 72
let cameraArray = await cameraManager.getSupportedCameras()
if (!cameraArray) {
    console.error('Failed to get the cameras');
}
W
wusongqing 已提交
73

74 75 76 77 78
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.
W
wusongqing 已提交
79 80 81
}

// Create a camera input stream.
82 83 84 85 86 87 88 89 90
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));
}
W
wusongqing 已提交
91

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
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.")
}
W
wusongqing 已提交
117

118
// 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.
W
wusongqing 已提交
119 120 121 122
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.
123 124 125 126 127
let photoOutput = await cameraManager.createPhotoOutput(photoProfilesArray[0], photoSurfaceId)
if (!photoOutput) {
    console.error('Failed to create the PhotoOutput instance.');
    return;
}
W
wusongqing 已提交
128 129 130

// Define video recording parameters.
let videoConfig = {
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
    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
W
wusongqing 已提交
151 152 153 154
}

// Create a video recording output stream.
let videoRecorder
155
media.createVideoRecorder().then((recorder) => {
W
wusongqing 已提交
156 157 158 159
    console.log('createVideoRecorder called')
    videoRecorder = recorder
})
// Set video recording parameters.
160
videoRecorder.prepare(videoConfig)
W
wusongqing 已提交
161
// Obtain the surface ID for video recording.
162 163
let videoSurfaceId
videoRecorder.getInputSurface().then((id) => {
W
wusongqing 已提交
164 165 166
    console.log('getInputSurface called')
    videoSurfaceId = id
})
167

W
wusongqing 已提交
168
// Create a VideoOutput object.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
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.
W
wusongqing 已提交
198
    }
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
}
```

**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.');
})
```
W
wusongqing 已提交
274

275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
##### 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.');
})
W
wusongqing 已提交
297 298 299 300
```

#### Setting Parameters

301
```typescript
W
wusongqing 已提交
302
// Check whether the camera has flash.
303 304 305 306 307 308 309
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) {
W
wusongqing 已提交
310 311
    // Check whether the auto flash mode is supported.
    let flashModeStatus
312
    captureSession.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO, async (err, status) => {
W
wusongqing 已提交
313 314 315 316 317 318 319 320 321
        if (err) {
            console.error('Failed to check whether the flash mode is supported. ${err.message}');
            return;
        }
        console.log('Callback returned with the flash mode support status: ' + status);
        flashModeStatus = status
    })
    if(flashModeStatus) {
        // Set the flash mode to auto.
322
        captureSession.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO, async (err) => {
W
wusongqing 已提交
323 324 325 326 327 328 329 330 331 332 333
            if (err) {
                console.error('Failed to set the flash mode  ${err.message}');
                return;
            }
            console.log('Callback returned with the successful execution of setFlashMode.');
        })
    }
}

// Check whether the continuous auto focus is supported.
let focusModeStatus
334
captureSession.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, async (err, status) => {
W
wusongqing 已提交
335 336 337 338 339 340 341
    if (err) {
        console.error('Failed to check whether the focus mode is supported. ${err.message}');
        return;
    }
    console.log('Callback returned with the focus mode support status: ' + status);
    focusModeStatus = status
})
342
if (focusModeStatus) {
W
wusongqing 已提交
343
    // Set the focus mode to continuous auto focus.
344
    captureSession.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, async (err) => {
W
wusongqing 已提交
345 346 347 348 349 350 351 352 353
        if (err) {
            console.error('Failed to set the focus mode  ${err.message}');
            return;
        }
        console.log('Callback returned with the successful execution of setFocusMode.');
    })
}

// Obtain the zoom ratio range supported by the camera.
354 355 356 357 358
let zoomRatioRange = await captureSession.getZoomRatioRange()
if (!zoomRatioRange) {
    console.error('Failed to get the zoom ratio range.');
    return;
}
W
wusongqing 已提交
359 360

// Set a zoom ratio.
361
captureSession.setZoomRatio(zoomRatioRange[0], async (err) => {
W
wusongqing 已提交
362 363 364 365 366 367 368 369 370 371
    if (err) {
        console.error('Failed to set the zoom ratio value ${err.message}');
        return;
    }
    console.log('Callback returned with the successful execution of setZoomRatio.');
})
```

#### Taking Photos

372
```typescript
W
wusongqing 已提交
373
let settings = {
374 375
    quality: camera.QualityLevel.QUALITY_LEVEL_HIGH,                                     // Set the image quality to high.
    rotation: camera.ImageRotation.ROTATION_0                                            // Set the image rotation angle to 0.
W
wusongqing 已提交
376 377
}
// Use the current photographing settings to take photos.
378
photoOutput.capture(settings, async (err) => {
W
wusongqing 已提交
379 380 381 382 383 384 385 386 387 388
    if (err) {
        console.error('Failed to capture the photo ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate the photo capture request success.');
});
```

#### Recording Videos

389
```typescript
W
wusongqing 已提交
390
// Start the video recording output stream.
391
videoOutput.start(async (err) => {
W
wusongqing 已提交
392 393 394 395 396 397 398 399
    if (err) {
        console.error('Failed to start the video output ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate the video output start success.');
});

// Start video recording.
400
videoRecorder.start().then(() => {
W
wusongqing 已提交
401 402 403 404
    console.info('videoRecorder start success');
}

// Stop video recording.
405
videoRecorder.stop().then(() => {
W
wusongqing 已提交
406 407 408 409
    console.info('stop success');
}

// Stop the video recording output stream.
410
videoOutput.stop((err) => {
W
wusongqing 已提交
411 412 413 414 415 416 417 418
    if (err) {
        console.error('Failed to stop the video output ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate the video output stop success.');
});
```

419 420
For details about the APIs used for saving photos, see [Image Processing](image.md#using-imagereceiver).

W
wusongqing 已提交
421 422
#### Releasing Resources

423
```typescript
424
// Stop the session.
425 426
captureSession.stop()

W
wusongqing 已提交
427
// Release the camera input stream.
428 429
cameraInput.release()

W
wusongqing 已提交
430
// Release the preview output stream.
431 432
previewOutput.release()

W
wusongqing 已提交
433
// Release the photographing output stream.
434 435
photoOutput.release()

W
wusongqing 已提交
436
// Release the video recording output stream.
437 438
videoOutput.release()

W
wusongqing 已提交
439
// Release the session.
440
captureSession.release()
W
wusongqing 已提交
441

442 443 444
// Set the session to null.
captureSession = null
```
W
wusongqing 已提交
445

446
## Process Flowchart
W
wusongqing 已提交
447

448 449
The following figure shows the process of using the camera.
![camera_framework process](figures/camera_framework_process.jpg)