使用b站的弹幕:1 弹幕的配置和获取弹幕的布局view:private IDanmakuView mDanmakuView ; // 弹幕控件private DanmakuContext mContext ; // 弹幕上下文private BaseDanmakuParser mParser ; // 数据对象
//弹幕之前的配置// 设置最大显示行数HashMap<Integer , Integer> maxLinesPair = new HashMap<Integer , Integer> ();maxLinesPair . put ( BaseDanmaku . TYPE_SCROLL_RL , 5 ); // 滚动弹幕最大显示5行,可以设置多个设置模式// 设置是否禁止重叠,可以设置多个模式HashMap<Integer , Boolean> overlappingEnablePair = new HashMap<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 ( new master . 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 void setStartDanmukuTime ( long ms ) { // lzw// 设置开始时间弹幕时间,在弹幕准备好了之后,不能用这个,应该用seek,这个要//要是刚刚准备开始的时候,应该用这个设置时间if ( ms > 0 ) {mDanmakuView . start ( ms );} else {mDanmakuView . start ();}Log . d ( "lu" , "danmaku start time " + mDanmakuView . getCurrentTime ()+ " ms " + ms );}
private void seekToDanmuKuTime ( long ms ) { // lzw seek 弹幕时间 就是移动到什么时候,//要是//启///动之后的弹幕,用这个mDanmakuView . seekTo ( ms );Log . d ( "lu" , "danmaku seek time " + mDanmakuView . getCurrentTime ()+ " ms " + ms );}2弹幕的启动:// 启动弹幕private void startDanmaku ( 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加进去private BaseDanmakuParser createParser ( String jsonArr ) {
if ( jsonArr == null ) {return new BaseDanmakuParser () {
@Overrideprotected Danmakus parse () {return new Danmakus ();}};}
try {BaseDanmakuParser parser = new AcFunDanmakuParser ();//加载的是jsonJSONSource jsonSource = new JSONSource ( jsonArr );IDataSource<?> dataSource = jsonSource ;parser . load ( dataSource );
return parser ;} catch ( JSONException e ) {e . printStackTrace ();}
return null ;
}
// 测试用的,加载自己的文件里的xml,这个也可以自己改成加载服务器上的xmlprivate BaseDanmakuParser createParser ( InputStream stream ) {
if ( stream == null ) {return new BaseDanmakuParser () {
@Overrideprotected Danmakus parse () {return new Danmakus ();}};}
ILoader loader = DanmakuLoaderFactory. create ( DanmakuLoaderFactory . TAG_BILI );//加载的xml
try {loader . load ( stream );} catch ( IllegalDataException e ) {e . printStackTrace ();}BaseDanmakuParser parser = new BiliDanmukuParser ();IDataSource<?> dataSource = loader . getDataSource ();parser . load ( dataSource );return parser ;
}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 void isShowDanmaku ( boolean show ) {if ( show ) {mDanmakuView . show ();
Log . d ( "lu" , "danmaku show" );} else {
mDanmakuView . hide ();Log . d ( "lu" , "danmaku hide" );}}}
8可以设置一个定时器,定时发送class AsyncAddTask extends TimerTask { // 定时发送的时候用
@Overridepublic void run () {for ( int i = 0 ; i < 20 ; i++ ) {
SystemClock . sleep ( 20 );}}}
总结:以上是在点播(视频)的使用,要是直播,其实原理也是差不多,就是建立一个WebSocket,时时更新数据,并且添加到弹幕里.
bilibili DanmakuFlameMaster在播放器上的使用
最新推荐文章于 2024-09-11 08:27:02 发布