... | ... | @@ -248,7 +248,7 @@ downloader.setOnDownloadSubtitleListener(new OnDownloadSubtitleListener() { |
|
|
2.Demo中,本地缓存视频的字幕模式跟随当前下载时的字幕模式。如有其他需求,可根据自己的业务加以调整。SubtitleView类中同样提供了setSubtitleModel方法。
|
|
|
|
|
|
```
|
|
|
player.setSubtitleModel(SubtitleModel.FIXED); player.setSubtitleModel(SubtitleModel.SELF_ADAPTION);
|
|
|
player.setSubtitleModel(SubtitleModel.FIXED); player.setSubtitleModel(SubtitleModel.SELF_ADAPTION);
|
|
|
```
|
|
|
|
|
|
## 4.6 访客信息收集功能
|
... | ... | @@ -256,7 +256,22 @@ downloader.setOnDownloadSubtitleListener(new OnDownloadSubtitleListener() { |
|
|
支持从服务器获取访客信息收集设置并显示,可以通过调用player的setOnVisitMsgListener(OnVisitMsgListener onVisitMsgListener)方法,得到访客信息收集设置。
|
|
|
|
|
|
```
|
|
|
//获得访客信息设置player.setOnVisitMsgListener(new OnVisitMsgListener() { /** * @param appearTime 收集器出现的时间(S) * @param imageURL 图片地址 * @param isJump 是否需要跳过 1跳过,0不跳过 * @param jumpURL 图片跳转的地址 * @param title 收集器名称 * @param visitorId 收集器ID * @param visitorMessage //要收集的信息 */ @Override public void onVisitMsg(int appearTime, String imageURL, int isJump, String jumpURL, String title, String visitorId, JSONArray visitorMessage) { }});
|
|
|
//获得访客信息设置
|
|
|
player.setOnVisitMsgListener(new OnVisitMsgListener() {
|
|
|
/**
|
|
|
* @param appearTime 收集器出现的时间(S)
|
|
|
* @param imageURL 图片地址
|
|
|
* @param isJump 是否需要跳过 1跳过,0不跳过
|
|
|
* @param jumpURL 图片跳转的地址
|
|
|
* @param title 收集器名称
|
|
|
* @param visitorId 收集器ID
|
|
|
* @param visitorMessage //要收集的信息
|
|
|
*/
|
|
|
@Override
|
|
|
public void onVisitMsg(int appearTime, String imageURL, int isJump, String jumpURL, String title, String visitorId, JSONArray visitorMessage) {
|
|
|
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -297,7 +312,19 @@ SDK提供HTTP通信日志调试功能。在使用SDK进行播放、上传、下 |
|
|
从服务器获取授权验证信息,可以通过调用player的setOnAuthMsgListener(OnAuthMsgListener onAuthMsgListener)方法,在该接口中回调授权验证信息。
|
|
|
|
|
|
```
|
|
|
//获得授权验证信息player.setOnAuthMsgListener(new OnAuthMsgListener() { /** * @param enable 视频是否可以完整播放 0:不允许完整播放 1:允许完整播放 * @param freetime 视频试看时间,单位:秒 * @param messaage 不允许播放,或者试看结束时播放器显示的提示内容 * @param marqueeInfo 跑马灯信息,具体使用方法请参考4.18章节 */ @Override public void onAuthMsg(int enable, int freetime, String messaage, MarqueeInfo marqueeInfo) { }});
|
|
|
//获得授权验证信息
|
|
|
player.setOnAuthMsgListener(new OnAuthMsgListener() {
|
|
|
/**
|
|
|
* @param enable 视频是否可以完整播放 0:不允许完整播放 1:允许完整播放
|
|
|
* @param freetime 视频试看时间,单位:秒
|
|
|
* @param messaage 不允许播放,或者试看结束时播放器显示的提示内容
|
|
|
* @param marqueeInfo 跑马灯信息,具体使用方法请参考4.18章节
|
|
|
*/
|
|
|
@Override
|
|
|
public void onAuthMsg(int enable, int freetime, String messaage, MarqueeInfo marqueeInfo{
|
|
|
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
## 4.11 视频压缩功能
|
... | ... | @@ -305,15 +332,93 @@ SDK提供HTTP通信日志调试功能。在使用SDK进行播放、上传、下 |
|
|
可以选择高质量压缩、中质量压缩、低质量压缩,压缩质量越高,压缩出来的文件就相对较大。
|
|
|
|
|
|
```
|
|
|
/** * 高质量压缩 * @param filePath 源文件路径 * @param compressOutPut 输出文件路径 * @param VideoCompress.CompressListener 压缩过程监听 */VideoCompress.compressVideoHigh(filePath, compressOutPut, new VideoCompress.CompressListener() { @Override public void onStart() { } @Override public void onSuccess() { } @Override public void onFail() { } @Override public void onProgress(float percent) { }});
|
|
|
/**
|
|
|
* 高质量压缩
|
|
|
* @param filePath 源文件路径
|
|
|
* @param compressOutPut 输出文件路径
|
|
|
* @param VideoCompress.CompressListener 压缩过程监听
|
|
|
*/
|
|
|
VideoCompress.compressVideoHigh(filePath, compressOutPut, new VideoCompress.CompressListener() {
|
|
|
@Override
|
|
|
public void onStart() {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onSuccess() {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onFail() {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onProgress(float percent) {
|
|
|
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
```
|
|
|
/** * 中质量压缩 * @param filePath 源文件路径 * @param compressOutPut 输出文件路径 * @param VideoCompress.CompressListener 压缩过程监听 */VideoCompress.compressVideoMedium(filePath, compressOutPut, new VideoCompress.CompressListener() { @Override public void onStart() { } @Override public void onSuccess() { } @Override public void onFail() { } @Override public void onProgress(float percent) { }});
|
|
|
/**
|
|
|
* 中质量压缩
|
|
|
* @param filePath 源文件路径
|
|
|
* @param compressOutPut 输出文件路径
|
|
|
* @param VideoCompress.CompressListener 压缩过程监听
|
|
|
*/
|
|
|
VideoCompress.compressVideoMedium(filePath, compressOutPut, new VideoCompress.CompressListener() {
|
|
|
@Override
|
|
|
public void onStart() {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onSuccess() {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onFail() {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onProgress(float percent) {
|
|
|
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
```
|
|
|
/** * 低质量压缩 * @param filePath 源文件路径 * @param compressOutPut 输出文件路径 * @param VideoCompress.CompressListener 压缩过程监听 */VideoCompress.compressVideoLow(filePath, compressOutPut, new VideoCompress.CompressListener() { @Override public void onStart() { } @Override public void onSuccess() { } @Override public void onFail() { } @Override public void onProgress(float percent) { }});
|
|
|
/**
|
|
|
* 低质量压缩
|
|
|
* @param filePath 源文件路径
|
|
|
* @param compressOutPut 输出文件路径
|
|
|
* @param VideoCompress.CompressListener 压缩过程监听
|
|
|
*/
|
|
|
VideoCompress.compressVideoLow(filePath, compressOutPut, new VideoCompress.CompressListener() {
|
|
|
@Override
|
|
|
public void onStart() {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onSuccess() {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onFail() {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onProgress(float percent) {
|
|
|
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
## 4.12 课堂练习功能
|
... | ... | @@ -321,13 +426,59 @@ SDK提供HTTP通信日志调试功能。在使用SDK进行播放、上传、下 |
|
|
支持用户自定义课堂练习功能的回调,可以通过调用player的setOnExercisesMsgListener(OnExercisesMsgListener onExercisesMsgListener)方法,当视频有课堂练习信息时,在该接口中回调课堂练习信息。
|
|
|
|
|
|
```
|
|
|
//获得视频课堂练习信息player.setOnExercisesMsgListener(new OnExercisesMsgListener() { @Override public void onExercisesMessage(JSONArray exArray) { }});
|
|
|
//获得视频课堂练习信息
|
|
|
player.setOnExercisesMsgListener(new OnExercisesMsgListener() {
|
|
|
@Override
|
|
|
public void onExercisesMessage(JSONArray exArray) {
|
|
|
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
课堂练习回调的格式为JSONArray,单条课堂练习的内容如下,请用户自行解析。
|
|
|
|
|
|
```
|
|
|
{ "id": 86, "backSecond": 5,//回看时间 "isJump": 0,//是否允许跳过 1跳过 ,0不跳过 "isPlay": 0,//答错是否可以继续 0不能, 1 能 "questions": [ { "answers": [ { "content": "A、答案A", "id": 608, "right": true }, { "content": "B、答案B", "id": 609, "right": true }, { "content": "C、答案C", "id": 610, "right": true }, { "content": "D、答案D", "id": 615, "right": false } ], "backSecond": 3,//回看时间 "content": "题目", "explainInfo": "试题详解", "id": 414, "type": 1 } ], "showTime": 20, "title": "课堂练习"}
|
|
|
{
|
|
|
"id": 86,
|
|
|
"backSecond": 5,//回看时间
|
|
|
"isJump": 0,//是否允许跳过 1跳过 ,0不跳过
|
|
|
"isPlay": 0,//答错是否可以继续 0不能, 1 能
|
|
|
"questions": [
|
|
|
|
|
|
{
|
|
|
"answers": [
|
|
|
{
|
|
|
"content": "A、答案A",
|
|
|
"id": 608,
|
|
|
"right": true
|
|
|
},
|
|
|
{
|
|
|
"content": "B、答案B",
|
|
|
"id": 609,
|
|
|
"right": true
|
|
|
},
|
|
|
{
|
|
|
"content": "C、答案C",
|
|
|
"id": 610,
|
|
|
"right": true
|
|
|
},
|
|
|
{
|
|
|
"content": "D、答案D",
|
|
|
"id": 615,
|
|
|
"right": false
|
|
|
}
|
|
|
],
|
|
|
"backSecond": 3,//回看时间
|
|
|
"content": "题目",
|
|
|
"explainInfo": "试题详解",
|
|
|
"id": 414,
|
|
|
"type": 1
|
|
|
}
|
|
|
|
|
|
],
|
|
|
"showTime": 20,
|
|
|
"title": "课堂练习"
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 4.13 投屏功能
|
... | ... | @@ -337,19 +488,63 @@ SDK提供HTTP通信日志调试功能。在使用SDK进行播放、上传、下 |
|
|
### 4.13.1 非加密视频的投屏
|
|
|
|
|
|
```
|
|
|
//搜索发现设备registryListener.setOnDeviceListChangedListener(new ProjectionDeviceListChangedListener() { @Override public void onDeviceAdded(ProjectionIDevice device) { //发现设备 } @Override public void onDeviceRemoved(ProjectionIDevice device) { //设备移除 }});
|
|
|
//搜索发现设备
|
|
|
registryListener.setOnDeviceListChangedListener(new ProjectionDeviceListChangedListener() {
|
|
|
@Override
|
|
|
public void onDeviceAdded(ProjectionIDevice device) {
|
|
|
//发现设备
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onDeviceRemoved(ProjectionIDevice device) {
|
|
|
//设备移除
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
```
|
|
|
//播放新的视频projectionPlayControl.playNew(playUrl, new ProjectionControlCallback() { @Override public void success(ProjectionIResponse response) { } @Override public void fail(ProjectionIResponse response) { }});
|
|
|
//播放新的视频
|
|
|
projectionPlayControl.playNew(playUrl, new ProjectionControlCallback() {
|
|
|
@Override
|
|
|
public void success(ProjectionIResponse response) {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void fail(ProjectionIResponse response) {
|
|
|
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
```
|
|
|
//暂停后恢复播放projectionPlayControl.play(new ProjectionControlCallback() { @Override public void success(ProjectionIResponse response) { } @Override public void fail(ProjectionIResponse response) { }});
|
|
|
//暂停后恢复播放
|
|
|
projectionPlayControl.play(new ProjectionControlCallback() {
|
|
|
@Override
|
|
|
public void success(ProjectionIResponse response) {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void fail(ProjectionIResponse response) {
|
|
|
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
```
|
|
|
//暂停播放projectionPlayControl.pause(new ProjectionControlCallback() { @Override public void success(ProjectionIResponse response) { } @Override public void fail(ProjectionIResponse response) { }});
|
|
|
//暂停播放
|
|
|
projectionPlayControl.pause(new ProjectionControlCallback() {
|
|
|
@Override
|
|
|
public void success(ProjectionIResponse response) {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void fail(ProjectionIResponse response) {
|
|
|
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
### 4.13.2 加密视频的投屏
|
... | ... | @@ -369,7 +564,22 @@ SDK提供HTTP通信日志调试功能。在使用SDK进行播放、上传、下 |
|
|
上传视频的时候,支持为视频配置水印。
|
|
|
|
|
|
```
|
|
|
//水印位置0,左上 1右上 2左下 3右下,默认3,非必填videoInfo.setCorner(int corner);//X轴偏移像素值,要求大于0,默认值5,超出视频大小按默认值,非必填videoInfo.setOffsetx(int offsetx);//Y轴偏移像素值,要求大于0,默认值5,超出视频大小按默认值,非必填videoInfo.setOffsety(int offsety);//字体类型:0,微软雅黑 1宋体 2黑体,默认0,非必填videoInfo.setFontfamily(int fontfamily);//字体大小,[0-100],默认12videoInfo.setFontsize(int fontsize);//16进制字体颜色,如#FFFFFF,不能写#号,默认灰色D3D3D3,非必填videoInfo.setFontcolor(String fontcolor);//透明度,[0-100],默认0,100为不透明,非必填videoInfo.setFontalpha(int fontalpha);//水印文字内容, 1-50个字符,数字、字母、汉字,不填写则文字水印不生效,填写错误,会导致上传失败videoInfo.setText(String text);
|
|
|
//水印位置0,左上 1右上 2左下 3右下,默认3,非必填
|
|
|
videoInfo.setCorner(int corner);
|
|
|
//X轴偏移像素值,要求大于0,默认值5,超出视频大小按默认值,非必填
|
|
|
videoInfo.setOffsetx(int offsetx);
|
|
|
//Y轴偏移像素值,要求大于0,默认值5,超出视频大小按默认值,非必填
|
|
|
videoInfo.setOffsety(int offsety);
|
|
|
//字体类型:0,微软雅黑 1宋体 2黑体,默认0,非必填
|
|
|
videoInfo.setFontfamily(int fontfamily);
|
|
|
//字体大小,[0-100],默认12
|
|
|
videoInfo.setFontsize(int fontsize);
|
|
|
//16进制字体颜色,如#FFFFFF,不能写#号,默认灰色D3D3D3,非必填
|
|
|
videoInfo.setFontcolor(String fontcolor);
|
|
|
//透明度,[0-100],默认0,100为不透明,非必填
|
|
|
videoInfo.setFontalpha(int fontalpha);
|
|
|
//水印文字内容, 1-50个字符,数字、字母、汉字,不填写则文字水印不生效,填写错误,会导致上传失败
|
|
|
videoInfo.setText(String text);
|
|
|
```
|
|
|
|
|
|
## 4.16 切换到备用线路
|
... | ... | @@ -379,7 +589,12 @@ SDK提供HTTP通信日志调试功能。在使用SDK进行播放、上传、下 |
|
|
## 4.17 获取播放时长和暂停时长
|
|
|
|
|
|
```
|
|
|
//获取播放时长(单位是秒)player.getPlayedTime();//获取暂停时长(单位是秒)player.getPausedTime();//当切换到另外一个视频时,需要调用player.resetPlayedAndPausedTime(),将上一个视频的播放时长和暂停时长重置为0player.resetPlayedAndPausedTime();
|
|
|
//获取播放时长(单位是秒)
|
|
|
player.getPlayedTime();
|
|
|
//获取暂停时长(单位是秒)
|
|
|
player.getPausedTime();
|
|
|
//当切换到另外一个视频时,需要调用player.resetPlayedAndPausedTime(),将上一个视频的播放时长和暂停时长重置为0
|
|
|
player.resetPlayedAndPausedTime();
|
|
|
```
|
|
|
|
|
|
## 4.18 跑马灯
|
... | ... | @@ -387,7 +602,11 @@ SDK提供HTTP通信日志调试功能。在使用SDK进行播放、上传、下 |
|
|
使用跑马灯。
|
|
|
|
|
|
```
|
|
|
<com.bokecc.sdk.mobile.play.MarqueeView android:id="@+id/mv_video" android:layout_width="match_parent" android:layout_height="match_parent" />
|
|
|
<com.bokecc.sdk.mobile.play.MarqueeView
|
|
|
android:id="@+id/mv_video"
|
|
|
android:layout_width="match_parent"
|
|
|
android:layout_height="match_parent"
|
|
|
/>
|
|
|
```
|
|
|
|
|
|
获取跑马灯数据。
|
... | ... | @@ -395,32 +614,96 @@ SDK提供HTTP通信日志调试功能。在使用SDK进行播放、上传、下 |
|
|
1.获取在线视频跑马灯数据
|
|
|
|
|
|
```
|
|
|
player.setOnAuthMsgListener(new OnAuthMsgListener() { //marqueeInfo:跑马灯信息 @Override public void onAuthMsg(int enable, int freetime, String messaage, MarqueeInfo marqueeInfo) { //获得跑马灯类型,text:文字,image:图片 String type = marqueeInfo.getType(); //获得循环次数 int loop = marqueeInfo.getLoop(); //获得文字信息 MarqueeInfo.TextBean textBean = marqueeInfo.getTextBean(); //获得文字内容 String content = textBean.getContent(); //获得字体大小 int font_size = textBean.getFont_size(); //获得文字颜色 String color = textBean.getColor(); if (!TextUtils.isEmpty(color) && color.length() == 8) { String textColor = "#" + color.substring(2, 8); if (textColor.length() == 7) { //textColor:文字颜色,格式如:#ffffff mv_video.setTextColor(textColor); } } //获得图片信息 MarqueeInfo.ImageBean imageBean = marqueeInfo.getImageBean(); //获得图片url String image_url= imageBean.getImage_url(); //获得图片宽度 int width= imageBean.getWidth(); //获得图片高度 int width = imageBean.getHeight(); //获得动作节点 ArrayList<MarqueeAction> action = marqueeInfo.getAction(); }});
|
|
|
player.setOnAuthMsgListener(new OnAuthMsgListener() {
|
|
|
//marqueeInfo:跑马灯信息
|
|
|
@Override
|
|
|
public void onAuthMsg(int enable, int freetime, String messaage, MarqueeInfo marqueeInfo) {
|
|
|
//获得跑马灯类型,text:文字,image:图片
|
|
|
String type = marqueeInfo.getType();
|
|
|
//获得循环次数
|
|
|
int loop = marqueeInfo.getLoop();
|
|
|
//获得文字信息
|
|
|
MarqueeInfo.TextBean textBean = marqueeInfo.getTextBean();
|
|
|
//获得文字内容
|
|
|
String content = textBean.getContent();
|
|
|
//获得字体大小
|
|
|
int font_size = textBean.getFont_size();
|
|
|
//获得文字颜色
|
|
|
String color = textBean.getColor();
|
|
|
if (!TextUtils.isEmpty(color) && color.length() == 8) {
|
|
|
String textColor = "#" + color.substring(2, 8);
|
|
|
if (textColor.length() == 7) {
|
|
|
//textColor:文字颜色,格式如:#ffffff
|
|
|
mv_video.setTextColor(textColor);
|
|
|
}
|
|
|
}
|
|
|
//获得图片信息
|
|
|
MarqueeInfo.ImageBean imageBean = marqueeInfo.getImageBean();
|
|
|
//获得图片url
|
|
|
String image_url= imageBean.getImage_url();
|
|
|
//获得图片宽度
|
|
|
int width= imageBean.getWidth();
|
|
|
//获得图片高度
|
|
|
int width = imageBean.getHeight();
|
|
|
//获得动作节点
|
|
|
ArrayList<MarqueeAction> action = marqueeInfo.getAction();
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
2.获取离线视频跑马灯数据
|
|
|
跑马灯的相关数据会跟随视频下载,demo将该数据中保存在了本地数据库object-box中,用户可根据自身逻辑和场景,进行更改和保存。demo中由DownloadInfo.getMarqueeData()方法获取到序列化到本地的String类型的跑马灯数据 marqueeData,之后作为参数传入player的getMarqueeInfo()方法,该方法会返回MarqueeInfo对象,用于MarqueeView使用和展示。具体请参考demo中使用。
|
|
|
|
|
|
```
|
|
|
if (!TextUtils.isEmpty(marqueeData)) { MarqueeInfo marqueeInfo=player.getMarqueeInfo(marqueeData); setMarqueeView(marqueeInfo); }
|
|
|
if (!TextUtils.isEmpty(marqueeData)) {
|
|
|
MarqueeInfo marqueeInfo=player.getMarqueeInfo(marqueeData);
|
|
|
setMarqueeView(marqueeInfo);
|
|
|
}
|
|
|
```
|
|
|
|
|
|
设置跑马灯类型。
|
|
|
|
|
|
```
|
|
|
//MarqueeView.TEXT:文字 MarqueeView.IMAGE:图片mv_video.setType();
|
|
|
//MarqueeView.TEXT:文字 MarqueeView.IMAGE:图片
|
|
|
mv_video.setType();
|
|
|
```
|
|
|
|
|
|
设置循环次数。
|
|
|
|
|
|
```
|
|
|
//loop:为-1时是无限循环,为其他正整数时是有限次循环 mv_video.setLoop(loop);
|
|
|
//loop:为-1时是无限循环,为其他正整数时是有限次循环
|
|
|
mv_video.setLoop(loop);
|
|
|
```
|
|
|
|
|
|
设置跑马灯动作节点,可定义多个节点。
|
|
|
|
|
|
```
|
|
|
//创建动作节点MarqueeAction marqueeAction = new MarqueeAction();//index:动作的执行顺序marqueeAction.setIndex(index);//duration:动作的执行时间(单位:ms)marqueeAction.setDuration(duration);//startXpos:动作起始点距离视频左上角原点水平距离,数据类型float,取值范围0~1,//具体距离:视频宽度*startXposmarqueeAction.setStartXpos(startXpos);//startYpos:动作起始点距离视频左上角原点垂直距离,数据类型float,取值范围0~1//具体距离:视频高度*startYposmarqueeAction.setStartYpos(startYpos);//startAlpha:起始点透明度,数据类型float,取值范围0~1marqueeAction.setStartAlpha(startAlpha);//endXpos:动作结束点距离视频左上角原点水平距离,数据类型float,取值范围0~1,//具体距离:视频宽度*endXposmarqueeAction.setEndXpos(endXpos);//endYpos:动作结束点距离视频左上角原点垂直距离,数据类型float,取值范围0~1//具体距离:视频高度*endYposmarqueeAction.setEndYpos(endYpos);//endAlpha:结束点透明度,数据类型float,取值范围0~1marqueeAction.setEndAlpha(endAlpha); //设置动作节点,marqueeActions:一组动作节点mv_video.setMarqueeActions(marqueeActions);
|
|
|
//创建动作节点
|
|
|
MarqueeAction marqueeAction = new MarqueeAction();
|
|
|
//index:动作的执行顺序
|
|
|
marqueeAction.setIndex(index);
|
|
|
//duration:动作的执行时间(单位:ms)
|
|
|
marqueeAction.setDuration(duration);
|
|
|
//startXpos:动作起始点距离视频左上角原点水平距离,数据类型float,取值范围0~1,
|
|
|
//具体距离:视频宽度*startXpos
|
|
|
marqueeAction.setStartXpos(startXpos);
|
|
|
//startYpos:动作起始点距离视频左上角原点垂直距离,数据类型float,取值范围0~1
|
|
|
//具体距离:视频高度*startYpos
|
|
|
marqueeAction.setStartYpos(startYpos);
|
|
|
//startAlpha:起始点透明度,数据类型float,取值范围0~1
|
|
|
marqueeAction.setStartAlpha(startAlpha);
|
|
|
//endXpos:动作结束点距离视频左上角原点水平距离,数据类型float,取值范围0~1,
|
|
|
//具体距离:视频宽度*endXpos
|
|
|
marqueeAction.setEndXpos(endXpos);
|
|
|
//endYpos:动作结束点距离视频左上角原点垂直距离,数据类型float,取值范围0~1
|
|
|
//具体距离:视频高度*endYpos
|
|
|
marqueeAction.setEndYpos(endYpos);
|
|
|
//endAlpha:结束点透明度,数据类型float,取值范围0~1
|
|
|
marqueeAction.setEndAlpha(endAlpha);
|
|
|
|
|
|
|
|
|
//设置动作节点,marqueeActions:一组动作节点
|
|
|
mv_video.setMarqueeActions(marqueeActions);
|
|
|
```
|
|
|
|
|
|
设置文字内容。
|
... | ... | @@ -444,13 +727,32 @@ if (!TextUtils.isEmpty(marqueeData)) { MarqueeInfo marqueeInfo=player.getMar |
|
|
通过url设置跑马灯图片。
|
|
|
|
|
|
```
|
|
|
/** * @param activity 上下文 * @param imageUrl 图片url * @param imageWidth 图片宽度(单位px) * @param imageHeight 图片高度(单位px) */mv_video.setMarqueeImage(activity, imageUrl, imageWidth, imageHeight);//设置跑马灯图片加载监听mv_video.setOnMarqueeImgFailListener(new OnMarqueeImgFailListener() { @Override public void onLoadMarqueeImgFail() { }});
|
|
|
/**
|
|
|
* @param activity 上下文
|
|
|
* @param imageUrl 图片url
|
|
|
* @param imageWidth 图片宽度(单位px)
|
|
|
* @param imageHeight 图片高度(单位px)
|
|
|
*/
|
|
|
mv_video.setMarqueeImage(activity, imageUrl, imageWidth, imageHeight);
|
|
|
|
|
|
//设置跑马灯图片加载监听
|
|
|
mv_video.setOnMarqueeImgFailListener(new OnMarqueeImgFailListener() {
|
|
|
@Override
|
|
|
public void onLoadMarqueeImgFail() {
|
|
|
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
通过Bitmap设置跑马灯图片。
|
|
|
|
|
|
```
|
|
|
/** * @param bitmap 图片bitmap * @param imageWidth 图片宽度(单位px) * @param imageHeight 图片高度(单位px) */mv_video.setMarqueeImage(bitmap, imageWidth, imageHeight);
|
|
|
/**
|
|
|
* @param bitmap 图片bitmap
|
|
|
* @param imageWidth 图片宽度(单位px)
|
|
|
* @param imageHeight 图片高度(单位px)
|
|
|
*/
|
|
|
mv_video.setMarqueeImage(bitmap, imageWidth, imageHeight);
|
|
|
```
|
|
|
|
|
|
运行跑马灯。
|
... | ... | @@ -467,13 +769,52 @@ Android 8.0及以上系统支持小窗播放,具体使用请参考Demo。 |
|
|
在AndroidManifest.xml文件中给播放Activity配置android:supportsPictureInPicture="true"和android:configChanges="smallestScreenSize|screenLayout|orientation"(避免Activity销毁重建)。
|
|
|
|
|
|
```
|
|
|
<activity android:name=".play.MediaPlayActivity" android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout" android:screenOrientation="portrait" android:supportsPictureInPicture="true" />
|
|
|
<activity
|
|
|
android:name=".play.MediaPlayActivity"
|
|
|
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout"
|
|
|
android:screenOrientation="portrait"
|
|
|
android:supportsPictureInPicture="true" />
|
|
|
```
|
|
|
|
|
|
进入小窗播放,以下是部分代码示例,详细代码参考Demo:
|
|
|
|
|
|
```
|
|
|
private PictureInPictureParams.Builder builder;private void useSmallWindowPlay() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (builder == null) { builder = new PictureInPictureParams.Builder(); } int width = rl_play_video.getWidth(); int height = rl_play_video.getHeight(); // 设置宽高比例值 if (width > 0 && height > 0) { float whRate = MultiUtils.calFloat(2, width, height); if (whRate > 0.42 && whRate < 2.39) { Rational aspectRatio = new Rational(width, height); builder.setAspectRatio(aspectRatio); } } if (actions != null && actions.size() > 0) { actions.clear(); } if (player.isPlaying()) { actions.add(pauseRemoteAction); } else { actions.add(playRemoteAction); } if (actions != null && actions.size() > 0) { builder.setActions(actions); } // 进入小窗模式 enterPictureInPictureMode(builder.build()); }}
|
|
|
private PictureInPictureParams.Builder builder;
|
|
|
|
|
|
private void useSmallWindowPlay() {
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
if (builder == null) {
|
|
|
builder = new PictureInPictureParams.Builder();
|
|
|
}
|
|
|
int width = rl_play_video.getWidth();
|
|
|
int height = rl_play_video.getHeight();
|
|
|
// 设置宽高比例值
|
|
|
if (width > 0 && height > 0) {
|
|
|
float whRate = MultiUtils.calFloat(2, width, height);
|
|
|
if (whRate > 0.42 && whRate < 2.39) {
|
|
|
Rational aspectRatio = new Rational(width, height);
|
|
|
builder.setAspectRatio(aspectRatio);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (actions != null && actions.size() > 0) {
|
|
|
actions.clear();
|
|
|
}
|
|
|
|
|
|
if (player.isPlaying()) {
|
|
|
actions.add(pauseRemoteAction);
|
|
|
} else {
|
|
|
actions.add(playRemoteAction);
|
|
|
}
|
|
|
if (actions != null && actions.size() > 0) {
|
|
|
builder.setActions(actions);
|
|
|
}
|
|
|
|
|
|
// 进入小窗模式
|
|
|
enterPictureInPictureMode(builder.build());
|
|
|
}
|
|
|
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 4.20 视频截图
|
... | ... | @@ -481,7 +822,19 @@ private PictureInPictureParams.Builder builder;private void useSmallWindowPlay() |
|
|
通过调用player.getVideoScreenShot(bitmap, videoScreenShotOutPath)获取当前播放视频的截图。
|
|
|
|
|
|
```
|
|
|
private void getVideoScreenShot() { String videoScreenShotOutPath = MultiUtils.getVideoScreenShotOutPath(); if (!TextUtils.isEmpty(videoScreenShotOutPath)) { Bitmap bitmap = tv_video.getBitmap(); //bitmap:视频画面的bitmap videoScreenShotOutPath:截图输出路径 boolean videoScreenShot = player.getVideoScreenShot(bitmap, videoScreenShotOutPath); if (videoScreenShot) { //通知系统相册更新 sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(videoScreenShotOutPath)))); } }}
|
|
|
private void getVideoScreenShot() {
|
|
|
String videoScreenShotOutPath = MultiUtils.getVideoScreenShotOutPath();
|
|
|
if (!TextUtils.isEmpty(videoScreenShotOutPath)) {
|
|
|
Bitmap bitmap = tv_video.getBitmap();
|
|
|
//bitmap:视频画面的bitmap videoScreenShotOutPath:截图输出路径
|
|
|
boolean videoScreenShot = player.getVideoScreenShot(bitmap, videoScreenShotOutPath);
|
|
|
if (videoScreenShot) {
|
|
|
//通知系统相册更新
|
|
|
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
|
|
|
Uri.fromFile(new File(videoScreenShotOutPath))));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 4.21 弹幕功能
|
... | ... | @@ -489,13 +842,71 @@ private void getVideoScreenShot() { String videoScreenShotOutPath = Multi |
|
|
发送弹幕。
|
|
|
|
|
|
```
|
|
|
/** * @param videoId 视频ID * @param danmuText 弹幕文字 * @param currentPosition 发送弹幕时的视频播放位置 * @param danmuColor 弹幕颜色(格式如:0xffffff) * @param onSendDanmuListener 发送结果 */player.sendDanmu(videoId, danmuText, currentPosition, danmuColor, new OnSendDanmuListener() { @Override public void onSuccess() { runOnUiThread(new Runnable() { @Override public void run() { isCanSendDanmu = false; sendDanmuInterval = 5; addDanmu(danmuText, danmuColor, currentPosition, true); } }); } @Override public void onFail(final String msg) { runOnUiThread(new Runnable() { @Override public void run() { MultiUtils.showToast(activity, "发送弹幕失败:" + msg); } }); } });
|
|
|
/**
|
|
|
* @param videoId 视频ID
|
|
|
* @param danmuText 弹幕文字
|
|
|
* @param currentPosition 发送弹幕时的视频播放位置
|
|
|
* @param danmuColor 弹幕颜色(格式如:0xffffff)
|
|
|
* @param onSendDanmuListener 发送结果
|
|
|
*/
|
|
|
player.sendDanmu(videoId, danmuText, currentPosition, danmuColor, new OnSendDanmuListener() {
|
|
|
@Override
|
|
|
public void onSuccess() {
|
|
|
runOnUiThread(new Runnable() {
|
|
|
@Override
|
|
|
public void run() {
|
|
|
isCanSendDanmu = false;
|
|
|
sendDanmuInterval = 5;
|
|
|
addDanmu(danmuText, danmuColor, currentPosition, true);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onFail(final String msg) {
|
|
|
runOnUiThread(new Runnable() {
|
|
|
@Override
|
|
|
public void run() {
|
|
|
MultiUtils.showToast(activity, "发送弹幕失败:" + msg);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
获取弹幕数据。
|
|
|
|
|
|
```
|
|
|
/** * @param videoId 视频ID * @param sec 段号 *每隔1分钟调用1次,段号递增 */player.getDanmuList(videoId, sec);//查询弹幕结果player.setOnDanmuListListener(new OnDanmuListListener() { /** * @param danmuInfos 弹幕信息 * danmuInfo组成字段: * content:字幕内容 fc:字幕颜色,格式如:0xffffff * pt:字幕相对于视频出现的时间 */ @Override public void onSuccess(final ArrayList<DanmuInfo> danmuInfos) { runOnUiThread(new Runnable() { @Override public void run() { } }); } @Override public void onFail(String msg) { }});
|
|
|
/**
|
|
|
* @param videoId 视频ID
|
|
|
* @param sec 段号
|
|
|
*每隔1分钟调用1次,段号递增
|
|
|
*/
|
|
|
player.getDanmuList(videoId, sec);
|
|
|
|
|
|
//查询弹幕结果
|
|
|
player.setOnDanmuListListener(new OnDanmuListListener() {
|
|
|
/**
|
|
|
* @param danmuInfos 弹幕信息
|
|
|
* danmuInfo组成字段:
|
|
|
* content:字幕内容 fc:字幕颜色,格式如:0xffffff
|
|
|
* pt:字幕相对于视频出现的时间
|
|
|
*/
|
|
|
@Override
|
|
|
public void onSuccess(final ArrayList<DanmuInfo> danmuInfos) {
|
|
|
runOnUiThread(new Runnable() {
|
|
|
@Override
|
|
|
public void run() {
|
|
|
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onFail(String msg) {
|
|
|
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
弹幕功能的演示请参考Demo。
|
... | ... | @@ -515,7 +926,16 @@ private void getVideoScreenShot() { String videoScreenShotOutPath = Multi |
|
|
```
|
|
|
|
|
|
```
|
|
|
Vibrator vibrator = vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);if (vibrator.hasVibrator() && isDynamicVideo){ //震动时长,单位毫秒 vibrator.vibrate(500);}//不用震动的时候,调用cancel()取消if (vibrator != null) { vibrator.cancel();}
|
|
|
Vibrator vibrator = vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
|
|
|
if (vibrator.hasVibrator() && isDynamicVideo){
|
|
|
//震动时长,单位毫秒
|
|
|
vibrator.vibrate(500);
|
|
|
}
|
|
|
|
|
|
//不用震动的时候,调用cancel()取消
|
|
|
if (vibrator != null) {
|
|
|
vibrator.cancel();
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 4.24 防拖拽
|
... | ... | @@ -523,7 +943,8 @@ Vibrator vibrator = vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERV |
|
|
启用防拖拽功能,未看部分禁止拖动,将isForbidDragToUnPlayPart的值改为true,详情参考Demo。
|
|
|
|
|
|
```
|
|
|
//未看部分禁止拖动:isForbidDragToUnPlayPart为false时允许拖动到未看部分,为true时不允许拖动到未看部分private boolean isForbidDragToUnPlayPart = true;
|
|
|
//未看部分禁止拖动:isForbidDragToUnPlayPart为false时允许拖动到未看部分,为true时不允许拖动到未看部分
|
|
|
private boolean isForbidDragToUnPlayPart = true;
|
|
|
```
|
|
|
|
|
|
## 4.25 自定义Logo
|
... | ... | @@ -531,13 +952,24 @@ Vibrator vibrator = vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERV |
|
|
在布局中使用CustomLogoView。
|
|
|
|
|
|
```
|
|
|
<com.bokecc.vod.view.CustomLogoView android:id="@+id/clv_logo" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" />
|
|
|
<com.bokecc.vod.view.CustomLogoView
|
|
|
android:id="@+id/clv_logo"
|
|
|
android:layout_width="match_parent"
|
|
|
android:layout_height="match_parent"
|
|
|
android:layout_centerInParent="true" />
|
|
|
```
|
|
|
|
|
|
设置Logo,logo图片不宜太大,控制在100KB内。
|
|
|
|
|
|
```
|
|
|
/** * @param img 图片地址 * @param xPosRate 相对于左上角的X轴位置偏移量与播放窗口宽度的比例 * @param yPosRate 相对于左上角的Y轴位置偏移量播放窗口高度的比例 * @param logoWidthRate Logo宽度相对于播放窗口宽度的比例 * @param logoHeightRate Logo高度相对于播放窗口高度的比例 */clv_logo.setCustomLogoInfo(img, xPosRate, yPosRate, logoWidthRate, logoHeightRate);
|
|
|
/**
|
|
|
* @param img 图片地址
|
|
|
* @param xPosRate 相对于左上角的X轴位置偏移量与播放窗口宽度的比例
|
|
|
* @param yPosRate 相对于左上角的Y轴位置偏移量播放窗口高度的比例
|
|
|
* @param logoWidthRate Logo宽度相对于播放窗口宽度的比例
|
|
|
* @param logoHeightRate Logo高度相对于播放窗口高度的比例
|
|
|
*/
|
|
|
clv_logo.setCustomLogoInfo(img, xPosRate, yPosRate, logoWidthRate, logoHeightRate);
|
|
|
```
|
|
|
|
|
|
展示logo,调用clv_logo.show()。
|
... | ... | @@ -549,7 +981,8 @@ clv_logo.show(); |
|
|
横竖屏切换时,刷新Logo。
|
|
|
|
|
|
```
|
|
|
//刷新logo视图clv_logo.refreshView();
|
|
|
//刷新logo视图
|
|
|
clv_logo.refreshView();
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -563,13 +996,24 @@ clv_logo.show(); |
|
|
DWMediaPlayer重载了MediaPlayer的setOnErrorListener()方法,如果需要在应用中提示错误信息,可调用此方法设置OnErrorListener。具体实现方式如下:
|
|
|
|
|
|
```
|
|
|
player.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { //在这里进行错误处理 return true; }});
|
|
|
player.setOnErrorListener(new MediaPlayer.OnErrorListener() {
|
|
|
@Override
|
|
|
public boolean onError(MediaPlayer mp, int what, int extra) {
|
|
|
//在这里进行错误处理
|
|
|
return true;
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
### 4.26.2 监听获得场景视频自定义的错误事件
|
|
|
|
|
|
```
|
|
|
player.setOnDreamWinErrorListener(new OnDreamWinErrorListener() { @Override public void onPlayError(HuodeException e) { //在这里进行错误处理 }});
|
|
|
player.setOnDreamWinErrorListener(new OnDreamWinErrorListener() {
|
|
|
@Override
|
|
|
public void onPlayError(HuodeException e) {
|
|
|
//在这里进行错误处理
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
## 4.27 自定义视频封面
|
... | ... | @@ -577,13 +1021,18 @@ player.setOnDreamWinErrorListener(new OnDreamWinErrorListener() { @Override |
|
|
1.根据后台管理系统上传的自定义封面,用于视频播放前的展示,用户设置的是否自动播放,决定展示时长。当设置为自动播放时,在视频缓冲加载结束之后,将隐藏该封面图,播放视频。当设置为非自动播放时,将持续展示封面图,直到用户点击播放按钮。
|
|
|
|
|
|
```
|
|
|
//视频缓冲完成自动播放 player.setAutoPlay(true); //持续展示视频封面 player.setAutoPlay(false);
|
|
|
//视频缓冲完成自动播放
|
|
|
player.setAutoPlay(true);
|
|
|
//持续展示视频封面
|
|
|
player.setAutoPlay(false);
|
|
|
```
|
|
|
|
|
|
2.视频的封面图展示与隐藏逻辑,更多的需要开发人员自行控制,可通过提供的api获取当前配置的封面rul。
|
|
|
|
|
|
```
|
|
|
//在onPrepared()方法中,获取到 playInfo对象PlayInfo playInfo = player.getPlayInfo();String coverUrl = playInfo.getCoverImage();
|
|
|
//在onPrepared()方法中,获取到 playInfo对象
|
|
|
PlayInfo playInfo = player.getPlayInfo();
|
|
|
String coverUrl = playInfo.getCoverImage();
|
|
|
```
|
|
|
|
|
|
3.当音视频模式切换时,需调用api,通知当前模式切换
|
... | ... | @@ -597,7 +1046,40 @@ player.playModelChanged(); |
|
|
1.在admin管理系统中配置答题器相关数据,播放器可以通过设置回调获取相关数据,以及相关回调方法
|
|
|
|
|
|
```
|
|
|
player.setOnAnswerSheetListener(new AnswerSheetListener() { @Override public void onAnswerSheet(List<AnswerSheetInfo> answerSheetInfoList) { //获取到返回的数据,将该数据绑定在视图中 MediaPlayActivity.this.answerSheetInfoList = answerSheetInfoList; sheetTimeList = new ArrayList<>(); for (int i = 0; i < answerSheetInfoList.size(); i++) { sheetTimeList.add(answerSheetInfoList.get(i).getShowTime()); } Collections.sort(sheetTimeList); } @Override public void onAnswerCommitSuccess(final List<AnswerCommitResult> commitResultList) { //提交答案成功回调 runOnUiThread(new Runnable() { @Override public void run() { //UI展示,相关逻辑 } }); } @Override public void onAnswerCommitFailed(int errorCode, String errorMessage) { //提交答案失败回调 runOnUiThread(new Runnable() { @Override public void run() { //UI展示,相关逻辑 } }); } });
|
|
|
player.setOnAnswerSheetListener(new AnswerSheetListener() {
|
|
|
@Override
|
|
|
public void onAnswerSheet(List<AnswerSheetInfo> answerSheetInfoList) {
|
|
|
//获取到返回的数据,将该数据绑定在视图中
|
|
|
MediaPlayActivity.this.answerSheetInfoList = answerSheetInfoList;
|
|
|
sheetTimeList = new ArrayList<>();
|
|
|
for (int i = 0; i < answerSheetInfoList.size(); i++) {
|
|
|
sheetTimeList.add(answerSheetInfoList.get(i).getShowTime());
|
|
|
}
|
|
|
Collections.sort(sheetTimeList);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onAnswerCommitSuccess(final List<AnswerCommitResult> commitResultList) {
|
|
|
//提交答案成功回调
|
|
|
runOnUiThread(new Runnable() {
|
|
|
@Override
|
|
|
public void run() {
|
|
|
//UI展示,相关逻辑
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onAnswerCommitFailed(int errorCode, String errorMessage) {
|
|
|
//提交答案失败回调
|
|
|
runOnUiThread(new Runnable() {
|
|
|
@Override
|
|
|
public void run() {
|
|
|
//UI展示,相关逻辑
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
```
|
|
|
|
|
|
2.答题器提交答案
|
... | ... | @@ -605,5 +1087,18 @@ player.playModelChanged(); |
|
|
```
|
|
|
//这里需要填入当前回答问题的id,以及答案列表player.onSubmitAnswer(int currentSheetInfoId,List<AnswerSheetInfo.Answer> selectedAnswer)
|
|
|
```
|
|
|
4.28.2 答题器相关设置
|
|
|
1.显示开关,SDK提供了答题器显示相关的api给到开发者,以满足用户可以随时控制答题器相关逻辑是否展示的自由度。当配置了答题器的相关内容时,默认为显示答题器。
|
|
|
```
|
|
|
player.setHideAnswerSheet(boolen hide);
|
|
|
```
|
|
|
2.当进度条拖动时,对于历史进度中未展示的相关答题器,存在有强制依次展示和不展示的两种不同逻辑,SDK以构造的方式进行强绑定,无参构造中,默认为强制依次显示。
|
|
|
```
|
|
|
DWIjkMediaPlayer player = new DWIjkMediaPlayer();
|
|
|
DWIjkMediaPlayer player = new DWIjkMediaPlayer(boolen force);
|
|
|
DWMediaPlayer player = new DWMediaPlayer();
|
|
|
DWMediaPlayer player = new DWMediaPlayer(boolen force);
|
|
|
```
|
|
|
|
|
|
|
|
|
具体的展示与逻辑信息,您可参考demo中的相关实现。 |
|
|
\ No newline at end of file |