Android视频播放器封装

作者: 撸代码的皇太极 | 来源:发表于2019-04-19 12:14 被阅读352次

    推荐一个视频播放器封装库的演示项目:iMusic视频播放器

    之前开发公司项目时,在部分项目中有用到著名的开源项目:节操视频播放器(后更名为饺子播放器)。然而在后期的项目维护时,索性从头开始,独立封装视频播放器框架,封装基础功能,方便后期迭代和维护。现已将其整理开源iMusic
    此播放器支持的特性包括但不限于:体积小、极简集成、完全自定义交互UI、支持常规的横竖屏切换、可拖拽的小窗口切换、可拖拽的全局悬浮窗口播放、界面跳转无缝衔接播放、全屏播放下手势识别调节等功能。网络数据交互采用MVP思想搭建框架。
    我们先来看下iMusic项目效果图:

    体验完整功能请前往iMusic下载体验
    视频播放器框架结构一览:
    播放器框架图示
    图中的TrackListener为播放器本身。如图所示,播放器框架设计之初被封装设计成为了一个可自定义UI、单例、代理模式的交互播放器。本篇将分三大类叙述视频播放器的封装实现过程。

    一、解码渲染

    解码器这里选择基于系统的MediaPlayer实现,如果你想更换解码器,请下载源码自定更换。画面渲染使用TextrueView实现,至于为什么不使用SurfaceView,自行Google一波。

    1.TextureView创建和初始化
       //初始化一个TextureView并添加至ViewGroup或找到你的TextureView 组件
       mTextureView=new TextureView(getContext());
       //设置画布监听
       textureView.setSurfaceTextureListener(this);
       //添加至布局
       fragment.addView(textureView,new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT, Gravity.CENTER));
        /**
         * TextureView准备好了回调
         * @param surface 内部画布渲染surface
         * @param width TextureView布局宽
         * @param height TextureView布局高
         */
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            Logger.d(TAG,"onSurfaceTextureAvailable-->width:"+width+",height:"+height);
            //这里对画面改变、转场播放做了处理,声明一个mSurfaceTexture ,在TextureView发生变化时更新
            if (mSurfaceTexture == null) {
                mSurfaceTexture = surface;
                //prepare();
            } else {
                mTextureView.setSurfaceTexture(mSurfaceTexture);
            }
        }
    
        /**
         * TextureView宽高发生变化时回调
         * @param surface 内部surface
         * @param width 新的TextureView布局宽
         * @param height 新的TextureView布局高
         */
        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
            Logger.d(TAG,"onSurfaceTextureSizeChanged-->width:"+width+",height:"+height);
        }
    
        /**
         * TextureView销毁时回调
         * @param surface 内部surface
         * @return Most applications should return true.
         */
        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            Logger.d(TAG,"onSurfaceTextureDestroyed");
            return null==mSurfaceTexture;
        }
    
        /**
         * TextureView刷新时回调
         * @param surface 内部surface
         */
        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
    
        }
    
    2.MediaPlayer初始化和准备播放
        mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        //设置准备播放监听器,在onPrepared回调中开始播放
        mMediaPlayer.setOnPreparedListener(this);
        //...此处省去一系列监听设置
        //异步准备
        mMediaPlayer.prepareAsync();
        
        /**
         * 播放器准备好了
         * @param mp 解码器
         */
        @Override
        public void onPrepared(MediaPlayer mp) {
            Logger.d(TAG,"onPrepared");
            if(null!=mSurfaceTexture){
                if(null!=mSurface){
                    mSurface.release();
                    mSurface=null;
                }
                mSurface =new Surface(mSurfaceTexture);
                mp.setSurface(mSurface);
            }
            //开始播放
            mp.start();
        }
    

    二、单例

    要实现单例播放,就必须有个被设计为单例模式的第三方委托代理类持有MediaPlayer,此库就取名为 VideoPlayerManager,VideoPlayerManager持有MediaPlayer和TextureView。播放视频前需要先释放一波,然后更新监听器。

        /**
         * 开始播放的入口开始播放、准备入口
         */-
        public void startPlayVideo(){
            //还原可能正在进行的播放任务
            VideoPlayerManager.getInstance().onReset();
            //更新内部监听器
            VideoPlayerManager.getInstance().addOnPlayerEventListener(this);
            //这个用在列表销毁时判断播放器是否需要销毁
            setWorking(true);
            //准备画面渲染图层
            if(null!=mSurfaceView){
                addTextrueViewToView(BaseVideoPlayer.this);
                //开始准备播放
                VideoPlayerManager.getInstance().startVideoPlayer(mDataSource,getContext());
            }
        }
        //VideoPlayerManager.getInstance().onReset();
        /**
         * 放播放器
         */
        private void reset() {
            try {
                if(null!=mMediaPlayer){
                    if(mMediaPlayer.isPlaying()){
                        mMediaPlayer.stop();
                    }
                    mMediaPlayer.reset();
                    mMediaPlayer.release();
                    mMediaPlayer=null;
                }
            }catch (RuntimeException e){
                e.printStackTrace();
            }
        }
    

    三、自定义交互UI

    播放器提供了三个交互类型的基类,分别是BaseVideoController(播放控制器)、BaseCoverController(封面控制器)、BaseGestureController(手势识别控制器),要实现自定义UI交互,需继承此三个类实现自己的业务交互。播放事件的UI刷新机制,是由BaseVideoPlayer统一调度,

    1. 自定义交互控制器

    交互控制器在本项目中被定义为:用户与播放器的UI交互控制器。如需自定义请继承BaseVideoController类并实现其抽象方法,调用播放器通道的setVideoController(V controller);绑定控制器。</br>
    如在播放过程中开启小窗口、悬浮窗播放器时,可指定控制器小窗口、悬浮窗专用的交互控制器。悬浮窗口的关闭按钮不支持自定义。另外,控制器还提供了子线程中的播放进度方法,100毫秒执行一次,主线程的播放进度方法是1000毫秒执行一次,请注意你的UI刷新。

    2. 自定义封面控制器

    封面控制器是指视频在开始播放前的封面显示图层,如需自定义请继承BaseCoverController类,调用播放器通道的setVideoCoverController(C controller);绑定控制器。BaseCoverController中默认实现了点击开始播放能力。若需自定义点击自己的View开始播放,请实现点击事件后
    调用BaseCoverController的mOnStartListener.onStartPlay();方法开始播放。

    3. 自定义手势识别器

    手势识别器是播放器在全屏状态下播放时,播放器内部检测用户手势滑动行为对播放器功能做出改变时的UI交互提示,如快进、快退、音量、亮度等调节后的UI显示交互,如需自定义
    请继承BaseGestureController类,实现其抽象方法,调用调用播放器通道的setVideoGestureController(G controller);绑定控制器。自定义手势识别器还支持消费手势触摸事件,详见BaseGestureController抽象方法onTouchEnevt介绍。

    全部功能请阅读视频播放器Wiki

    相关文章

      网友评论

        本文标题:Android视频播放器封装

        本文链接:https://www.haomeiwen.com/subject/esdqgqtx.html