human: 如何处理七牛云的直播云基础能力使用

gpt: [直播云](https://developer.qiniu.com/pili) > SDK 下载 > 播放端 >[QPlayer2
Windows端](https://developer.qiniu.com/pili/sdk/12642/qplayer2-windows) > [基于
Core 的 QPlayer2 接入指南](https://developer.qiniu.com/pili/sdk/12644/based-on-
qplayer2-windows-access-guide-to-the-core) > 基础能力使用

#  基础能力使用

最近更新时间: 2024-03-26 15:00:25

在 [快速开始 __](http://developer.qiniu.io/pili/12645/qplayer2-core-windows-quick-
start)中，我们完成了qplayer2播放器的创建\播放\销毁，本文介绍如何使用qplayer2的播放能力

## 播放

### 创建播放数据

    
    
    QMedia::QMediaModelBuilder* pmodel_builder = new QMedia::QMediaModelBuilder;
    //添加播放地址
    pmodel_builder->add_stream_element(user_type, url_type, quality, url, is_selected, referer, back_up_url, render_type);
    //添加字幕地址
    pmodel_builder->add_subtitle_element(subtitle_name, subtitle_url,subtitle_is_selected);
    //创建 QMediaModel
    //is_live 是否是直播。true 直播,false 点播
    //reconstruct_time_line 是否重构时间轴，true 重构，false 不重构
    QMedia::QMediaModel* pmodel = pmodel_builder->build(is_live, reconstruct_time_line);
    

add_stream_element 属性说明

属性名 | 属性说明  
---|---  
userType | 用户自定义Type，目前预留，可以填空字符串  
url | 资源地址  
urlType | 媒体的资源属性 只包含视频/只包含音频/同时有视频音频  
quality | 清晰度  
isSelected | 是否起播时播放该流  
backupUrl | 备用地址  
referer | http/https 协议的地址 支持该属性  
renderType | 视频的渲染类型  
hlsDrmKey | 私有DRM解密的key，用在私有hls加密视频播放的场景中  
mp4DrmKey | mp4 drm 的解密 key 用于 CENC-AES-CTR 加密的视频播放场景中  
mp4QNDrmComKey | mp4 七牛私有 drm 的解密 comkey 用于七牛私有 mp4 加密的视频播放场景中  
mp4QNDrmFileKey | mp4 七牛私有 drm 的解密 filekey 用于七牛私有 mp4 加密的视频播放场景中  
  
## MP4 加密

目前 QPlayer2 支持七牛私有加密以及显式的 CENC-AES-CTR 加密，暂不支持隐式加密。CENC-AES-CTR 的初始化向量(IV)
由加密工具随机生成并存储在加密后的 MP4 文件中，QPlayer2 读取 MP4 文件的 IV 和QMediaModel 存储的 mp4DrmKey
进行解密。

### 播放 mp4 加密视频

    
    
    QMedia::QMediaModelBuilder* pmodel_builder = new QMedia::QMediaModelBuilder;
    //添加 CENC-AES-CTR 加密视频播放地址
    pmodel_builder->add_stream_element_mp4_drm(user_type, url_type, quality, url, is_selected, referer, back_up_url，mp4_drm_key, render_type);
    //添加 hls 加密视频播放地址
    pmodel_builder->add_stream_element_hls_drm(user_type, url_type, quality, url, is_selected, referer, back_up_url，hls_drm, render_type);
    //添加七牛私有 MP4 加密视频播放地址
    pmodel_builder->add_stream_element_qn_mp4_drm(user_type, url_type, quality, url, is_selected, referer, back_up_url，mp4_qn_drm_com_key，mp4_qn_drm_file_key, render_type);
    //添加字幕地址
    pmodel_builder->add_subtitle_element(subtitle_name, subtitle_url,subtitle_is_selected);
    //创建 QMediaModel
    //is_live 是否是直播。true 直播,false 点播
    //reconstruct_time_line 是否重构时间轴，true 重构，false 不重构
    QMedia::QMediaModel* pmodel = pmodel_builder->build(is_live, reconstruct_time_line);
    

## 对 MP4 文件进行 CENC-AES-CTR 加密

可以选择 ffmpeg 对一个 MP4 进行加密。加密命令如下：

    
    
    ffmpeg -i test2.mp4  -vcodec copy -acodec copy -encryption_scheme cenc-aes-ctr -encryption_key c7e16c4403654b85847037383f0c2db3 -encryption_kid a7e61c373e219033c21091fa607bf3b8 encrypted_IV_test.mp4
    

命令说明

test2.mp4 为输入文件

encrypted_IV_test.mp4 为输出文件

-vcodec copy 和 -acodec copy ：指定视频流和音频流的编码方式为原始流的拷贝，即不进行重新编码，保持与原始文件相同的编码格式。

-encryption_scheme cenc-aes-ctr ：设置加密方案为 CENC-AES-CTR，即采用 CTR 模式进行加密。

-encryption_key c7e16c4403654b85847037383f0c2db3 指定加密所使用的密钥，即解密所使用的 key。这里的c7e16c4403654b85847037383f0c2db3 是一个示例密钥，您可以替换为您自己的密钥，格式要求为：16字节的16进制数据。

-encryption_kid a7e61c373e219033c21091fa607bf3b8：指定加密所使用的密钥标识符（KID）。这里的 a7e61c373e219033c21091fa607bf3b8 是一个示例 KID，您可以替换为您自己的密钥标识符, 格式要求为：16字节的16进制数据。

加密后可通过ffplay 4.4 版本进行播放验证，播放正常即可。命令如下：

    
    
    ffplay encrypted_IV_test.mp4 -decryption_key c7e16c4403654b85847037383f0c2db3
    

### 视频URL类型枚举

    
    
    enum class QUrlType : uint32_t {
    QAUDIO_AND_VIDEO = 0,
    //仅包含音频
    QAUDIO = 1,
    //仅包含视频
    QVIDEO = 2,
    //无
    NONE = 3
    };
    

### 播放媒体资源

    
    
    /// <summary>
    /// 播放音视频资源
    /// </summary>
    /// <param name="pmedia_model"> 音视频资源 </param>
    /// <param name="start_pos"> 起播时间戳 毫秒 </param>
    /// <returns> true: 调用成功 false: 调用失败 </returns>
    mpPlayerWindow->get_control_handler()->play_media_model(pmodel, 0);
    

### 播放错误监听

添加监听前实现接口 QIPlayerMediaNetworkListener
。当视频起播时，如果遇到网络等问题原因，导致没有和服务器建立链接，那么会导致视频播放失败，总共会有3次重试机会，3次都失败的情况下会回调onOpenFailed方法。  
当视频已经起播后，在中途遇到网络等问题原因，进入buffer,
那么内核会一直重试，直到再次连接上服务端继续播放，或者用户通过接口停止播放该视频，在重试的过程中 onReconnectStart /
onReconnectEnd
会被回调，那么可以监控回调的次数来做业务层的结束播放的策略，当然在正常播放的情况下，这两个方法也是会被回调的，所以最好结合buffer的回调数据一起使用。

    
    
    /// <summary>
    /// 开始重连
    /// </summary>
    /// <param name="user_type"> 重连 url 的 userType </param>
    /// <param name="url_type">重连 url 的 urlType </param>
    /// <param name="url"> 重连的 url </param>
    /// <param name="retry_time"> 重连 url 的次数 </param>
    void on_reconnect_start(const std::string & user_type, QMedia::QUrlType url_type, const std::string & url, int retry_time) override;
    
    /// <summary>
    /// 重连结束
    /// </summary>
    /// <param name="user_type"> 重连 url 的 userType </param>
    /// <param name="url_type"> 重连 url 的 urlType </param>
    /// <param name="url"> 重连的 url </param>
    /// <param name="retry_time"></param>
    /// <param name="error"> 重连 url 的次数 </param>
    void on_reconnect_end(const std::string & user_type, QMedia::QUrlType url_type, const std::string & url, int retry_time, QMedia::QOpenError error) override;
    
    /// <summary>
    /// 打开失败
    /// </summary>
    /// <param name="user_type"> 打开失败 url 的 userType </param>
    /// <param name="url_type"> 打开失败 url 的 urlType </param>
    /// <param name="url"> 打开失败的 url </param>
    /// <param name="error">  打开失败 url 的 错误码 </param>
    void on_open_failed(const std::string & user_type, QMedia::QUrlType url_type, const std::string & url, QMedia::QOpenError error) override;
    
    
    
    void on_reconnect_start(const std::string &user_type, QMedia::QUrlType url_type, const std::string& url, int retry_time){
    }
    
    void on_reconnect_end(const std::string &user_type, QMedia::QUrlType url_type, const std::string& url, int retry_time, QMedia::QOpenError error) {
    }
    
    void on_open_failed(const std::string &user_type, QMedia::QUrlType url_type, const std::string& url, QMedia::QOpenError error){
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_media_network_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_media_network_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_media_network_listeners();
    

### 播放错误码枚举

    
    
    enum class QPLAYER_API QOpenError : int64_t {
    UNKNOW = 10000,
    NONE = 0, 
    IOERROR = -5,
    INTERRUPT = -1414092869,
    URL_INVALID = -875574520,
    FORMAT_INVALID = -1094995529
    };
    

### 暂停播放

    
    
    /// <summary>
    /// 暂停渲染
    /// </summary>
    /// <returns> true: 调用成功 false: 调用失败 </returns>
    mpPlayerWindow->get_control_handler()->pause_render();
    

### 恢复播放

    
    
    /// <summary>
    /// 在暂停渲染状态下 恢复渲染
    /// </summary>
    /// <returns> true: 调用成功 false: 调用失败 </returns>
    mpPlayerWindow->get_control_handler()->resume_render();
    

### 停止当前视频播放

    
    
    /// <summary>
    /// 停止当前视频播放
    /// </summary>
    /// <returns> true: 调用成功 false: 调用失败 </returns>
    mpPlayerWindow->get_control_handler()->stop();
    

## 鉴权

鉴权功能介绍见[鉴权相关文档 __](http://developer.qiniu.io/pili/12223/qplayer2-core-
authentication-related)

### 强制网络鉴权

调用该接口时，会强制进行网络鉴权

    
    
    /// <summary>
    /// 下一次鉴权强制通过网络鉴权
    /// </summary>
    /// <returns> true: 调用成功 false: 调用失败 </returns>
    mpPlayerWindow->get_control_handler()->force_authentication_from_network();
    

### 鉴权监听

添加监听前实现接口 QIPlayerAuthenticationListener 协议。

    
    
    /// <summary>
    /// 鉴权失败
    /// </summary>
    /// <param name="error"> 鉴权失败错误码 </param>
    void on_authentication_failed(QMedia::QAuthenticationErrorType error) override;
    
    /// <summary>
    /// 鉴权成功
    /// </summary>
    void on_authentication_success() override;
    
    
    
    void on_authentication_failed(QMedia::QAuthenticationErrorType error){
    }
    
    void on_authentication_success(){
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_authentication_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_authentication_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_authentication_listeners();
    

### 鉴权错误码枚举

    
    
    enum class QPLAYER_API QAuthenticationErrorType : uint32_t {
    	NONE = 0,                //鉴权出错
    	NO_BASE_AUTH = 1,		 //缺少基础功能权限
    	NO_VR_AUTH = 2,			 //缺少 VR 功能权限
    	NO_BLIND_AUTH = 3,		 //缺少色盲功能权限
    	NO_SEI_AUTH = 4,		 //缺少 SEI 功能权限
    	NO_SRT_AUTH = 5			 //缺少 SRT 功能权限
    };
    

## 切换视频进度

参数为要定位的position 单位毫秒

    
    
    /// <summary>
    /// seek
    /// </summary>
    /// <param name="position"> seek 的位置 单位 ms </param>
    /// <returns></returns>
    mpPlayerWindow->get_control_handler()->seek(100);
    

### 切换视频进度结果监听

添加监听前实现接口 QIPlayerSeekListener

    
    
    /// <summary>
    /// seek 成功回调
    /// </summary>
    void on_seek_success() override;
    
    /// <summary>
    ///  seek 失败回调
    /// </summary>
    void on_seek_failed() override;
    
    
    
    void on_seek_success() {
    }
    
    void on_seek_failed() {
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_seek_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_seek_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_seek_listeners();
    

## 视频解码方式

目前支持的解码方式有:软解、硬解、自动，一般情况下，使用自动，内核会根据手机的硬件情况，要播放的视频资源编码格式等信息，挑选合适的解码方式进行解码，各个解码方式的优劣情况如下  
软解: 解码较慢，但是兼容性好，适用于所有手机  
硬解：解码性能高，但是有一定兼容性，比如某些视频资源的编码格式，硬解芯片不支持。并且相对于软解，首帧的速度慢。

### 设置优先选择哪种解码方式

设置完成后下一次播放生效.  
最终的解码方式可能不是设置的，在设置的解码方式不能正确解码时，内核会进行降级，选择其他能正确解码的方式

    
    
    /// <summary>
    /// 设置解码方式
    /// </summary>
    /// <param name="type"> 解码方式 </param>
    /// <returns> true: 调用成功 false: 调用失败 </returns>
    mpPlayerWindow->get_control_handler()->set_decode_type(QMedia::QPlayerSetting::QPlayerDecoder::QPLAYER_DECODER_SETTING_AUTO);
    

### 优先选择的解码方式枚举

该枚举主要用于设置解码方式

    
    
    enum class QPLAYER_API QPlayerDecoder : uint16_t
    {
    	//自动选择
    	QPLAYER_DECODER_SETTING_AUTO = 0,
    	//硬解优先
    	QPLAYER_DECODER_SETTING_HARDWARE_PRIORITY = 1,
    	//软解优先
    	QPLAYER_DECODER_SETTING_SOFT_PRIORITY = 2,
    };
    

### 播放器视频解码监听相关

添加监听前实现接口 QIPlayerVideoDecodeListender 协议。

    
    
    /// <summary>
    /// 播放器解码类型回调
    /// </summary>
    /// <param name="type"> 解码类型 </param>
    void on_video_decode_by_type(QMedia::QDecoderType type) override;
    
    /// <summary>
    /// 解码失败回调
    /// </summary>
    /// <param name="retry"> 是否降级重试成功 true 是 false 否 </param>
    void on_decode_failed(bool retry) override;
    
    /// <summary>
    /// 如果当前视频解码所在设备或者 sdk 不支持，则回调该函数
    /// </summary>
    /// <param name="codec_id"> 视频解码的 id  </param>
    void on_not_support_codec_format(int codec_id) override;
    
    
    
    void on_video_decode_by_type(QMedia::QDecoderType type) {
    }
    
    void on_decode_failed(bool retry) {
    }
    
    void on_not_support_codec_format(int codec_id) {
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_video_decode_type_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_video_decode_type_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_video_decode_type_listeners();
    

### 解码方式枚举

该枚举主要用于监听返回的解码方式

    
    
    enum class QPLAYER_API QDecoderType : uint32_t {
    	NONE = 0,
    	SOFTWARE = 1,
    	HARDWARE = 31
    };
    

## 设置起播方式

下一次播放生效

    
    
    /// <summary>
    /// 设置起播方式
    /// </summary>
    /// <param name="action"> 起播方式 </param>
    /// <returns> true: 调用成功 false: 调用失败 </returns>
    mpPlayerWindow->get_control_handler()->set_start_action(QMedia::QPlayerSetting::QPlayerStart::QPLAYER_START_SETTING_PLAYING);
    

### 起播方式枚举

    
    
    enum class  QPlayerStart : uint16_t {
    	//起播播放
    	QPLAYER_START_SETTING_PLAYING = 0,
    	//起播暂停在首帧
    	QPLAYER_START_SETTING_PAUSE = 1,
    };
    

## 设置 seek 方式

下一次播放生效

    
    
    /// <summary>
    /// 设置seek方式
    /// </summary>
    /// <param name="mode"> seek方式 </param>
    /// <returns> true: 调用成功 false: 调用失败 </returns>
    mpPlayerWindow->get_control_handler()->set_seek_mode(QMedia::QPlayerSetting::QPlayerSeek::QPLAYER_SEEK_SETTING_NORMAL);
    

### seek方式枚举

    
    
    enum class  QPlayerSeek : uint16_t {
    	//关键帧seek，每次seek 都seek到离目标位置向前的最近的一个关键帧，耗时少
    	QPLAYER_SEEK_SETTING_NORMAL = 0,
    	//精准seek，耗时比关键帧seek多，且耗时和视频的gop间隔的大小成正比
    	QPLAYER_SEEK_SETTING_ACCURATE = 1
    };
    

## 播放器状态

在整个播放器实例生命周期中，播放会在不同的状态中切换，用户可以通过监听播放器状态，实现上层业务逻辑，  
比如在视频播放完时，展示其他视频的推荐页，那么只需监听播放器状态回调，待回调的状态是COMPLETED，则展示推荐页

### 播放器状态枚举

    
    
    enum class QPLAYER_API QPlayerState : uint32_t {
    	NONE = 0,//初始状态
    	INIT = 1,//播放器开始创建各种对象 没有对应的state 创建完对象就上报这个状态
    	PREPARE = 2,//开始拉视频数据解码变换等，重新换地址后，都走这个状态
    	PLAYING = 4,//播放中
    	PAUSED_RENDER = 6,//用户暂停
    	COMPLETED = 7,//播放完成
    	SEEKING = 8, //SEEK
    	STOPPED = 9,//播放器停止中
    	MISTAKE = 10,//播放出错（是否需要分 可恢复 和 不可恢复 ）
    	END = 11,//播放器释放各种对象完成
    	MEDIA_ITEM_PREPARE = 12, //开始拉视频数据解码变换等，重新换地址后，都走这个状态 针对Media Item的play 方式
    	RELEASE = 13 //播放器结束，且释放各类资源
    };
    

### 播放器状态变更监听相关

添加监听前需要签订QIPlayerStateChangeListener协议。

    
    
    /// <summary>
    /// 当前的播放状态发生改变时回调
    /// </summary>
    /// <param name="state"> 当前的播放状态 </param>
    void on_state_changed(QMedia::QPlayerState state) override;
    
    
    
    void on_state_changed(QMedia::QPlayerState state) {
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_state_change_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_state_change_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_state_change_listeners();
    

## 播放速度

播放速度的调整范围建议在0.25-2.0之间，这样会有一个比较好的效果

### 设置播放速度

参数为倍速值

    
    
    /// <summary>
    /// 设置播放速度
    /// </summary>
    /// <param name="speed"> 需要设置的倍速 </param>
    /// <returns> true: 调用成功 false: 调用失败 </returns>
    mpPlayerWindow->get_control_handler()->set_speed(0.5);
    

### 速度变更监听相关

添加监听前实现接口 QIPlayerSpeedListener

    
    
    /// <summary>
    /// 播放速度改变回调
    /// </summary>
    /// <param name="speed"> 当前的播放速度 </param>
    void on_speed_changed(float speed) override;
    
    
    
    void on_speed_changed(float speed) {
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_speed_change_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_speed_change_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_speed_change_listeners();
    

## 清晰度

QPlayer2 提供的清晰度能力是无缝切换清晰度方案，在切换过程中，画面是连续的画面，不会出现类似跳帧的情况。  
使用无缝切换清晰度功能，必须在 mediaModel 中配置多路清晰度，如果使用非 immediately
方式(即异步方式)时，同时只能有一次切换会话存在，会话结束后，才能切下一次

### 切换视频清晰度

    
    
    /// <summary>
    /// 切换清晰度,针对一个视频由多路url流组成的情况下，可以按找流来进行清晰度切换，
    /// 比如一个视频由2路url组成，一路视频，一路音频，那么可以只切换音频路的url达到音频的清晰度切换，也可以
    /// 只切换视频路的url达到视频的清晰度切换。
    /// </summary>
    /// <param name="user_type"> 要切换的url流的userType </param>
    /// <param name="url_type"> 要切换的url流的urlType </param>
    /// <param name="quality_index"> 要切换到哪一路清晰度 </param>
    /// <param name="immediately"> true: 立即切换，直播情况下 
    mpPlayerWindow->get_control_handler()->switch_quality(pinner_ele->get_user_type(), pinner_ele->get_url_type(), 1080, true);
    

### 播放器清晰度相关监听

添加监听前实现接口 QIPlayerQualityListener

    
    
    /// <summary>
    /// 开始切换清晰度
    /// </summary>
    /// <param name="user_type"> 切换清晰度的 URL 的 userType </param>
    /// <param name="url_type"> 切换清晰度的 URL 的 urlType </param>
    /// <param name="old_quality"> 切换清晰度前的清晰度 </param>
    /// <param name="new_quality"> 切换清晰度后的清晰度 </param>
    void on_quality_switch_start(const std::string & user_type, QMedia::QUrlType url_type, int old_quality, int new_quality) override;
    
    /// <summary>
    /// 清晰度切换完成
    /// </summary>
    /// <param name="user_type"> 切换清晰度的 URL 的 userType </param>
    /// <param name="url_type"> 切换清晰度的 URL 的 urlType </param>
    /// <param name="old_quality"> 切换清晰度前的清晰度 </param>
    /// <param name="new_quality"> 切换清晰度后的清晰度 </param>
    void on_quality_switch_complete(const std::string & user_type, QMedia::QUrlType url_type, int old_quality, int new_quality) override;
    
    /// <summary>
    /// 清晰度切换取消
    /// </summary>
    /// <param name="user_type"> 切换清晰度的 URL 的 userType </param>
    /// <param name="url_type"> 切换清晰度的 URL 的 urlType </param>
    /// <param name="old_quality"> 切换清晰度前的清晰度 </param>
    /// <param name="new_quality"> 切换清晰度后的清晰度 </param>
    void on_quality_switch_canceled(const std::string & user_type, QMedia::QUrlType url_type, int old_quality, int new_quality) override;
    
    /// <summary>
    /// 清晰度切换失败
    /// </summary>
    /// <param name="user_type"> 切换清晰度的 URL 的 userType </param>
    /// <param name="url_type"> 切换清晰度的 URL 的 urlType </param>
    /// <param name="old_quality"> 切换清晰度前的清晰度 </param>
    /// <param name="new_quality"> 切换清晰度后的清晰度 </param>
    void on_quality_switch_failed(const std::string & user_type, QMedia::QUrlType url_type, int old_quality, int new_quality) override;
    
    /// <summary>
    /// 目前仅支持同时有一个清晰度切换事件，如果前一个切换还未完成，再次切换清晰度，则会回调该函数
    /// </summary>
    /// <param name="user_type"> 切换清晰度的 URL 的 userType </param>
    /// <param name="url_type"> 切换清晰度的 URL 的 urlType </param>
    void on_quality_switch_retry_later(const std::string & user_type, QMedia::QUrlType url_type) override;
    
    
    
    void on_quality_switch_start(const std::string & user_type, QMedia::QUrlType url_type, int old_quality, int new_quality) {
    }
    
    void on_quality_switch_complete(const std::string & user_type, QMedia::QUrlType url_type, int old_quality, int new_quality)  {
    }
    
    void on_quality_switch_canceled(const std::string & user_type, QMedia::QUrlType url_type, int old_quality, int new_quality) {
    }
    
    void on_quality_switch_failed(const std::string & user_type, QMedia::QUrlType url_type, int old_quality, int new_quality) {
    }
    
    void on_quality_switch_retry_later(const std::string & user_type, QMedia::QUrlType url_type) {
    }
    
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_quality_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_quality_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_quality_listeners();
    

### 直播支持多路清晰度切换

无缝切换清晰度方案需要配置以下三个条件

  1. 首先切换的模式要选择立即切换即：immediately=true
  2. 服务端配置PTS透传，
  3. 对应的清晰度要做主动转码设置  
如果无法满足以上3个条件，那么建议用最基础的能力来实现清晰度切换，即每个清晰度都是一个media
model，切换时，调用playMediaModel来播放新的清晰度流。

## 视频宽高改变监听

在视频首帧渲染时，会调用该回调，告诉上层当前的视频宽高是多少，如果在这个这个视频播放的生命周期中，宽高改变，那么还会再次调用该回调.  
添加监听前实现接口 QIPlayerVideoFrameSizeChangeListener。

    
    
    /// <summary>
    /// 推流端视频长宽变化回调
    /// </summary>
    /// <param name="width"> 宽度 </param>
    /// <param name="height"> 高度 </param>
    void on_video_frame_size_changed(int width, int height) override;
    
    
    
    void on_video_frame_size_changed(int width, int height){
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_video_frame_size_change_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_video_frame_size_change_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_video_frame_size_change_listeners();
    

## 播放进度监听

添加监听前实现接口 QIPlayerProgressListener

只有在点播的时候 duration 和 progress 才有意义，直播的话这两个值没有参考意义

    
    
    /// <summary>
    /// 进度变更回调
    /// </summary>
    /// <param name="progress"> 当前进度 单位：毫秒 </param>
    /// <param name="duration"> 当前视频总时长 单位： 毫秒 </param>
    void on_progress_changed(int64_t progress, int64_t duration) override;
    
    
    
    void on_progress_changed(int64_t progress, int64_t duration) {
    }
    
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_progress_change_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_progress_change_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_progress_change_listeners();
    

## 实时帧率

### 实时帧率监听

添加监听前实现接口 QIPlayerFPSListener

    
    
    /// <summary>
    /// fps 改变回调
    /// </summary>
    /// <param name="fps"> fps 帧率 </param>
    void on_fps_changed(long fps) override;
    
    
    
    void on_fps_changed(long fps) {
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_fps_change_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_fps_change_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_fps_change_listeners();
    

## 像素格式或者音频sample格式不支持的监听

添加监听前实现接口 QIPlayerFormatListener

    
    
    /// <summary>
    /// 当前有 format 不支持，视频无法播放
    /// </summary>
    void on_format_not_support() override;
    
    
    
    void on_format_not_support() {
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_format_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_format_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_format_listeners();
    

## 缓冲拉流监听

添加监听前实现接口 QIPlayerDownloadListener

    
    
    /// <summary>
    /// 下载数据变化回调
    /// </summary>
    /// <param name="download_speed"> 下载速度 </param>
    /// <param name="buffer_pos"> 缓冲进度 </param>
    void on_download_changed(int64_t download_speed, int64_t buffer_pos) override;
    
    
    
    void on_download_changed(int64_t download_speed, int64_t buffer_pos){
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_download_change_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_download_change_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_download_change_listeners();
    

## 播放器操作不允许执行监听

添加监听前实现接口 QIPlayerCommandNotAllowListener 。在某些状态下，一些操作将不被执行，通过该监听回调上来通知

    
    
    /// <summary>
    /// 操作不被允许的回调
    /// </summary>
    /// <param name="command_name"> 操作名称 </param>
    /// <param name="state"> 操作被检测时播放器的状态 </param>
    void on_command_not_allow(const std::string& command_name, QMedia::QPlayerState state) override;
    
    
    
    void on_command_not_allow(const std::string& command_name, QMedia::QPlayerState state){
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_command_not_allow_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_command_not_allow_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_command_not_allow_listeners();
    

## buffering 监听

添加监听前实现接口 QIPlayerBufferingListener

    
    
    /// <summary>
    /// buffering 开始通知
    /// </summary>
    void on_buffering_start() override;
    
    /// <summary>
    /// buffering 结束通知
    /// </summary>
    void on_buffering_end() override;
    
    
    
    void on_buffering_start(){
    }
    void on_buffering_end(){
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_buffering_change_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_buffering_change_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_buffering_change_listeners();
    

## 静音播放

控制播放器静音，且该静音非系统的声音设置，仅仅只是把播放器设置为静音

### 设置静音播放

    
    
    mpPlayerWindow->get_control_handler()->set_mute(false);
    

### 静音播放相关监听

添加监听前实现接口 QIPlayerAudioListener

    
    
    /// <summary>
    /// 静音状态改变回调
    /// </summary>
    /// <param name="is_mute"> 是否静音 true 静音 false 非静音 </param>
    void on_mute_changed(bool is_mute) override;
    
    
    
    void on_mute_changed(bool is_mute){
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_audio_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_audio_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_audio_listeners();
    

## 截图

调用截图接口，就会回调截图时的video画面，并以jpeg的格式返回

    
    
    mpPlayerWindow->get_control_handler()->shoot_video();
    

### 截图图片类型枚举

    
    
    enum class QPLAYER_API QShootVideoType : uint32_t {
    	NONE = 0,
    	JEPG = 1
    };
    

### 截图相关监听

添加监听前实现接口 QIPlayerShootVideoListener

    
    
    /// <summary>
    /// 截图成功回调
    /// </summary>
    /// <param name="image_data"> 图片数据 </param>
    /// <param name="size"> 图片数据的长度 </param>
    /// <param name="width"> 图片的宽度 </param>
    /// <param name="height"> 图片的高度 </param>
    /// <param name="type"> 图片类型 </param>
    void on_shoot_video_success(const std::unique_ptr<uint8_t[]>& image_data, uint64_t size, int width, int height, QMedia::QShootVideoType type) override;
    
    /// <summary>
    /// 截图失败回调
    /// </summary>
    void on_shoot_video_failed() override;
    
    
    
    void on_shoot_video_success(const std::unique_ptr<uint8_t[]>& image_data, uint64_t size, int width, int height, QMedia::QShootVideoType type){
    }
    
    void on_shoot_video_failed(){
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_shoot_video_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_shoot_video_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_shoot_video_listeners();
    

## 码率

### 实时码率监听

添加监听前实现接口 QIPlayerBiteRateListener

    
    
    /// <summary>
    /// 码率变化回调
    /// </summary>
    /// <param name="bit_rate"> 码率 单位：bps </param>
    void on_bite_rate_changed(int bit_rate) override;
    
    
    
    void on_bite_rate_changed(int bit_rate) {
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_bite_rate_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_bite_rate_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_bite_rate_listeners();
    

## SEI 数据回调

用户自定义数据可以带在H264或者H265的编码帧里，用于实现一些基于时间轴的业务场景。  
开启该功能后，如果视频资源内带有SEI数据 会通过监听接口抛给业务层。  
该功能需要单独开通，具体可以联系技术支持咨询。

### 开启 SEI

    
    
    mpPlayerWindow->get_control_handler()->set_sei_enable(true);
    

### SEI 数据监听

添加监听前实现接口 QIPlayerSEIDataListener

    
    
    /// <summary>
    /// SEI 数据回调，且回调时机为 SEI 数据所在帧的时间
    /// </summary>
    /// <param name="data"> SEI 数据 </param>
    /// <param name="size"> SEI 数据的长度 </param>
    void on_sei_data(const std::unique_ptr<uint8_t[]>& data, uint64_t size) override;
    
    
    
    void on_sei_data(const std::unique_ptr<uint8_t[]>& data, uint64_t size){
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_sei_data_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_sei_data_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_sei_data_listeners();
    

## 渲染相关监听

添加监听前实现接口 QIPlayerRenderListener

    
    
    /// <summary>
    /// 首帧耗时回调
    /// </summary>
    /// <param name="elapsed_time"> 从 play_media_model 开始到首帧渲染出来的总耗时 单位：毫秒 </param>
    void on_first_frame_rendered(int64_t elapsed_time) override;
    
    
    
    void on_first_frame_rendered(int64_t elapsed_time){
    }
    
    //添加监听
    mpPlayerWindow->get_render_handler()->add_render_listener(this);
    //移除监听
    mpPlayerWindow->get_render_handler()->remove_render_listener(this);
    //移除所有监听
    mpPlayerWindow->get_render_handler()->remove_all_render_listeners();
    

## 视频数据上抛相关监听

添加监听前实现接口 QIPlayerVideoDataListener

    
    
    /// 视频数据上抛回调
    /// </summary>
    /// <param name="width"> 视频宽度 </param>
    /// <param name="height"> 视频高度 </param>
    /// <param name="video_type"> 视频类型 </param>
    /// <param name="buffer"> 视频数据 </param>
    /// <param name="size"> 视频数据长度 </param>
    void on_video_data(int width, int height, QMedia::QVideoType video_type, const std::unique_ptr<uint8_t[]>& buffer, uint64_t size) override;
    
    
    
    void on_video_data(int width, int height, QMedia::QVideoType video_type, const std::unique_ptr<uint8_t[]>& buffer, uint64_t size){
    }
    
    //添加监听
    mpPlayerWindow->get_render_handler()->add_player_video_data_listener(this);
    //移除监听
    mpPlayerWindow->get_render_handler()->remove_player_video_data_listener(this);
    //移除所有监听
    mpPlayerWindow->get_render_handler()->remove_all_player_video_data_listeners();
    

## 音频数据上抛相关监听

添加监听前实现接口 QIPlayerAudioDataListener

    
    
    /// 音频数据回调
    /// </summary>
    /// <param name="sample_rate"> 采样率 </param>
    /// <param name="format"> 格式 </param>
    /// <param name="channel_num"> 通道数 </param>
    /// <param name="channel_layout"> 声道 </param>
    /// <param name="audio_data"> 音频数据 </param>
    /// <param name="size">数据大小</param>
    void on_audio_data(int sample_rate, QMedia::QSampleFormat format, int channel_num, QMedia::QChannelLayout channel_layout, const std::unique_ptr<uint8_t[]>& audio_data, uint64_t size) override;
    
    
    
    void on_audio_data(int sample_rate, QMedia::QSampleFormat format, int channel_num, QMedia::QChannelLayout channel_layout, const std::unique_ptr<uint8_t[]>& audio_data, uint64_t size){
    }
    
    //添加监听
    mpPlayerWindow->get_render_handler()->add_player_audio_data_listener(this);
    //移除监听
    mpPlayerWindow->get_render_handler()->remove_player_audio_data_listener(this);
    //移除所有监听
    mpPlayerWindow->get_render_handler()->remove_all_player_audio_data_listeners();
    

## 设置视频渲染比例

    
    
    mpPlayerWindow->get_render_handler()->set_render_ratio(QMedia::QPlayerSetting::QPlayerRenderRatio::QPLAYER_RATIO_SETTING_AUTO);
    

### 视频比例枚举

    
    
    enum class  QPlayerRenderRatio : uint16_t {
    	//自动
    	QPLAYER_RATIO_SETTING_AUTO = 1,
    	//拉升
    	QPLAYER_RATIO_SETTING_STRETCH = 2,
    	//铺满
    	QPLAYER_RATIO_SETTING_FULL_SCREEN = 3,
    	//16:9
    	QPLAYER_RATIO_SETTING_16_9 = 4,
    	//4:3
    	QPLAYER_RATIO_SETTING_4_3 = 5
    
    };
    

## 设置色觉优化

    
    
    mpPlayerWindow->get_render_handler()->set_blind_type(QMedia::QPlayerSetting::QPlayerBlind::QPLAYER_BLIND_SETTING_NONE);
    

### 色觉优化枚举

    
    
    enum class  QPlayerBlind : uint16_t {
    	//无
    	QPLAYER_BLIND_SETTING_NONE = 0,
    	//红色盲
    	QPLAYER_BLIND_SETTING_RED = 1,
    	//绿色盲
    	QPLAYER_BLIND_SETTING_GREEN = 2,
    	//蓝色盲
    	QPLAYER_BLIND_SETTING_BLUE = 3
    };
    

## 字幕

### 字幕数据设置

    
    
    //添加字幕地址
    pmodel_builder->add_subtitle_element(subtitle_name, subtitle_url,subtitle_is_selected);
    

### 设置是否开启字幕

    
    
    mpPlayerWindow->get_control_handler()->set_subtitle_enable(false);
    

### 设置字幕名称

    
    
    mpPlayerWindow->get_control_handler()->set_subtitle("English");
    

### 字幕监听

添加监听前实现接口 QIPlayerSubtitleListener

    
    
    /// <summary>
    /// 字幕文本回调
    /// </summary>
    /// <param name="text"> 当前字幕的文本 </param>
    void on_subtitle_text_changed(const std::string & text) override;
    
    /// <summary>
    /// 字幕切换回调
    /// </summary>
    /// <param name="name"> 当前的字幕名称 </param>
    void on_subtitle_name_changed(const std::string & name) override;
    
    /// <summary>
    /// 字幕开启状态改变回调
    /// </summary>
    /// <param name="enable"> 当前字幕是否开启 true 开启 false 关闭 </param>
    void on_subtitle_enable(bool enable) override;
    
    /// <summary>
    /// 字幕加载结果回调
    /// </summary>
    /// <param name="name"> 字幕名称 </param>
    /// <param name="result"> 字幕加载结果 true 成功 false 失败 </param>
    void on_subtitle_loaded(const std::string & name, bool result) override;
    
    /// <summary>
    /// 字幕解码结果回调
    /// </summary>
    /// <param name="name"> 字幕名称 </param>
    /// <param name="result"> 字幕解码结果 true 成功 false 失败 </param>
    void on_subtitle_decoded(const std::string & name, bool result) override;
    
    
    
    
    void on_subtitle_text_changed(const std::string & text) {
    }
    
    void on_subtitle_name_changed(const std::string & name) {
    }
    
    void on_subtitle_enable(bool enable) {
    }
    
    void on_subtitle_loaded(const std::string & name, bool result) {
    }
    
    void on_subtitle_decoded(const std::string & name, bool result) {
    }
    
    //添加监听
    mpPlayerWindow->get_control_handler()->add_player_subtitle_listener(this);
    //移除监听
    mpPlayerWindow->get_control_handler()->remove_player_subtitle_listener(this);
    //移除所有监听
    mpPlayerWindow->get_control_handler()->remove_all_player_subtitle_listeners();
    

以上内容是否对您有帮助？