bilibili DanmakuFlameMaster在播放器上的使用

使用b站的弹幕:
1 弹幕的配置和获取弹幕的布局view:
privateIDanmakuViewmDanmakuView;// 弹幕控件
privateDanmakuContextmContext;// 弹幕上下文
privateBaseDanmakuParsermParser;// 数据对象


//弹幕之前的配置
// 设置最大显示行数
HashMap<Integer,Integer> maxLinesPair =newHashMap<Integer,Integer>();
maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL,5);// 滚动弹幕最大显示5行,可以设置多个设置模式
// 设置是否禁止重叠,可以设置多个模式
HashMap<Integer,Boolean> overlappingEnablePair =newHashMap<Integer,Boolean>();
overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL,true);
overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP,true);

mDanmakuView= (IDanmakuView)findViewById(R.id.vod_danmaku);//获取弹幕的view
mContext= DanmakuContext.create();//创建弹幕上下文
mContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN,3)
// 描边样式
// 是否合并重复弹幕setDuplicateMergingEnabled
.setDuplicateMergingEnabled(false)
.setScrollSpeedFactor(1.2f)
// .setCacheStuffer(new SpannedCacheStuffer(),
// mCacheStufferAdapter)
// //.setCacheStuffer(new BackgroundCacheStuffer()) //
// 绘制背景使用BackgroundCacheStuffer

.setMaximumVisibleSizeInScreen(40)
// 同屏最大显示数量(弹幕密度(只对滚动有效))
.setScaleTextSize(1.2f).setMaximumLines(maxLinesPair)
.preventOverlapping(overlappingEnablePair)
.setScrollSpeedFactor(1.0f);// 设置弹幕滚动速度系数,只对滚动弹幕有效



mDanmakuView//mDanmakuView表示的是布局中弹幕view
.setCallback(newmaster.flame.danmaku.controller.DrawHandler.Callback() {
@Override
public void updateTimer(DanmakuTimer timer) {
// lzw 这里是更新时间后的回调
}

@Override
public void drawingFinished() {

}

@Override
public void danmakuShown(BaseDanmaku danmaku) {
Log.d("danmaku","danmakuShown(): text="
+ danmaku.text);
}

@Override
public void prepared() {
//因为要是点播弹幕,当播放器有历史记录,的时候,希望弹幕与播放时间同步,就在这里//操作
// 在这里是用这个,因为初始化的时候,start不起作用
// 坑,要是刚进去的时候,马上seek,不起作用,因此发现这里有个回调,在这里进行处理,补坑,这个是handler里面的回调
setStartDanmukuTime(mVodDTO.getSeekPos());//根据播放器的进度设置弹幕开始的//时候的进度
Log.d("lu","danmaku start callback "
+mVodDTO.getSeekPos());
}else{
mDanmakuView.start();
}
}
});

private voidsetStartDanmukuTime(longms) {// lzw
// 设置开始时间弹幕时间,在弹幕准备好了之后,不能用这个,应该用seek,这个要
//要是刚刚准备开始的时候,应该用这个设置时间
if(ms >0) {
mDanmakuView.start(ms);
}else{
mDanmakuView.start();
}
Log.d("lu","danmaku start time "+ mDanmakuView.getCurrentTime()
+" ms "+ ms);
}

private voidseekToDanmuKuTime(longms) {// lzw seek 弹幕时间 就是移动到什么时候,
//要是//启///动之后的弹幕,用这个
mDanmakuView.seekTo(ms);
Log.d("lu","danmaku seek time "+ mDanmakuView.getCurrentTime()
+" ms "+ ms);
}
2弹幕的启动:
// 启动弹幕
private voidstartDanmaku(String jsonArr) {// lzw
// 这个是对弹幕的初始化,并且启动,具体实现,看弹幕里的Handler

// mParser = createParser(this.getResources().openRawResource(
// R.raw.comments));//这里是加载自己文件中的xml
mParser= createParser(jsonArr);//解析 json,或者是xml

mDanmakuView.release();// 先释放之前的资源,和还原时间
mDanmakuView.prepare(mParser,mContext);
// lzw 显示,弹幕的时间,内存之类的,测试的时候用,true 为显示
// mDanmakuView.showFPS(true);// 画面的帧数值,帧数值越高, 画面会越流畅,
mDanmakuView.enableDanmakuDrawingCache(true);
Log.d("lu","danmaku start");
// lzw 设置弹幕开始时间,播放点播的时候,可能会有历史记录,注意,这里要用seek, 但是刚进去的时候,进度条是为0,
// 因此加个mVodDTO
// if (mFooterSeekBar != null) {
// seekToDanmuKuTime(mFooterSeekBar.getProgress());
// Log.d("lu", "danmaku seek "+mFooterSeekBar.getProgress());
// }
// if (mVodDTO != null && mVodDTO.getSeekPos() != 0) {//lzw
// 在这里是用这个,因为初始化的时候,进度条是为0的
// //lzw 坑,要是刚进去的时候,马上seek,不起作用
// seekToDanmuKuTime(mVodDTO.getSeekPos());
// Log.d("lu", "danmaku seek "+ mVodDTO.getSeekPos());
// }
}
3弹幕的加载数据:
/ 加载json串,就是把从服务器上获取的json加进去
privateBaseDanmakuParser createParser(String jsonArr) {

if(jsonArr ==null) {
return new BaseDanmakuParser() {

@Override
protectedDanmakus parse() {
return new Danmakus();
}
};
}

try{
BaseDanmakuParser parser =newAcFunDanmakuParser();//加载的是json
JSONSource jsonSource =newJSONSource(jsonArr);
IDataSource<?> dataSource = jsonSource;
parser.load(dataSource);

returnparser;
}catch(JSONException e) {
e.printStackTrace();
}

return null;

}

// 测试用的,加载自己的文件里的xml,这个也可以自己改成加载服务器上的xml
privateBaseDanmakuParser createParser(InputStream stream) {

if(stream ==null) {
return new BaseDanmakuParser() {

@Override
protectedDanmakus parse() {
return new Danmakus();
}
};
}

ILoader loader = DanmakuLoaderFactory
.create(DanmakuLoaderFactory.TAG_BILI);//加载的xml

try{
loader.load(stream);
}catch(IllegalDataException e) {
e.printStackTrace();
}
BaseDanmakuParser parser =newBiliDanmukuParser();
IDataSource<?> dataSource = loader.getDataSource();
parser.load(dataSource);
returnparser;

}
4弹幕的解析格式:
有两种解析方式。一种是xml,一种是json
ILoader loader = DanmakuLoaderFactory.create(DanmakuLoaderFactory.TAG_BILI);//这个是xml的方式

DanmakuLoaderFactory.TAG_ACFUN//这个是josn

在调用的时候,会有个判断,是加载json还是xmL,(这个可以看源码)
if (TAG_BILI.equalsIgnoreCase(tag)) {
            return BiliDanmakuLoader.instance();
        } else if(TAG_ACFUN.equalsIgnoreCase(tag))
            return AcFunDanmakuLoader.instance();}

 BiliDanmakuLoader//这个是对xml进行解析

AcFunDanmakuLoader//这个是对json进行解析
如果是直接跟b站的内容格式是一样的话,就可以直接传入下载的地址,里面有对http,https,file的下载处理,如果要是有自己的格式话。
那么就自己转成b站一样的格式,


内容格式xml:
// <d p="23.826000213623,1,25,16777215,1422201084,0,057075e9,757076900">我从未见过如此厚颜无耻之猴</d>
                // 0:时间(弹幕出现时间)
                // 1:类型(1从左至右滚动弹幕|6从右至左滚动弹幕|5顶端固定弹幕|4底端固定弹幕|7高级弹幕|8脚本弹幕)
                // 2:字号
                // 3:颜色
                // 4:时间戳 ?
                // 5:弹幕池id
                // 6:用户hash
                // 7:弹幕id


json格式:记住传入的json最开始的时候一定应该是个数组

 JSONObject obj = jsonObject;
                Log.d("lu","弹幕json"+"\n"+obj.toString());
                String c = obj.getString("c");
                String[] values = c.split(",");
                if (values.length > 0) {
                    int type = Integer.parseInt(values[2]); // 弹幕类型
                    if (type == 7)
                        // FIXME : hard code
                        // TODO : parse advance danmaku json
                        continue;
                    long time = (long) (Float.parseFloat(values[0]) * 1000); // 出现时间
                    int color = Integer.parseInt(values[1]) | 0xFF000000; // 颜色
                    float textSize = Float.parseFloat(values[3]); // 字体大小
                    BaseDanmaku item = mContext.mDanmakuFactory.createDanmaku(type, mContext);
                    if (item != null) {
                        item.time = time;
                        item.textSize = textSize * (mDispDensity - 0.6f);
                        item.textColor = color;
                        item.textShadowColor = color <= Color.BLACK ? Color.WHITE : Color.BLACK;
                        DanmakuUtils.fillText(item, obj.optString("m", "...."));
                        item.index = i;
                        item.setTimer(mTimer);
                        danmakus.addItem(item);
                    }
                }

弹幕json格式:
[{"c":"0,16777215,1,25,196050,1364468342","m":"。。。。。。。。。。。。。。。。。。。。。。"}]

表达的意思:
{"c": "播放时间,颜色,模式,字号,uid,发送时间", "m": "弹幕内容"}  
这里介绍下c里面各自参数:
1、播放时间单位是秒 如1.234
2、颜色是十进制
3、模式在BaseDanmaku里有声明,总结一下就是
1:滚动弹幕
4:底端弹幕
5:顶端弹幕



5 弹幕的添加:
从输入框输入文字,添加一个弹幕
danmaku.text= strText;// 文字
danmaku.padding= 5;// 内距离
danmaku.priority= 0;// 可能会被各种过滤器过滤并隐藏显示
danmaku.time= mDanmakuView.getCurrentTime()+ 5;// 时间,取当前弹幕时间,加上五毫秒
danmaku.textSize= 16f* (mParser.getDisplayer().getDensity()- 0.6f);// 大小
danmaku.textColor= Color.WHITE;// 字体颜色
danmaku.textShadowColor= Color.WHITE;// 字体描边的颜色
// danmaku.underlineColor = Color.GREEN;//下滑线
danmaku.borderColor= Color.GREEN;// 边框线
// danmaku.isLive;// 是否是直播
mDanmakuView.addDanmaku(danmaku)

6弹幕的生命周期:
mDanmakuView.pause();//弹幕暂停,加在activity的生命周期里和播放器的生命周期方法里
mDanmakuView.resume();//弹幕复苏,加在activity的生命周期和播放器的生命周期方法里
mDanmakuView.release();//弹幕释放
if(mFooterSeekBar!= null) {
seekToDanmuKuTime(mFooterSeekBar.getProgress());//mFooterSeekBar是播放器的进度条(相对于点播,要是直播就没有必要矫正)
// 每次复苏的时候,我都对时间进行一次矫正,但是有时候得注意进度条返回的时间是否是一致的
Log.d("lu","danmaku resume "+ mFooterSeekBar.getProgress());
}

7弹幕是否显示:
// lzw 是否显示弹幕
private voidisShowDanmaku(booleanshow) {
if(show) {
mDanmakuView.show();

Log.d("lu","danmaku show");
}else{

mDanmakuView.hide();
Log.d("lu","danmaku hide");
}
}
}

8可以设置一个定时器,定时发送
classAsyncAddTaskextendsTimerTask{// 定时发送的时候用

@Override
public void run() {
for(inti = 0;i < 20;i++) {

SystemClock.sleep(20);
}
}
}
总结:以上是在点播(视频)的使用,要是直播,其实原理也是差不多,就是建立一个WebSocket,时时更新数据,并且添加到弹幕里.
展开阅读全文

没有更多推荐了,返回首页