当前位置:   article > 正文

制作一个OpenHarmony视频播放器

制作一个OpenHarmony视频播放器

简介

媒体子系统是 OpenHarmony 中重要的子系统,可以提供音视频播放能力。媒体子系统为开发者提供一套简单且易于理解的接口,使得开发者能够方便接入系统并使用系统的媒体资源。媒体子系统提供以下常用功能:

  • 音视频播放(AVPlayer9+),AudioPlayer6+ 和 VideoPlayer8+ 整合,升级了状态机和错误码,推荐使用
  • 音视频录制(AVRecorder9+),AudioRecorder6+ 和 VideoRecorder9+ 整合,推荐使用
  • 音频播放(AudioPlayer6+),AVPlayer9+ 发布后停止维护,请使用 AVPlayer9+
  • 视频播放(VideoPlayer8+),AVPlayer9+ 发布后停止维护,请使用 AVPlayer9+
  • 音频录制(AudioRecorder6+),AVRecorder9+ 发布后停止维护,请使用 AVRecorder9+
  • 视频录制(VideoRecorder9+),AVRecorder9+ 发布后停止维护,请使用 AVRecorder9+

从 3.2 开始 OpenHarmony 推出了 AVPlayer 和 AVRecorder 接口,之前的 VideoPlayer、AudioPlayer 这些接口会停止维护,所以我们今天学习下怎么使用 AVPlayer 接口


导入模块

import media from '@ohos.multimedia.media';` ​
  • 1
  • 创建 avplayer
this.avPlayer = await media.createAVPlayer()` ​
  • 1

如上,我们使用的是 promise 接口,对应的接口定义为:

/**
  * Creates an AVPlayer instance.
  * @since 9
  * @syscap SystemCapability.Multimedia.Media.AVPlayer
  * @param callback Callback used to return AVPlayer instance if the operation is successful; returns null otherwise.
  * @throws { BusinessError } 5400101 - No memory. Return by callback.
  */
  function createAVPlayer(callback: AsyncCallback<AVPlayer>): void;

 /**
  * Creates an AVPlayer instance.
  * @since 9
  * @syscap SystemCapability.Multimedia.Media.AVPlayer
  * @returns A Promise instance used to return AVPlayer instance if the operation is successful; returns null otherwise.
  * @throws { BusinessError } 5400101 - No memory. Return by promise.
  */
  function createAVPlayer() : Promise<AVPlayer>;` ​

*   注册 avplayer 回调
   
   `//注册状态变化回调,不同状态时做不同动作
   avPlayer.on('stateChange', async (state, reason) => {
   	……
   })
   //注册时间变化回调,方便更新进度条时间
   avPlayer.on('timeUpdate', (time:number) => {
   	……
   })
  • 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
  • 27
  • 28
  • avplayer 播放流程

//视频播放伪代码
async avPlayerDemo() {
    this.avPlayer.on('stateChange', async (state, reason) => {
        switch (state) {
            case 'idle': // 成功调用reset接口后触发该状态机上报
                console.info(TAG + 'state idle called')
                this.avPlayer.release() // 释放avplayer对象
                break;
            case 'initialized': // avplayer 设置播放源后触发该状态上报
                console.info(TAG + 'state initialized called ')
                this.avPlayer.surfaceId = this.surfaceID // 设置显示画面,当播放的资源为纯音频时无需设置
                this.avPlayer.prepare().then(() => {
                    console.info(TAG+ 'prepare success');
                }, (err) => {
                    console.error(TAG + 'prepare filed,error message is :' + err.message)
                })
                break;
            case 'prepared': // prepare调用成功后上报该状态机
                console.info(TAG + 'state prepared called')
                this.avPlayer.play() // 调用播放接口开始播放
                break;
            case 'playing': // play成功调用后触发该状态机上报
                console.info(TAG + 'state playing called')
                if (this.count == 0) {
                    this.avPlayer.pause() // 调用暂停播放接口
                } else {
                    this.avPlayer.seek(10000, media.SeekMode.SEEK_PREV_SYNC) // 前向seek置10秒处,触发seekDone回调函数
                }
                break;
            case 'paused': // pause成功调用后触发该状态机上报
                console.info(TAG + 'state paused called')
                if (this.count == 0) {
                    this.count++
                    this.avPlayer.play() // 继续调用播放接口开始播放
                }
                break;
            case 'completed': // 播放结束后触发该状态机上报
                console.info(TAG + 'state completed called')
                this.avPlayer.stop() //调用播放结束接口
                break;
            case 'stopped': // stop接口成功调用后触发该状态机上报
                console.info(TAG + 'state stopped called')
                this.avPlayer.reset() // 调用reset接口初始化avplayer状态
                break;
            case 'released':
                console.info(TAG + 'state released called')
                break;
            case 'error':
                console.info(TAG + 'state error called')
                break;
            default:
                console.info(TAG + 'unkown state :' + state)
                break;
        }
    })

    // 创建avPlayer实例对象
    this.avPlayer = await media.createAVPlayer()
    let fdPath = 'fd://'
    let pathDir = "/data/storage/el2/base/haps/entry/files" // pathDir在FA模型和Stage模型的获取方式不同,请参考开发步骤首行的说明,根据实际情况自行获取。
    // path路径的码流可通过"hdc file send D:\xxx\H264_AAC.mp4 /data/app/el2/100/base/ohos.acts.multimedia.media.avplayer/haps/entry/files" 命令,将其推送到设备上
    let path = pathDir  + '/H264_AAC.mp4'
    let file = await fs.open(path)
    fdPath = fdPath + '' + file.fd
    //赋值url后就会进入stateChange callback
    this.avPlayer.url = fdPath
}
  • 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
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 其他播放控制接口
          /**
         * Prepare audio/video playback, it will request resource for playing.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param callback A callback instance used to return when prepare completed.
         * @throws { BusinessError } 5400102 - Operation not allowed. Return by callback.
         * @throws { BusinessError } 5400106 - Unsupport format. Return by callback.
         */
        prepare(callback: AsyncCallback<void>): void;
    
        /**
         * Prepare audio/video playback, it will request resource for playing.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @returns A Promise instance used to return when prepare completed.
         * @throws { BusinessError } 5400102 - Operation not allowed. Return by promise.
         * @throws { BusinessError } 5400106 - Unsupport format. Return by promise.
         */
        prepare(): Promise<void>;
    
        /**
         * Play audio/video playback.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param callback A callback instance used to return when play completed.
         * @throws { BusinessError } 5400102 - Operation not allowed. Return by callback.
         */
        play(callback: AsyncCallback<void>): void;
    
        /**
         * Play audio/video playback.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @returns A Promise instance used to return when play completed.
         * @throws { BusinessError } 5400102 - Operation not allowed. Return by promise.
         */
        play(): Promise<void>;
    
        /**
         * Pause audio/video playback.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param callback A callback instance used to return when pause completed.
         * @throws { BusinessError } 5400102 - Operation not allowed. Return by callback.
         */
        pause(callback: AsyncCallback<void>): void;
    
        /**
         * Pause audio/video playback.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @returns A Promise instance used to return when pause completed.
         * @throws { BusinessError } 5400102 - Operation not allowed. Return by promise.
         */
        pause(): Promise<void>;
    
        /**
         * Stop audio/video playback.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param callback A callback instance used to return when stop completed.
         * @throws { BusinessError } 5400102 - Operation not allowed. Return by callback.
         */
        stop(callback: AsyncCallback<void>): void;
    
         /**
          * Stop audio/video playback.
          * @since 9
          * @syscap SystemCapability.Multimedia.Media.AVPlayer
          * @returns A Promise instance used to return when stop completed.
          * @throws { BusinessError } 5400102 - Operation not allowed. Return by promise.
          */
        stop(): Promise<void>;
    
        /**
         * Reset AVPlayer, it will to idle state and can set src again.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param callback A callback instance used to return when reset completed.
         * @throws { BusinessError } 5400102 - Operation not allowed. Return by callback.
         */
        reset(callback: AsyncCallback<void>): void;
    
        /**
         * Reset AVPlayer, it will to idle state and can set src again.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @returns A Promise instance used to return when reset completed.
         * @throws { BusinessError } 5400102 - Operation not allowed. Return by promise.
         */
        reset(): Promise<void>;
    
        /**
         * Releases resources used for AVPlayer.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param callback A callback instance used to return when release completed.
         * @throws { BusinessError } 5400102 - Operation not allowed. Return by callback.
         */
        release(callback: AsyncCallback<void>): void;
    
        /**
         * Releases resources used for AVPlayer.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @returns A Promise instance used to return when release completed.
         * @throws { BusinessError } 5400102 - Operation not allowed. Return by promise.
         */
        release(): Promise<void>;
    
        /**
         * Jumps to the specified playback position.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param timeMs Playback position to jump, should be in [0, duration].
         * @param mode See @SeekMode .
         */
        seek(timeMs: number, mode?:SeekMode): void;` ​
  • 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
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 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
  • 117
  • 118
  • 其他回调接口
          /**
         * Register or unregister listens for media playback events.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback event to listen for.
         * @param callback Callback used to listen for the playback stateChange event.
         */
        on(type: 'stateChange', callback: (state: AVPlayerState, reason: StateChangeReason) => void): void;
        off(type: 'stateChange'): void;
        /**
         * Register or unregister listens for media playback events.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback event to listen for.
         * @param callback Callback used to listen for the playback volume event.
         */
        on(type: 'volumeChange', callback: Callback<number>): void;
        off(type: 'volumeChange'): void;
        /**
         * Register or unregister listens for media playback events.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback event to listen for.
         * @param callback Callback used to listen for the playback end of stream
         */
        on(type: 'endOfStream', callback: Callback<void>): void;
        off(type: 'endOfStream'): void;
        /**
         * Register or unregister listens for media playback events.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback event to listen for.
         * @param callback Callback used to listen for the playback seekDone event.
         */
        on(type: 'seekDone', callback: Callback<number>): void;
        off(type: 'seekDone'): void;
        /**
         * Register or unregister listens for media playback events.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback event to listen for.
         * @param callback Callback used to listen for the playback speedDone event.
         */
        on(type: 'speedDone', callback: Callback<number>): void;
        off(type: 'speedDone'): void;
        /**
         * Register or unregister listens for media playback events.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback event to listen for.
         * @param callback Callback used to listen for the playback setBitrateDone event.
         */
        on(type: 'bitrateDone', callback: Callback<number>): void;
        off(type: 'bitrateDone'): void;
        /**
         * LRegister or unregister listens for media playback events.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback event to listen for.
         * @param callback Callback used to listen for the playback timeUpdate event.
         */
        on(type: 'timeUpdate', callback: Callback<number>): void;
        off(type: 'timeUpdate'): void;
        /**
         * Register or unregister listens for media playback events.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback event to listen for.
         * @param callback Callback used to listen for the playback durationUpdate event.
         */
        on(type: 'durationUpdate', callback: Callback<number>): void;
        off(type: 'durationUpdate'): void;
        /**
         * Register or unregister listens for video playback buffering events.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback buffering update event to listen for.
         * @param callback Callback used to listen for the buffering update event, return BufferingInfoType and the value.
         */
        on(type: 'bufferingUpdate', callback: (infoType: BufferingInfoType, value: number) => void): void;
        off(type: 'bufferingUpdate'): void;
        /**
         * Register or unregister listens for start render video frame events.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback event to listen for.
         * @param callback Callback used to listen for the playback event return .
         */
        on(type: 'startRenderFrame', callback: Callback<void>): void;
        off(type: 'startRenderFrame'): void;
        /**
         * Register or unregister listens for video size change event.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback event to listen for.
         * @param callback Callback used to listen for the playback event return video size.
         */
        on(type: 'videoSizeChange', callback: (width: number, height: number) => void): void;
        off(type: 'videoSizeChange'): void;
        /**
         * Register or unregister listens for audio interrupt event, refer to {@link #audio.InterruptEvent}
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback event to listen for.
         * @param callback Callback used to listen for the playback event return audio interrupt info.
         */
        on(type: 'audioInterrupt', callback: (info: audio.InterruptEvent) => void): void;
        off(type: 'audioInterrupt'): void;
        /**
         * Register or unregister listens for available bitrate list collect completed events for HLS protocol stream playback.
         * This event will be reported after the {@link #prepare} called.
         * @since 9
         * @syscap SystemCapability.Multimedia.Media.AVPlayer
         * @param type Type of the playback event to listen for.
         * @param callback Callback used to listen for the playback event return available bitrate list.
         */
        on(type: 'availableBitrates', callback: (bitrates: Array<number>) => void): void;
        off(type: 'availableBitrates'): void;
  • 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
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 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
  • 117
  • 118

简单样例

  • 界面
 build() {
       Stack({ alignContent: Alignment.Center }) {
         if (this.isShowMenu) {
           Column() {
             //视频名称
             PlayTitle({ title: this.displayName, handleBack: this.handleBack })
             Row() {
               //播放控件
               PreVideo({ handleClick: this.handlePrevClick })
               PlayButton({ isPlaying: $isPlaying })
               NextVideo({ handleClick: this.handleNextClick })
             }
             .margin({ top: '40%' })
   
             Blank()
             //时间刻度
             Row() {
               Text(getTimeString(this.currentTime))
                 .fontSize(25)
                 .fontColor(Color.White)
               Blank()
               Text(this.fileAsset ? getTimeString(this.fileAsset.duration) : '00:00')
                 .fontSize(25)
                 .fontColor(Color.White)
             }
             .width('95%')
   		  //进度条
             Slider({ value: this.fileAsset ? this.currentTime / this.fileAsset.duration * 100 : 0 })
               .width('92%')
               .selectedColor(Color.White)
               .onChange((value: number) => {
                 Logger.info(TAG, 'seek time change')
                 this.currentTime = this.fileAsset.duration * value / 100
                 this.videoPlayer.seek(this.currentTime)
               })
           }
           .height('100%')
           .zIndex(2)
         }
         Row() {
           XComponent({
             id: 'componentId',
             type: 'surface',
             controller: this.mxcomponentController
           })
             .onLoad(() => {
               Logger.info(TAG, 'onLoad is called')
               this.playVideo()
             })
             .width('100%')
             .aspectRatio(this.ratio)
         }
         .height('100%')
         .width('100%')
         .justifyContent(FlexAlign.Center)
       }
       .width('100%')
       .height('100%')
       .backgroundColor(Color.Black)
       .onClick(() => {
         this.isShowMenu = !this.isShowMenu
       })
     }
  • 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
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 播放
      //根据视频文件获取视频源尺寸并生成surface
      //视频文件的路径在/storage/media/100/local/files/Videos
      async prepareVideo() {
        this.ratio = this.fileAsset.width / this.fileAsset.height
        this.mxcomponentController.setXComponentsurfaceSize({
          surfaceWidth: this.fileAsset.width,
          surfaceHeight: this.fileAsset.height
        })
        this.surfaceId = this.mxcomponentController.getXComponentsurfaceId()
        this.fd = await this.fileAsset.open('Rw')
        Logger.info(TAG, `fd://' ${this.fd} `)
        return 'fd://' + this.fd
      }
      //初始化视频文件并初始化avplayer
      async playVideo() {
        Logger.info(TAG, 'playVideo')
        try{
          await this.getMediaList()
          let fdPath = await this.prepareVideo()
          this.videoPlayer.on('timeUpdate', (time:number) => {
            console.info('timeUpdate success,and new time is :' + time)
            this.currentTime = time;
          })
          await this.videoPlayer.initVideoPlayer(fdPath, this.surfaceId)
          this.isPlaying = true
        }catch(error) {
          Logger.info(TAG, `playVideo error ${JSON.stringify(error)}`)
        }
      }
  • 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
  • 27
  • 28
  • 29

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/431619
推荐阅读
相关标签
  

闽ICP备14008679号