video-playback.md 19.4 KB
Newer Older
W
wusongqing 已提交
1 2
# Video Playback Development

G
Gloria 已提交
3
## Introduction
W
wusongqing 已提交
4

G
Gloria 已提交
5 6 7 8 9
You can use video playback APIs to convert audio data into audible analog signals and play the signals using output devices. You can also manage playback tasks. For example, you can start, suspend, stop playback, release resources, set the volume, seek to a playback position, set the playback speed, and obtain track information. This document describes development for the following video playback scenarios: full-process, normal playback, video switching, and loop playback.

## Working Principles

The following figures show the video playback state transition and the interaction with external modules for video playback.
W
wusongqing 已提交
10 11 12 13 14

**Figure 1** Video playback state transition

![en-us_image_video_state_machine](figures/en-us_image_video_state_machine.png)

G
Gloria 已提交
15
**Figure 2** Interaction with external modules for video playback
W
wusongqing 已提交
16 17 18

![en-us_image_video_player](figures/en-us_image_video_player.png)

G
Gloria 已提交
19 20
**NOTE**: When a third-party application calls a JS interface provided by the JS interface layer, the framework layer invokes the audio component through the media service of the native framework to output the audio data decoded by the software to the audio HDI. The graphics subsystem outputs the image data decoded by the codec HDI at the hardware interface layer to the display HDI. In this way, video playback is implemented.

W
wusongqing 已提交
21
*Note: Video playback requires hardware capabilities such as display, audio, and codec.*
W
wusongqing 已提交
22

W
wusongqing 已提交
23
1. A third-party application obtains a surface ID from the XComponent.
W
wusongqing 已提交
24 25 26
2. The third-party application transfers the surface ID to the VideoPlayer JS.
3. The media service flushes the frame data to the surface buffer.

W
wusongqing 已提交
27 28
## Compatibility

W
wusongqing 已提交
29
Use the mainstream playback formats and resolutions, rather than custom ones to avoid playback failures, frame freezing, and artifacts. The system is not affected by incompatibility issues. If such an issue occurs, you can exit stream playback mode.
W
wusongqing 已提交
30 31 32

The table below lists the mainstream playback formats and resolutions.

W
wusongqing 已提交
33
| Video Container Format|                     Description                     |               Resolution              |
W
wusongqing 已提交
34 35 36 37 38 39
| :----------: | :-----------------------------------------------: | :--------------------------------: |
|     mp4      | Video format: H.264/MPEG-2/MPEG-4/H.263; audio format: AAC/MP3| Mainstream resolutions, such as 1080p, 720p, 480p, and 270p|
|     mkv      | Video format: H.264/MPEG-2/MPEG-4/H.263; audio format: AAC/MP3| Mainstream resolutions, such as 1080p, 720p, 480p, and 270p|
|      ts      |   Video format: H.264/MPEG-2/MPEG-4; audio format: AAC/MP3   | Mainstream resolutions, such as 1080p, 720p, 480p, and 270p|
|     webm     |          Video format: VP8; audio format: VORBIS          | Mainstream resolutions, such as 1080p, 720p, 480p, and 270p|

W
wusongqing 已提交
40 41
## How to Develop

G
Gloria 已提交
42
For details about the APIs, see [VideoPlayer in the Media API](../reference/apis/js-apis-media.md#videoplayer8).
W
wusongqing 已提交
43 44 45 46 47

### Full-Process Scenario

The full video playback process includes creating an instance, setting the URL, setting the surface ID, preparing for video playback, playing video, pausing playback, obtaining track information, seeking to a playback position, setting the volume, setting the playback speed, stopping playback, resetting the playback configuration, and releasing resources.

W
wusongqing 已提交
48
For details about the **url** types supported by **VideoPlayer**, see the [url attribute](../reference/apis/js-apis-media.md#videoplayer_attributes).
W
wusongqing 已提交
49

W
wusongqing 已提交
50
For details about how to create an XComponent, see [XComponent](../reference/arkui-ts/ts-basic-components-xcomponent.md).
W
wusongqing 已提交
51

W
wusongqing 已提交
52
```js
W
wusongqing 已提交
53 54
import media from '@ohos.multimedia.media'
import fileIO from '@ohos.fileio'
W
wusongqing 已提交
55 56 57
export class VideoPlayerDemo {
  // Report an error in the case of a function invocation failure.
  failureCallback(error) {
W
wusongqing 已提交
58 59 60
    console.info(`error happened,error Name is ${error.name}`);
    console.info(`error happened,error Code is ${error.code}`);
    console.info(`error happened,error Message is ${error.message}`);
W
wusongqing 已提交
61
  }
W
wusongqing 已提交
62

W
wusongqing 已提交
63 64
  // Report an error in the case of a function invocation exception.
  catchCallback(error) {
W
wusongqing 已提交
65 66 67
    console.info(`catch error happened,error Name is ${error.name}`);
    console.info(`catch error happened,error Code is ${error.code}`);
    console.info(`catch error happened,error Message is ${error.message}`);
W
wusongqing 已提交
68
  }
W
wusongqing 已提交
69

W
wusongqing 已提交
70 71
  // Used to print the video track information.
  printfDescription(obj) {
W
wusongqing 已提交
72
    for (let item in obj) {
W
wusongqing 已提交
73 74 75
      let property = obj[item];
      console.info('key is ' + item);
      console.info('value is ' + property);
W
wusongqing 已提交
76
    }
W
wusongqing 已提交
77 78 79 80
  }

  async videoPlayerDemo() {
    let videoPlayer = undefined;
W
wusongqing 已提交
81
    let surfaceID = 'test' // The surfaceID parameter is used for screen display. Its value is obtained through the XComponent API. For details about the document link, see the method of creating the XComponent.
W
wusongqing 已提交
82 83 84 85 86
    let fdPath = 'fd://'
    // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\H264_AAC.mp4 /data/app/el1/bundle/public/ohos.acts.multimedia.video.videoplayer/ohos.acts.multimedia.video.videoplayer/assets/entry/resources/rawfile" command.
    let path = '/data/app/el1/bundle/public/ohos.acts.multimedia.video.videoplayer/ohos.acts.multimedia.video.videoplayer/assets/entry/resources/rawfile/H264_AAC.mp4';
    await fileIO.open(path).then((fdNumber) => {
      fdPath = fdPath + '' + fdNumber;
JoyboyCZ's avatar
JoyboyCZ 已提交
87
      console.info('open fd success fd is' + fdPath);
W
wusongqing 已提交
88 89 90 91 92 93 94 95
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
    });
    // Call createVideoPlayer to create a VideoPlayer instance.
    await media.createVideoPlayer().then((video) => {
      if (typeof (video) != 'undefined') {
W
wusongqing 已提交
96 97
        console.info('createVideoPlayer success!');
        videoPlayer = video;
W
wusongqing 已提交
98
      } else {
W
wusongqing 已提交
99
        console.info('createVideoPlayer fail!');
W
wusongqing 已提交
100 101
      }
    }, this.failureCallback).catch(this.catchCallback);
W
wusongqing 已提交
102
    // Set the playback source for the player.
W
wusongqing 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    videoPlayer.url = fdPath;

    // Set the surface ID to display the video image.
    await videoPlayer.setDisplaySurface(surfaceID).then(() => {
      console.info('setDisplaySurface success');
    }, this.failureCallback).catch(this.catchCallback);

    // Call the prepare API to prepare for playback.
    await videoPlayer.prepare().then(() => {
      console.info('prepare success');
    }, this.failureCallback).catch(this.catchCallback);

    // Call the play API to start playback.
    await videoPlayer.play().then(() => {
      console.info('play success');
    }, this.failureCallback).catch(this.catchCallback);

    // Pause playback.
    await videoPlayer.pause().then(() => {
      console.info('pause success');
    }, this.failureCallback).catch(this.catchCallback);

W
wusongqing 已提交
125
    // Use a promise to obtain the video track information communication_dsoftbus.
W
wusongqing 已提交
126 127 128
    let arrayDescription;
    await videoPlayer.getTrackDescription().then((arrlist) => {
      if (typeof (arrlist) != 'undefined') {
W
wusongqing 已提交
129
        arrayDescription = arrlist;
W
wusongqing 已提交
130
      } else {
W
wusongqing 已提交
131
        console.log('video getTrackDescription fail');
W
wusongqing 已提交
132 133 134 135 136
      }
    }, this.failureCallback).catch(this.catchCallback);

    for (let i = 0; i < arrayDescription.length; i++) {
      this.printfDescription(arrayDescription[i]);
W
wusongqing 已提交
137 138
    }

W
wusongqing 已提交
139
    // Seek to the 50s position. For details about the input parameters, see the API document.
W
wusongqing 已提交
140 141 142 143 144
    let seekTime = 50000;
    await videoPlayer.seek(seekTime, media.SeekMode.SEEK_NEXT_SYNC).then((seekDoneTime) => {
      console.info('seek success');
    }, this.failureCallback).catch(this.catchCallback);

W
wusongqing 已提交
145
    // Set the volume. For details about the input parameters, see the API document.
W
wusongqing 已提交
146 147 148 149 150
    let volume = 0.5;
    await videoPlayer.setVolume(volume).then(() => {
      console.info('setVolume success');
    }, this.failureCallback).catch(this.catchCallback);

W
wusongqing 已提交
151
    // Set the playback speed. For details about the input parameters, see the API document.
W
wusongqing 已提交
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
    let speed = media.PlaybackSpeed.SPEED_FORWARD_2_00_X;
    await videoPlayer.setSpeed(speed).then(() => {
      console.info('setSpeed success');
    }, this.failureCallback).catch(this.catchCallback);

    // Stop playback.
    await videoPlayer.stop().then(() => {
      console.info('stop success');
    }, this.failureCallback).catch(this.catchCallback);

    // Reset the playback configuration.
    await videoPlayer.reset().then(() => {
      console.info('reset success');
    }, this.failureCallback).catch(this.catchCallback);

    // Release playback resources.
    await videoPlayer.release().then(() => {
      console.info('release success');
    }, this.failureCallback).catch(this.catchCallback);

    // Set the related instances to undefined.
    videoPlayer = undefined;
    surfaceID = undefined;
  }
W
wusongqing 已提交
176 177 178 179 180 181
}
```

### Normal Playback Scenario

```js
W
wusongqing 已提交
182 183
import media from '@ohos.multimedia.media'
import fileIO from '@ohos.fileio'
W
wusongqing 已提交
184 185 186
export class VideoPlayerDemo {
  // Report an error in the case of a function invocation failure.
  failureCallback(error) {
W
wusongqing 已提交
187 188 189
    console.info(`error happened,error Name is ${error.name}`);
    console.info(`error happened,error Code is ${error.code}`);
    console.info(`error happened,error Message is ${error.message}`);
W
wusongqing 已提交
190
  }
W
wusongqing 已提交
191

W
wusongqing 已提交
192 193
  // Report an error in the case of a function invocation exception.
  catchCallback(error) {
W
wusongqing 已提交
194 195 196
    console.info(`catch error happened,error Name is ${error.name}`);
    console.info(`catch error happened,error Code is ${error.code}`);
    console.info(`catch error happened,error Message is ${error.message}`);
W
wusongqing 已提交
197
  }
W
wusongqing 已提交
198

W
wusongqing 已提交
199 200 201 202 203 204 205 206 207 208 209
  // Used to print the video track information.
  printfDescription(obj) {
    for (let item in obj) {
      let property = obj[item];
      console.info('key is ' + item);
      console.info('value is ' + property);
    }
  }

  async videoPlayerDemo() {
    let videoPlayer = undefined;
W
wusongqing 已提交
210
    let surfaceID = 'test' // The surfaceID parameter is used for screen display. Its value is obtained through the XComponent API. For details about the document link, see the method of creating the XComponent.
W
wusongqing 已提交
211 212 213 214 215
    let fdPath = 'fd://'
    // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\H264_AAC.mp4 /data/app/el1/bundle/public/ohos.acts.multimedia.video.videoplayer/ohos.acts.multimedia.video.videoplayer/assets/entry/resources/rawfile" command.
    let path = '/data/app/el1/bundle/public/ohos.acts.multimedia.video.videoplayer/ohos.acts.multimedia.video.videoplayer/assets/entry/resources/rawfile/H264_AAC.mp4';
    await fileIO.open(path).then((fdNumber) => {
      fdPath = fdPath + '' + fdNumber;
JoyboyCZ's avatar
JoyboyCZ 已提交
216
      console.info('open fd success fd is' + fdPath);
W
wusongqing 已提交
217 218 219 220
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
W
wusongqing 已提交
221
    });
W
wusongqing 已提交
222 223 224
    // Call createVideoPlayer to create a VideoPlayer instance.
    await media.createVideoPlayer().then((video) => {
      if (typeof (video) != 'undefined') {
W
wusongqing 已提交
225 226
        console.info('createVideoPlayer success!');
        videoPlayer = video;
W
wusongqing 已提交
227
      } else {
W
wusongqing 已提交
228
        console.info('createVideoPlayer fail!');
W
wusongqing 已提交
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
      }
    }, this.failureCallback).catch(this.catchCallback);
    // Set the playback source for the player.
    videoPlayer.url = fdPath;

    // Set the surface ID to display the video image.
    await videoPlayer.setDisplaySurface(surfaceID).then(() => {
      console.info('setDisplaySurface success');
    }, this.failureCallback).catch(this.catchCallback);

    // Call the prepare API to prepare for playback.
    await videoPlayer.prepare().then(() => {
      console.info('prepare success');
    }, this.failureCallback).catch(this.catchCallback);

    // Call the play API to start playback.
    await videoPlayer.play().then(() => {
      console.info('play success');
    }, this.failureCallback).catch(this.catchCallback);

    // Stop playback.
    await videoPlayer.stop().then(() => {
      console.info('stop success');
    }, this.failureCallback).catch(this.catchCallback);

    // Release playback resources.
    await videoPlayer.release().then(() => {
      console.info('release success');
    }, this.failureCallback).catch(this.catchCallback);

    // Set the related instances to undefined.
    videoPlayer = undefined;
    surfaceID = undefined;
  }
}
W
wusongqing 已提交
264 265 266 267 268
```

### Switching to the Next Video Clip

```js
W
wusongqing 已提交
269 270
import media from '@ohos.multimedia.media'
import fileIO from '@ohos.fileio'
W
wusongqing 已提交
271 272 273
export class VideoPlayerDemo {
  // Report an error in the case of a function invocation failure.
  failureCallback(error) {
W
wusongqing 已提交
274 275 276
    console.info(`error happened,error Name is ${error.name}`);
    console.info(`error happened,error Code is ${error.code}`);
    console.info(`error happened,error Message is ${error.message}`);
W
wusongqing 已提交
277
  }
W
wusongqing 已提交
278

W
wusongqing 已提交
279 280
  // Report an error in the case of a function invocation exception.
  catchCallback(error) {
W
wusongqing 已提交
281 282 283
    console.info(`catch error happened,error Name is ${error.name}`);
    console.info(`catch error happened,error Code is ${error.code}`);
    console.info(`catch error happened,error Message is ${error.message}`);
W
wusongqing 已提交
284
  }
W
wusongqing 已提交
285

W
wusongqing 已提交
286 287 288 289 290 291 292 293 294 295 296
  // Used to print the video track information.
  printfDescription(obj) {
    for (let item in obj) {
      let property = obj[item];
      console.info('key is ' + item);
      console.info('value is ' + property);
    }
  }

  async videoPlayerDemo() {
    let videoPlayer = undefined;
W
wusongqing 已提交
297
    let surfaceID = 'test' // The surfaceID parameter is used for screen display. Its value is obtained through the XComponent API. For details about the document link, see the method of creating the XComponent.
W
wusongqing 已提交
298 299 300 301 302 303
    let fdPath = 'fd://'
    // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\H264_AAC.mp4 /data/app/el1/bundle/public/ohos.acts.multimedia.video.videoplayer/ohos.acts.multimedia.video.videoplayer/assets/entry/resources/rawfile" command.
    let path = '/data/app/el1/bundle/public/ohos.acts.multimedia.video.videoplayer/ohos.acts.multimedia.video.videoplayer/assets/entry/resources/rawfile/H264_AAC.mp4';
    let nextPath = '/data/app/el1/bundle/public/ohos.acts.multimedia.video.videoplayer/ohos.acts.multimedia.video.videoplayer/assets/entry/resources/rawfile/MP4_AAC.mp4';
    await fileIO.open(path).then((fdNumber) => {
      fdPath = fdPath + '' + fdNumber;
JoyboyCZ's avatar
JoyboyCZ 已提交
304
      console.info('open fd success fd is' + fdPath);
W
wusongqing 已提交
305 306 307 308
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
W
wusongqing 已提交
309
    });
W
wusongqing 已提交
310 311 312
    // Call createVideoPlayer to create a VideoPlayer instance.
    await media.createVideoPlayer().then((video) => {
      if (typeof (video) != 'undefined') {
W
wusongqing 已提交
313 314
        console.info('createVideoPlayer success!');
        videoPlayer = video;
W
wusongqing 已提交
315
      } else {
W
wusongqing 已提交
316
        console.info('createVideoPlayer fail!');
W
wusongqing 已提交
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
      }
    }, this.failureCallback).catch(this.catchCallback);
    // Set the playback source for the player.
    videoPlayer.url = fdPath;

    // Set the surface ID to display the video image.
    await videoPlayer.setDisplaySurface(surfaceID).then(() => {
      console.info('setDisplaySurface success');
    }, this.failureCallback).catch(this.catchCallback);

    // Call the prepare API to prepare for playback.
    await videoPlayer.prepare().then(() => {
      console.info('prepare success');
    }, this.failureCallback).catch(this.catchCallback);

    // Call the play API to start playback.
    await videoPlayer.play().then(() => {
      console.info('play success');
    }, this.failureCallback).catch(this.catchCallback);

    // Reset the playback configuration.
    await videoPlayer.reset().then(() => {
      console.info('reset success');
    }, this.failureCallback).catch(this.catchCallback);

    // Obtain the next video FD address.
    fdPath = 'fd://'
    await fileIO.open(nextPath).then((fdNumber) => {
      fdPath = fdPath + '' + fdNumber;
JoyboyCZ's avatar
JoyboyCZ 已提交
346
      console.info('open fd success fd is' + fdPath);
W
wusongqing 已提交
347 348 349 350 351 352 353 354
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
    });
    // Set the second video playback source.
    videoPlayer.url = fdPath;

W
wusongqing 已提交
355
    // Call the prepare API to prepare for playback.
W
wusongqing 已提交
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
    await videoPlayer.prepare().then(() => {
      console.info('prepare success');
    }, this.failureCallback).catch(this.catchCallback);

    // Call the play API to start playback.
    await videoPlayer.play().then(() => {
      console.info('play success');
    }, this.failureCallback).catch(this.catchCallback);

    // Release playback resources.
    await videoPlayer.release().then(() => {
      console.info('release success');
    }, this.failureCallback).catch(this.catchCallback);

    // Set the related instances to undefined.
    videoPlayer = undefined;
    surfaceID = undefined;
  }
}
W
wusongqing 已提交
375 376 377 378 379
```

### Looping a Video Clip

```js
W
wusongqing 已提交
380 381
import media from '@ohos.multimedia.media'
import fileIO from '@ohos.fileio'
W
wusongqing 已提交
382 383 384
export class VideoPlayerDemo {
  // Report an error in the case of a function invocation failure.
  failureCallback(error) {
W
wusongqing 已提交
385 386 387
    console.info(`error happened,error Name is ${error.name}`);
    console.info(`error happened,error Code is ${error.code}`);
    console.info(`error happened,error Message is ${error.message}`);
W
wusongqing 已提交
388
  }
W
wusongqing 已提交
389

W
wusongqing 已提交
390 391
  // Report an error in the case of a function invocation exception.
  catchCallback(error) {
W
wusongqing 已提交
392 393 394
    console.info(`catch error happened,error Name is ${error.name}`);
    console.info(`catch error happened,error Code is ${error.code}`);
    console.info(`catch error happened,error Message is ${error.message}`);
W
wusongqing 已提交
395
  }
W
wusongqing 已提交
396

W
wusongqing 已提交
397 398 399 400 401 402 403 404 405 406 407
  // Used to print the video track information.
  printfDescription(obj) {
    for (let item in obj) {
      let property = obj[item];
      console.info('key is ' + item);
      console.info('value is ' + property);
    }
  }

  async videoPlayerDemo() {
    let videoPlayer = undefined;
W
wusongqing 已提交
408
    let surfaceID = 'test' // The surfaceID parameter is used for screen display. Its value is obtained through the XComponent API. For details about the document link, see the method of creating the XComponent.
W
wusongqing 已提交
409 410 411 412 413
    let fdPath = 'fd://'
    // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\H264_AAC.mp4 /data/app/el1/bundle/public/ohos.acts.multimedia.video.videoplayer/ohos.acts.multimedia.video.videoplayer/assets/entry/resources/rawfile" command.
    let path = '/data/app/el1/bundle/public/ohos.acts.multimedia.video.videoplayer/ohos.acts.multimedia.video.videoplayer/assets/entry/resources/rawfile/H264_AAC.mp4';
    await fileIO.open(path).then((fdNumber) => {
      fdPath = fdPath + '' + fdNumber;
JoyboyCZ's avatar
JoyboyCZ 已提交
414
      console.info('open fd success fd is' + fdPath);
W
wusongqing 已提交
415 416 417 418
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
W
wusongqing 已提交
419
    });
W
wusongqing 已提交
420 421 422
    // Call createVideoPlayer to create a VideoPlayer instance.
    await media.createVideoPlayer().then((video) => {
      if (typeof (video) != 'undefined') {
W
wusongqing 已提交
423 424
        console.info('createVideoPlayer success!');
        videoPlayer = video;
W
wusongqing 已提交
425
      } else {
W
wusongqing 已提交
426
        console.info('createVideoPlayer fail!');
W
wusongqing 已提交
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
      }
    }, this.failureCallback).catch(this.catchCallback);
    // Set the playback source for the player.
    videoPlayer.url = fdPath;

    // Set the surface ID to display the video image.
    await videoPlayer.setDisplaySurface(surfaceID).then(() => {
      console.info('setDisplaySurface success');
    }, this.failureCallback).catch(this.catchCallback);

    // Call the prepare API to prepare for playback.
    await videoPlayer.prepare().then(() => {
      console.info('prepare success');
    }, this.failureCallback).catch(this.catchCallback);
    // Set the loop playback attribute.
    videoPlayer.loop = true;
W
wusongqing 已提交
443
    // Call the play API to start loop playback.
W
wusongqing 已提交
444
    await videoPlayer.play().then(() => {
W
wusongqing 已提交
445
      console.info('play success, loop value is ' + videoPlayer.loop);
W
wusongqing 已提交
446 447 448
    }, this.failureCallback).catch(this.catchCallback);
  }
}
W
wusongqing 已提交
449
```