Android集成bilibili播放器以及弹幕
发布日期:2021-05-27 02:49:01 浏览次数:18 分类:技术文章

本文共 18059 字,大约阅读时间需要 60 分钟。

考虑到开发直播和视频播放的必要性,网上了解到b站开源播放器()好用,集成下试试。

运行后发现b站原生的只能播放没有其他选项,考虑到方便性,采用这个方案:

https://github.com/CarGuo/GSYVideoPlayer

步骤

1.gradle集成(JCenter什么的别忘了)

//ijkplayer的封装    implementation 'com.shuyu:gsyVideoPlayer-java:6.0.3'    //是否需要ExoPlayer模式    implementation 'com.shuyu:GSYVideoPlayer-exo2:6.0.3'    //根据你的需求ijk模式的so    implementation 'com.shuyu:gsyVideoPlayer-armv5:6.0.3'    implementation 'com.shuyu:gsyVideoPlayer-armv7a:6.0.3'    implementation 'com.shuyu:gsyVideoPlayer-arm64:6.0.3'    implementation 'com.shuyu:gsyVideoPlayer-x64:6.0.3'    implementation 'com.shuyu:gsyVideoPlayer-x86:6.0.3'    //弹幕    implementation  'com.github.ctiao:DanmakuFlameMaster:0.9.16'    compile 'com.github.ctiao:ndkbitmap-armv7a:0.9.21'    compile 'com.github.ctiao:ndkbitmap-armv5:0.9.21'    compile 'com.github.ctiao:ndkbitmap-x86:0.9.21'

2.播放器的封装

public class DanmakuVideoPlayer extends StandardGSYVideoPlayer {    private BaseDanmakuParser mParser;//解析器对象    private IDanmakuView mDanmakuView;//弹幕view    private DanmakuContext mDanmakuContext;    private TextView mSendDanmaku, mToogleDanmaku;    private long mDanmakuStartSeekPosition = -1;    private boolean mDanmaKuShow = true;    private File mDumakuFile;    public DanmakuVideoPlayer(Context context, Boolean fullFlag) {        super(context, fullFlag);    }    public DanmakuVideoPlayer(Context context) {        super(context);    }    public DanmakuVideoPlayer(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public int getLayoutId() {        return R.layout.danmaku_layout;    }    @Override    protected void init(Context context) {        super.init(context);        mDanmakuView = (DanmakuView) findViewById(R.id.danmaku_view);        mSendDanmaku = (TextView) findViewById(R.id.send_danmaku);        mToogleDanmaku = (TextView) findViewById(R.id.toogle_danmaku);        //初始化弹幕显示        initDanmaku();        mSendDanmaku.setOnClickListener(this);        mToogleDanmaku.setOnClickListener(this);    }    @Override    public void onPrepared() {        super.onPrepared();        onPrepareDanmaku(this);    }    @Override    public void onVideoPause() {        super.onVideoPause();        danmakuOnPause();    }    @Override    public void onVideoResume(boolean isResume) {        super.onVideoResume(isResume);        danmakuOnResume();    }    @Override    protected void clickStartIcon() {        super.clickStartIcon();        if (mCurrentState == CURRENT_STATE_PLAYING) {            danmakuOnResume();        } else if (mCurrentState == CURRENT_STATE_PAUSE) {            danmakuOnPause();        }    }    @Override    public void onCompletion() {        releaseDanmaku(this);    }    @Override    public void onSeekComplete() {        super.onSeekComplete();        int time = mProgressBar.getProgress() * getDuration() / 100;        //如果已经初始化过的,直接seek到对于位置        if (mHadPlay && getDanmakuView() != null && getDanmakuView().isPrepared()) {            resolveDanmakuSeek(this, time);        } else if (mHadPlay && getDanmakuView() != null && !getDanmakuView().isPrepared()) {            //如果没有初始化过的,记录位置等待            setDanmakuStartSeekPosition(time);        }    }    @Override    public void onClick(View v) {        super.onClick(v);        switch (v.getId()) {            case R.id.send_danmaku:                addDanmaku(true);                break;            case R.id.toogle_danmaku:                mDanmaKuShow = !mDanmaKuShow;                resolveDanmakuShow();                break;        }    }    @Override    protected void cloneParams(GSYBaseVideoPlayer from, GSYBaseVideoPlayer to) {        ((DanmakuVideoPlayer) to).mDumakuFile = ((DanmakuVideoPlayer) from).mDumakuFile;        super.cloneParams(from, to);    }    /**     处理播放器在全屏切换时,弹幕显示的逻辑     需要格外注意的是,因为全屏和小屏,是切换了播放器,所以需要同步之间的弹幕状态     */    @Override    public GSYBaseVideoPlayer startWindowFullscreen(Context context, boolean actionBar, boolean statusBar) {        GSYBaseVideoPlayer gsyBaseVideoPlayer = super.startWindowFullscreen(context, actionBar, statusBar);        if (gsyBaseVideoPlayer != null) {            DanmakuVideoPlayer gsyVideoPlayer = (DanmakuVideoPlayer) gsyBaseVideoPlayer;            //对弹幕设置偏移记录            gsyVideoPlayer.setDanmakuStartSeekPosition(getCurrentPositionWhenPlaying());            gsyVideoPlayer.setDanmaKuShow(getDanmaKuShow());            onPrepareDanmaku(gsyVideoPlayer);        }        return gsyBaseVideoPlayer;    }    /**     处理播放器在退出全屏时,弹幕显示的逻辑     需要格外注意的是,因为全屏和小屏,是切换了播放器,所以需要同步之间的弹幕状态     */    @Override    protected void resolveNormalVideoShow(View oldF, ViewGroup vp, GSYVideoPlayer gsyVideoPlayer) {        super.resolveNormalVideoShow(oldF, vp, gsyVideoPlayer);        if (gsyVideoPlayer != null) {            DanmakuVideoPlayer gsyDanmaVideoPlayer = (DanmakuVideoPlayer) gsyVideoPlayer;            setDanmaKuShow(gsyDanmaVideoPlayer.getDanmaKuShow());            if (gsyDanmaVideoPlayer.getDanmakuView() != null &&                    gsyDanmaVideoPlayer.getDanmakuView().isPrepared()) {                resolveDanmakuSeek(this, gsyDanmaVideoPlayer.getCurrentPositionWhenPlaying());                resolveDanmakuShow();                releaseDanmaku(gsyDanmaVideoPlayer);            }        }    }    protected void danmakuOnPause() {        if (mDanmakuView != null && mDanmakuView.isPrepared()) {            mDanmakuView.pause();        }    }    protected void danmakuOnResume() {        if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {            mDanmakuView.resume();        }    }    public void setDanmaKuStream(File is) {        mDumakuFile = is;        if (!getDanmakuView().isPrepared()) {            onPrepareDanmaku((DanmakuVideoPlayer) getCurrentPlayer());        }    }    private void initDanmaku() {        // 设置最大显示行数        HashMap
maxLinesPair = new HashMap
(); maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 5); // 滚动弹幕最大显示5行 // 设置是否禁止重叠 HashMap
overlappingEnablePair = new HashMap
(); overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true); overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true); DanamakuAdapter danamakuAdapter = new DanamakuAdapter(mDanmakuView); mDanmakuContext = DanmakuContext.create(); mDanmakuContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 3).setDuplicateMergingEnabled(false).setScrollSpeedFactor(1.2f).setScaleTextSize(1.2f) .setCacheStuffer(new SpannedCacheStuffer(), danamakuAdapter) // 图文混排使用SpannedCacheStuffer .setMaximumLines(maxLinesPair) .preventOverlapping(overlappingEnablePair); if (mDanmakuView != null) { if (mDumakuFile != null) { mParser = createParser(getIsStream(mDumakuFile)); } //todo 这是为了demo效果,实际上需要去掉这个,外部传输文件进来 mParser = createParser(this.getResources().openRawResource(R.raw.comments)); mDanmakuView.setCallback(new master.flame.danmaku.controller.DrawHandler.Callback() { @Override public void updateTimer(DanmakuTimer timer) { } @Override public void drawingFinished() { } @Override public void danmakuShown(BaseDanmaku danmaku) { } @Override public void prepared() { if (getDanmakuView() != null) { getDanmakuView().start(); if (getDanmakuStartSeekPosition() != -1) { resolveDanmakuSeek(DanmakuVideoPlayer.this, getDanmakuStartSeekPosition()); setDanmakuStartSeekPosition(-1); } resolveDanmakuShow(); } } }); mDanmakuView.enableDanmakuDrawingCache(true); } } private InputStream getIsStream(File file) { try { InputStream instream = new FileInputStream(file); InputStreamReader inputreader = new InputStreamReader(instream); BufferedReader buffreader = new BufferedReader(inputreader); String line; StringBuilder sb1 = new StringBuilder(); sb1.append("
"); //分行读取 while ((line = buffreader.readLine()) != null) { sb1.append(line); } sb1.append(""); Log.e("3333333", sb1.toString()); instream.close(); return new ByteArrayInputStream(sb1.toString().getBytes()); } catch (java.io.FileNotFoundException e) { Log.d("TestFile", "The File doesn't not exist."); } catch (IOException e) { Log.d("TestFile", e.getMessage()); } return null; } /** 弹幕的显示与关闭 */ private void resolveDanmakuShow() { post(new Runnable() { @Override public void run() { if (mDanmaKuShow) { if (!getDanmakuView().isShown()) getDanmakuView().show(); mToogleDanmaku.setText("弹幕关"); } else { if (getDanmakuView().isShown()) { getDanmakuView().hide(); } mToogleDanmaku.setText("弹幕开"); } } }); } /** 开始播放弹幕 */ private void onPrepareDanmaku(DanmakuVideoPlayer gsyVideoPlayer) { if (gsyVideoPlayer.getDanmakuView() != null && !gsyVideoPlayer.getDanmakuView().isPrepared() && gsyVideoPlayer.getParser() != null) { gsyVideoPlayer.getDanmakuView().prepare(gsyVideoPlayer.getParser(), gsyVideoPlayer.getDanmakuContext()); } } /** 弹幕偏移 */ private void resolveDanmakuSeek(DanmakuVideoPlayer gsyVideoPlayer, long time) { if (mHadPlay && gsyVideoPlayer.getDanmakuView() != null && gsyVideoPlayer.getDanmakuView().isPrepared()) { gsyVideoPlayer.getDanmakuView().seekTo(time); } } /** 创建解析器对象,解析输入流 @param stream @return */ private BaseDanmakuParser createParser(InputStream stream) { if (stream == null) { return new BaseDanmakuParser() { @Override protected Danmakus parse() { return new Danmakus(); } }; } ILoader loader = DanmakuLoaderFactory.create(DanmakuLoaderFactory.TAG_BILI); try { loader.load(stream); } catch (IllegalDataException e) { e.printStackTrace(); } BaseDanmakuParser parser = new BiliDanmukuParser(); IDataSource
dataSource = loader.getDataSource(); parser.load(dataSource); return parser; } /** 释放弹幕控件 */ private void releaseDanmaku(DanmakuVideoPlayer danmakuVideoPlayer) { if (danmakuVideoPlayer != null && danmakuVideoPlayer.getDanmakuView() != null) { Debuger.printfError("release Danmaku!"); danmakuVideoPlayer.getDanmakuView().release(); } } public BaseDanmakuParser getParser() { if (mParser == null) { if (mDumakuFile != null) { mParser = createParser(getIsStream(mDumakuFile)); } } return mParser; } public DanmakuContext getDanmakuContext() { return mDanmakuContext; } public IDanmakuView getDanmakuView() { return mDanmakuView; } public long getDanmakuStartSeekPosition() { return mDanmakuStartSeekPosition; } public void setDanmakuStartSeekPosition(long danmakuStartSeekPosition) { this.mDanmakuStartSeekPosition = danmakuStartSeekPosition; } public void setDanmaKuShow(boolean danmaKuShow) { mDanmaKuShow = danmaKuShow; } public boolean getDanmaKuShow() { return mDanmaKuShow; } /** 模拟添加弹幕数据 */ private void addDanmaku(boolean islive) { BaseDanmaku danmaku = mDanmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL); if (danmaku == null || mDanmakuView == null) { return; } danmaku.text = "这是一条弹幕 " + getCurrentPositionWhenPlaying(); danmaku.padding = 5; danmaku.priority = 8; // 可能会被各种过滤器过滤并隐藏显示,所以提高等级 danmaku.isLive = islive; danmaku.setTime(mDanmakuView.getCurrentTime() + 500); danmaku.textSize = 25f * (mParser.getDisplayer().getDensity() - 0.6f); danmaku.textColor = Color.RED; danmaku.textShadowColor = Color.WHITE; danmaku.borderColor = Color.GREEN; mDanmakuView.addDanmaku(danmaku); }}

3.Activity中使用该播放器播放

public class VideoPlayActivity extends BaseCommonActivity {    //假地址    String path = "http://vjs.zencdn.net/v/oceans.mp4";    @BindView(R.id.danmaku_player)    DanmakuVideoPlayer danmakuVideoPlayer;    OrientationUtils orientationUtils;    boolean isPlay;    boolean isPause;    boolean isDestory;    @Override    protected void initData() {    }    @Override    protected void initView() {        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);        }        //使用自定义的全屏切换图片,!!!注意xml布局中也需要设置为一样的        //必须在setUp之前设置        danmakuVideoPlayer.setShrinkImageRes(R.drawable.custom_shrink);        danmakuVideoPlayer.setEnlargeImageRes(R.drawable.custom_enlarge);        //String url = "https://res.exexm.com/cw_145225549855002";        String url = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4";        //String url = "https://res.exexm.com/cw_145225549855002";        danmakuVideoPlayer.setUp(url, true, null, "测试视频");        resolveNormalVideoUI();        //外部辅助的旋转,帮助全屏        orientationUtils = new OrientationUtils(this, danmakuVideoPlayer);        //初始化不打开外部的旋转        orientationUtils.setEnable(false);        danmakuVideoPlayer.setIsTouchWiget(true);        //关闭自动旋转        danmakuVideoPlayer.setRotateViewAuto(false);        danmakuVideoPlayer.setLockLand(false);        danmakuVideoPlayer.setShowFullAnimation(false);        danmakuVideoPlayer.setNeedLockFull(true);        //detailPlayer.setOpenPreView(true);        danmakuVideoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //直接横屏                orientationUtils.resolveByClick();                //第一个true是否需要隐藏actionbar,第二个true是否需要隐藏statusbar                danmakuVideoPlayer.startWindowFullscreen(VideoPlayActivity.this, true, true);            }        });        danmakuVideoPlayer.setVideoAllCallBack(new GSYSampleCallBack() {            @Override            public void onPrepared(String url, Object... objects) {                super.onPrepared(url, objects);                //开始播放了才能旋转和全屏                orientationUtils.setEnable(true);                isPlay = true;                getDanmu();            }            @Override            public void onAutoComplete(String url, Object... objects) {                super.onAutoComplete(url, objects);            }            @Override            public void onClickStartError(String url, Object... objects) {                super.onClickStartError(url, objects);            }            @Override            public void onQuitFullscreen(String url, Object... objects) {                super.onQuitFullscreen(url, objects);                if (orientationUtils != null) {                    orientationUtils.backToProtVideo();                }            }        });        danmakuVideoPlayer.setLockClickListener(new LockClickListener() {            @Override            public void onClick(View view, boolean lock) {                if (orientationUtils != null) {                    //配合下方的onConfigurationChanged                    orientationUtils.setEnable(!lock);                }            }        });    }    //获取弹幕    private void getDanmu() {        DanmakuVideoPlayer currentPlayer = (DanmakuVideoPlayer)danmakuVideoPlayer.getCurrentPlayer();        File file = new File("text");        currentPlayer.setDanmaKuStream(file);    }    private void resolveNormalVideoUI() {        //增加title        danmakuVideoPlayer.getTitleTextView().setVisibility(View.GONE);        danmakuVideoPlayer.getBackButton().setVisibility(View.GONE);    }    @Override    protected void bindPresenter() {    }    @Override    public int getLayoutId() {        return R.layout.activity_video_player;    }    @Override    public void onBackPressed() {        if (orientationUtils != null) {            orientationUtils.backToProtVideo();        }        if (GSYVideoManager.backFromWindowFull(this)) {            return;        }        super.onBackPressed();    }    @Override    protected void onPause() {        getCurPlay().onVideoPause();        super.onPause();        isPause = true;    }    @Override    protected void onResume() {        getCurPlay().onVideoResume();        super.onResume();        isPause = false;    }    @Override    protected void onDestroy() {        super.onDestroy();        if (isPlay) {            getCurPlay().release();        }        //GSYPreViewManager.instance().releaseMediaPlayer();        if (orientationUtils != null)            orientationUtils.releaseListener();        isDestory = true;    }    @Override    public void onConfigurationChanged(Configuration newConfig) {        super.onConfigurationChanged(newConfig);        //如果旋转了就全屏        if (isPlay && !isPause) {            danmakuVideoPlayer.onConfigurationChanged(this, newConfig, orientationUtils, true, true);        }    }    private GSYVideoPlayer getCurPlay() {        if (danmakuVideoPlayer.getFullWindowPlayer() != null) {            return  danmakuVideoPlayer.getFullWindowPlayer();        }        return danmakuVideoPlayer;    }}

4.该activity的布局

转载地址:https://blog.csdn.net/kururunga/article/details/87366084 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:JavaEE学习之路 一
下一篇:Failed to resolve: common Open File

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年08月23日 04时22分50秒