目录

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

从API version 11开始,支持使用AVPlayer实现端到端播放流媒体资源。本开发指导将以完整地播放一个流媒体作为示例,向开发者讲解AVPlayer流媒体播放相关功能。

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

在进行应用开发的过程中,开发者可以通过AVPlayer的信息监听回调函数OH_AVPlayerOnInfoCallback和错误监听回调函数OH_AVPlayerOnErrorCallback主动获取播放过程信息。如果应用在视频播放器处于错误状态时执行操作,系统会抛出异常或生成其他未定义的行为。

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

播放状态变化示意图:

开发建议

当前指导仅介绍如何实现流媒体资源播放,如需播放本地资源,请参考使用AVPlayer播放视频(C/C++)。如果在应用开发过程中涉及后台播放、播放冲突等情况,请根据实际需要参考以下说明。

避免播放被系统强制中断。此功能仅适用于ArkTS API,如需使用此功能请参考使用AVPlayer播放视频(ArkTS)。

开发步骤及注意事项

在CMake脚本中链接如下动态库:

target_link_libraries(entry PUBLIC
    libavplayer.so
    libnative_media_core.so
    libhilog_ndk.z.so
)

使用OH_AVPlayer_SetOnInfoCallback()、OH_AVPlayer_SetOnErrorCallback()接口设置信息监听回调函数和错误监听回调函数,需要在CMake脚本中链接libnative_media_core.so动态库。

开发者使用系统日志能力时,需引入如下头文件。

#include <hilog/log.h>

并需要在CMake脚本中链接libhilog_ndk.z.so动态库。

开发者通过引入avplayer.h、avplayer_base.h和native_averrors.h头文件,使用流媒体播放相关API。

详细的API说明请参考AVPlayer。

  1. 创建AVPlayer实例:调用OH_AVPlayer_Create()接口,AVPlayer初始化为AVPlayerState.AV_IDLE状态。

    OH_AVPlayer *player = OH_AVPlayer_Create();
  2. 设置回调监听函数:使用OH_AVPlayer_SetOnInfoCallback()和OH_AVPlayer_SetOnErrorCallback()接口设置信息监听回调函数和错误监听回调函数,配合全流程场景使用。获取更多信息的同时还可以通过设置userData区分不同播放实例。

    支持的监听事件如下所示:

    事件类型 说明
    OH_AVPlayerOnInfoCallback

    必要事件,监听播放器的过程信息。

    需要播放器在AV_IDLE状态下、未调用设置资源接口前完成设置监听。如果在调用设置资源接口后再设置监听,会导致无法收到资源设置过程中上报的OH_AVPlayerOnInfoCallback事件。

    OH_AVPlayerOnErrorCallback

    必要事件,监听播放器的错误信息。

    需要播放器在AV_IDLE状态下、未调用设置资源接口前完成设置监听。如果在调用设置资源接口后再设置监听,会导致无法收到资源设置过程中上报的OH_AVPlayerOnErrorCallback事件。

    // 设置回调,监听信息。
    LOG("call OH_AVPlayer_SetOnInfoCallback");
    int32_t ret = OH_AVPlayer_SetOnInfoCallback(player, OHAVPlayerOnInfoCallback, nullptr);
    LOG("OH_AVPlayer_SetOnInfoCallback ret:%{public}d", ret);
    LOG("call OH_AVPlayer_SetOnErrorCallback");
    ret = OH_AVPlayer_SetOnErrorCallback(player, OHAVPlayerOnErrorCallback, nullptr);
    LOG("OH_AVPlayer_SetOnErrorCallback ret:%{public}d", ret);
  3. 设置资源:调用OH_AVPlayer_SetURLSource(),设置属性URL(支持点播和直播源),AVPlayer进入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(),设置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(),设置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(),设置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()设置播放画面窗口。此函数必须在SetSource之后,Prepare之前调用。

    ret = OH_AVPlayer_SetVideoSurface(player, context->nativeWindow_);
    LOG("OH_AVPlayer_SetVideoSurface ret:%{public}d", ret);
  8. 准备播放:调用OH_AVPlayer_Prepare(),AVPlayer进入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(),设置AVPlayer音频音效模式。

    LOG("AVPlayerState AV_PREPARED");
    ret = OH_AVPlayer_SetAudioEffectMode(player, EFFECT_NONE); // 设置音频音效模式。
    LOG("OH_AVPlayer_SetAudioEffectMode ret:%{public}d", ret);
  10. 播放控制:包含播放OH_AVPlayer_Play()、暂停OH_AVPlayer_Pause()、跳转OH_AVPlayer_Seek()、停止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()重置资源,AVPlayer重新进入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()销毁实例,AVPlayer进入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. 新建工程,下载示例工程。
  2. 编译新建工程并运行。