直播云

  • 直播云 > SDK 下载 > 播放端 >QPlayer2 Harmony 端 > 基于 Core 的 QPlayer2 接入指南 > 基础能力使用

    基础能力使用

    最近更新时间: 2024-11-14 16:40:29

    基础能力使用

    快速开始 中,我们完成了qplayer2播放器的创建\播放\销毁,本文介绍如何使用qplayer2的播放能力

    播放

    创建播放数据

    let builder : QMediaModelBuilder = new QMediaModelBuilder()
    builder.addStreamElement("",QPlayerUrlType.QAUDIO_AND_VIDEO,1080,"你的地址",true,"","")
    let model : QMediaModel = builder.build(false)
    

    addStreamElements 属性说明

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

    视频URL类型枚举

    export enum QPlayerUrlType {
      QAUDIO_AND_VIDEO = 0, //音视频
      QAUDIO = 1,  //纯音频
      QVIDEO = 2,  //纯视频
      NONE = 3,    //无
    }
    

    播放媒体资源

    /*** 播放音视频资源
     * @param model 音视频资源
     */ 
    this.mPlayerContext.get_control_handler().playMediaModel(model,0)
    

    播放错误监听

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

    private mMediaNetworkListener : QIPlayerMediaNetworkListener = {
    /***
     开始重连
     @param context 当前的播放器
     @param userType 重连url流的userType
     @param urlType 重连url流的urlType
     @param url 重连的url
     @param retryTime 已重试的次数
    */
        onReconnectStart:(context : QIPlayerContext , userType: string , urlType: QPlayerUrlType , url: string , retryTime: number ) => {
          
        },
    /***
     重连结束
     @param context 当前的播放器
     @param userType 重连url流的userType
     @param urlType 重连url流的urlType
     @param url 重连的url
     @param retryTime 已重试的次数
     @param error 错误码
    */
        onReconnectEnd:(context : QIPlayerContext , userType: string , urlType: QPlayerUrlType , url: string , retryTime: number , error: QPlayerOpenError ) => {
          
        },
    /***
     打开失败
     @param context 当前的播放器
     @param userType 重连url流的userType
     @param urlType 重连url流的urlType
     @param url 重连的url
     @param error 错误码
    */
        onOpenFailed:(context : QIPlayerContext , userType: string , urlType: QPlayerUrlType , url: string , error: QPlayerOpenError ) => {
          
        }
      }
    
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerMediaNetworkListener(this.mMediaNetworkListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerMediaNetworkListener(this.mMediaNetworkListener)
    //移除全部监听
    this.mPlayerContext.get_control_handler().removeAllPlayerMediaNetworkListener()
    

    播放错误码枚举

    export enum QPlayerOpenError{
      UNKNOW = 10000,
      NONE = 0,
      IOERROR = -5,
      INTERRUPT = -1414092869,
      URL_INVALID = -875574520,
      FORMAT_INVALID = -1094995529
    }
    

    暂停播放

    this.mPlayerContext.get_control_handler().pauseRender()
    

    恢复播放

    this.mPlayerContext.get_control_handler().resumeRender()
    

    停止当前视频播放

    this.mPlayerContext.get_control_handler().stop()
    

    播放 drm 视频

    mp4 加密

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

    对 MP4 文件进行七牛私有加密方式播放

    let builder : QMediaModelBuilder = new QMediaModelBuilder()
    builder.addStreamElementWithMp4QNDrm("",QPlayerUrlType.QAUDIO_AND_VIDEO,1080,"你的地址",true,"","","mp4QNDrmComKey","mp4QNDrmFileKey")
    let model : QMediaModel = builder.build(false)
    this.mPlayerContext.get_control_handler().playMediaModel(model,0)
    

    对 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
    

    QPlayer2 对加密后 MP4 文件进行播放

    let builder : QMediaModelBuilder = new QMediaModelBuilder()
    builder.addStreamElementWithMp4Drm("",QPlayerUrlType.QAUDIO_AND_VIDEO,1080,"你的地址",true,"","","mp4DrmKey")
    let model : QMediaModel = builder.build(false)
    this.mPlayerContext.get_control_handler().playMediaModel(model,0)
    

    HLS 加密

    let builder : QMediaModelBuilder = new QMediaModelBuilder()
    builder.addStreamElementWithHlsDrm("",QPlayerUrlType.QAUDIO_AND_VIDEO,1080,"你的地址",true,"","","hlsDrmKey")
    let model : QMediaModel = builder.build(false)
    this.mPlayerContext.get_control_handler().playMediaModel(model,0)
    

    鉴权

    鉴权功能介绍见 鉴权相关文档

    鉴权监听

    private mAuthenticationListener : QIPlayerAuthenticationListener = {
    /**
     @brief 鉴权失败回调
     @param context 当前播放器
     @param error 失败错误码
     */
        onAuthenticationFailed:(context: QIPlayerContext, error:QPlayerAuthenticationErrorType)=>{
          this.addToastView(`鉴权失败:${error.valueOf()}`)
        },
    
    /**
     @brief 鉴权成功回调
     @param context 当前播放器
     */
        onAuthenticationSuccess:(context: QIPlayerContext)=>{
          this.addToastView("鉴权成功")
        }
      }
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerAuthenticationListener(this.mAuthenticationListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerAuthenticationListener(this.mAuthenticationListener)
    //移除全部监听
    this.mPlayerContext.get_control_handler().removeAllPlayerAuthenticationListener()
    

    鉴权错误码枚举

    /**
     鉴权不通过错误码
     */
    export enum QPlayerAuthenticationErrorType {
      NONE,             //鉴权出错
      NO_BASE_AUTH,     //缺少基础功能权限
      NO_VR_AUTH,       //缺少VR功能权限
      NO_BLIND_AUTH,    //缺少色盲功能权限
      NO_SEI_AUTH,      //缺少SEI功能权限
      NO_SRT_AUTH,      //缺少SRT功能权限
      NO_APM_AUTH       //缺少APM功能权限
    };
    

    视频解码方式

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

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

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

    this.mPlayerContext.get_control_handler().setDecoderType(QPlayerDecoderPriority.AUTO)
    

    优先选择的解码方式枚举

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

    typedef NS_ENUM(NSInteger, QPlayerDecoder) {
    export enum QPlayerDecoderPriority {
      AUTO = 0,  //自动
      HARDWARE_PRIORITY = 1,  //硬解优先
      SOFT_PRIORITY = 2,       //软解优先
    }
    };
    

    播放器视频解码监听相关

    private mDecoderTypeListener : QIPlayerVideoDecodeListener = {
        
      /**
       当前视频用的是哪种解码方式
       @param context 当前的播放器
       @param type 解码方式
       */
      onVideoDecodeByType:(context : QIPlayerContext , type: QPlayerDecoderType) =>{
    }
    
      /**
       * 通知当前视频解码失败,
       * @param retry 底层是重试
       */
      onDecodeFailed:(context : QIPlayerContext , retry: boolean) => {
    }
    
      /**
       如果当前视频编码 所在设备或者sdk不支持 则回调该方法
       @param context 当前的播放器
       @param codecId 视频的编码id
       */
      onNotSupportCodecFormat:(context : QIPlayerContext , codec: number) => {
    }
    }
    
     //添加监听
    this.mPlayerContext.get_control_handler().addPlayerVideoDecodeTypeListener(this.mDecoderTypeListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayeVideoDecodeTypeListener(this.mDecoderTypeListener)
    //移除所有监听
    this.mPlayerContext.get_control_handler().removeAllPlayerVideoDecodeTypeListener()
    

    解码方式枚举

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

    export enum QPlayerDecoderType{
      NONE = 0,          //无
      SOFTWARE = 1,          //软解
      HARDWARE = 30,          //硬解
    }
    

    切换视频进度

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

    this.mPlayerContext.get_control_handler().seek(1000)
    

    设置起播方式

    下一次播放生效

    this.mPlayerContext.get_control_handler().setSeekMode(QPlayerSeek.NORMAL)
    

    seek方式枚举

    export enum QPlayerSeek {
      NORMAL = 0,   //关键帧
      ACCURATE = 1, //精准
    }
    

    seek 状态监听

    一般情况下 seek都会成功,如果网络差的情况下,会无限loading(除非调用stop才会停止),直到seek到指定的位置为止。但是如果视频源本身是格式不正确的,比如pts错乱等问题,才会导致seek失败,所以在seek失败回调中,做好提示工作就好,不要尝试再次seek

    private mSeekListener : QIPlayerSeekListener = {
    /**
     seek成功回调
     @param context 当前的播放器
    */
        onSeekSuccess:(context : QIPlayerContext) => {
        },
    
    /**
     seek失败回调
     @param context 当前的播放器
    */
        onSeekFailed:(context : QIPlayerContext) => {
        }
      }
    
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerSeekListener(this.mSeekListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerSeekListener(this.mSeekListener)
    //移除全部监听
    this.mPlayerContext.get_control_handler().removeAllPlayerSeekListener()
    

    获取当前播放状态

    this.mPlayerContext.get_control_handler().currentPlayerState
    

    获取视频时长

    this.mPlayerContext.get_control_handler().duration
    

    获取当前进度

    this.mPlayerContext.get_control_handler().currentPosition
    

    获取当前下载速度

    this.mPlayerContext.get_control_handler().downloadSpeed
    

    获取当前缓冲进度

    this.mPlayerContext.get_control_handler().bufferPostion
    

    播放器状态

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

    播放器状态枚举

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

    播放器状态变更监听相关

    private mStateChangeListener : QIPlayerStateChangeListener ={
    /**
     状态变更回调
     @param context 当前的播放器 
     @param state 播放器状态
     */
          onStateChange:(context : QIPlayerContext ,state: QPlayerState)=>{
          }
       }
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerStateListener(this.mStateChangeListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerStateListener(this.mStateChangeListener)
    //移除全部监听
    this.mPlayerContext.get_control_handler().removeAllPlayerStateListener()
    

    播放速度

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

    设置播放速度

    参数为倍速值

    this.mPlayerContext.get_control_handler().setSpeed(0.5)
    

    获取当前播放速度

    this.mPlayerContext.get_control_handler().playerSpeed
    

    速度变更监听相关

    
    private mPlaySpeed : QIPlayerSpeedListener = {
    /**
     倍速改变回调
     @param context 当前的播放器 
     @param speed 改变后的倍速
    */
        onSpeedChanged:(context : QIPlayerContext, speed:number)=>{
        }
    }
    
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerSpeedChangeListener(this.mPlaySpeed)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayeSpeedChangeListener(this.mPlaySpeed)
    //移除所有监听
    this.mPlayerContext.get_control_handler().removeAllPlayerSpeedChangeListener()
    

    清晰度

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

    切换视频清晰度

    //使用该方法时,mediaModel中需要存在多个StreamElement
    
    /**
      切换清晰度
      @param userType 切换清晰度的url流的userType
      @param urlType 切换清晰度的url流的 urlType
      @param quality 要切到哪路清晰度
      @param immediately true 立即切换 用于直播流,false 无缝切换,切换过程是一个异步过程,用于点播流
      @return true 调用成功, false 调用失败
    */
    this.mPlayerContext.get_control_handler().switchQuality("",QPlayerUrlType.QAUDIO_AND_VIDEO,1080,false)
    

    获取当前的清晰度

    //使用该方法时,mediaModel中需要存在多个StreamElement,返回清晰度数值标记
    
    /**
     获取指定 userType urlType 的清晰度
      @param userType 切换清晰度的url流的userType
      @param urlType 切换清晰度的url流的 urlType
      @return true 调用成功, false 调用失败
    */
    this.mPlayerContext.get_control_handler().getCurrentQuality("",QPlayerUrlType.QAUDIO_AND_VIDEO)
    

    获取当前正在切换的清晰度

    /**
     获取指定 userType urlType 流正在切换的清晰度(非immediately方式)
      @param userType 切换清晰度的url流的userType
      @param urlType 切换清晰度的url流的 urlType
      @return true 调用成功, false 调用失败
    */
    this.mPlayerContext.get_control_handler().getSwitchingQuality("",QPlayerUrlType.QAUDIO_AND_VIDEO)
    

    播放器清晰度相关监听

    private mQualityListener: QIPlayerQualityListener = {
    /**
       开始清晰度切换
       @param context 当前的播放器
       @param usertype 开始切换清晰度的url流的userType
       @param urlType 开始切换清晰度的url流的
       @param oldQuality 切换前的清晰度
       @param newQuality 要切到哪路清晰度
       */
      onQualitySwitchStart:(context : QIPlayerContext , usertype: string , urlType: QPlayerUrlType , oldQuality: number , newQuality: number ) =>{
    }
    
      /**
       清晰度切换完成
       @param context 当前的播放器
       @param usertype 开始切换清晰度的url流的userType
       @param urlType 开始切换清晰度的url流的
       @param oldQuality 切换前的清晰度
       @param newQuality 要切到哪路清晰度
       */
      onQualitySwitchComplete:(context : QIPlayerContext , usertype: string , urlType: QPlayerUrlType , oldQuality: number , newQuality: number ) =>{
    }
    
      /**
       清晰度切换取消
       @param context 当前的播放器
       @param usertype 开始切换清晰度的url流的userType
       @param urlType 开始切换清晰度的url流的
       @param oldQuality 切换前的清晰度
       @param newQuality 要切到哪路清晰度
       */
      onQualitySwitchCanceled:(context : QIPlayerContext , usertype: string , urlType: QPlayerUrlType , oldQuality: number , newQuality: number ) =>{
    }
    
      /**
       清晰度切换失败
       @param context 当前的播放器
       @param usertype 开始切换清晰度的url流的userType
       @param urlType 开始切换清晰度的url流的
       @param oldQuality 切换前的清晰度
       @param newQuality 要切到哪路清晰度
       */
      onQualitySwitchFailed:(context : QIPlayerContext , usertype: string , urlType: QPlayerUrlType , oldQuality: number , newQuality: number ) =>{
    }
    
      /**
       目前仅支持同时有一个清晰度切换,如果前一个还未切换完,再次发起切换 会回调这个函数
       @param context 当前的播放器
       @param usertype 开始切换清晰度的url流的userType
       @param urlType 开始切换清晰度的url流的
       */
      onQualitySwitchRetryLater:(context : QIPlayerContext ,  usertype: string , urlType: QPlayerUrlType ) =>{
    }
    
    
      }
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerQualityListener(this.mQualityListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerQualityListener(this.mQualityListener)
    //移除所有监听
    this.mPlayerContext.get_control_handler().removeAllPlayerQualityListener()
    

    直播支持多路清晰度切换

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

    1. 首先切换的模式要选择立即切换即:immediately=true
    2. 服务端配置PTS透传,
    3. 对应的清晰度要做主动转码设置

    如果无法满足以上3个条件,那么建议用最基础的能力来实现清晰度切换,即每个清晰度都是一个media model,切换时,调用playMediaModel来播放新的清晰度流。

    视频宽高改变监听

    在视频首帧渲染时,会调用该回调,告诉上层当前的视频宽高是多少,如果在这个这个视频播放的生命周期中,宽高改变,那么还会再次调用该回调.

    private mVideoFrameSizeChangedListener : QIPlayerVideoFrameSizeChangeListener ={
    
        /**
       推流端视频长宽变化回调
       @param context 当前的播放器
       @param width 视频宽度
       @param height 视频高度
       */
      onVideoFrameSizeChanged:(context : QIPlayerContext, width: number, height:number ) =>{
    }
    
    }
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerVideoFrameSizeChangeListener(this.mVideoFrameSizeChangedListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerVideoFrameSizeChangeListener(this.mVideoFrameSizeChangedListener)
    //移除所有监听
    this.mPlayerContext.get_control_handler().removeAllPlayerVideoFrameSizeChangeListener()
    

    播放进度监听

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

    private mProgressListener : QIPlayerProgressListener = {
    /***
     进度变更回调
     @param context 当前的播放器
     @param progress 当前进度 单位毫秒
     @param duration 当前视频总时长 单位毫秒
    */
        onProgressChanged:(context:QIPlayerContext,  progress:number, duration:number) => {
        }
      }
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerProgressChangeListener(this.mProgressListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerProgressChangeListener(this.mProgressListener)
    //移除全部监听
    this.mPlayerContext.get_control_handler().removeAllPlayerProgressChangeListener()
    

    实时帧率

    获取当前fps

    this.mPlayerContext.get_control_handler().fps
    

    实时帧率监听

    private mFPSListener : QIPlayerFPSListener = {
    /**
     @brief fps 改变的回调
     @param context 当前的播放器
     @param fps 帧率
     */
          onFPSChanged:(context:QIPlayerContext, FPS:number)=>{
          }
       }
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerFPSChangeListener(this.mFPSListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerFPSChangeListener(this.mFPSListener)
    //移除全部监听
    this.mPlayerContext.get_control_handler().removeAllPlayerFPSChangeListener()
    

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

    private mFormatListener : QIPlayerFormatListener = {
    /**
     @brief 当前有format 不支持,所以视频没法播放
     @param context 当前的播放器
     */
        onFormatNotSupport:(context:QIPlayerContext)=>{
        }
      }
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerFormatListener(this.mFormatListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerFormatListener(this.mFormatListener)
    //移除全部监听
    this.mPlayerContext.get_control_handler().removeAllPlayerFormatListener()
    

    缓冲拉流监听

    private mDownloadListener : QIPlayerDownloadListener = {
    /**
     @brief 拉流速率改变
     @param context 当前的播放器
     @param downloadSpeed 速度 单位: b/s (比特每秒)
     @param bufferPos 缓冲的进度
     */
          onDownloadChanged:(context:QIPlayerContext, speed:number, bufferPos:number)=>{
          }
       }
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerDownloadChangeListener(this.mDownloadListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerDownloadChangeListener(this.mDownloadListener)
    //移除全部监听
    this.mPlayerContext.get_control_handler().removeAllPlayerDownloadChangeListener()
    

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

    在某些状态下,一些操作将不被执行,通过该监听回调上来通知

    private mCommandNotAllowListener : QIPlayerCommandNotAllowListener = {
    /**
     @brief 操作不被允许回调
     @param context 操作异常的播放器
     @param commandName 操作名称
     @param state 操作被检测时播放器的状态
     */
        onCommandNotAllow:(context:QIPlayerContext, commandName:string, state:QPlayerState)=>{}
      }
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerCommandNotAllowListener(this.mCommandNotAllowListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerCommandNotAllowListener(this.mCommandNotAllowListener)
    //移除全部监听
    this.mPlayerContext.get_control_handler().removeAllPlayerCommandNotAllowListener()
    

    buffering 监听

    private mBufferingListener : QIPlayerBufferingListener = {
    
    /**
     @brief 开始buffering
     @param context 当前播放器  
     */
        onBufferingStart:(context:QIPlayerContext)=>{
        },
    
    /**
     @brief 结束buffering
     @param context 当前播放器
     */
        onBufferingEnd:(context: QIPlayerContext)=>{}
      }
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerBufferingChangeListener(this.mBufferingListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerBufferingChangeListener(this.mBufferingListener)
    //移除全部监听
    this.mPlayerContext.get_control_handler().removeAllPlayerBufferingChangeListener()
    

    截图

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

    /**
     截图
     */
    this.mPlayerContext.get_control_handler().shootVideo()
    

    截图图片类型枚举

    /**
     截图图片类型
     */
    export enum  QPlayerShootVideoType {
      NONE = 0,
      JPEG            //jpeg格式
    };
    

    截图相关监听

    private mShootVideoListener : QIPlayerShootVideoListener = {
    /**
       截图成功回调
       @param context 当前的播放器
       @param imageData 图片的 NSData 数据
       @param width 图片的宽
       @param height 图片的高
       @param type 图片类型
       */
      onShootSuccessful:(context : QIPlayerContext, imageData:Uint8Array, width:number, height:number, type: QPlayerShootVideoType) =>{
    }
    
      /**
       截图失败回调
       @param context 当前的播放器
       */
      onShootFailed:(context : QIPlayerContext) =>{
    }
    }
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerShootVideoListener(this.mShootVideoListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerShootVideoListener(this.mShootVideoListener)
    //移除所有监听
    this.mPlayerContext.get_control_handler().removeAllPlayerShootVideoListener()
    

    码率

    获取当前码率

    this.mPlayerContext.get_control_handler().biteRate
    

    实时码率监听

    private mBiteRateListener : QIPlayerBiteRateListener = {
    /**
     @brief 码率变换回调
     @param context 当前播放器 
     @param bitrate 比特率, 单位:bps
     */
        onBiteRateChanged:(context:QIPlayerContext, bitrate:number)=>{}
      }
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerBiteRateChangeListener(this.mBiteRateListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerBiteRateChangeListener(this.mBiteRateListener)
    //移除全部监听
    this.mPlayerContext.get_control_handler().removeAllPlayerBiteRateChangeListener()
    

    SEI 数据回调

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

    开启 SEI

    this.mPlayerContext.get_control_handler().setSEIEnable(true)
    

    SEI 数据监听

    private mSEIListener: QIPlayerSEIDataListener = {
    
      /**
       SEI 数据回调,且回调时机为SEI数据所在帧的时间
       @param context 当前的播放器
       @param data SEI 数据
       */
      onSEIData:(context:QIPlayerContext, data:Uint8Array)=>{
    }
    }
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerSEIDataListener(this.mSEIListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerSEIDataListener(this.mSEIListener)
    //移除所有监听
    this.mPlayerContext.get_control_handler().removeAllPlayerSEIDataListener()
    

    视频数据上抛

    开启视频数据上抛

    this.mPlayerContext.get_control_handler().setVideoDataEnable(true)
    

    设置视频回调数据类型

    this.mPlayerContext.get_control_handler().setVideoDataType(QVideoType.RGBA)
    

    视频回调数据类型枚举

    export enum QVideoType {
      YUV_420P = 1,
      NV12 = 2,
      RGBA = 3
    };
    

    视频数据上抛相关监听

    private mVideoDataListener : QIPlayerVideoDataListener = {
        onVideoData:(context : QIPlayerContext, width: number, height: number, videoType: QVideoType, buffer: Uint8Array) => {
        }
      }
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerVideoDataListener(this.mVideoDataListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerVideoDataListener(this.mVideoDataListener)
    //移除所有监听
    this.mPlayerContext.get_control_handler().removeAllPlayerVideooDataListener()
    

    音频数据上抛相关监听

    开启音频数据上抛

    this.mPlayerContext.get_control_handler().setAudioDataEnable(true)
    

    音频数据上抛相关监听

    private mAudioDataListener : QIPlayerAudioDataListener = {
        onAudioData:(context : QIPlayerContext, sampleRate: number, format:QSampleFormat, channelNum: number, channelLayout: QChannelLayout, data:Uint8Array)=>{
        }
    
      }
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerAudioDataListener(this.mAudioDataListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerAudioDataListener(this.mAudioDataListener)
    //移除所有监听
    this.mPlayerContext.get_control_handler().removeAllPlayerAudioDataListener()
    

    渲染相关监听

    private mRenderListener : QIPlayerRenderListener = {
    /**
     首帧耗时回调
     @param context 当前的播放器
     @param elapsedTime 从play 开始到首帧渲染出来的总耗时 单位毫秒
    */
          onFirstFrameRendered:(context : QIPlayerContext, elapsedTime:number) => {
          }
       }
    
    //添加监听
    this.mPlayerContext.get_render_handler().addPlayerRenderListener(this.mRenderListener)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerRenderListener(this.mRenderListener)
    //移除全部监听
    this.mPlayerContext.get_control_handler().removeAllPlayerRenderListener()
    

    设置视频渲染比例

    this.mPlayerContext.get_render_handler().setRenderRatio(QRenderRatio.AUTO)
    

    视频比例枚举

    export enum QRenderRatio {
      AUTO = 1,
      FULL_SCREEN,      //铺满
      STRETCH,          //拉伸
      Ratio_16_9,       //16:9
      Ratio_4_3,        //4:3
    }
    

    设置视频缩放比例

    /***
    * 设置画面缩放
    * @param scale 缩放倍数
    * @return true 设置成功 false 设置失败
    */
    this.mPlayerContext.get_render_handler().setScale(0.2)
    

    设置视频镜像类型

    /***
    * 设置镜像
    * @param type 镜像类型
    * @return true 设置成功 false 设置失败
    */
    this.mPlayerContext.get_render_handler().setMirrorType(QPlayerMirror.MIRROR_NONE)
    

    镜像枚举

    export declare enum QPlayerMirror {
        MIRROR_NONE = 0,
        MIRROR_X = 1,
        MIRROR_Y = 2,
        MIRROR_X_Y = 3
    }
    

    设置视频旋转

    /***
    * 设置旋转
    * @param angle 旋转角度(0<=angle<=360)
    * @return true 设置成功 false 设置失败
    */
    this.mPlayerContext.get_render_handler().setRotation(180)
    

    设置色觉优化

    this.mPlayerContext.get_render_handler().setBlindType(QBlindType.NONE)
    

    色觉优化枚举

    export enum QBlindType {
      NONE = 0, //无
      RED = 1, //红色盲
      GREEN = 2, //绿色盲
      BLUE = 3, //蓝色盲
    }
    

    VR视频播放

    在播放VR视频时,需要在mediaModel中配置vr视频的资源 并且将streamElement的QPlayerRenderType设置为PANORAMA_EQUIRECT_ANGULAR
    然后通过设置vr视频视角改变视频朝向
    该功能需要单独开通,具体可以联系技术支持咨询。

    /***
     * 设置VR视频的旋转角度
     * @param rotateX 横向角度 (360度制)
     * @param rotateY 纵向角度 (360度制)
     * @return true 设置成功 false 设置失败
     */
    this.mPlayerContext.get_render_handler().setPanoramaViewRotate(0,0)
                      
    

    视频类型枚举

    export enum QVideoRenderType {
      NONE = -1,
      PLANE = 0,
      PANORAMA_EQUIRECT_ANGULAR = 1,
    }
    
    

    后台播放

    后台播放除了 QPlayer2 设置以外,还需要申请鸿蒙的长时任务和音频后台播放。同时还在 module.json 中需要申请后台播放权限

    设置是否支持后台播放

    /**
     *设置是否后台播放
     * @param enable yes后台播放,no后台播放暂停
     */
    this.mPlayerContext.get_control_handler().setBackgroundPlayEnable(true)
    

    鸿蒙长时任务和音频后台播放

    async createSession() {
        let type: AVSessionManager.AVSessionType = 'audio';
        let session = await AVSessionManager.createAVSession(this.context,'SESSION_NAME', type);
    
        // 激活接口要在元数据、控制命令注册完成之后再执行
        await session.activate();
        console.info(`session create done : sessionId : ${session.sessionId}`);
      }
      onBackground() {
        // Ability has back to background
        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
        this.createSession()
        let wantAgentInfo : wantAgent.WantAgentInfo = {
          wants: [
            {
              bundleName: "com.qiniu.qplayer2demo",
              abilityName: "EntryAbility"
            }
          ],
          // 点击通知后,动作类型
          operationType: wantAgent.OperationType.START_ABILITY,
          requestCode: 0,
          // 点击通知后,动作执行属性
          wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
        };
    
        wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj : WantAgent) => {
          hilog.info(0x0000, 'testTag', '%{public}s', 'getWantAgent');
          backgroundTaskManager.startBackgroundRunning(this.context,
            backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, wantAgentObj).then(() => {
            console.info("Operation startBackgroundRunning succeeded");
          }).catch((err: BusinessError) => {
            console.error("Operation startBackgroundRunning failed Cause: " + err);
          });
        });
      }
    

    后台播放权限申请

     {
        "name": "ohos.permission.KEEP_BACKGROUND_RUNNING"
     }
    

    字幕

    字幕数据设置

    let builder : QMediaModelBuilder = new QMediaModelBuilder()
    builder.addStreamElement("",QPlayerUrlType.QAUDIO_AND_VIDEO,1080,"你的地址",true,"","")
    builder.addSubtitleElement("中文","你的地址",true)
    let model = builder.build(false)
    

    设置是否开启字幕

    /**
     *设置是否开启字幕
     * @param enable yes开启,no关闭
     */
    this.mPlayerContext.get_control_handler().setSubtitleEnable(true)
    

    设置字幕名称

    /**
     *设置字幕
     * @param name 设置为名称为 name 的字幕。
     */
    this.mPlayerContext.get_control_handler().setSubtitleEnable(true)
    

    字幕监听

    private mSubtitleCallBack : QIPlayerSubtitleListener = {
    
    /**
     字幕文本更改监听
     @param context 当前的播放器
     @param text 字幕文本
    */
        onSubtitleTextChange:(context : QIPlayerContext , text: string ) => {
        },
    /**
     字幕名称更改监听
     @param context 当前的播放器
     @param name 字幕名称 key
    */
        onSubtitleNameChange:(context : QIPlayerContext , name: string ) => {
    
        },
    /**
     字幕状态监听
     @param context 当前的播放器
     @param enable yes当前字幕状态关开启,no当前字幕状态关闭
    */
        onSubtitleEnable:(context : QIPlayerContext , enable: boolean ) => {
          
        },
    /**
     字幕加载状态监听
     @param context 当前的播放器
     @param name 字幕名称
     @param result yes 加载成功,no 加载失败
    */
        onSubtitleLoaded:(context : QIPlayerContext , name: string , result: boolean ) => {
        },
    /**
     字幕解码状态监听
     @param context 当前的播放器
     @param name 字幕名称
     @param result yes 加载成功,no 加载失败
    */
        onSubtitleDecoded:(context : QIPlayerContext , name: string , result: boolean ) => {
        }
      }
    
    
    
    //添加监听
    this.mPlayerContext.get_control_handler().addPlayerSubtitleListener(this.mSubtitleCallBack)
    //移除监听
    this.mPlayerContext.get_control_handler().removePlayerSubtitleListener(this.mSubtitleCallBack)
    //移除所有监听
    this.mPlayerContext.get_control_handler().removeAllPlayerSubtitleListener()
    
    以上内容是否对您有帮助?
  • Qvm free helper
    Close