video-recording.md 11.9 KB
Newer Older
G
Gloria 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
# Video Recording

OpenHarmony provides the AVRecorder for you to develop the video recording service. The AVRecorder supports audio recording, audio encoding, video encoding, audio encapsulation, and video encapsulation. It is applicable to simple video recording scenarios and can be used to generate local video files directly.

You will learn how to use the AVRecorder to complete the process of starting, pausing, resuming, and stopping recording.

During application development, you can use the **state** attribute of the AVRecorder to obtain the AVRecorder state or call **on('stateChange')** to listen for state changes. Your code must meet the state machine requirements. For example, **pause()** is called only when the AVRecorder is in the **started** state, and **resume()** is called only when it is in the **paused** state.

**Figure 1** Recording state transition 

![Recording state change](figures/video-recording-status-change.png)

For details about the state, see [AVRecorderState](../reference/apis/js-apis-media.md#avrecorderstate9).

## How to Develop

> **NOTE**
> 
> The AVRecorder only processes video data. To complete video recording, it must work with the video data collection module, which transfers the captured video data to the AVRecorder for data processing through the surface. A typical video data collection module is the camera module, which currently is available only to system applications. For details, see [Camera](../reference/apis/js-apis-camera.md).

Read [AVRecorder](../reference/apis/js-apis-media.md#avrecorder9) for the API reference.

1. Create an **AVRecorder** instance. The AVRecorder is the **idle** state.
   
   ```ts
   import media from '@ohos.multimedia.media'
27 28
   let avRecorder: media.AVRecorder;
   media.createAVRecorder().then((recorder: media.AVRecorder) => {
29
     avRecorder = recorder
30
   }, (error: Error) => {
31
     console.error('createAVRecorder failed')
G
Gloria 已提交
32 33 34 35 36 37 38 39 40 41 42
   })
   ```

2. Set the events to listen for.
   | Event Type| Description|
   | -------- | -------- |
   | stateChange | Mandatory; used to listen for changes of the **state** attribute of the AVRecorder.|
   | error | Mandatory; used to listen for AVRecorder errors.|

   ```ts
   // Callback function for state changes.
43
   avRecorder.on('stateChange', (state: media.AVRecorderState, reason: media.StateChangeReason) => {
44
     console.info('current state is: ' + state);
G
Gloria 已提交
45 46
   })
   // Callback function for errors.
47
   avRecorder.on('error', (err: BusinessError) => {
48
     console.error('error happened, error message is ' + err);
G
Gloria 已提交
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
   })
   ```

3. Set video recording parameters and call **prepare()**. The AVRecorder enters the **prepared** state.
   > **NOTE**
   >
   > Pay attention to the following when configuring parameters:
   > 
   > - In pure video recording scenarios, set only video-related parameters in **avConfig** of **prepare()**.
   >   If audio-related parameters are configured, the system regards it as audio and video recording.
   > 
   > - The [recording specifications](avplayer-avrecorder-overview.md#supported-formats) in use must be those supported. The video bit rate, resolution, and frame rate are subject to the ranges supported by the hardware device.
   > 
   > - The recording output URL (URL in **avConfig** in the sample code) must be in the format of fd://xx (where xx indicates a file descriptor). You must call [ohos.file.fs](../reference/apis/js-apis-file-fs.md) to implement access to the application file. For details, see [Application File Access and Management](../file-management/app-file-access.md).

   ```ts
65
   class AVProfile {
66 67 68 69 70 71
     fileFormat: media.ContainerFormatType;
     videoBitrate: number;
     videoCodec: media.CodecMimeType;
     videoFrameWidth: number;
     videoFrameHeight: number;
     videoFrameRate: number;
G
Gloria 已提交
72
   }
73
   class AVConfig {
74 75 76 77
     videoSourceType: media.VideoSourceType;
     profile: AVProfile;
     url: string;
     rotation: number;
78 79
   }
   let avProfile: AVProfile = {
80 81 82 83 84 85
     fileFormat: media.ContainerFormatType.CFT_MPEG_4, // Video file encapsulation format. Only MP4 is supported.
     videoBitrate : 100000, // Video bit rate.
     videoCodec: media.CodecMimeType.VIDEO_AVC, // Video file encoding format. Both MPEG-4 and AVC are supported.
     videoFrameWidth: 640, // Video frame width.
     videoFrameHeight: 480, // Video frame height.
     videoFrameRate: 30 // Video frame rate.
G
Gloria 已提交
86
   }
87
   let avConfig: AVConfig = {
88 89 90 91
     videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, // Video source type. YUV and ES are supported.
     profile : avProfile,
     url: 'fd://35', // Create, read, and write a file by referring to the sample code in Application File Access and Management.
     rotation: 0, // Video rotation angle. The default value is 0, indicating that the video is not rotated. The value can be 0, 90, 180, or 270.
92
   }
G
Gloria 已提交
93
   avRecorder.prepare(avConfig).then(() => {
94
     console.info('avRecorder prepare success')
95
   }, (error: Error) => {
96
     console.error('avRecorder prepare failed')
G
Gloria 已提交
97 98 99 100 101 102 103 104 105 106
   })
   ```

4. Obtain the surface ID required for video recording.
   
   Call **getInputSurface()**. The returned surface ID is transferred to the video data collection module (video input source), which is the camera module in the sample code.

   The video data collection module obtains the surface based on the surface ID and transmits video data to the AVRecorder through the surface. Then the AVRecorder processes the video data.
   
   ```ts
107
   avRecorder.getInputSurface().then((surfaceId: string) => {
G
Gloria 已提交
108
     console.info('avRecorder getInputSurface success')
109
   }, (error: Error) => {
G
Gloria 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
     console.error('avRecorder getInputSurface failed')
   })
   ```

5. Initialize the video data input source.

   This step is performed in the video data collection module. For the camera module, you need to create a **Camera** instance, obtain the camera list, create a camera input stream, and create a video output stream. For details, see [Recording](camera-recording-case.md).

6. Start recording. 

   Start the input source to input video data, for example, by calling **camera.VideoOutput.start**. Then call **AVRecorder.start()** to switch the AVRecorder to the **started** state.

7. Call **pause()** to pause recording. The AVRecorder enters the **paused** state. In addition, pause data input in the video data collection module, for example, by calling **camera.VideoOutput.stop**.

8. Call **resume()** to resume recording. The AVRecorder enters the **started** state again.

9. Call **stop()** to stop recording. The AVRecorder enters the **stopped** state again. In addition, stop camera recording in the video data collection module.

10. Call **reset()** to reset the resources. The AVRecorder enters the **idle** state. In this case, you can reconfigure the recording parameters.

11. Call **release()** to release the resources. The AVRecorder enters the **released** state. In addition, release the video data input source resources (camera resources in this example).


## Sample Code

Refer to the sample code below to complete the process of starting, pausing, resuming, and stopping recording.


```ts
import media from '@ohos.multimedia.media'
140
import { BusinessError } from '@ohos.base';
G
Gloria 已提交
141
const TAG = 'VideoRecorderDemo:'
142 143 144 145 146 147 148 149 150 151 152 153 154 155
class AVProfile {
  fileFormat: media.ContainerFormatType;
  videoBitrate: number;
  videoCodec: media.CodecMimeType;
  videoFrameWidth: number;
  videoFrameHeight: number;
  videoFrameRate: number;
}
class AVConfig {
  videoSourceType: media.VideoSourceType;
  profile: AVProfile;
  url: string;
  rotation: number;
}
G
Gloria 已提交
156
export class VideoRecorderDemo {
157 158 159
  private avRecorder: media.AVRecorder;
  private videoOutSurfaceId: string;
  private avProfile: AVProfile = {
G
Gloria 已提交
160 161 162 163 164 165 166
    fileFormat: media.ContainerFormatType.CFT_MPEG_4, // Video file encapsulation format. Only MP4 is supported.
    videoBitrate : 100000, // Video bit rate.
    videoCodec: media.CodecMimeType.VIDEO_AVC, // Video file encoding format. Both MPEG-4 and AVC are supported.
    videoFrameWidth: 640, // Video frame width.
    videoFrameHeight: 480, // Video frame height.
    videoFrameRate: 30 // Video frame rate.
  }
167
  private avConfig: AVConfig = {
G
Gloria 已提交
168 169 170 171 172 173 174 175 176
    videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, // Video source type. YUV and ES are supported.
    profile : this.avProfile,
    url: 'fd://35', // Create, read, and write a file by referring to the sample code in Application File Access and Management.
    rotation: 0, // Video rotation angle. The default value is 0, indicating that the video is not rotated. The value can be 0, 90, 180, or 270.
  }

  // Set AVRecorder callback functions.
  setAvRecorderCallback() {
    // Callback function for state changes.
177
    this.avRecorder.on('stateChange', (state: media.AVRecorderState, reason: media.StateChangeReason) => {
G
Gloria 已提交
178 179 180
      console.info(TAG + 'current state is: ' + state);
    })
    // Callback function for errors.
181
    this.avRecorder.on('error', (err: BusinessError) => {
G
Gloria 已提交
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
      console.error(TAG + 'error ocConstantSourceNode, error message is ' + err);
    })
  }

  // Complete camera-related preparations.
  async prepareCamera() {
    // For details on the implementation, see the camera document.
  }

  // Start the camera stream output.
  async startCameraOutput() {
    // Call start of the VideoOutput class to start video output.
  }

  // Stop the camera stream output.
  async stopCameraOutput() {
    // Call stop of the VideoOutput class to stop video output.
  }

  // Release the camera instance.
  async releaseCamera() {
    // Release the instances created during camera preparation.
  }

  // Process of starting recording.
  async startRecordingProcess() {
    // 1. Create an AVRecorder instance.
    this.avRecorder = await media.createAVRecorder();
    this.setAvRecorderCallback();
    // 2. Obtain the file descriptor of the recorded file. The obtained file descriptor is passed in to the URL in avConfig. The implementation is omitted here.
    // 3. Set recording parameters to complete the preparations.
    await this.avRecorder.prepare(this.avConfig);
214
    this.videoOutSurfaceId = await this.avRecorder.getInputSurface();
G
Gloria 已提交
215 216 217 218 219
    // 4. Complete camera-related preparations.
    await this.prepareCamera();
    // 5. Start the camera stream output.
    await this.startCameraOutput();
    // 6. Start recording.
220
    await this.avRecorder.start();
G
Gloria 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
  }

  // Process of pausing recording.
  async pauseRecordingProcess() {
    if (this.avRecorder.state ==='started') { // pause() can be called only when the AVRecorder is in the started state .
      await this.avRecorder.pause();
      await this.stopCameraOutput(); // Stop the camera stream output.
    }
  }

  // Process of resuming recording.
  async resumeRecordingProcess() {
    if (this.avRecorder.state === 'paused') { // resume() can be called only when the AVRecorder is in the paused state .
      await this.startCameraOutput(); // Start camera stream output.
      await this.avRecorder.resume();
    }
  }

  async stopRecordingProcess() {
    // 1. Stop recording.
    if (this.avRecorder.state === 'started'
242
    || this.avRecorder.state ==='paused') { // stop() can be called only when the AVRecorder is in the started or paused state.
G
Gloria 已提交
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
      await this.avRecorder.stop();
      await this.stopCameraOutput();
    }
    // 2. Reset the AVRecorder.
    await this.avRecorder.reset();
    // 3. Release the AVRecorder instance.
    await this.avRecorder.release();
    // 4. After the file is recorded, close the file descriptor. The implementation is omitted here.
    // 5. Release the camera instance.
    await this.releaseCamera();
  }

  // Complete sample code for starting, pausing, resuming, and stopping recording.
  async videoRecorderDemo() {
    await this.startRecordingProcess();         // Start recording.
    // You can set the recording duration. For example, you can set the sleep mode to prevent code execution.
    await this.pauseRecordingProcess();         // Pause recording.
    await this.resumeRecordingProcess();        // Resume recording.
    await this.stopRecordingProcess();          // Stop recording.
  }
}
```

 <!--no_check-->