使用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);//获取弹幕的viewmContext= 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() {@Overridepublic void updateTimer(DanmakuTimer timer) {// lzw 这里是更新时间后的回调}
@Overridepublic void drawingFinished() {
}
@Overridepublic void danmakuShown(BaseDanmaku danmaku) {Log.d("danmaku","danmakuShown(): text="+ danmaku.text);}
@Overridepublic 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));//这里是加载自己文件中的xmlmParser= 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() {
@OverrideprotectedDanmakus parse() {return new Danmakus();}};}
try{BaseDanmakuParser parser =newAcFunDanmakuParser();//加载的是jsonJSONSource jsonSource =newJSONSource(jsonArr);IDataSource<?> dataSource = jsonSource;parser.load(dataSource);
returnparser;}catch(JSONException e) {e.printStackTrace();}
return null;
}
// 测试用的,加载自己的文件里的xml,这个也可以自己改成加载服务器上的xmlprivateBaseDanmakuParser createParser(InputStream stream) {
if(stream ==null) {return new BaseDanmakuParser() {
@OverrideprotectedDanmakus 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,一种是jsonILoader 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 jsoncontinue;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.2342、颜色是十进制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{// 定时发送的时候用
@Overridepublic void run() {for(inti = 0;i < 20;i++) {
SystemClock.sleep(20);}}}
总结:以上是在点播(视频)的使用,要是直播,其实原理也是差不多,就是建立一个WebSocket,时时更新数据,并且添加到弹幕里.
bilibili DanmakuFlameMaster在播放器上的使用
最新推荐文章于 2024-09-11 08:19:30 发布