跳到主要内容

使用AVPlayer播放视频(ArkTS)

当前提供两种视频播放开发的方案:

  • AVPlayer:功能较完善的音视频播放ArkTS/JS API,集成了流媒体和本地资源解析,媒体资源解封装,视频解码和渲染功能,适用于对媒体资源进行端到端播放的场景,可直接播放mp4、mkv等格式的视频文件。
  • Video组件:封装了视频播放的基础能力,需要设置数据源及基础信息即可播放视频,但相对扩展能力较弱。Video组件由ArkUI提供能力,相关指导请参考UI开发文档-Video组件

本开发指导将介绍如何使用AVPlayer开发视频播放功能,以完整播放一个视频作为示例,实现端到端播放原始媒体资源。

播放的全流程包含:创建AVPlayer,设置播放资源和窗口,设置播放参数(音量/倍速/缩放模式),播放控制(播放/暂停/跳转/停止),重置,销毁资源。在进行应用开发的过程中,开发者可以通过AVPlayer的state属性主动获取当前状态或使用on('stateChange')方法监听状态变化。如果应用在视频播放器处于错误状态时执行操作,系统可能会抛出异常或生成其他未定义的行为。

图1 播放状态变化示意图

状态的详细说明请参考AVPlayerState。当播放处于prepared / playing / paused / completed状态时,播放引擎处于工作状态,这需要占用系统较多的运行内存。当客户端暂时不使用播放器时,调用reset()或release()回收内存资源,做好资源释放。

开发建议

当前指导仅介绍如何实现媒体资源播放,在应用开发过程中可能会涉及后台播放、播放冲突等情况,请根据实际需要参考以下说明。

  • 如果要实现后台播放或熄屏播放,需要接入AVSession(媒体会话)申请长时任务,避免播放被系统强制中断。
  • 应用在播放过程中,若播放的媒体数据涉及音频,根据系统音频管理策略(参考处理音频焦点事件),可能会被其他应用打断,建议应用主动监听音频打断事件,根据其内容提示,做出相应的处理,避免出现应用状态与预期效果不一致的问题。
  • 面对设备同时连接多个音频输出设备的情况,应用可以通过on('audioOutputDeviceChangeWithInfo')监听音频输出设备的变化,从而做出相应处理。
  • 如果需要访问在线媒体资源,需要申请 ohos.permission.INTERNET 权限。

开发步骤及注意事项

详细的API说明请参考AVPlayer

  1. 调用createAVPlayer()创建AVPlayer实例,初始化进入idle状态。

    import { media } from '@kit.MediaKit';

    // 创建avPlayer实例对象。
    let avPlayer = await media.createAVPlayer();
  2. 设置业务需要的监听事件,搭配全流程场景使用。支持的监听事件包括:

    事件类型说明
    stateChange必要事件,监听播放器的state属性改变。 需要播放器在idle状态下、未调用设置资源接口前完成设置监听,若在调用设置资源接口后再设置监听,可能导致无法收到资源设置过程中上报的stateChange事件。
    error必要事件,监听播放器的错误信息。 需要播放器在idle状态下、未调用设置资源接口前完成设置监听,若在调用设置资源接口后再设置监听,可能导致无法收到资源设置过程中上报的error事件。
    durationUpdate用于进度条,监听进度条长度,刷新资源时长。
    timeUpdate用于进度条,监听进度条当前位置,刷新当前时间。
    seekDone响应API调用,监听seek()请求完成情况。 当使用seek()跳转到指定播放位置后,如果seek操作成功,将上报该事件。
    speedDone响应API调用,监听setSpeed()请求完成情况。 当使用setSpeed()设置播放倍速后,如果setSpeed操作成功,将上报该事件。
    volumeChange响应API调用,监听setVolume()请求完成情况。 当使用setVolume()调节播放音量后,如果setVolume操作成功,将上报该事件。
    bitrateDone响应API调用,用于HLS协议流,监听setBitrate()请求完成情况。 当使用setBitrate()指定播放比特率后,如果setBitrate操作成功,将上报该事件。
    availableBitrates用于HLS协议流,监听HLS资源的可选bitrates,用于setBitrate()。
    bufferingUpdate用于网络播放,监听网络播放缓冲信息。
    startRenderFrame用于视频播放,监听视频播放首帧渲染时间。 当AVPlayer首次起播进入playing状态后,等到首帧视频画面被渲染到显示画面时,将上报该事件。应用通常可以利用此事件上报,进行视频封面移除,达成封面与视频画面的顺利衔接。
    videoSizeChange用于视频播放,监听视频播放的宽高信息,可用于调整窗口大小、比例。
    audioInterrupt监听音频焦点切换信息,搭配属性audioInterruptMode使用。 如果当前设备存在多个媒体正在播放,音频焦点被切换(即播放其他媒体如通话等)时将上报该事件,应用可以及时处理。
    // 此处仅为示例,开发者根据需要设置合适的监听事件。
    import { BusinessError } from '@kit.BasicServicesKit';
    import { audio } from '@kit.AudioKit';

    avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
    // 开发者根据需要写入业务逻辑。
    });
    avPlayer.on('error', (error: BusinessError) => {
    // 开发者根据需要写入业务逻辑。
    });
    avPlayer.on('durationUpdate', (duration: number) => {
    // 开发者根据需要写入业务逻辑。
    });
    avPlayer.on('timeUpdate', (time:number) => {
    // 开发者根据需要写入业务逻辑。
    });
    avPlayer.on('seekDone', (seekDoneTime:number) => {
    // 开发者根据需要写入业务逻辑。
    });
    avPlayer.on('speedDone', (speed:number) => {
    // 开发者根据需要写入业务逻辑。
    });
    avPlayer.on('volumeChange', (vol: number) => {
    // 开发者根据需要写入业务逻辑。
    });
    avPlayer.on('bitrateDone', (bitrate:number) => {
    // 开发者根据需要写入业务逻辑。
    });
    avPlayer.on('availableBitrates', (bitrates: Array<number>) => {
    // 开发者根据需要写入业务逻辑。
    });
    avPlayer.on('bufferingUpdate', (infoType: media.BufferingInfoType, value: number) => {
    // 开发者根据需要写入业务逻辑。
    });
    avPlayer.on('startRenderFrame', () => {
    // 开发者根据需要写入业务逻辑。
    });
    avPlayer.on('videoSizeChange', (width: number, height: number) => {
    // 开发者根据需要写入业务逻辑。
    });
    avPlayer.on('audioInterrupt', (info: audio.InterruptEvent) => {
    // 开发者根据需要写入业务逻辑。
    });
  3. 设置资源:设置属性url,AVPlayer进入initialized状态。

    下面代码示例中的url仅作示意使用,开发者需根据实际情况,确认资源有效性并设置:

    let url = 'https://xxx.xxx.xxx.mp4';
    if (avPlayer == null) {
    return;
    }
    avPlayer.url = url;
  4. 设置窗口:获取并设置属性surfaceId,用于设置显示画面。

    应用需要从XComponent组件获取surfaceId,获取方式请参考getXComponentSurfaceId

    // 通过接口getXComponentSurfaceId获取surfaceId。
    let surfaceId = '';
    if (avPlayer == null) {
    return;
    }
    if (surfaceId === '') {
    return;
    }
    avPlayer.surfaceId = surfaceId;
  5. 准备播放:调用prepare(),AVPlayer进入prepared状态,此时可以获取duration,设置缩放模式、音量等。

    import { BusinessError } from '@kit.BasicServicesKit';

    avPlayer.prepare((err: BusinessError) => {
    if (err) {
    console.error('Failed to prepare,error message is :' + err.message);
    } else {
    console.info('Succeeded in preparing');
    }
    });
  6. 视频播控:播放play(),暂停pause(),跳转seek(),停止stop() 等操作。

    import { BusinessError } from '@kit.BasicServicesKit';

    // 播放操作。
    avPlayer.play().then(() => {
    console.info('Succeeded in playing');
    }, (err: BusinessError) => {
    console.error('Failed to play,error message is :' + err.message);
    });
    // 暂停操作。
    avPlayer.pause((err: BusinessError) => {
    if (err) {
    console.error('Failed to pause,error message is :' + err.message);
    } else {
    console.info('Succeeded in pausing');
    }
    });
    // 跳转操作。
    let seekTime: number = 1000;
    avPlayer.seek(seekTime, media.SeekMode.SEEK_PREV_SYNC);
    // 停止操作。
    avPlayer.stop((err: BusinessError) => {
    if (err) {
    console.error('Failed to stop,error message is :' + err.message);
    } else {
    console.info('Succeeded in stopping');
    }
    });
  7. (可选)更换资源:调用reset()重置资源,AVPlayer重新进入idle状态,允许更换资源url。

    import { BusinessError } from '@kit.BasicServicesKit';

    avPlayer.reset((err: BusinessError) => {
    avPlayer.url = url;
    if (err) {
    console.error('Failed to reset,error message is :' + err.message);
    } else {
    console.info('Succeeded in resetting');
    }
    });
    // 更换url。
    let url = 'https://xxx.xxx.xxx.mp4';
    if (avPlayer == null) {
    return;
    }
    avPlayer.url = url;
  8. 退出播放:调用release()销毁实例,AVPlayer进入released状态,退出播放。

    import { BusinessError } from '@kit.BasicServicesKit';

    avPlayer.release((err: BusinessError) => {
    if (err) {
    console.error('Failed to release,error message is :' + err.message);
    } else {
    console.info('Succeeded in releasing');
    }
    });

运行完整示例

  1. 新建工程,下载示例工程,并将示例工程的以下资源复制到对应目录。

    AVPlayerArkTSVideo
    entry/src/main/ets/
    └── pages
    └── Index.ets (播放界面)
    entry/src/main/resources/
    ├── base
    │ ├── element
    │ │ ├── color.json
    │ │ ├── float.json
    │ │ └── string.json
    │ └── media
    │ ├── ic_video_play.svg (播放键图片资源)
    │ └── ic_video_pause.svg (暂停键图片资源)
    └── rawfile
    └── test1.mp4 (视频资源)
  2. 编译新建工程并运行。