• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# AVPlayer播放器开发指导
2
3## 简介
4
5AVPlayer主要工作是将Audio/Video媒体资源转码为可供渲染的图像和可听见的音频模拟信号,并通过输出设备进行播放,同时对播放任务进行管理,包括开始播放、暂停播放、停止播放、释放资源、设置音量、跳转播放位置、获取轨道信息等功能控制。
6
7## 运作机制
8
9该模块提供了播放状态变化示意图[AVPlayerState](../reference/apis/js-apis-media.md#avplayerstate9)、音频播放外部模块交互图和视频播放外部模块交互图。
10
11**图1** 播放状态变化示意图<a name = avplayer_state></a>
12
13![zh-ch_image_avplayer_state_machine](figures/zh-ch_image_avplayer_state_machine.png)
14
15
16**图2** 音频播放外部模块交互图
17
18![zh-ch_image_avplayer_audio](figures/zh-ch_image_avplayer_audio.png)
19
20**说明**:应用通过调用JS接口层提供的AVPlayer js接口实现相应功能时,框架层会通过Player Framework的播放服务解析成音频数据流,音频数据流经过软件解码后输出至Audio Framework的音频服务,由音频子系统输出至硬件接口层的音频HDI,实现音频播放功能。完整的音乐播放器工作需要:应用(应用适配)、Player Framework、Audio Framework、Audio HDI(驱动适配)共同实现。
21
22*注意:音频播放需要音频子系统配合*
23
241. 应用把url传递给AVPlayer JS。
252. 播放服务把音频PCM数据流输出给音频服务,音频服务输出给Audio HDI。
26
27
28**图3** 视频播放外部模块交互图
29
30![zh-ch_image_avplayer_video](figures/zh-ch_image_avplayer_video.png)
31
32**说明**:应用通过调用JS接口层提供的AVPlayer js接口实现相应功能时,框架层会通过Player Framework的播放服务解析成单独的音频数据流和视频数据流,音频数据流经过软件解码后输出至Audio Framework的音频服务,由音频子系统输出至硬件接口层的音频HDI,实现音频播放功能。视频数据流经过硬件(推荐)/软件解码后输出至Graphic Framework的渲染服务(Renderer Service),由RS子系统输出至硬件接口层的显示HDI。完整的视频播放器工作需要:应用(应用适配)、XCompomemt组件、Player Framework、Graphic Framework、Audio Framework、Display HDI(驱动适配)和Audio HDI(驱动适配)共同实现。
33
34*注意:视频播放需要显示、音频、解码等多个子系统配合。*
35
361. 应用从Xcomponent组件获取surfaceID,[获取方式](../reference/arkui-ts/ts-basic-components-xcomponent.md)。
372. 应用把url、surfaceID传递给AVPlayer JS。
383. 播放服务把视频ES数据流输出给Codec HDI,解码获得视频帧(NV12/NV21/RGBA)。
394. 播放服务把音频PCM数据流输出给音频服务,音频服务输出给Audio HDI。
405. 播放服务把视频帧(NV12/NV21/RGBA)输出给RS服务,RS服务输出给Display HDI。
41
42## 兼容性说明
43
44视频播放支持的视频格式分必选规格和可选规格。必选规格为所有厂商均支持的视频格式。对于可选规格,厂商将基于实际情况决定是否实现。建议开发者做兼容处理,保证全平台兼容。
45推荐使用主流的播放格式和主流分辨率,不建议开发者自制非常或者异常码流,以免产生无法播放、卡住、花屏等兼容性问题。若发生此类问题不会影响系统,退出码流播放即可。
46
47|  视频格式  |  是否必选规格  |
48|:--------:|:-----:|
49|   H264   |   是  |
50|  MPEG2   |   否  |
51|  MPEG4   |   否  |
52|   H263   |   否  |
53|    VP8   |   否  |
54
55主流的播放格式和主流分辨率如下:
56
57| 视频容器规格 |                     规格描述                      |               分辨率               |
58| :----------: | :-----------------------------------------------: | :--------------------------------: |
59|     mp4      | 视频格式:H264/MPEG2/MPEG4/H263 音频格式:AAC/MP3 | 主流分辨率,如1080P/720P/480P/270P |
60|     mkv      | 视频格式:H264/MPEG2/MPEG4/H263 音频格式:AAC/MP3 | 主流分辨率,如1080P/720P/480P/270P |
61|      ts      |   视频格式:H264/MPEG2/MPEG4 音频格式:AAC/MP3    | 主流分辨率,如1080P/720P/480P/270P |
62|     webm     |          视频格式:VP8 音频格式:VORBIS           | 主流分辨率,如1080P/720P/480P/270P |
63
64| 音频容器规格  |   规格描述   |
65| :----------: | :----------: |
66|     m4a      | 音频格式:AAC |
67|     aac      | 音频格式:AAC |
68|     mp3      | 音频格式:MP3 |
69|     ogg      | 音频格式:VORBIS |
70|     wav      | 音频格式:PCM |
71
72## 开发指导
73
74详细API含义可参考:[媒体服务API文档AVPlayer](../reference/apis/js-apis-media.md#avplayer9)
75
76### 播放流程说明
77
78播放的全流程场景包含:创建实例,设置资源,设置窗口(视频),准备播放(获取轨道信息/音量/倍速/焦点模式/缩放模式/设置bitrates),播控(播放/暂停/Seek/音量/停止),重置资源,销毁播放
79
801:创建实例[createAVPlayer()](../reference/apis/js-apis-media.md#mediacreateavplayer9),AVPlayer初始化[idle](#avplayer_state)状态
81
822:设置业务需要的监听事件,搭配全流程场景使用
83
843:设置资源 [url](../reference/apis/js-apis-media.md#avplayer_属性),AVPlayer进入[initialized](#avplayer_state)状态,此时可以设置视频窗口 [surfaceId](../reference/apis/js-apis-media.md#avplayer_属性),支持的规格可参考:[AVPlayer属性说明](../reference/apis/js-apis-media.md#avplayer_属性)
85
864:准备播放 [prepare()](../reference/apis/js-apis-media.md#avplayer_prepare),AVPlayer进入[prepared](#avplayer_state)状态
87
885:视频播控:播放 [play()](../reference/apis/js-apis-media.md#avplayer_play),暂停 [pause()](../reference/apis/js-apis-media.md#avplayer_pause),跳转 [seek()](../reference/apis/js-apis-media.md#avplayer_seek),停止 [stop()](../reference/apis/js-apis-media.md#avplayer_stop) 等操作
89
906:重置资源 [reset()](../reference/apis/js-apis-media.md#avplayer_reset),AVPlayer重新进入[idle](#avplayer_state)状态,允许更换资源 [url](../reference/apis/js-apis-media.md#avplayer_属性)
91
927:销毁播放 [release()](../reference/apis/js-apis-media.md#avplayer_release),AVPlayer进入[released](#avplayer_state)状态,退出播放
93
94> **说明:**
95>
96> prepared/playing/paused/compeled 状态时,播放引擎处于工作状态,这需要占用系统较多的运行内存,当客户端暂时不使用播放器时,要求调用 reset() 或 release() 回收。
97
98### 监听事件
99
100| 事件类型                                          | 说明                                                         |
101| ------------------------------------------------- | ------------------------------------------------------------ |
102| stateChange<a name = stateChange></a>             | 必要事件,监听播放器的状态机                                 |
103| error<a name = error></a>                         | 必要事件,监听播放器的错误信息                               |
104| durationUpdate<a name = durationUpdate></a>       | 用于进度条,监听进度条长度,刷新资源时长                     |
105| timeUpdate<a name = timeUpdate></a>               | 用于进度条,监听进度条当前位置,刷新当前时间                 |
106| seekDone<a name = seekDone></a>                   | 响应api调用,监听seek()请求完成情况                          |
107| speedDone<a name = speedDone></a>                 | 响应api调用,监听setSpeed()请求完成情况                      |
108| volumeChange<a name = volumeChange></a>           | 响应api调用,监听setVolume()请求完成情况                     |
109| bitrateDone<a name = bitrateDone></a>             | 响应api调用,用于HLS协议流,监听setBitrate()请求完成情况     |
110| availableBitrates<a name = availableBitrates></a> | 用于HLS协议流,监听HLS资源的可选bitrates,用于setBitrate()   |
111| bufferingUpdate<a name = bufferingUpdate></a>     | 用于网络播放,监听网络播放缓冲信息                           |
112| startRenderFrame<a name = startRenderFrame></a>   | 用于视频播放,监听视频播放首帧渲染时间                       |
113| videoSizeChange<a name = videoSizeChange></a>     | 用于视频播放,监听视频播放的宽高信息,可用于调整窗口大小、比例 |
114| audioInterrupt<a name = audioInterrupt></a>       | 用于视频播放,监听音频焦点切换信息,搭配属性audioInterruptMode使用 |
115
116###
117
118### 全量接口示例
119
120```js
121import media from '@ohos.multimedia.media'
122import audio from '@ohos.multimedia.audio';
123import fs from '@ohos.file.fs'
124
125const TAG = 'AVPlayerDemo:'
126export class AVPlayerDemo {
127  private count:number = 0
128  private avPlayer
129  private surfaceID:string // surfaceID用于播放画面显示,具体的值需要通过Xcomponent接口获取,相关文档链接见上面Xcomponent创建方法
130
131  // 注册avplayer回调函数
132  setAVPlayerCallback() {
133    // 状态机变化回调函数
134    this.avPlayer.on('stateChange', async (state, reason) => {
135      switch (state) {
136        case 'idle': // 成功调用reset接口后触发该状态机上报
137          console.info(TAG + 'state idle called')
138          this.avPlayer.release() // 释放avplayer对象
139          break;
140        case 'initialized': // avplayer 设置播放源后触发该状态上报
141          console.info(TAG + 'state initialized called ')
142          this.avPlayer.surfaceId = this.surfaceID // 设置显示画面,当播放的资源为纯音频时无需设置
143          this.avPlayer.prepare().then(() => {
144            console.info(TAG+ 'prepare success');
145          }, (err) => {
146            console.error(TAG + 'prepare filed,error message is :' + err.message)
147          })
148          break;
149        case 'prepared': // prepare调用成功后上报该状态机
150          console.info(TAG + 'state prepared called')
151          this.avPlayer.play() // 调用播放接口开始播放
152          break;
153        case 'playing': // play成功调用后触发该状态机上报
154          console.info(TAG + 'state playing called')
155          if (this.count == 0) {
156            this.avPlayer.pause() // 调用暂停播放接口
157          } else {
158            this.avPlayer.seek(10000, media.SeekMode.SEEK_PREV_SYNC) // 前向seek置10秒处,触发seekDone回调函数
159          }
160          break;
161        case 'paused': // pause成功调用后触发该状态机上报
162          console.info(TAG + 'state paused called')
163          if (this.count == 0) {
164            this.count++
165            this.avPlayer.play() // 继续调用播放接口开始播放
166          }
167          break;
168        case 'completed': // 播放结束后触发该状态机上报
169          console.info(TAG + 'state completed called')
170          this.avPlayer.stop() //调用播放结束接口
171          break;
172        case 'stopped': // stop接口成功调用后触发该状态机上报
173          console.info(TAG + 'state stopped called')
174          this.avPlayer.reset() // 调用reset接口初始化avplayer状态
175          break;
176        case 'released':
177          console.info(TAG + 'state released called')
178          break;
179        case 'error':
180          console.info(TAG + 'state error called')
181          break;
182        default:
183          console.info(TAG + 'unkown state :' + state)
184          break;
185      }
186    })
187    // 时间上报监听函数
188    this.avPlayer.on('timeUpdate', (time:number) => {
189      console.info(TAG + 'timeUpdate success,and new time is :' + time)
190    })
191    // 音量变化回调函数
192    this.avPlayer.on('volumeChange', (vol:number) => {
193      console.info(TAG + 'volumeChange success,and new volume is :' + vol)
194      this.avPlayer.setSpeed(media.AVPlayerSpeed.SPEED_FORWARD_2_00_X) // 设置两倍速播放,并触发speedDone回调
195    })
196    // 视频播放结束触发回调
197    this.avPlayer.on('endOfStream', () => {
198      console.info(TAG + 'endOfStream success')
199    })
200    // seek操作回调函数
201    this.avPlayer.on('seekDone', (seekDoneTime:number) => {
202      console.info(TAG + 'seekDone success,and seek time is:' + seekDoneTime)
203      this.avPlayer.setVolume(0.5) // 设置音量为0.5,并触发volumeChange回调函数
204    })
205    // 设置倍速播放回调函数
206    this.avPlayer.on('speedDone', (speed:number) => {
207      console.info(TAG + 'speedDone success,and speed value is:' + speed)
208    })
209    // bitrate设置成功回调函数
210    this.avPlayer.on('bitrateDone', (bitrate:number) => {
211      console.info(TAG + 'bitrateDone success,and bitrate value is:' + bitrate)
212    })
213    // 缓冲上报回调函数
214    this.avPlayer.on('bufferingUpdate', (infoType: media.BufferingInfoType, value: number) => {
215      console.info(TAG + 'bufferingUpdate success,and infoType value is:' + infoType + ', value is :' + value)
216    })
217    // 首帧上报回调函数
218    this.avPlayer.on('startRenderFrame', () => {
219      console.info(TAG + 'startRenderFrame success')
220    })
221    // 视频宽高上报回调函数
222    this.avPlayer.on('videoSizeChange', (width: number, height: number) => {
223      console.info(TAG + 'videoSizeChange success,and width is:' + width + ', height is :' + height)
224    })
225    // 焦点上报回调函数
226    this.avPlayer.on('audioInterrupt', (info: audio.InterruptEvent) => {
227      console.info(TAG + 'audioInterrupt success,and InterruptEvent info is:' + info)
228    })
229    // HLS上报所有支持的比特率
230    this.avPlayer.on('availableBitrates', (bitrates: Array<number>) => {
231      console.info(TAG + 'availableBitrates success,and availableBitrates length is:' + bitrates.length)
232    })
233  }
234
235  async avPlayerDemo() {
236    // 创建avPlayer实例对象
237    this.avPlayer = await media.createAVPlayer()
238    let fdPath = 'fd://'
239    let pathDir = "/data/storage/el2/base/haps/entry/files" // pathDir在FA模型和Stage模型的获取方式不同,请参考开发步骤首行的说明,根据实际情况自行获取。
240    // path路径的码流可通过"hdc file send D:\xxx\H264_AAC.mp4 /data/app/el2/100/base/ohos.acts.multimedia.media.avplayer/haps/entry/files" 命令,将其推送到设备上
241    let path = pathDir  + '/H264_AAC.mp4'
242    let file = await fs.open(path)
243    fdPath = fdPath + '' + file.fd
244    this.avPlayer.url = fdPath
245  }
246}
247```
248
249### 正常播放场景
250
251```js
252import media from '@ohos.multimedia.media'
253import fs from '@ohos.file.fs'
254
255const TAG = 'AVPlayerDemo:'
256export class AVPlayerDemo {
257  private avPlayer
258  private surfaceID:string // surfaceID用于播放画面显示,具体的值需要通过Xcomponent接口获取,相关文档链接见上面Xcomponent创建方法
259
260  // 注册avplayer回调函数
261  setAVPlayerCallback() {
262    // 状态机变化回调函数
263    this.avPlayer.on('stateChange', async (state, reason) => {
264      switch (state) {
265        case 'idle': // 成功调用reset接口后触发该状态机上报
266          console.info(TAG + 'state idle called')
267          break;
268        case 'initialized': // avplayer 设置播放源后触发该状态上报
269          console.info(TAG + 'state initialized called ')
270          this.avPlayer.surfaceId = this.surfaceID // 设置显示画面,当播放的资源为纯音频时无需设置
271          this.avPlayer.prepare().then(() => {
272            console.info(TAG+ 'prepare success');
273          }, (err) => {
274            console.error(TAG + 'prepare filed,error message is :' + err.message)
275          })
276          break;
277        case 'prepared': // prepare调用成功后上报该状态机
278          console.info(TAG + 'state prepared called')
279          this.avPlayer.play() // 调用播放接口开始播放
280          break;
281        case 'playing': // play成功调用后触发该状态机上报
282          console.info(TAG + 'state playing called')
283          break;
284        case 'paused': // pause成功调用后触发该状态机上报
285          console.info(TAG + 'state paused called')
286          break;
287        case 'completed': // 播放结束后触发该状态机上报
288          console.info(TAG + 'state completed called')
289          this.avPlayer.stop() //调用播放结束接口
290          break;
291        case 'stopped': // stop接口成功调用后触发该状态机上报
292          console.info(TAG + 'state stopped called')
293          this.avPlayer.release() // 调用reset接口初始化avplayer状态
294          break;
295        case 'released':
296          console.info(TAG + 'state released called')
297          break;
298        case 'error':
299          console.info(TAG + 'state error called')
300          break;
301        default:
302          console.info(TAG + 'unkown state :' + state)
303          break;
304      }
305    })
306  }
307
308  async avPlayerDemo() {
309    // 创建avPlayer实例对象
310    this.avPlayer = await media.createAVPlayer()
311    let fileDescriptor = undefined
312    // 使用资源管理模块的getRawFileDescriptor获取集成在应用中的媒体资源,并使用AVPlayer的fdSrc属性完成媒体资源初始化
313    // 其中的参数fd/offset/length定义请查看媒体API文档,globalThis.abilityContext参数为系统环境变量,在系统启动时在主界面保存为全局变量
314    await globalThis.abilityContext.resourceManager.getRawFileDescriptor('H264_AAC.mp4').then((value) => {
315        fileDescriptor = {fd: value.fd, offset: value.offset, length: value.length}
316    })
317    this.avPlayer.fdSrc = fileDescriptor
318  }
319}
320```
321
322### 单曲循环场景
323
324```js
325import media from '@ohos.multimedia.media'
326import fs from '@ohos.file.fs'
327
328const TAG = 'AVPlayerDemo:'
329export class AVPlayerDemo {
330  private count:number = 0
331  private avPlayer
332  private surfaceID:string // surfaceID用于播放画面显示,具体的值需要通过Xcomponent接口获取,相关文档链接见上面Xcomponent创建方法
333
334  // 注册avplayer回调函数
335  setAVPlayerCallback() {
336    // 状态机变化回调函数
337    this.avPlayer.on('stateChange', async (state, reason) => {
338      switch (state) {
339        case 'idle': // 成功调用reset接口后触发该状态机上报
340          console.info(TAG + 'state idle called')
341          break;
342        case 'initialized': // avplayer 设置播放源后触发该状态上报
343          console.info(TAG + 'state initialized called ')
344          this.avPlayer.surfaceId = this.surfaceID // 设置显示画面,当播放的资源为纯音频时无需设置
345          this.avPlayer.prepare().then(() => {
346            console.info(TAG+ 'prepare success');
347          }, (err) => {
348            console.error(TAG + 'prepare filed,error message is :' + err.message)
349          })
350          break;
351        case 'prepared': // prepare调用成功后上报该状态机
352          console.info(TAG + 'state prepared called')
353          this.avPlayer.loop = true // 设置单曲循环播放,单曲循环播放至结尾后会触发endOfStream回调
354          this.avPlayer.play() // 调用播放接口开始播放
355          break;
356        case 'playing': // play成功调用后触发该状态机上报
357          console.info(TAG + 'state playing called')
358          break;
359        case 'paused': // pause成功调用后触发该状态机上报
360          console.info(TAG + 'state paused called')
361          break;
362        case 'completed': // 播放结束后触发该状态机上报
363          console.info(TAG + 'state completed called')
364          // 当第二次触发endOfStream回调后取消循环播放,再次播放到结尾后触发completed状态机上报
365          this.avPlayer.stop() //调用播放结束接口
366          break;
367        case 'stopped': // stop接口成功调用后触发该状态机上报
368          console.info(TAG + 'state stopped called')
369          this.avPlayer.release() // 调用reset接口初始化avplayer状态
370          break;
371        case 'released':
372          console.info(TAG + 'state released called')
373          break;
374        case 'error':
375          console.info(TAG + 'state error called')
376          break;
377        default:
378          console.info(TAG + 'unkown state :' + state)
379          break;
380      }
381    })
382    // 视频播放结束触发回调
383    this.avPlayer.on('endOfStream', () => {
384      console.info(TAG + 'endOfStream success')
385      if (this.count == 1) {
386        this.avPlayer.loop = false // 取消循环播放
387      } else {
388        this.count++
389      }
390    })
391  }
392
393  async avPlayerDemo() {
394    // 创建avPlayer实例对象
395    this.avPlayer = await media.createAVPlayer()
396    let fdPath = 'fd://'
397    let pathDir = "/data/storage/el2/base/haps/entry/files" // pathDir在FA模型和Stage模型的获取方式不同,请参考开发步骤首行的说明,根据实际情况自行获取。
398    // path路径的码流可通过"hdc file send D:\xxx\H264_AAC.mp4 /data/app/el2/100/base/ohos.acts.multimedia.media.avplayer/haps/entry/files" 命令,将其推送到设备上
399    let path = pathDir  + '/H264_AAC.mp4'
400    let file = await fs.open(path)
401    fdPath = fdPath + '' + file.fd
402    this.avPlayer.url = fdPath
403  }
404}
405```
406### 视频切换场景
407
408```js
409import media from '@ohos.multimedia.media'
410import fs from '@ohos.file.fs'
411
412const TAG = 'AVPlayerDemo:'
413export class AVPlayerDemo {
414  private count:number = 0
415  private avPlayer
416  private surfaceID:string // surfaceID用于播放画面显示,具体的值需要通过Xcomponent接口获取,相关文档链接见上面Xcomponent创建方法
417
418  async nextVideo() {
419    let fdPath = 'fd://'
420    let pathDir = "/data/storage/el2/base/haps/entry/files" // pathDir在FA模型和Stage模型的获取方式不同,请参考开发步骤首行的说明,根据实际情况自行获取。
421    // path路径的码流可通过"hdc file send D:\xxx\H264_MP3.mp4 /data/app/el2/100/base/ohos.acts.multimedia.media.avplayer/haps/entry/files" 命令,将其推送到设备上
422    let path = pathDir  + '/H264_MP3.mp4'
423    let file = await fs.open(path)
424    fdPath = fdPath + '' + file.fd
425    this.avPlayer.url = fdPath // 再次触发initialized状态机上报
426  }
427
428  // 注册avplayer回调函数
429  setAVPlayerCallback() {
430    // 状态机变化回调函数
431    this.avPlayer.on('stateChange', async (state, reason) => {
432      switch (state) {
433        case 'idle': // 成功调用reset接口后触发该状态机上报
434          console.info(TAG + 'state idle called')
435          await this.nextVideo() // 切换下一个视频播放
436          break;
437        case 'initialized': // avplayer 设置播放源后触发该状态上报
438          console.info(TAG + 'state initialized called ')
439          this.avPlayer.surfaceId = this.surfaceID // 设置显示画面,当播放的资源为纯音频时无需设置
440          this.avPlayer.prepare().then(() => {
441            console.info(TAG+ 'prepare success');
442          }, (err) => {
443            console.error(TAG + 'prepare filed,error message is :' + err.message)
444          })
445          break;
446        case 'prepared': // prepare调用成功后上报该状态机
447          console.info(TAG + 'state prepared called')
448          this.avPlayer.play() // 调用播放接口开始播放
449          break;
450        case 'playing': // play成功调用后触发该状态机上报
451          console.info(TAG + 'state playing called')
452          break;
453        case 'paused': // pause成功调用后触发该状态机上报
454          console.info(TAG + 'state paused called')
455          break;
456        case 'completed': // 播放结束后触发该状态机上报
457          console.info(TAG + 'state completed called')
458          if (this.count == 0) {
459            this.count++
460            this.avPlayer.reset() //调用重置接口准备切换下一个视频
461          } else {
462            this.avPlayer.release() //切换视频后播放至结尾释放avplayer对象
463          }
464          break;
465        case 'stopped': // stop接口成功调用后触发该状态机上报
466          console.info(TAG + 'state stopped called')
467          break;
468        case 'released':
469          console.info(TAG + 'state released called')
470          break;
471        case 'error':
472          console.info(TAG + 'state error called')
473          break;
474        default:
475          console.info(TAG + 'unkown state :' + state)
476          break;
477      }
478    })
479  }
480
481  async avPlayerDemo() {
482    // 创建avPlayer实例对象
483    this.avPlayer = await media.createAVPlayer()
484    let fdPath = 'fd://'
485    let pathDir = "/data/storage/el2/base/haps/entry/files" // pathDir在FA模型和Stage模型的获取方式不同,请参考开发步骤首行的说明,根据实际情况自行获取。
486    // path路径的码流可通过"hdc file send D:\xxx\H264_AAC.mp4 /data/app/el2/100/base/ohos.acts.multimedia.media.avplayer/haps/entry/files" 命令,将其推送到设备上
487    let path = pathDir  + '/H264_AAC.mp4'
488    let file = await fs.open(path)
489    fdPath = fdPath + '' + file.fd
490    this.avPlayer.url = fdPath
491  }
492}
493```