直播云

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

    基础能力使用

    最近更新时间: 2024-11-13 17:01:57

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

    播放

    创建播放数据

    以下配置的mediaModel是一个有2个清晰度的播放数据,包含2个清晰度1080 和 720 ,同时包含2个srt字幕文件,起播的时候会自动播放1080P的链接和加载中文的字幕

    //创建MediaModel的构造器
    builder = QMediaModelBuilder()
    //配置视频元素
    builder.addStreamElement(
                "",                                             //userType 预留字段可以填空
                QURLType.QAUDIO_AND_VIDEO,                      //资源的类型,指该元素是包含音频还是视频还是都包含
                1080,                                           //清晰度数值标记
                "http://demo-videos.qnsdk.com/qiniu-1080p.mp4", //视频的地址
                true                                            //是否是默认元素,默认元素是指,起播的时候默认会播放这个元素
    )
    
    builder.addStreamElement(
                "",                                             //userType 预留字段可以填空
                QURLType.QAUDIO_AND_VIDEO,                      //资源的类型,指该元素是包含音频还是视频还是都包含
                720,                                            //清晰度数值标记
                "http://demo-videos.qnsdk.com/qiniu-720p.mp4",  //视频的地址
                false                                           //是否是默认元素,默认元素是指,起播的时候默认会播放这个元素
    )
    
    builder.addSubtitleElement("中文",                                      //字幕名称(唯一的key)
                "http://demo-videos.qnsdk.com/qiniu-2023-chinese.srt",     //srt字幕地址
                true)                                                      //是否是默认字幕 默认元素是指,起播的时候默认加载这个字幕
            builder.addSubtitleElement("英文",
                "http://demo-videos.qnsdk.com/qiniu-2023-english.srt", 
                false)
    
    val mediaModel = builder.build(false) //此处的参数指代该资源是否是一个直播资源,是直播的话就是true,不是直播就是false
    

    以下配置的mediaModel是一个音频和视频分成2路url的的播放数据 ,起播的时候会同时播放这两个元素

    builder = QMediaModelBuilder()
            builder.addStreamElement(
                "",                                              //userType 预留字段可以填空
                QURLType.QAUDIO,                                 //资源的类型,这里的url对应的资源只有音频所以这里用QAUDIO
                100,                                             //清晰度数值标记为100
                "http://demo-videos.qnsdk.com/only-audio.m4s",   //资源地址
                true                                             //是否是默认元素,默认元素是指,起播的时候默认会播放这个元素
            )
            builder.addStreamElement(
                "",                                                           //userType 预留字段可以填空
                QURLType.QVIDEO,                                              //资源的类型,这里的url对应的资源只有视频所以这里用QVIDEO
                1080,                                                         //清晰度数值标记为1080
                "http://demo-videos.qnsdk.com/only-video-1080p-60fps.m4s",    //资源地址
                true                                                          //是否是默认元素,此处也是默认播放,所以也是true
            )
    
    val mediaModel = builder.build(false) //此处的参数指代该资源是否是一个直播资源,是直播的话就是true,不是直播就是false
    

    addStreamElement方法的所有参数

    参数名 参数含义
    userType 用户自定义Type,目前预留,可以填空字符串
    urlType 媒体的资源属性 只包含视频/只包含音频/同时有视频音频
    quality 清晰度
    url 资源地址
    isSelected 是否起播时播放该流
    backupUrl 备用地址
    referer http/https 协议的地址 支持该属性 用于防盗链referer参数
    videoRenderType 视频的渲染类型,默认是QVideoRenderType.PLANE, 如果是VR视频此处为QVideoRenderType.PANORAMA_EQUIRECT_ANGULAR
    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 进行解密。

    配置DRM加密视频

    //七牛私有HLS解密密钥
    builder = QMediaModelBuilder()
            url = "http://80rjmu.com1.z0.glb.clouddn.com/ncyY3ioGAakS-Lg252IscrXNxyo=/Fgny-rvibYqoFP-lPkI53JfmoIx5"
            builder.addStreamElement("", QURLType.QAUDIO_AND_VIDEO, 0, url, true, "", "", QVideoRenderType.PLANE, "testtesttesttest")
            mVideoList.add(Pair(url, builder.build(false)))
    
    //公有MP4解密密钥
    builder = QMediaModelBuilder()
            url = "https://sdk-release.qnsdk.com/CENC_AES-CTR.mp4"
            builder.addStreamElement("", QURLType.QAUDIO_AND_VIDEO, 0, url, true, "", "", QVideoRenderType.PLANE, "", "c7e16c4403654b85847037383f0c2db3")
            mVideoList.add(Pair(url, builder.build(false)))
    
    //私有MP4解密密钥
    builder = QMediaModelBuilder()
            url = "https://kodo.koafun.com/drm-16884581530881688458153078-new.mp4"
            builder.addStreamElement("", QURLType.QAUDIO_AND_VIDEO, 0, url, true, "", "", QVideoRenderType.PLANE, "", "", "comnew", "filenew")
            mVideoList.add(Pair(url, builder.build(false)))
    

    对 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 文件进行播放

    
    builder = QMediaModelBuilder()
    //配置视频元素
    builder.addStreamElement(
                "",                                             //userType 预留字段可以填空
                QURLType.QAUDIO_AND_VIDEO,                      //资源的类型,指该元素是包含音频还是视频还是都包含
                1080,                                           //清晰度数值标记
                "https://sdk-release.qnsdk.com/CENC_AES-CTR.mp", //视频的地址
                true                                            //是否是默认元素,默认元素是指,起播的时候默认会播放这个元素
                "c7e16c4403654b85847037383f0c2db3"              //mp4 解密使用的秘钥
    )
    
    
    val mediaModel = builder.build(false) //此处的参数指代该资源是否是一个直播资源,是直播的话就是true,不是直播就是false                                                   //预留字段,可以为
    

    视频URL类型枚举

    QAUDIO_AND_VIDEO(0),  //包含视频和音频
    QAUDIO(1),            //仅包含音频
    QVIDEO(2),           //仅包含视频
    NONE(5);             //无
    

    播放媒体资源

    上一步中我们创建了一些mediaModel,接下来我们将播放他们

    mQPlayerView.playerControlHandler.playMediaModel(
                    mediaModel, //要播放的媒体资源
                    0           //起播的位置,如果是直播这里必须为0,不然有不可预见的问题发生
    )
    

    播放错误监听

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

    val listener =  object: QIPlayerMediaNetworkListener {
    
        /***
         * 开始重连
         *
         * @param userType 重连stream element的userType
         * @param urlType 重连stream element的urlType
         * @param url 重连的url
         * @param retryTime 已重试的次数
         */
        override fun onReconnectStart(userType: String, urlType: QURLType, url: String, retryTime: Int) {
        }
    
        /***
         * 重连结束
         *
         * @param userType 重连stream element的userType
         * @param urlType 重连stream element的urlType
         * @param url 重连的url
         * @param retryTime 已重试的次数
         * @param error 错误码
         */
        override fun onReconnectEnd(userType: String, urlType: QURLType, url: String, retryTime: Int, error: OpenError) {
        }
    
        /***
         * 打开失败
         *
         * @param userType 重连stream element的userType
         * @param urlType 重连stream element的urlType
         * @param url 重连的url
         * @param error 错误码
         */
        override fun onOpenFailed(userType: String, urlType: QURLType, url: String, error: OpenError) {
    
             //当非用户中断时,才展示错误面板
             if (error != QIPlayerMediaNetworkListener.OpenError.INTERRUPT) {
                //展示错误面板
             }
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerMediaNetworkListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerMediaNetworkListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerMediaNetworkListener()
    

    播放错误码枚举

    UNKOWN(10000),
    NONE(0),
    IOERROR(-5),
    INTERRUPT(-1414092869),
    URL_INVALID(-875574520),
    FORMAT_INVALID(-1094995529);
    

    SRT字幕

    要使用SRT字幕需要满足四个条件

    1. 视频源配置了字幕(配置方式参阅播放条目)
    2. 字幕功能开启mQPlayerView.playerControlHandler.setSubtitleEnable(true)
    3. 有生效的字幕(以下方式二选一)
    • 在视频源配置了isDefault=True的字幕启动播放
    • 通过接口设置生效字幕 mQPlayerView.playerControlHandler..setSubtitle(subtitleName)
    1. 通过字幕回调监听,每当时间轴触发了新的字幕条目,则该监听会回调,并将最新的一条字幕文案传递给监听接口,用户可以以自己的展示方式来展示这条字幕条目

    字幕回调监听

    val listener =  object: QIPlayerSubtitleListener {
    
        //text:最新的字幕条目
        override fun on_subtitle_text_change(text: String) {
            //更新字幕文案展示
        }
    
        //name:字幕的名称
        override fun on_subtitle_name_change(name: String) {
           //字幕变更回调
        }
    
        override fun on_subtitle_close() {
            //字幕能力关闭
        }
        //name:字幕的名称
        //result:加载的结果
        override fun on_subtitle_loaded(name: String, result: Boolean) {
            //字幕加载结束
        }
        //name:字幕的名称
        //result:解析的结果
        override fun on_subtitle_decoded(name: String, result: Boolean) {
            //字幕解析结束
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerSubtitleListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerSubtitleListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerSubtitleListeners()
    

    预加载

    播放预加载实例用于点播(一般用在短视频场景中),不能用在直播上,播放预加载实例能提升首帧的速度。
    预加载的加载时机策略由业务层自行实现

    预加载的简单使用

    //创建预加载实例,一般是提前创建
    mediaItem = QMediaItemContext(mediaModel, logLevel, localStorageDir, startPos)
    
    //开始预加载
    mediaItem.playMediaControlHandler.start()
    
    //在需要播放时调用播放预加载实例接口
    mQPlayerView.playerControlHandler.playMediaItem(mediaItem)
    
    //播放完成后
    停止预加载实例
    mediaItem.playMediaControlHandler.stop()
    

    预加载实例状态枚举

    NONE(100)         //初始状态
    PREPARE(101)      //开始加载前,准备工作状态
    LOADING(102)      //开始加载
    PAUSED(103)       //暂停加载
    STOPED(104)       //停止加载, 无法恢复
    ERROR(105)        //加载出错
    PREPARE_USE(106)  //准备使用播放
    USED(107)         //已经使用
    DISCARD(108)      //废弃
    

    预加载实例状态监听

    val listener =  object: QIMediaItemStateChangeListener {
    
        //状态变更回调时回调,返回变更后的状态
         override fun onStateChanged(state: QMediaItemState) {
    
        }
    }
    
    //添加监听
    mediaItem.playMediaControlHandler.addMediaItemStateChangeListener(listener)
    //移除监听
    mediaItem.playMediaControlHandler.removeMediaItemStateChangeListener(listener)
    //移除所有监听
    mediaItem.playMediaControlHandler.removeAllPlayMediaStateChangeListener()
    

    预加载的状态枚举

    NONE(100),//初始状态
    PREPARE(101),
    LOADING(102),
    PAUSED(103),
    STOPED(104),
    ERROR(105),
    PREPARE_USE(106),
    USED(107),
    DISCARD(108);
    

    设置日志等级

    mQPlayerView.playerControlHandler.setLogLevel(QLogLevel.LOG_INFO)
    

    暂停播放

    mQPlayerView.playerControlHandler.pauseRender()
    

    恢复播放

    mQPlayerView.playerControlHandler.resumeRender()
    
    

    停止当前视频播放

    mQPlayerView.playerControlHandler.stop()
    
    

    鉴权

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

    强制网络鉴权

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

    mQPlayerView.playerControlHandler.forceAuthenticationFromNetwork() 
    

    鉴权监听

    val listener =  object: QIPlayerAuthenticationListener {
        /**
         * 鉴权失败回调,同时,会停止当前的视频播放,且状态切换成 @see[QPlayerState.ERROR]
         */
        fun on_authentication_failed(error_type: QAuthenticationErrorType) {
        }
    
        /**
         * 鉴权成功回调
         */
        fun on_authentication_success() {
        }
    
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerAuthenticationListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerAuthenticationListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerAuthentications()
    
    

    鉴权错误码枚举

    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功能权限
    

    切换视频进度

    mQPlayerView.playerControlHandler.seek(2000) //参数为要定位的position 单位毫秒
    
    

    Seek监听

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

    val listener =  object: QIPlayerSeekListener {
    
    	/*seek失败回调*/
    	override fun onSeekFailed() {
        }
    	/*seek成功回调*/
        override fun onSeekSuccess() {
        }
    	
    }
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerSeekListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerSeekListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerSeekListener()
    

    视频解码方式

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

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

    //下一次播放生效
    //最终的解码方式可能不是设置的,在设置的解码方式不能正确解码时,内核会进行降级,选择其他能正确解码的方式
    mQPlayerView.playerControlHandler.setDecodeType(QPlayerSetting.QPlayerDecoder.QPLAYER_DECODER_SETTING_AUTO)
    
    

    优先选择的解码方式枚举

    //自动选择
    QPLAYER_DECODER_SETTING_AUTO(0),
    //硬解优先
    QPLAYER_DECODER_SETTING_HARDWARE_PRIORITY(1),
    //软解优先
    QPLAYER_DECODER_SETTING_SOFT_PRIORITY(2),
    //混解优先
    QPLAYER_DECODER_SETTING_FIRST_FRAME_ACCEL_PRIORITY(3),
    

    播放器视频解码监听相关

    val listener =  object: QIPlayerVideoDecodeListener {
    
        //setDecodeType 设置了优先使用哪种解码方式,经过内核处理后,该回调将正真的视频解码方式返回
        override fun onVideoDecodeByType(type: QPlayerDecodeType) {
    
        }
    
        
        // 如果当前视频编码 所在设备或者sdk不支持 则回调该方法
        // codecId 视频的编码id
        override fun notSupportCodecFormat(codecId: Int) {
        }
        /**
         * 通知当前视频解码失败,
         * @param retry 底层是否重试
         */
        override fun onDecodeFailed(retry: Boolean) {
        }
    }
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerVideoDecodeTypeListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerVideoDecodeTypeListener(listener)
    //移除所有播放器视频解码监听
    mQPlayerView.playerControlHandler.removeAllPlayerVideoDecodeTypeListener()
    
    

    解码方式枚举

    NONE(0),
    //软解
    SOFTWARE(1),
    //surface 硬解
    HARDWARE_SURFACE(10),
    //buffer 硬解
    HARDWARE_BUFFER(11),
    //混解
    FIRST_FRAME_ACCEL(2);
    

    设置起播方式

    //下一次播放生效
    mQPlayerView.playerControlHandler.setStartAction(QPlayerSetting.QPlayerStart.QPLAYER_START_SETTING_PLAYING) 
    
    

    解码方式枚举

    //起播播放
    QPLAYER_START_SETTING_PLAYING(0),
    //起播暂停在首帧
    QPLAYER_START_SETTING_PAUSE(1),
    

    设置seek方式

    //下一次seek即生效
    mQPlayerView.playerControlHandler.setSeekMode(QPlayerSetting.QPlayerSeek.QPLAYER_SEEK_SETTING_NORMAL) 
    
    

    seek方式枚举

    //关键帧seek,每次seek 都seek到离目标位置向前的最近的一个关键帧,耗时少
    QPLAYER_SEEK_SETTING_NORMAL(0),
    //精准seek,耗时比关键帧seek多,且耗时和视频的gop间隔的大小成正比
    QPLAYER_SEEK_SETTING_ACCURATE(1),
    

    获取当前播放状态

    mQPlayerView.playerControlHandler.currentPlayerState
    
    

    获取当前进度

    mQPlayerView.playerControlHandler.currentPosition
    
    

    获取视频时长

    mQPlayerView.playerControlHandler.duration
    
    

    获取当前下载速度

    mQPlayerView.playerControlHandler.downloadSpeed
    
    

    获取当前缓冲进度

    mQPlayerView.playerControlHandler.bufferPositon
    
    

    播放器状态

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

    播放器状态枚举

    NONE(0),//初始状态
    INIT(1),//播放器开始创建各种对象 
    PREPARE(2),//开始播放一个新视频的时候先进入这个状态,进行一些准备工作
    PLAYING(4),//播放中
    PAUSED_RENDER(6),//暂停
    COMPLETED(7),//播放完成
    SEEKING(8), //SEEK
    
    STOPPED(9),//播放停止
    ERROR(10),//播放出错
    END(11),//播放器释放各种对象完成
    MEDIA_ITEM_PREPARE(12), //预加载的Prepare状态,开始播放一个新视频的时候先进入这个状态,进行一些准备工作
    RELEASE(13); //播放器结束,且释放各类资源
    

    播放器状态变更监听相关

    val listener =  object: QIPlayerStateChangeListener {
    
        //状态变更回调时回调,返回变更后的状态
        override fun onStateChanged(state: QPlayerState) {
    
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerStateChangeListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerStateChangeListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerStateChangeListener()
    
    

    播放速度

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

    设置播放速度

    //即时播放生效
    mQPlayerView.playerControlHandler.setSpeed(1.25f) //参数为倍速值
    
    

    获取当前速度

    mQPlayerView.playerControlHandler.speed
    
    

    速度变更监听相关

    val listener =  object: QIPlayerSpeedListener {
    
        //播放倍速变更回调
        override fun onSpeedChanged(speed: Float) {
    
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerSpeedChangeListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerSpeedChangeListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerSpeedChangeListener()
    
    

    清晰度

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

    切换视频清晰度

    //使用该方法时,mediaModel中需要存在多个StreamElement
    mQPlayerView.playerControlHandler.switchQuality(
                                 "",                          //要切换的StreamElement的userType
                                 QURLType.QAUDIO_AND_VIDEO,   //要切换的StreamElement的urltype
                                 1080,                        //要切换的StreamElement的清晰度数值标记
                                 false                        //是否immediately方式,true:立即切换过程中会出现卡一下,一般用于直播,false:非立即切换下,切换过程无缝切换,只能用于点播。
    ) 
    
    

    获取当前的清晰度

    //使用该方法时,mediaModel中需要存在多个StreamElement,返回清晰度数值标记
    mQPlayerView.playerControlHandler.getCurrentQuality(
                                 "",                          //要查询的StreamElement的userType
                                 QURLType.QAUDIO_AND_VIDEO   //要查询的StreamElement的urltype
    ) 
    
    

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

    //获取指定 userType urlType 流正在切换的清晰度(非immediately方式)
    mQPlayerView.playerControlHandler.getSwitchingQuality(
                                 "",                          //要查询的StreamElement的userType
                                 QURLType.QAUDIO_AND_VIDEO   //要查询的StreamElement的urltype
    ) 
    
    

    播放器清晰度相关监听

    val listener =  object: QIPlayerQualityListener {
    
        /**
         * 开始清晰度切换
         * @param userType 开始切换清晰度的stream element的userType
         * @param urlType 开始切换清晰度的stream element的 urlType @see[QURLType]
         * @param newQuality 要切到哪路清晰度
         * @param oldQuality 切换前的清晰度
         */
        override fun onQualitySwitchStart(userType: String, urlType: QURLType, newQuality: Int, oldQuality: Int) {
    
        }
    
        /**
         * 清晰度切换完成
         * @param userType 开始切换清晰度的stream element的userType
         * @param urlType 开始切换清晰度的stream element的urlType @see[QURLType]
         * @param newQuality 要切到哪路清晰度
         * @param oldQuality 切换前的清晰度
         */
        override fun onQualitySwitchComplete(userType: String, urlType: QURLType, newQuality: Int, oldQuality: Int) {
        }
    
        /**
         * 清晰度切换取消
         * @param userType 开始切换清晰度的stream element的userType
         * @param urlType 开始切换清晰度的stream element的 urlType @see[QURLType]
         * @param newQuality 要切到哪路清晰度
         * @param oldQuality 切换前的清晰度
         */
        override fun onQualitySwitchCanceled(userType: String, urlType: QURLType, newQuality: Int, oldQuality: Int) {
        }
    
        /**
         * 清晰度切换失败
         * @param userType 开始切换清晰度的url流的userType
         * @param urlType 开始切换清晰度的url流的 urlType @see[QURLType]
         * @param newQuality 要切到哪路清晰度
         * @param oldQuality 切换前的清晰度
         */
        override fun onQualitySwitchFailed(userType: String, urlType: QURLType, newQuality: Int, oldQuality: Int) {
        }
    
        /**
         * 目前仅支持同时有一个清晰度切换,如果前一个还未切换完,再次发起切换 会回调这个函数
         * @param userType 开始切换清晰度的url流的userType
         * @param urlType 开始切换清晰度的url流的 urlType @see[QURLType]
         * @param newQuality 要切到哪路清晰度
         * **/
        override fun onQualitySwitchRetryLater(userType: String, urlType: QURLType, newQuality: Int) {
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerQualityListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerQualityListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerQualityListener()
    
    

    直播支持多路清晰度切换

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

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

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

    播放进度监听

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

    val listener =  object: QIPlayerProgressListener {
    
        /**
         * 进度变更回调
         * @param duration 总时长 单位毫秒
         * @param progress 当前进度 单位毫秒
         */
        override fun onProgressChanged(duration: Long, progress: Long) {
    
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerProgressChangeListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerProgressChangeListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerProgressChangeListener()
    
    

    实时帧率

    获取当前fps

    mQPlayerView.playerControlHandler.fps
    
    

    实时帧率监听

    val listener =  object: QIPlayerFPSListener {
    
        /**
         * fps 改变的回调
         * @param fps 帧率
         */
        override fun onFPSChanged(fps: Int) {
    
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerFPSChangeListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerFPSChangeListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerFPSChangeListener()
    
    

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

    val listener =  object: QIPlayerFormatListener {
    
        /**
         * 当前有format 不支持,所以视频没法播放
         */
        override fun onFormatNotSupport() {
    
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerFormatListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerFormatListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerFormatListeners()
    
    

    缓冲拉流监听

    val listener =  object: QIPlayerDownloadListener {
    
        /**
         * 拉流速率改变
         * @param speed 单位 b/s(比特每秒)
         * @param bufferProgress 缓冲的进度
         */
        override onDownloadChanged(speed: Long, bufferProgress: Long) {
    
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerDownloadChangeListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerDownloadChangeListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerDownloadChangeListener()
    
    

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

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

    val listener =  object: QIPlayerCommandNotAllowListener {
    
        /**
         * 操作不被允许
         * @param commandName 操作名称
         * @param state 操作被检测时播放器的状态
         */
        override fun onCommandNotAllow(commandName: String, state: QPlayerState) {
    
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerCommandNotAllowListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerCommandNotAllowListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerCommandNotAllowListener()
    
    

    buffering 监听

    val listener =  object: QIPlayerBufferingListener {
    
        /**
         * 开始buffering
         */
        override fun onBufferingStart() {
            //展示buffering UI
        }
    
         /**
         * 结束buffering
         */
        override fun onBufferingEnd() {
            //隐藏buffering UI
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerBufferingChangeListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerBufferingChangeListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerBufferingChangeListener()
    
    

    码率

    获取当前码率

    mQPlayerView.playerControlHandler.biteRate
    
    

    实时码率监听

    val listener =  object: QIPlayerBiteRateListener {
    
        /**
         * 码率变换回调
         * @param biteRate 比特率, 单位:bps
         */
        override fun onBiteRateChanged(biteRate: Long) {
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerBiteRateChangeListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerBiteRateChangeListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerBiteRateChangeListener()
    
    

    SEI 数据回调

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

    开启 SEI

    mQPlayerView.playerControlHandler.setSEIEnable(true)
    

    SEI 数据监听

    val listener =  object: QIPlayerSEIDataListener {
    
        /**
         * SEI 数据回调,且回调时机为SEI数据所在帧的时间
         * @param data SEI 数据
         */
        override fun onSEIData(data: ByteArray) {
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerSEIDataListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerSEIDataListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerSEIDataListeners()
    
    

    音频数据上抛相关监听

    开启音频数据监听

    mQPlayerView.playerControlHandler.setAudioDataCallbackEnable(true)
    

    音频数据监听

    val listener =  object: QIPlayerAudioDataListener {
    
        /**
         * 音频数据回调
         * @param sampleRate 采样率
         * @param format 音频位宽
         * @param channelNum 声道数
         * @param channelLayout 声道布局
         * @param data 音频数据
         */
        override fun onAudioData(sampleRate: Int, format: QSampleFormat, channelNum: Int, channelLayout:QChannelLayout, data: ByteArray){
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerAudioDataListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerAudioDataListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerAudioDataListeners()
    
    

    视频数据上抛相关监听

    开启视频数据监听

    mQPlayerView.playerControlHandler.setVideoDataCallbackEnable(true)
    

    音频数据监听

    val listener =  object: QIPlayerVideoDataListener {
    
        /***
         * 视频数据回调
         * @param width 视频宽度
         * @param height 视频高度
         * @param type 视频数据类型
         * @param data 视频数据
         */
        override fun onVideoData(width: Int, height: Int, type: QVideoDataType, data: ByteArray) {
        }
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerVideoDataListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerVideoDataListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerVideoDataListeners()
    
    

    渲染相关监听

    val listener =  object: QIPlayerRenderListener {
    
        //首帧耗时回调 从play 开始到首帧渲染出来的总耗时 单位毫秒
        override fun onFirstFrameRendered(elapsedTime: Long) {
    
        }
    }
    
    //添加监听
    mQPlayerView.playerRenderHandler.addPlayerRenderListener(listener)
    //移除监听
    mQPlayerView.playerRenderHandler.removePlayerRenderListener(listener)
    //移除所有监听
    mQPlayerView.playerRenderHandler.removeAllPlayerRenderListener()
    

    设置视频缩放比例

    /***
    * 设置画面缩放
    * @param scale 缩放倍数
    * @return true 设置成功 false 设置失败
    */
    mQPlayerView.playerRenderHandler.setScale(2.0f) 
    

    设置视频镜像类型

    /***
    * 设置镜像
    * @param type 镜像类型
    * @return true 设置成功 false 设置失败
    */
    mQPlayerView.playerRenderHandler.setMirrorType(QPlayerSetting.QPlayerMirror.QPLAYER_MIRROR_X) 
    

    镜像枚举

    //无镜像
    QPLAYER_MIRROR_NONE(0),
    //横向镜像
    QPLAYER_MIRROR_X(1),
    //垂直镜像
    QPLAYER_MIRROR_Y(2),
    //横向和垂直都镜像
    QPLAYER_MIRROR_XY(3),
    

    设置视频旋转

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

    设置视频渲染比例

    mQPlayerView.playerRenderHandler.setRenderRatio(QPlayerSetting.QPlayerRenderRatio.QPLAYER_RATIO_SETTING_AUTO) 
    

    视频比例枚举

    //自动
    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),
    

    设置色觉优化

    mQPlayerView.playerControlHandler.setBlindType(QPlayerSetting.QPlayerBlind.QPLAYER_BLIND_SETTING_NONE) 
    

    色觉优化枚举

    //无
    QPLAYER_BLIND_SETTING_NONE(0),
    //红色盲
    QPLAYER_BLIND_SETTING_RED(1),
    //绿色盲
    QPLAYER_BLIND_SETTING_GREEN(2),
    //蓝色盲
    QPLAYER_BLIND_SETTING_BLUE(3),
    

    VR视频播放

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

    /***
    * 设置VR视频的旋转角度
    * @param rotateX 横向角度 (360度制)
    * @param rotateY 纵向角度 (360度制)
    * @return true 设置成功 false 设置失败
    */
    mQPlayerView.playerRenderHandler.setPanoramaViewRotate(mCurrentRotationY, -mCurrentRotationX)
    
    

    视频类型枚举

    NONE(-1),
    //普通视频
    PLANE(0),
    //ANGULAR类 VR视频
    PANORAMA_EQUIRECT_ANGULAR(1),
    

    截图

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

    mQPlayerView.playerControlHandler.shootVideo()
    

    截图监听

    val listener =  object: QIPlayerShootVideoListener {
    
    	/**
         * 截图成功
         */
        override fun onShootSuccessful(
            image: ByteArray, //图片的二进制数组
            width: Int,			//图片的宽
            height: Int,		//图片的高
            type: QIPlayerShootVideoListener.ShootVideoType //图片的类型(jpeg)
        ) {
            //保存截图
            //展示截图
        }
    
    	/**
         * 截图失败回调
         */
        override fun onShootFailed() {
            
        }
    
    }
    
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerShootVideoListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerShootVideoListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerShootVideoListeners()
    

    静音

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

    /**
    @param isMute true: 静音 false:非静音
    */
    mQPlayerView.playerControlHandler.setMute(true)
    

    静音监听

    val listener =  object: QIPlayerAudioListener {
    
    	//静音改变回调
    	override fun onMuteChanged(is_mute: Boolean) {
        }
    }
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerAudioListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerAudioListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerAudioListener()
    

    视频宽高改变监听

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

    val listener =  object: QIPlayerVideoFrameSizeChangeListener {
    
    	//宽:width 高:height
    	onVideoFrameSizeChanged(width: Int, height: Int) {
        }
    }
    //添加监听
    mQPlayerView.playerControlHandler.addPlayerVideoFrameSizeChangeListener(listener)
    //移除监听
    mQPlayerView.playerControlHandler.removePlayerVideoFrameSizeChangeListener(listener)
    //移除所有监听
    mQPlayerView.playerControlHandler.removeAllPlayerVideoFrameSizeChangeListener()
    
    以上内容是否对您有帮助?
  • Qvm free helper
    Close