产品
热门产品
存储与大数据
人工智能
SaaS集成
基础PaaS
研发运维
企业应用
专有部署
热门产品
图像技术 IA
面向图片场景提供的多种人工智能技术
视频直播 LIVE
大规模实时转码、低延时的直播服务
存储与大数据
存储服务
对象存储 OBS
稳定、安全、可靠的云存储服务
人工智能
AI开发平台
AI零代码平台
AI能力定制平台
视觉分析
视图计算 VEC
云边融合 AI赋能的智能视图计算
内容审核
内容审核 CM
图片审核|文本审核|音频审核|视频审核
人脸与人体识别
人脸人体识别 FHR
人脸识别|人体识别|人脸比对|摔倒检测
OCR识别
OCR识别 OCR
卡证识别|通用文本识别|车牌识别
图像技术
图像技术 IA
面向图片场景提供的多种人工智能技术
AI市场
模型市场 MaaS
图片、音频、视频等多场景的算法模型
SaaS集成
基础组件
APIcloud
API文档、调试、MOCK一体化协作平台
统一身份认证平台
统一的身份认证、授权管理
基础PaaS
视频应用
视频直播 LIVE
大规模实时转码、低延时的直播服务
视频点播 VOD
视频流畅播放服务
音视频通话 RTC
便捷的跨平台实时音视频互动直播服务
媒体处理 MPC
简洁的云媒体转码及内容合成处理服务
视频工具
视频工具 SDK
视频剪辑SDK | 播放SDK
物联网平台
帝视物联网视频 SDK
低延时、海量存储的物联网视频监控服务
企业物联网平台
设备管理|设备接入|规则引擎|应用开发
生活物联网平台
针对消费级智能设备的物联网平台
边缘计算
边云协同操作系统
网络与CDN
内容分发网络 CDN
安全、稳定、低延时的分发加速服务
P2P内容分发网络 PCDN
利用闲置资源而构建的低成本高品质CDN
应用开发
云短信 SMS
融合三网,安全可信的短信服务
支付 360PAY
一站式支付解决方案
消息推送 360PUSH
高效、精确、实时的消息推送
研发运维
研发效能
兼容性测试
提供数百款TOP机型的云测服务
真机租用
远程真机租用,流畅体验如手机在手
ios预审
智能扫描、分析、筛查ios审核的被拒风险点
企业应用
视频应用
幕印企业学堂
企业培训|内容付费|知识营销
易讲教室直播
视频技术与传统教室融合
企业工具
亿方云企业网盘
在线编辑、文件管理、知识管理
电子签章
无纸办公,远程签署各种电子合同
安全应用
SSL证书
一站式的 HTTPS 解决方案
三六零天御加固保
提供安全可靠的加固防护产品及服务
专有部署
云计算
360Stack云计算管理平台
规划、建设、运维一体的云计算解决方案
大数据
奇麟大数据
企业级一站式大数据平台
容器服务
360容器管理平台
可对外私有化的容器云平台
AI开发平台
360AI开发平台 专有版
全流程机器学习开发平台
更多产品,敬请期待
解决方案
产品解决方案
行业解决方案
产品解决方案
视频
通用直播解决方案
短视频解决方案
公共语音房聊天室解决方案
物联网
儿童手表音视频通话
云端NVR解决方案
数据上云
通用存储解决方案
IoT设备
AI+IPC解决方案
智能门锁解决方案
安防传感解决方案
智能网关解决方案
个护健康解决方案
账号体系
360用户帐号体系解决方案
行业解决方案
智慧城市
智慧社区解决方案
智慧交通解决方案
电商视频解决方案
电商视频解决方案
电商平台收款解决方案
教育
在线教育解决方案
互动课堂解决方案
全屋智能
智慧公寓解决方案
智慧酒店解决方案
家庭智能解决方案
智慧安防解决方案
医疗
健康看护解决方案
智能制造
工业物联网解决方案
游戏
游戏音视频解决方案
更多解决方案,敬请期待
帮助支持
技术社区
关于我们
控制台
登录
注册
SDK管理
云直播
产品文档
常见问题
API文档
云点播
产品文档
快速入门
API文档
CDN
产品文档
API文档
云存储
产品文档
SDK手册
API文档
互动直播
产品文档
API文档
操作指南
SDK管理
播放SDK
上传SDK
剪辑SDK
媒体处理
产品文档
API文档
帝视
产品文档
API文档
操作指南
支付平台
产品列表
产品文档
渠道接入解析
内容审核
产品文档
API文档
OCR识别
产品文档
API文档
人脸与人体识别
产品文档
API文档
SSL证书
产品说明
购买指南
电子签章
产品介绍
接入流程
云短信
接口文档
物联网平台
产品简介
快速入门
幕印企业学堂
产品介绍
生活物联网平台
产品简介
快速入门
图片处理
产品介绍
接口文档
视图计算
产品介绍
快速入门
常见问题
易讲-教室直播
产品介绍
帮助说明
Android互动直播
版本说明
Windows互动直播
开发文档
版本说明
iOS互动直播
Android推流
开发文档
版本说明
iOS推流
iOS推流SDK开发文档
Android上传SDK
Android上传SDK接入文档
Android上传SDK版本说明
IOS上传SDK
iOS上传sdk开发文档
IOS上传SDK版本说明
Net SDK
iOS
开发文档
版本说明
Android
开发文档
版本说明
IoT SDK
iOS
开发文档
版本说明
Android
开发文档
版本说明
Web
开发文档
版本说明
固件端
开发文档
WEB播放SDK
WEB播放器介绍
跨域请求媒体源失败
QHWW-Player
VCloudPlayer
拍摄SDK
iOS
开发文档
版本说明
Android
开发文档
版本说明
剪辑SDK
iOS
版本说明
开发文档
Android
开发文档
版本说明
投屏SDK
iOS
开发文档
Android
开发文档
播放SDK
iOS
开发文档
版本说明
Android
开发文档
版本说明
Web 上传SDK
首页
>
开发者中心
>
SDK管理
>
播放SDK
>
Android
>
开发文档
# Android播放SDK开发文档 ### Android播放SDK简单介绍 智汇云以SDK形式提供视频直播点播播放器,可以帮助开发者快速实现视频播放能力。SDK包含jar包、so库、demo及开发文档。智汇云SDK支持插件机制,可以缩小嵌入客户端的大小。 ### 功能说明 系统属性 | 系统特性 | 支持内容 | | -------- | ------------ | | 系统版本 | 4.0+ | | 流媒体协议 | RTMP、http(s)、http(m3u8) | | 硬件特性 | armv5、armv7、x86、arm64 | 支持协议 | 直播协议 | 协议优势 | 缺陷 | | -------- | ------------ | ------------ | | RTMP | 延时相对较低 | 大并发时消耗性能较大且防火墙不友好 | | http(FLV)| 延时比较低 | 对防火墙友好,但移动端支持不友好 | | http(M3u8)| 在移动端支持最好,延时比较大,一般在10-20s左右 |延时比较大 | 点播协议 | 协议优势 | 缺陷 | | -------- | ------------ | ------------ | | http(M3u8)| 移动端支持比较好 | 多个小文件分发,系统维度难度相对大 | | http(FLV)| 一般直播转回放可以用 | 移动端需要用SDK播放 | | http(mp4)| 在移动端支持相对好 | 对播放器要求比较高,容错性比较差 | 解码库说明 类型 | 体积 | 支持协议 | 支持容器 | 适用场景 ---|---|---|---|---|--- 系统播放器 | 无体积 |http |以系统支持为准,不支持flv,解码器少|个别视频播放, 精简版 | 小 | http/https/rtmp/hls | mp4/flv/m3u8/ts | 在乎体积大小,点播播放和直播flv场景 录制版 | 中 | http/https/rtmp/hls | mp4/flv/m3u8/ts |在乎体积大小,附带边播边录功能 全解码版 | 大 | http/https/rtmp/hls | mp4/flv/m3u8/ts/avi/rm/rmvb/mkv/mov/... | 体积较大,但可以播放绝大多数视频 含录制全解码 | 大 | http/https/rtmp/hls | mp4/flv/m3u8/ts/avi/rm/rmvb/mkv/mov/... | 能播放市面上绝大多数视频,且还能边播边录制到本地 功能列表 | 系统特性 | 支持内容 | |--------------|----------------------------------------------------| | 解码方式 | 支持软硬解码切换 | | 基础播放功能 | 开始、暂停、停止、快进、快退、静音等基础播放器功能 | | 播放屏幕 | 全屏、非全屏 | | 播放截图 | 支持从视频流中截图 | |画面填充|直冲多种画面的预览模式包括:原始尺寸、视频屏幕、全屏铺满、16:9、4:3等| |获取文件meta信息|支持获取视频文件属性信息| | 解码标准 | 以用户选择为准 | | 视频格式 | 以用户选择为准 | | 多实例播放 | 多实例支持 | | 倍速播放 | 支持 | | 视频缓存支持 |支持,支持视频下载 | |播放器秒开|在1s之内快速打开视频播放| |是否追帧|支持自由设置| |缓冲策略|支持自由配置| |边播放边录制|支持| |云引擎配置|支持云引擎配置参数| |多码率播放|支持无缝切换多码率播放,支持网络自适应| |渲染后置处理|支持业务自定义后置处理方式,自由接管渲染模式| |画质设置|支持亮度、饱和度、锐利度设置| |镜像播放|支持镜像播放| |统计信息,如实时帧率、码率|帧率、码率实时信息回调给客户,方便客户做不同网络状况下的业务| ### 业务流程图  ### SDK集成 #### 下载SDK sdk下载链接:[https://zyun.360.cn/developer](https://zyun.360.cn/developer) - jar > qhvc_tools_sdk.jar > qhvc_player_sdk.jar - so > armeabi-v7a/libtranscore.so > armeabi-v7a/libjplayer.so > armeabi-v7a/libviewer.so > armeabi-v7a/libffmpeg.so > armeabi-v7a/libsubtitle.so > armeabi-v7a/libundistort.so demo下载链接:[https://github.com/360livecloud/android_demo.git](https://github.com/360livecloud/android_demo.git) #### 配置说明 将qhvc_tools_sdk.jar、qhvc_player_sdk.jar放到工程libs目录下,在build.gradle中配置: ``` dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') } ``` 将libffmpeg.so、libtranscore.so、libjplayer.so、libviewer.so、libsubtitle.so、libundistort.so放到工程src/main/jniLibs/armeabi-v7a/目录下,在build.gradle中配置: ``` android { defaultConfig { ndk { // 设置支持的CPU架构,目前只支持armeabi-v7a、arm64-v8a abiFilters 'armeabi-v7a' } } } ``` 注: 1. 若qhvc_tools_sdk.jar、libtranscore.so已在接入其他模块时引入,请保留高版本,版本号可通过`Stats.getVersion()`获取。 2. 若需减小APK体积,请参考#插件化支持# #### 权限配置 ``` <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ``` #### 混淆规则 ``` -keep class com.qihoo.livecloud.** { <fields>; <methods>; } -keep class com.qihoo.videocloud.** { <fields>; <methods>; } -keep class net.qihoo.videocloud.** { <fields>; <methods>; } -keep class com.qihoo.bugreport.** { <fields>; <methods>; } -keep class com.qihoo.jiagu.** { <fields>; <methods>; } -keep class com.yunfan.net.** { <fields>; <methods>; } ``` #### SDK初始化 需要调用`QHVCSdk.getInstance().init()`,接口说明如下: appId(也叫businessId)是为业务分配的业务ID(appId获取地址:登录[视频云官网](https://zyun.360.cn/)-控制台-SDK-应用管理-新建应用)【见下图】;version为业务端APP的版本号;machineId为设备唯一标识;uid为业务方用户标识,只要保证唯一即可。  [点此查看应用ID](https://zyun.360.cn/console/sdk/application) > 对appId和channelID这两个参数的引入,在设计之初目的是为了每个业务有独立的ID,通过appId来获取云端的一些参数控制,特别是视频缓冲策略、P2P行为、硬解码黑白名单以及解码库类型;channelID更多的为数据统计打点的唯一标注,可以通过云点播和云直播的服务标识来获取,以此获取播放数据反馈。UserID的设计是为了业务方和视频云唯一的沟通桥梁,只要保持唯一即可,一般为用户ID的加密字符串,通过UserID可以排查到一个用户的级别的失败日志; ``` QHVCSdkConfig.Builder builder = new QHVCSdkConfig.Builder(this) .setAppId("appId") .setAppVersion("version") .setMachineId("machineId") .setUserId("uid"); QHVCSdk.getInstance().init(builder.build()); ``` #### APPID合法性验证 需要调用 `public int validityCheck(String appId, String authorization, long authTime, int randomNum, final QHVCAppAuth.ResultCallback<String> callback)`,接口说明如下: 合法性验证需要用到appId, Access Key(简称AK)和Secret Key(简称SK)。AK、SK获取地址: 登录[视频云官网](https://zyun.360.cn/)-用户中心-秘钥管理【见下图】。 只有appId、Access Key以及Secret Key相匹配,才能通过鉴权,否则将无法正常使用SDK。  [点此查看秘钥](https://zyun.360.cn/console/usercenter/accesskey) ==注意:此接口必须在启动APP后120秒内调用,否则将无法正常使用SDK。== appId使用和SDK初始化时同样的内容,callback可以用来监听合法性验证结果。 计算authorization时需要使用AK、SK以及当前系统的时间戳和随机数。 **为了保证AK、SK的安全,请业务接入时,务必把AK和SK存储在服务端,并且把authorization的计算也放在服务端来做。** 计算authorization的示例代码如下: ``` private void videocloudValidCheck() { int randomNum = new Random(100000000).nextInt(); //随机数 long authTime = System.currentTimeMillis() / 1000; //时间戳 (unix时间戳(10位)) //TODO 为了保证ak、sk的安全,请业务接入时,务必把AK和SK存储在服务端,并且把authorization的计算也放在服务端来做。 String authorization = getServerAuthorization(appId, AK, SK, randomNum, authTime); QHVCSdk.getInstance().validityCheck(appId, authorization, authTime, randomNum, new QHVCAppAuth.ResultCallback<String>() { @Override public void onSuccess(String data) { Logger.i(TAG, "validityCheck onSuccess, data: " + data); } @Override public void onFailed(int errCode, String errMsg) { Logger.e(TAG, "validityCheck onFailed, errCode: " + errCode + ", errMsg: " + errMsg); } }); } private String getServerAuthorization(String appID, String ak, String sk, int randNum, long authTime) { HashMap<String, String> mapParams = new HashMap<>(); mapParams.put("appid", appID); String strParams = getParams(mapParams); String paramSign = makeParamSign(strParams, randNum); String authString = ak + "\n" + authTime + "\n" + randNum + "\n" + paramSign; String encryptString = null; try { encryptString = encryptHMAC(authString, sk); } catch (Exception e) { e.printStackTrace(); } Logger.i(TAG, "apiAuth(), encryptString: " + encryptString); return ak + ":" + encryptString; } private String getParams(Map<String, String> mapParams) { String strParams; if (mapParams == null || mapParams.isEmpty()) { strParams = ""; } else { StringBuilder sbParams = new StringBuilder(); Object[] key_arr = mapParams.keySet().toArray(); Arrays.sort(key_arr);/*key升序排列*/ for (Object key : key_arr) { String value = mapParams.get(key); if (!TextUtils.isEmpty(value)) { sbParams.append("&").append(key).append("=").append(value); } } strParams = sbParams.substring(1); } return strParams; } private String makeParamSign(String param, int randNum) { return MD5.encryptMD5(MD5.encryptMD5(param) + randNum); } public String encryptHMAC(String data, String key) throws Exception { final String KEY_MAC = "HmacSHA1"; SecretKey secretKey = new SecretKeySpec(key.getBytes(), KEY_MAC); Mac mac = Mac.getInstance(KEY_MAC); mac.init(secretKey); byte[] rawHmac = mac.doFinal(data.getBytes()); return Base64.encodeToString(rawHmac, Base64.DEFAULT); } ``` 相关错误码: ``` int AUTH_OK = 1; //鉴权成功 int AUTH_FAILED = -11001; //鉴权未通过(鉴权失败) int AUTH_NOT_INVOKED = -11002; //未调用鉴权接口 ``` #### 调试 为便于接入时定位问题,可以在开发版本中打开logcat日志,播放相关TAG为QHVCPlayer。 ``` DebugUtils debugUtils = new DebugUtils(); debugUtils.setWriteLogs(true) .setPlayerLogLevel(Constants.ELogLevel.LOG_LEVEL_DEBUG) .setTransportLogLevel(Constants.ELogLevel.LOG_LEVEL_DEBUG); QHVCSdkConfig.Builder builder = new QHVCSdkConfig.Builder(this) .setAppId("appId") .setAppVersion("version") .setMachineId("machineId") .setUserId("uid"), .setDebugUtils(debugUtils); QHVCSdk.getInstance().init(builder.build()); ``` 除SDK初始化时可指定是否开启日志外,业务方也可以调用以下接口随时开启或关闭日志。 ``` DebugUtils debugUtils = new DebugUtils(); debugUtils.setWriteLogs(true) .setPlayerLogLevel(Constants.ELogLevel.LOG_LEVEL_DEBUG) .setTransportLogLevel(Constants.ELogLevel.LOG_LEVEL_DEBUG); /** * 更新日志配置 * * @param debugUtils 日志配置 */ QHVCSdk.getInstance().updateDebugUtils(debugUtils); ``` ### 接口说明 #### 直播 参考: demo\src\main\java\com\qihoo\videocloud\player\live\LiveActivity.java ##### 创建渲染View ``` <com.qihoo.videocloud.view.QHVCTextureView android:id="@+id/playView" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` ``` public class LiveActivity extends Activity { private IQHVCPlayerAdvanced qhvcPlayer; private QHVCTextureView playView; @Override protected void onCreate(Bundle savedInstanceState) { playView = (QHVCTextureView) findViewById(R.id.playView); } } ``` ##### 播放视频 ``` private void startPlay() { qhvcPlayer = new QHVCPlayer(this); playView.onPlay(); playView.setPlayer(qhvcPlayer); qhvcPlayer.setDisplay(playView); qhvcPlayer.setDataSource(IQHVCPlayer.PLAYTYPE_LIVE, url, null); qhvcPlayer.setOnPreparedListener(new IQHVCPlayer.OnPreparedListener() { @Override public void onPrepared() { qhvcPlayer.start(); } }); qhvcPlayer.setOnInfoListener(new IQHVCPlayer.OnInfoListener() { @Override public void onInfo(int handle, int what, int extra) { if (what == IQHVCPlayer.INFO_DEVICE_RENDER_QUERY_SURFACE) { if (playView != null) { if (qhvcPlayer != null && !qhvcPlayer.isPaused()) { playView.render_proc(PlayerCallback.DEVICE_RENDER_QUERY_SURFACE, 0/*不使用此变量*/); } } } else if (what == IQHVCPlayer.INFO_RENDER_RESET_SURFACE) { if (playView != null) { playView.pauseSurface(); } } } }); qhvcPlayer.prepareAsync(); } ``` ##### 停止播放 ``` private void stopPlay() { playView.stopRender(); qhvcPlayer.stop(); qhvcPlayer.release(); qhvcPlayer = null; } ``` #### 点播 参考:demo\src\main\java\com\qihoo\videocloud\player\vod\VodActivity.java 与直播方式基本一致,仅在设置数据源时略有不同: ``` qhvcPlayer.setDataSource(IQHVCPlayer.PLAYTYPE_VOD, url, null); ``` #### 其他 接口使用方式可参考Android系统播放器MediaPlayer。 ### 接口详解 #### 基础API ``` /** * 设置播放器渲染View * * @param display: 目前支持GL2VideoView、TexturePlayView、GLTextureView、LiveCloudPlayView */ void setDisplay(ILiveCloudDisplay display); ``` ``` /** * 设置视频源 * * @param playType 播放类型 {@link #PLAYTYPE_LIVE}, {@link #PLAYTYPE_VOD} * @param url 视频源地址 * @param channelId 业务id * @return result IQHVCPlayer.ERROR_OK 其他:Error */ int setDataSource(@PlayType int playType, @NonNull String url, @NonNull String channelId); /** * 设置视频源 * * @param playType 播放类型 {@link #PLAYTYPE_LIVE}, {@link #PLAYTYPE_VOD} * @param url url * @param channelId 业务id * @param options 播放器可选属性 {@link IQHVCPlayerAdvanced.OptionKey} * @return result IQHVCPlayer.ERROR_OK 其他:Error */ int setDataSource(@PlayType int playType, @NonNull String url, @NonNull String channelId, @Nullable Map<String, Object> options); /** * 设置视频源 * * @param playType 播放类型 {@link #PLAYTYPE_LIVE}, {@link #PLAYTYPE_VOD} * @param sn sn(需要走调度流程) * @param channelId 业务id * @param sign 鉴权签名 * @param options 播放器可选属性 {@link IQHVCPlayerAdvanced.OptionKey} * @return result IQHVCPlayer.ERROR_OK 其他:Error */ int setDataSource(@PlayType int playType, @NonNull String sn, @NonNull String channelId, @NonNull String sign, @Nullable Map<String, Object> options); ``` ``` /** * 准备播放,异步方法 * 注: 调用此方法开始走调度流程 * * 成功: 回调OnPreparedListener的onPrepared()接口 - 调度成功,应用层可调用start(0)开始播放 * 失败: 回调onError(ERROR_PREPARE_FAILED, ERROR_EXTRA_PREPARE_DISPATCH_FAILED) * @return IQHVCPlayer.ERROR_OK 其他:Error */ int prepareAsync(); ``` ``` /** * 开始播放 * * @return IQHVCPlayer.ERROR_OK 其他:Error */ int start(); /** * 是否正在播放 */ boolean isPlaying(); /** * 目标时间点,单位:ms(毫秒) * 目前只支持回看拖动 * * @param millis 要拖动到的目标时间 * @return IQHVCPlayer.ERROR_OK 其他:Error */ int seekTo(int millis); /** * 暂停播放 * * @return IQHVCPlayer.ERROR_OK 其他:Error */ int pause(); /** * 视频是否处于暂停状态 */ boolean isPaused(); /** * 结束播放 * * @return IQHVCPlayer.ERROR_OK 其他:Error */ int stop(); /** * 播放器资源回收 */ void release(); ``` ``` /** * 获取当前已播放时间,单位:ms(毫秒)<br> * 注: 只支持点播(回看)<br> * * @return 当前已播放时间 */ int getCurrentPosition(); /** * 获取视频文件总时长,单位:ms(毫秒)<br> * 注: 只支持点播(回看)<br> * * @return 视频文件总时长 */ int getDuration(); /** * 获取当前帧时间戳 单位:ms(毫秒) * 注: 目前只支持rtsp * * @return 帧时间戳 */ long getLiveCurrentTimestamp(); /** * 获取视频信息 * * @return */ Map<String, Object> getMediaInformation(); /** * 获取渲染模式 * * @return 渲染模式 */ int getRenderMode(); /** * 获取 Native版本号 * * @return 版本号 */ String getNativeVersion(); /** * 获取视频的旋转属性 * * @return 视频的旋转角度 */ int getPropertyRotate(); /** * 是否是录制状态 * * @return ture - 当前是录制状态 */ boolean getRecordingState(); ``` ``` /** * 设置是否静音播放 * * @param mute true: 静音播放,false:正常播放, 默认是false * @return IQHVCPlayer.ERROR_OK 其他:Error */ int setMute(boolean mute); /** * 是否是静音状态 * * @return ture - 当前是静音状态 */ boolean isMute(); /** * 设置音量 * * @param volume 音量范围 0.0~1.0(1.0最大) * @return IQHVCPlayer.ERROR_OK 其他:Error */ void setVolume(float volume); /** * 获取播放器当前音量 * * @return 音量范围 0.0~1.0(1.0最大) <0 无效 */ float getVolume(); ``` ``` /** * 设置播放时是否屏幕常亮 * * @param screenOn <br>true: 屏幕常亮, <br>false:系统默认, 默认是true。 */ void setScreenOnWhilePlaying(boolean screenOn); /** * 设置fontconfig配置文件,在setSubtitles之前调用 * * @param path 配置文件地址 例如/sdcard/test/fonts.conf * @return {@link #ERROR_OK } 其他:{@link Error} */ int setFontConfig(String path); /** * 设置字幕,在setDataSource之后调用 * * @param subtitles 字幕文件地址数组,字幕文件地址必须是本地文件 * @param defaultIndex 设置默认字幕的索引 * @return {@link #ERROR_OK } 其他:{@link Error} */ int setSubtitles(String[] subtitles, int defaultIndex); /** * 切换字幕 * @param index 字幕的索引,索引小于0表示禁用字幕 * @return {@link #ERROR_OK } 其他:{@link Error} */ int switchSubtitles(int index); ``` ``` interface OnPreparedListener { /** * Called when the media file is ready for playback. */ void onPrepared(); } /** * Register a callback to be invoked when the media source is ready for playback. * * @param listener */ void setOnPreparedListener(OnPreparedListener listener); /** * Interface definition of a callback to be invoked indicating * the completion of a seek operation. */ interface OnSeekCompleteListener { /** * Called to indicate the completion of a seek operation. * * @param handle playerId. the player that issued the seek operation */ void onSeekComplete(int handle); } /** * Register a callback to be invoked when a seek operation has been completed. * * @param listener */ void setOnSeekCompleteListener(OnSeekCompleteListener listener); /** * Interface definition of a callback to be invoked when there * has been an error during an asynchronous operation (other errors * will throw exceptions at method call time). */ interface OnErrorListener { /** * Called to indicate an error. * * @param handle playerId. the player the error pertains to * @param what the type of error that has occurred: * @param extra an extra code, specific to the error. Typically * implementation dependent. * @return True if the method handled the error, false if it didn't. * Returning false, or not having an OnErrorListener at all, will * cause the OnCompletionListener to be called. */ boolean onError(int handle, int what, int extra); } /** * Register a callback to be invoked when an error has happened during an asynchronous operation. * * @param listener */ void setOnErrorListener(OnErrorListener listener); /** * Interface definition for a callback to be invoked when playback of * a media source has completed. */ interface OnCompletionListener { /** * Called when the end of a media source is reached during playback. * * @param handle playerId. the player that reached the end of the file */ void onCompletion(int handle); } /** * Register a callback to be invoked when the end of a media source has been reached during playback. * * @param listener */ void setOnCompletionListener(OnCompletionListener listener); /** * Interface definition of a callback to be invoked to communicate some * info and/or warning about the media or its playback. */ interface OnInfoListener { /** * Called to indicate an info or a warning. * * @param handle playerId. * @param what the type of info or warning. * @param extra an extra code, specific to the info. Typically * implementation dependent. * @return True if the method handled the info, false if it didn't. */ void onInfo(int handle, int what, int extra); } /** * Register a callback to be invoked when an info/warning is available. * * @param listener */ void setOnInfoListener(OnInfoListener listener); /** * Interface definition of a callback to be invoked when the * video size is first known or updated */ interface OnVideoSizeChangedListener { /** * Called to indicate the video size * <p> * The video size (width and height) could be 0 if there was no video, * no display surface was set, or the value was not determined yet. * * @param handle the player associated with this callback * @param width the width of the video * @param height the height of the video */ void onVideoSizeChanged(int handle, int width, int height); } /** * Register a callback to be invoked when the video size is known or updated. * * @param listener */ void setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener); /** * Interface definition of a callback to be invoked indicating buffering * status of a media resource being streamed over the network. */ interface OnBufferingUpdateListener { /** * Called to update status in buffering a media stream received through * progressive HTTP download. The received buffering percentage * indicates how much of the content has been buffered or played. * For example a buffering update of 80 percent when half the content * has already been played indicates that the next 30 percent of the * content to play has been buffered. * * @param handle handle * @param percent the percentage (0-100) of the content * that has been buffered or played thus far */ void onBufferingUpdate(int handle, int percent); } /** * Register a callback to be invoked when the status of a network stream's buffer has changed. * * @param listener */ void setOnBufferingUpdateListener(OnBufferingUpdateListener listener); /** * 缓冲事件 * <p> * 播放器根据缓冲策略,缓冲一定量的数据才会开始播放。 */ interface OnBufferingEventListener { /** * 播放器开始缓冲 */ void onBufferingStart(int handle); /** * 缓冲进度 * * @param handle handle * @param progress 缓冲进度 */ void onBufferingProgress(int handle, int progress); /** * 播放器结束缓冲 * <p> * 在播放状态下,缓冲结束,自动开始播放。 */ void onBufferingStop(int handle); } void setOnBufferingEventListener(OnBufferingEventListener listener); interface onProgressChangeListener { /** * 播放进度回调, 只有点播(回看)才会回调 * * @param total 总长度, 单位:毫秒 * @param progress 当前播放位置, 单位: 毫秒 */ void onProgressChange(int handle, int total, int progress); } void setOnProgressChangeListener(onProgressChangeListener listener); /** * 音量listener */ interface OnAudioVolumeListener { void onAudioVolume(int handle, int volume); } /** * 设置音量回调(只支持直播) * 收到INFO_LIVE_PLAY_START后调用 * <p> * 设置音量回调:listener != null && period > 0 * 删除音量回调: listener == null || period <= 0 * * @param listener * @param period 回调时间间隔 * @return {@link #ERROR_OK } 其他:{@link Error} */ int setOnAudioVolumeListener(OnAudioVolumeListener listener, long period); ``` #### 高级API ``` /** * 为播放器设置渲染SurfaceTexture * * @param from * @param texture {@link SurfaceTexture} 播放器渲染的texture */ public void setSurface(String from, SurfaceTexture texture); /** * 为播放器渲染的surface设置Viewport * * @param x x位置 * @param y y位置 * @param width 宽度 * @param height 高度 * @return 0: 调用成功 <0: 调用失败 */ public int setSurfaceViewport(int x, int y, int width, int height); /** * 获取播放器句柄 */ long getPlayerId(); /** * 多个播放器设为一组(数据流同步场景) * * @param group 组id * @return 0: 调用成功 <0: 调用失败 */ int addToGroup(int group); /** * 获取播放器当前缓冲时长 ,单位:ms(毫秒) * * @return 当前缓冲时长 */ long getCacheDuration(); /** * 获取主播直播流的流时间 * * @return 当前直播流时间 */ long getCurrentStreamTime(); ``` ``` /** * 设置视频源 * * @param playType 播放类型 {@link #PLAYTYPE_LIVE}, {@link #PLAYTYPE_VOD} * @param sn sn (需要走调度流程) * @param channelId 业务id * @param sign 鉴权签名 * @param options 播放器可选属性 {@link OptionKey} * @return IQHVCPlayer.ERROR_OK 其他:Error */ int setDataSource(@PlayType int playType, @NonNull String sn, @NonNull String channelId, @NonNull String sign, @Nullable Map<String, Object> options); ``` ``` /** * 获取当前使用的解码模式 * * @return 解码模式 {@link #LIVECLOUD_SOFT_DECODE_MODE}, {@link #LIVECLOUD_SMART_DECODE_MODE} */ @DecodeMode int getDecoderMode(); /** * 设置播放器是否渲染图像 * * @param isRender: true: 不渲染图像,只播放声音 false:播放声音和图像 * @return IQHVCPlayer.ERROR_OK 其他:Error */ int disableRender(boolean isDisableRender); /** * 是否开启缓冲逻辑 (默认开启) * * @param enable: 是否开启 true: 开启 false:不开启 * @return IQHVCPlayer.ERROR_OK 其他:Error */ int enableBufferingLogic(boolean enable); /** * 是否开启畸变矫正 * * @param enable: 是否开启 true: 开启 false:不开启 */ void enableUndistort(boolean enable); /** * 设置畸变矫正参数 * @param type 算法类型 * @param param 算法参数 * @see QHVCPlayerUndistortParam */ void setUndistorType(@QHVCPlayerUndistortType int type,Map<Integer,Integer> param); /** * 是否开启硬编 * * @param width 视频宽 * @param height 视频高 * @return */ boolean isUseHdRedord(int width, int height); /** * 卡录seek后清缓存调用 * * @return IQHVCPlayer.ERROR_OK 其他:Error */ int liveFlushBuffer(); /** * 设置视频画质增强filter属性 * * @param brightness 亮度 取值范围(-0.2f, 0.35f) * @param contrast 对比度 取值范围(0.9f, 1.6f) * @param saturation 饱和度 取值范围(0.15f, 2f) */ void setFilterValues(float brightness, float contrast, float saturation); /** * 是否使用中转surface * @param enable 是否使用中转surface */ void useSwapSurface(boolean enable); /** * 向播放器写入帧数据(推数据模式,目前仅支持relay) * * @param playerId * @param type 数据包格式 * @param nativeData 帧数据 * @param size 数据长度 * @param pts * @param dts * @param iskey 是否是关键帧 * @paran nativeStreamCodecContext 解码上下文信息 * @return */ int writeStream(long playerId, @Constants.QHVCPacketType int type, long nativeData, int size, long pts, long dts, int iskey, long nativeStreamCodecContext); ``` ``` /** * 精确seekTo * * @param millis 要拖动到的目标时间 * @param accurate 是否进行精准seek;accurate=false等同于void seekTo(long msec); * @return IQHVCPlayer.ERROR_OK 其他:Error */ int seekTo(int millis, boolean accurate); /** * 倍速播放 * * @param rate 播放速度,取值1~n(建议n<=5) * @return IQHVCPlayer.ERROR_OK 其他:Error */ int setPlayBackRate(float rate); /** * 结束播放 * * @param reason 停止播放的原因 * @return IQHVCPlayer.ERROR_OK 其他:Error */ int stop(int reason); ``` ``` interface OnPlayerNetStatsListener { /** * 流量计算回调函数 * * @param handle (int)playerId * @param dvbps 播放器下行视频每秒字节数 * @param dabps 播放器下行音频每秒字节数 * @param dvfps 播放器下行视频每秒帧数 * @param dafps 播放器下行音频每秒帧数 * @param fps 当前fps * @param bitrate 当前bitrate * @param param1 保留 * @param param2 保留 * @param param3 保留 */ void onPlayerNetStats(int handle, long dvbps, long dabps, long dvfps, long dafps, long fps, long bitrate, long param1, long param2, long param3); } /** * 流量统计信息回调(暂时只支持直播) * * @param listener */ void setOnPlayerNetStatsListener(OnPlayerNetStatsListener listener); interface OnAudioPCMListener { /** * pcm 数据回调 * * @param handle player handle * @param id 帧数据id * @param buffer 帧数据 * @param timestamp time stamp * @param channels 声道数 * @param sampleRate 采样率 * @param bitsPerSample 采样位数 */ void onAudioPCM(int handle, int id, ByteBuffer buffer, long timestamp, int channels, int sampleRate, int bitsPerSample); } /** * 设置音频数据回调(只支持直播) * * @param listener */ void setOnAudioPCMListener(OnAudioPCMListener listener); interface OnPacketListener { /** * 音频/视频数据回调 * * @param handle (int)playerId * @param context native player context * @param packet audio/video packet * @return 处理后的音频/视频数据 */ long onPacket(int handle, long context, long packet); } /** * 设置音频/视频数据回调 * * @param listener */ void setOnPacketListener(OnPacketListener listener); interface OnSeiMetaListener { /** * sei meta数据回调 * * @param handle (int)playerId * @param type 类型 * @param data 数据 */ void onSeiMeta(int handle, long type, byte[] data); } /** * 设置sei meta回调 * * 注意需要设置: {@link #setDataSource( int, String, String, String, Map<String, Object> options)} 设置options.put(IQHVCPlayerAdvanced.KEY_OPTION_ENABLE_ANALYZE_SEI, Boolean.TRUE) * * @param listener */ void setOnSeiMetaListener(OnSeiMetaListener listener); ``` ### 附加功能 #### 截图 ``` /** * 截图 (同步方法,会阻塞线程),该方法已被废弃,请调用IQHVCPlayerAdvanced.snapshot(QHVCSnapshotListener) * * @param path 存储路径 * @return true 成功,false 失败 */ boolean snapshot(String path); /** * 视频截图回调接口 */ interface SurfaceTextureSnapshotListener { /** * 截图成功 * * @param bitmap 截图,格式:ARGB_8888 */ void onSuccess(Bitmap bitmap); /** * 截图失败 * * @param errCode 错误码,参见{@link } * @param errMsg */ void onError(int errCode, String errMsg); } /** * 截图回调接口 */ interface QHVCSnapshotListener extends SurfaceTextureEGLSurface.SurfaceTextureSnapshotListener { } /** * 截图 (异步方法) * * @param snapshotListener 回调接口 * @return true 成功,false 失败 */ boolean snapshot(IQHVCPlayerAdvanced.QHVCSnapshotListener snapshotListener) ``` #### 视频录制 ``` /** * 开始录制 * <p> * 注意:不支持暂停时录制<br> * 录制mp4: fmt使用 {@link IQHVCPlayerAdvanced#RECORDER_FORMAT_MP4}, Config使用VideoRecordConfig * 录制gif: fmt使用 {@link IQHVCPlayerAdvanced#RECORDER_FORMAT_GIF}, Config使用GifRecordConfig * * @param filePath 录像存储路径(确保有读写权限) * @param fmt 存储格式 {@link RecorderFormat} <br> * @param config 配置 * @param listener callback * @return 0:成功 <0: 失败 */ int startRecorder(String filePath, @RecorderFormat String fmt, RecordConfig config, OnRecordListener listener); /** * 结束录制(异步接口) * * @return 0: 调用成功 <0: 调用失败 */ int stopRecorder(); ``` #### 多码率支持 ``` /** * 切换分辨率<br> * 此接口是异步的,从切换分辨率到切换完成 有5秒延迟 * * @param index 数据源索引,{@link #setDataSource(String[] source, int index, int playType)}设置的source的索引 * @param listener 状态回调 */ void switchResolution(int index, QHVCSwitchResolutionListener listener); /** * 取消分辨率切换 * * @param reason 取消切换原因 * @return 0: 调用成功 <0: 调用失败 */ int switchResolutionStop(String reason); /** * 自动切换分辨率 * * @param isAdapt 是否根据网络状况自动切换分辨率 * @param listener 状态回调 * @return 0: 调用成功 <0: 调用失败 */ int setResolutionAdapt(boolean isAdapt, QHVCSwitchResolutionListener listener); /** * 切分辨率错误 */ interface QHVCSwitchResolutionError { /** * 不支持的状态 * <p> * - 仅支持在播放状态下切换<br> * - 一次切换结束后,才能进行下一次切换<br> */ int NOT_SUPPORT_STATUS = -1; /** * 切换失败 */ int FAILED = -2; } /** * 切换分辨率回调 */ interface QHVCSwitchResolutionListener { /** * 切换准备 */ void onPrepare(); /** * 切换中 */ void onStart(); /** * 切换分辨率成功 * * @param index 当前播放source index * @param url 当前播放url */ void onSuccess(int index, String url); /** * 切换失败 * * @param errorCode 错误码 {@link QHVCSwitchResolutionError} * @param errorMsg 错误信息 */ void onError(int errorCode, String errorMsg); } ``` ### 插件化支持 为减小APK体积,播放SDK支持插件化方式接入,业务方仅需接入JAR包即可,不需要捆包带SO文件,最终APK体积预计增加500KB。 > 播放器插件下载并加载成功前,播放SDK会使用系统播放器保障基本的播放需求,请使用`QHVCPlayerBuilder.getInstance().getPlayer(context)`创建播放器实例,不要使用`new QHVCPlayer()`。系统播放器功能有限,请业务方根据当前创建的播放器类型处理业务需求。判断是否是系统播放器,请调用`isSystemMediaPlayer()`接口。 ``` /** * 创建播放器实例 * * @param context context * @return 若智汇云播放器插件已下载并加载,则使用智汇云播放器;否则使用系统播放器 */ QHVCPlayerBuilder.getInstance().getPlayer(Context context); ``` 插件化基本流程:  ``` /** * 设置是否自带插件,如果使用插件化方式接入,该接口必须第一个被调用,必须早于QHVCPlayerBuilder.getInstance().getPlayer(context)接口 * * @param defaultPluginInstalled true自带,false不自带 */ QHVCPlayerPlugin.getInstance().setDefaultPluginInstalled(boolean defaultPluginInstalled); ``` ``` /** * 安装插件 * * @param context context * @param listener 下载监听接口,若业务方需要自行实现插件下载功能,需要实现该接口 * @param callback 回调接口 * @return 错误码,{@link LiveCloudPluginConstant#ERROR_INSTALL_RUNNING}表示插件正在后台安装或升级, * {@link LiveCloudPluginConstant#ERROR_SUCCESS}表示插件开始安装或升级 */ QHVCPlayerPlugin.getInstance().checkInstallPlugin(Context context, final PluginDownloadListener listener, final PluginCallback callback); ``` ``` /** * 升级插件,若新插件已下载,执行本地升级逻辑;否则后台静默下载新插件,待APP下次启动时再次执行本地升级逻辑<br> * 注意:<br> * 1.该接口需要在{@link #setDefaultPluginInstalled(boolean)}接口后且{@link #loadPlugin()}接口前调用<br> * 2.为避免插件下载占用网络带宽进而影响当前业务,建议设置{@link PluginDownloadListener}参数自行选择时机下载插件<br> * 3.如无特殊需求,业务方无需主动调用该接口,播放器插件会在后台自动升级 * * @param context context * @param listener 下载监听接口,若业务方需要自行实现插件下载功能,需要实现该接口 * @return 错误码,参见{@link LiveCloudPluginConstant#ERROR_UNKNOWN}等 */ QHVCPlayerPlugin.getInstance().checkUpdatePlugin(Context context, final PluginDownloadListener listener); /** * 设置插件后台静默升级下载监听接口<br> * 注意:插件会后台自动升级,业务方可设置该监听接口以便管理下载时机。 * * @param listener 下载监听接口,若业务方需要自行实现插件下载功能,需要实现该接口 */ QHVCPlayerPlugin.getInstance().setPluginDownloadListener(PluginDownloadListener listener); ``` ``` /** * 加载已安装的插件 * * @return 错误码,参见{@link #ERROR_UNKNOWN}等 */ QHVCPlayerPlugin.getInstance().loadPlugin(); ``` ``` /** * 移除插件,该接口必须在加载插件前调用方可生效 * * @return 错误码,参见{@link LocalServerPlugin#ERROR_UNKNOWN}等 */ QHVCPlayerPlugin.getInstance().removePlugin(); ``` 示例: ``` public void initPlayerProxy(Context context) { final QHVCPlayerPlugin liveCloudPlugin = QHVCPlayerPlugin.getInstance(); //设置接入时不带插件,使用插件化方案时必须第一个调用该接口 liveCloudPlugin.setDefaultPluginInstalled(false); if (liveCloudPlugin.isDefaultPluginInstalled()) { initPlayer(context); } else if (liveCloudPlugin.isPluginInstalled()) { //插件已下载,必须加载后才能使用 int result = liveCloudPlugin.loadPlugin(); if (result == QHVCPlayerPlugin.ERROR_SUCCESS) { initPlayer(context); } } else { liveCloudPlugin.checkInstallOrUpdatePlugin(context, new QHVCPlayerPlugin.PluginCallback() { @Override public void onStart(Context context) { } @Override public void onProgress(Context context, int progress) { } @Override public void onComplete(Context context, boolean background, int result) { if (result == QHVCPlayerPlugin.ERROR_SUCCESS) { //插件下载完成,必须加载后才能使用 int loadResult = liveCloudPlugin.loadPlugin(); if (loadResult == QHVCPlayerPlugin.ERROR_SUCCESS) { initPlayer(context); } } } @Override public void onCancel(Context context) { } }); } } private void initPlayer(Context context) { //此时调用QHVCPlayerBuilder.getInstance().getPlayer(Context context)接口返回的即为智汇云播放器,否则为系统播放器 } ``` ### 多类型播放器支持 智汇云SDK支持多种类型的的播放器,分别为: 类型 | 体积 | 支持协议 | 支持容器 | 编码器 ---|---|---|---|---|--- 系统播放器 | 0 | 精简版 | 小 | http/rtmp/hls | mp4/flv/m3u8/ts | 无 录制版 | 中 | http/rtmp/hls | mp4/flv/m3u8/ts | H264/AAC 多解码器版 | 大 | http/rtmp/hls | mp4/flv/m3u8/ts/avi/rm/rmvb/mkv/mov/... | 无 多解码器+录制版 | 大 | http/rtmp/hls | mp4/flv/m3u8/ts/avi/rm/rmvb/mkv/mov/... | H264/AAC 业务方可以在接入SDK时捆包自带播放器,也可以使用插件化方式动态下载指定类型的播放器,该接口需要在`loadPlugin()`前调用,建议与`setDefaultPluginInstalled(boolean defaultPluginInstalled)`一起调用。 ``` /** * 设置播放器插件类型,默认为标准版本<br> * 注意:该接口需要在{@link #loadPlugin()}接口前调用方可生效 * * @param playerPluginType 播放器插件类型,参见{@link #TYPE_NORMAL}等 */ QHVCPlayerPlugin.getInstance().setPlayerPluginType(String playerPluginType); ``` ### 视频渲染自定义 播放器视频渲染通过OpenGL实现,业务方可通过自定义顶点着色器、片段着色器实现自己的渲染效果,也可以在视频渲染基础上绘制其他内容。参考示例代码[下载](http://rs-beijing.oss.yunpan.360.cn/Object.getFile/livecloudsdk/Q3VzdG9tUGxheWVyUmVuZGVyLmphdmE=)。 ``` /** * 设置视频渲染高级接口,必须在{@link IQHVCPlayer#setDisplay(ILiveCloudDisplay)}前调用 * * @param surfaceRenderListener 视频渲染高级接口 */ QHVCPlayer.setSurfaceRenderListener(SurfaceRenderListener surfaceRenderListener); ``` ``` /** * 视频渲染高级接口,业务方可通过自定义顶点着色器及片段着色器修改默认的渲染 * <p> * <p>顶点着色器: * <pre> * private final static String VERTEX_SHADER = "" + "uniform mat4 uTextureMatrix;\n" + "attribute vec4 aPosition;\n" + "attribute vec4 aTextureCoord;\n" + "varying vec2 vTextureCoord;\n" + "void main() {\n" + " gl_Position = aPosition;\n" + " vTextureCoord = (uTextureMatrix * aTextureCoord).xy;\n" + "}"; * </pre> * <p>片段着色器: * <pre> * private final static String FRAGMENT_SHADER_OES = "" + "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" + "varying vec2 vTextureCoord;\n" + "void main() {\n" + " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" + "}"; * </pre> */ public interface SurfaceRenderListener { /** * 顶点着色器-默认顶点着色器 */ String VERTEX_DEFAULT_SHADER = BaseGLRender.VERTEX_SHADER_MATRIX_TEXTURE; /** * 顶点着色器-顶点坐标<br> * attribute vec4 aPosition; */ String VERTEX_ATTRIBUTE_POSITION = "aPosition"; /** * 顶点着色器-纹理坐标<br> * attribute vec4 aTextureCoord; */ String VERTEX_ATTRIBUTE_TEXTURE_COORD = "aTextureCoord"; /** * 顶点着色器-纹理变换矩阵<br> * uniform mat4 uTextureMatrix */ String VERTEX_UNIFORM_TEXTURE_MATRIX = "uTextureMatrix"; /** * 顶点着色器-变换后的纹理坐标,用于片段着色器<br> * varying vec2 vTextureCoord; */ String VERTEX_VARYING_TEXTURE_COORD = "vTextureCoord"; /** * 片段着色器-默认片段着色器 */ String FRAGMENT_DEFAULT_SHADER = BaseGLRender.FRAGMENT_SHADER_OES; /** * 片段着色器-纹理单元<br> * uniform samplerExternalOES sTexture; */ String FRAGMENT_UNIFORM_TEXTURE = "sTexture"; /** * 创建着色器程序 * * @param program 着色器程序 */ void onCreateProgram(int program); /** * 删除着色器程序 * * @param program 着色器程序 */ void onDeleteProgram(int program); /** * 创建着色器 * * @param type 着色器类型,参见{@link GLES20#GL_VERTEX_SHADER}、{@link GLES20#GL_FRAGMENT_SHADER} * @return 顶点着色器脚本代码(业务方需调用glCompileShader),为空时使用智汇云默认顶点着色器 */ int onCreateShader(int type); /** * 删除顶点着色器 * * @param shader 顶点着色器 */ void onDeleteShader(int shader); /** * 渲染<br> * 注意:业务方必须主动调用<code>GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCoords.capacity() / 2);</code> * * @param program 着色器程序 * @param vertexCoords 顶点坐标,默认值{1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f} * @param textureCoords 纹理坐标,默认值{1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f} * @param textureMatrix 纹理变换矩阵,Mat4x4 * @param textureUnit 纹理单元,默认值{@link GLES20#GL_TEXTURE0} * @param textureTarget 纹理绑定目标,默认值{@link GLES11Ext#GL_TEXTURE_EXTERNAL_OES} * @param texture 纹理名称 */ void onDraw(int program, FloatBuffer vertexCoords, FloatBuffer textureCoords, float[] textureMatrix, int textureUnit, int textureTarget, int texture); } ``` ### 错误码说明 | 状态码 | 含义 | |--------|--------------------| | 1000 | 未知错误 | | 1001 | prepare失败 | | 1002 | 开始播放就失败 | | 1003 | 不支持的视频格式 | | 1004 | 文件不能打开 | | 1005 | 播放器插件加载失败 | | 1006 | 无效参数 | | 1007 | 当前播放器状态无效 | | 1008 | IO异常 | | 1009 | 安全异常 | | 1010 | 不支持的操作 | | 1011 | 鉴权失败 | | 状态码 | 详细错误信息 | |--------|---------------------------------------| | 10001 | 详细信息为空 | | 10002 | 调度返回的url为null | | 10003 | startplay时,setsession失败 | | 10004 | 回放状态下,文件没有打开,或者url失效 | | 10005 | jplayer open失败 | | 10006 | 调度sn失败 | | 10007 | 拿不到媒体信息、或者打不开连接 | | 10008 | 手机不支持硬解码 | | 10009 | 连接断开或者失败 | | 10010 | 录像出现错误 | | 10011 | 无效的录像文件 | | 1011 | 不支持的视频格式 |
即刻开始使用
只需完成注册与实名认证,即可体验我们的贴心服务
立即使用
请您联系我们
邮箱
g-zyun@360.cn
电话
010-58781360
小安提醒您
试用小安,请确保该账户已通过智汇云实名认证
前往认证中心>>
1对1免费
咨询智汇云专属顾问
为您量身定制产品解决方案
您的姓名 :
手机号 :
公司名称(选填) :
相关产品 :
留言内容 :
需求描述
产品建议
其他
提交
登录后才可以留言哦
立即登录
去注册账号