使用AVPlayer播放流媒体(C/C++)
======================

从API version 11开始，支持使用[AVPlayer](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer)实现端到端播放流媒体资源。本开发指导将以完整地播放一个流媒体作为示例，向开发者讲解AVPlayer流媒体播放相关功能。

播放的全流程包含：创建AVPlayer、设置回调监听函数、设置播放资源、设置播放参数（音量/倍速/焦点模式）、设置播放窗口、播放控制（播放/暂停/跳转/停止）、重置、销毁播放器实例。

在进行应用开发的过程中，开发者可以通过AVPlayer的信息监听回调函数[OH\_AVPlayerOnInfoCallback](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-base-h#oh_avplayeroninfocallback)和错误监听回调函数[OH\_AVPlayerOnErrorCallback](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-base-h#oh_avplayeronerrorcallback)主动获取播放过程信息。如果应用在视频播放器处于错误状态时执行操作，系统会抛出异常或生成其他未定义的行为。

状态的详细说明请参考[AVPlayerState](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-base-h#avplayerstate)。当播放处于prepared/playing/paused/completed状态时，播放引擎处于工作状态，这需要占用系统较多的运行内存。当客户端暂时不使用播放器时，调用reset()或release()回收内存资源，合理利用资源。

**播放状态变化示意图：**

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/e7/v3/6gGdE0uYQhSeN0CMZv1RIA/zh-cn_image_0000002625188245.png?HW-CC-KV=V1&HW-CC-Date=20260612T073524Z&HW-CC-Expire=86400&HW-CC-Sign=44FE1C79BEF2A3BF36637C62D577777ADE0C0BD2CC9E21460E0172EBAEA82B96)

#### 开发建议

当前指导仅介绍如何实现流媒体资源播放，如需播放本地资源，请参考[使用AVPlayer播放视频(C/C++)](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/using-ndk-avplayer-for-video-playback)。如果在应用开发过程中涉及后台播放、播放冲突等情况，请根据实际需要参考以下说明。

避免播放被系统强制中断。此功能仅适用于ArkTS API，如需使用此功能请参考[使用AVPlayer播放视频(ArkTS)](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/video-playback)。

*   应用在播放过程中，若播放的媒体数据涉及音频，根据系统音频管理策略（参考[处理音频焦点变化](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/audio-playback-concurrency#处理音频焦点变化)事件），会存在被其他应用打断的情况，建议通过[OH\_AVPlayer\_SetOnInfoCallback()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_setoninfocallback)主动监听音频打断事件[AVPlayerOnInfoType](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-base-h#avplayeroninfotype).AV\_INFO\_TYPE\_INTERRUPT\_EVENT，根据具体内容提示，做出相应的处理，避免出现应用状态与预期效果不一致的问题。
*   面对设备同时连接多个音频输出设备的情况，建议通过[OH\_AVPlayer\_SetOnInfoCallback()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_setoninfocallback)主动监听音频输出设备变更事件[AVPlayerOnInfoType](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-base-h#avplayeroninfotype).AV\_INFO\_TYPE\_AUDIO\_OUTPUT\_DEVICE\_CHANGE，并做出相应处理。
*   应用在播放过程中，系统内部会因为网络数据下载失败、媒体服务异常终止等发生异常。建议通过[OH\_AVPlayer\_SetOnErrorCallback()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_setonerrorcallback)接口设置错误监听回调函数，根据不同错误类型，做出相应处理，避免出现播放异常。

#### 开发步骤及注意事项

*   在CMake脚本中链接动态库。
    
    target\_link\_libraries(sample PUBLIC libavplayer.so)
    
*   使用[OH\_AVPlayer\_SetOnInfoCallback()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_setoninfocallback)、[OH\_AVPlayer\_SetOnErrorCallback()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_setonerrorcallback)接口设置信息监听回调函数和错误监听回调函数，需要在CMake脚本中链接如下动态库。
    
    target\_link\_libraries(sample PUBLIC libnative\_media\_core.so)
    
*   开发者使用系统日志能力时，需引入如下头文件。
    
    #include <hilog/log.h>
    
    并需要在CMake脚本中链接如下动态库。
    
    target\_link\_libraries(sample PUBLIC libhilog\_ndk.z.so)
    

开发者通过引入[avplayer.h](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h)、[avplayer\_base.h](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-base-h)和[native\_averrors.h](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-averrors-h)头文件，使用流媒体播放相关API。

详细的API说明请参考[AVPlayer](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer)。

1.  创建AVPlayer实例：调用[OH\_AVPlayer\_Create()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_create)接口，AVPlayer初始化为[AVPlayerState](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-base-h#avplayerstate).AV\_IDLE状态。
    
    OH\_AVPlayer \*player = OH\_AVPlayer\_Create();
    
2.  设置回调监听函数：使用[OH\_AVPlayer\_SetOnInfoCallback()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_setoninfocallback)和[OH\_AVPlayer\_SetOnErrorCallback()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_setonerrorcallback)接口设置信息监听回调函数和错误监听回调函数，配合全流程场景使用。获取更多信息的同时还可以通过设置userData区分不同播放实例。
    
    支持的监听事件如下所示：
    
    | 事件类型 | 说明 |
    | :-- | :-- |
    | OH\_AVPlayerOnInfoCallback | 
    必要事件，监听播放器的过程信息。
    
    需要播放器在AV\_IDLE状态下、未调用设置资源接口前完成设置监听。如果在调用设置资源接口后再设置监听，会导致无法收到资源设置过程中上报的OH\_AVPlayerOnInfoCallback事件。
    
     |
    | OH\_AVPlayerOnErrorCallback | 
    
    必要事件，监听播放器的错误信息。
    
    需要播放器在AV\_IDLE状态下、未调用设置资源接口前完成设置监听。如果在调用设置资源接口后再设置监听，会导致无法收到资源设置过程中上报的OH\_AVPlayerOnErrorCallback事件。
    
     |
    
    // 设置回调，监听信息。
    LOG("call OH\_AVPlayer\_SetPlayerOnInfoCallback");
    int32\_t ret = OH\_AVPlayer\_SetOnInfoCallback(player, OHAVPlayerOnInfoCallback, nullptr);
    LOG("OH\_AVPlayer\_SetPlayerOnInfoCallback ret:%{public}d", ret);
    
    LOG("call OH\_AVPlayer\_SetPlayerOnErrorCallback");
    ret = OH\_AVPlayer\_SetOnErrorCallback(player, OHAVPlayerOnErrorCallback, nullptr);
    LOG("OH\_AVPlayer\_SetPlayerOnErrorCallback ret:%{public}d", ret);
    
3.  设置资源：调用[OH\_AVPlayer\_SetURLSource()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_seturlsource)，设置属性URL（支持点播和直播源），AVPlayer进入[AVPlayerState](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-base-h#avplayerstate).AV\_INITIALIZED（初始化）状态。
    
    LOG("player %{public}s >> URL source", url);
    LOG("call %{public}s", "OH\_AVPlayer\_SetUrlSource");
    ret = OH\_AVPlayer\_SetURLSource(player, url);
    LOG("OH\_AVPlayer\_SetUrlSource ret:%{public}d", ret);
    
4.  （可选）设置智能追帧：直播场景下调用[OH\_AVPlayer\_SetPlaybackStrategy()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_setplaybackstrategy)，设置AVPlayer启用智能追帧。
    
    void OHAVPlayerSetPlaybackStrategy(OH\_AVPlayer \*player)
    {
        // 设置播放策略。
        OH\_AVPlaybackStrategy \*myStrategy = OH\_AVPlaybackStrategy\_Create();
        double waterLine = 6.0;
        OH\_AVPlaybackStrategy\_SetThresholdForAutoQuickPlay(myStrategy, waterLine); // 直播场景设置智能追帧。
        int32\_t ret = OH\_AVPlayer\_SetPlaybackStrategy(player, myStrategy);
        LOG("OH\_AVPlayer\_SetPlaybackStrategy ret:%{public}d", ret);
        OH\_AVPlaybackStrategy\_Destroy(myStrategy);
    }
    
5.  （可选）设置音频流类型：调用[OH\_AVPlayer\_SetAudioRendererInfo()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_setaudiorendererinfo)，设置AVPlayer音频流类型。
    
    // 设置音频流类型。
    LOG("call %{public}s", "OH\_AVPlayer\_SetAudioRendererInfo");
    OH\_AudioStream\_Usage streamUsage = OH\_AudioStream\_Usage::AUDIOSTREAM\_USAGE\_UNKNOWN;
    ret = OH\_AVPlayer\_SetAudioRendererInfo(player, streamUsage);
    LOG("OH\_AVPlayer\_SetAudioRendererInfo ret:%{public}d", ret);
    
6.  （可选）设置音频打断模式：调用[OH\_AVPlayer\_SetAudioInterruptMode()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_setaudiointerruptmode)，设置AVPlayer音频流打断模式。
    
    // 设置音频流打断模式。
    LOG("call OH\_AVPlayer\_SetAudioInterruptMode");
    OH\_AudioInterrupt\_Mode interruptMode = OH\_AudioInterrupt\_Mode::AUDIOSTREAM\_INTERRUPT\_MODE\_INDEPENDENT;
    ret = OH\_AVPlayer\_SetAudioInterruptMode(player, interruptMode);
    LOG("OH\_AVPlayer\_SetAudioInterruptMode ret:%{public}d", ret);
    
7.  设置播放画面窗口：调用[OH\_AVPlayer\_SetVideoSurface()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_setvideosurface)设置播放画面窗口。此函数必须在SetSource之后，Prepare之前调用。
    
    ret = OH\_AVPlayer\_SetVideoSurface(player, context->nativeWindow\_);
    LOG("OH\_AVPlayer\_SetVideoSurface ret:%{public}d", ret);
    
8.  准备播放：调用[OH\_AVPlayer\_Prepare()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_prepare)，AVPlayer进入[AVPlayerState](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-base-h#avplayerstate).AV\_PREPARED（准备）状态，此时可以获取时长，设置音量。
    
    ret = OH\_AVPlayer\_Prepare(player); // 设置播放源后触发该状态上报。
    if (ret != AV\_ERR\_OK) {
        // 处理异常。
        LOG("player %{public}s", "OH\_AVPlayer\_Prepare Err");
    }
    
9.  （可选）设置音频音效模式：调用[OH\_AVPlayer\_SetAudioEffectMode()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_setaudioeffectmode)，设置AVPlayer音频音效模式。
    
    LOG("AVPlayerState AV\_PREPARED");
    ret = OH\_AVPlayer\_SetAudioEffectMode(player, EFFECT\_NONE); // 设置音频音效模式。
    LOG("OH\_AVPlayer\_SetAudioEffectMode ret:%{public}d", ret);
    
10.  播放控制：包含播放[OH\_AVPlayer\_Play()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_play)、暂停[OH\_AVPlayer\_Pause()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_pause)、跳转[OH\_AVPlayer\_Seek()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_seek)、停止[OH\_AVPlayer\_Stop()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_stop)等操作。
     
     static napi\_value NAPI\_Global\_Play(napi\_env env, napi\_callback\_info info) {
         int ret = -1;
         auto context = SampleManager::GetInstance();
         if (context->player\_ != NULL) {
             ret = OH\_AVPlayer\_Play(context->player\_);
             LOG("OH\_AVPlayer\_Play ret:%{public}d", ret);
         } else {
             LOG("no found Player Instances");
         }
         napi\_value value;
         napi\_create\_int32(env, ret, &value);
         return value;
     }
     
     static napi\_value NAPI\_Global\_Pause(napi\_env env, napi\_callback\_info info) {
         int ret = 100;
         auto context = SampleManager::GetInstance();
         if (context->player\_ != NULL) {
             ret = OH\_AVPlayer\_Pause(context->player\_);
             LOG("OH\_AVPlayer\_Pause ret:%{public}d", ret);
         } else {
             LOG("no found Player Instances");
         }
         napi\_value value;
         napi\_create\_int32(env, ret, &value);
         return value;
     }
     
     static napi\_value NAPI\_Global\_Seek(napi\_env env, napi\_callback\_info info) {
         size\_t argc = 2;
         napi\_value args\[2\] = {nullptr};
         napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
         int seekValue;
         napi\_get\_value\_int32(env, args\[0\], &seekValue);
         int mode;
         napi\_get\_value\_int32(env, args\[1\], &mode);
         auto context = SampleManager::GetInstance();
         if (context->player\_ != NULL) {
             int ret;
             switch (mode) {
             case 0:
                 LOG("call NAPI\_Global\_Seek value:%{public}d  mode:AV\_SEEK\_NEXT\_SYNC", seekValue);
                 ret = OH\_AVPlayer\_Seek(context->player\_, seekValue, AV\_SEEK\_NEXT\_SYNC);
                 break;
             case 1:
                 LOG("call NAPI\_Global\_Seek value:%{public}d  mode:AV\_SEEK\_PREVIOUS\_SYNC", seekValue);
                 ret = OH\_AVPlayer\_Seek(context->player\_, seekValue, AV\_SEEK\_PREVIOUS\_SYNC);
                 break;
             case 2:
                 LOG("call NAPI\_Global\_Seek value:%{public}d  mode:AV\_SEEK\_CLOSEST", seekValue);
                 ret = OH\_AVPlayer\_Seek(context->player\_, seekValue, AV\_SEEK\_CLOSEST);
                 break;
             default:
                 LOG("call NAPI\_Global\_Seek value:%{public}d  mode:AV\_SEEK\_PREVIOUS\_SYNC", seekValue);
                 ret = OH\_AVPlayer\_Seek(context->player\_, seekValue, AV\_SEEK\_PREVIOUS\_SYNC);
                 break;
             }
             LOG("OH\_AVPlayer\_Seek ret:%{public}d", ret);
         } else {
             LOG("no found Player Instances");
         }
         napi\_value value;
         napi\_create\_int32(env, 0, &value);
         return value;
     }
     
     static napi\_value NAPI\_Global\_Stop(napi\_env env, napi\_callback\_info info) {
         int ret = 100;
         auto context = SampleManager::GetInstance();
         if (context->player\_ != NULL) {
             ret = OH\_AVPlayer\_Stop(context->player\_);
             LOG("OH\_AVPlayer\_Stop ret:%{public}d", ret);
         } else {
             LOG("no found Player Instances");
         }
         napi\_value value;
         napi\_create\_int32(env, ret, &value);
         return value;
     }
     
11.  （可选）更换资源：调用[OH\_AVPlayer\_Reset()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_reset)重置资源，AVPlayer重新进入[AVPlayerState](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-base-h#avplayerstate).AV\_IDLE（空闲）状态，允许更换资源URL。
     
     static napi\_value NAPI\_Global\_Reset(napi\_env env, napi\_callback\_info info) {
         int ret = 100;
         auto context = SampleManager::GetInstance();
         if (context->player\_ != NULL) {
             ret = OH\_AVPlayer\_Reset(context->player\_);
             LOG("OH\_AVPlayer\_Reset ret:%{public}d", ret);
         } else {
             LOG("no found Player Instances");
         }
         napi\_value value;
         napi\_create\_int32(env, ret, &value);
         return value;
     }
     
12.  退出播放：调用[OH\_AVPlayer\_Release()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-h#oh_avplayer_release)销毁实例，AVPlayer进入[AVPlayerState](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avplayer-base-h#avplayerstate).AV\_RELEASED（释放）状态，退出播放。如果后续再操作AVPlayer实例，则行为未知，可能导致应用进程崩溃，应用异常退出等情况。
     
     static napi\_value NAPI\_Global\_Release(napi\_env env, napi\_callback\_info info) {
         int ret = -1;
         auto context = SampleManager::GetInstance();
         if (context->player\_ != NULL) {
             ret = OH\_AVPlayer\_Release(context->player\_);
             LOG("OH\_AVPlayer\_Release ret:%{public}d", ret);
         } else {
             LOG("no found Player Instances");
         }
         napi\_value value;
         napi\_create\_int32(env, ret, &value);
         return value;
     }
     

#### 运行完整示例

1.  新建工程，下载[示例工程](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/DocsSample/Media/AVPlayer/AVPlayerNDKStreamingMedia)。
2.  编译新建工程并运行。