美文网首页
九、Android视频框架PlayerBase#事件处理流程

九、Android视频框架PlayerBase#事件处理流程

作者: YongtaoHuang | 来源:发表于2019-09-24 10:15 被阅读0次

    上一篇:https://www.jianshu.com/p/5de2ee571728

    下一篇:
    https://www.jianshu.com/p/1840eb899ef4

    BaseVideoView主要事件

    BaseVideoView主要事件分三块:
    1、setOnPlayerEventListener
    2、setOnErrorEventListener
    3、setOnReceiverEventListener

        public BaseVideoView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context, attrs, defStyleAttr);
        }
    
        private void init(Context context, AttributeSet attrs, int defStyleAttr) {
            mPlayer = createPlayer();
            //attach listener
            mPlayer.setOnPlayerEventListener(mInternalPlayerEventListener);
            mPlayer.setOnErrorEventListener(mInternalErrorEventListener);
            //init style setter.
            mStyleSetter = new StyleSetter(this);
            mSuperContainer = onCreateSuperContainer(context);
            mSuperContainer.setStateGetter(mInternalStateGetter);
            mSuperContainer.setOnReceiverEventListener(mInternalReceiverEventListener);
            addView(mSuperContainer,
                    new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                            ViewGroup.LayoutParams.MATCH_PARENT));
        }
    

    具体来分析setOnPlayerEventListener、setOnErrorEventListener和setOnReceiverEventListener这三个事件监听器方法。
    其中:setOnPlayerEventListener和setOnErrorEventListener属于AVPlayer;
    setOnReceiverEventListener属于SuperContainer。

    public final class AVPlayer implements IPlayer{
        // 播放事件监听器
        private OnPlayerEventListener mOnPlayerEventListener;
        // 错误事件监听器
        private OnErrorEventListener mOnErrorEventListener;
    
        @Override
        public void setOnPlayerEventListener(OnPlayerEventListener onPlayerEventListener) {
            this.mOnPlayerEventListener = onPlayerEventListener;
        }
    
        @Override
        public void setOnErrorEventListener(OnErrorEventListener onErrorEventListener) {
            this.mOnErrorEventListener = onErrorEventListener;
        }
    }
    
    public class SuperContainer extends FrameLayout implements OnTouchGestureListener {
        // 接收器事件监听器
        private OnReceiverEventListener mOnReceiverEventListener;
        public void setOnReceiverEventListener(OnReceiverEventListener onReceiverEventListener) {
            this.mOnReceiverEventListener = onReceiverEventListener;
        }
    }
    

    具体看一下OnPlayerEventListener、OnErrorEventListener和OnReceiverEventListener这三个接口:

    public interface OnPlayerEventListener {
        // -990开头的播放代码
        void onPlayerEvent(int eventCode, Bundle bundle);
    }
    
    public interface OnErrorEventListener {
        // -880开头的错误代码
        void onErrorEvent(int eventCode, Bundle bundle);
    }
    
    public interface OnReceiverEventListener {
        void onReceiverEvent(int eventCode, Bundle bundle);
    }
    

    具体阅读OnPlayerEventListener

    OnPlayerEventListener接口具体实现在BaseVideoView和AVPlayer中:

    public class BaseVideoView extends FrameLayout implements IVideoView, IStyleSetter {
       private OnPlayerEventListener mInternalPlayerEventListener =
                new OnPlayerEventListener() {
            @Override
            public void onPlayerEvent(int eventCode, Bundle bundle) {
                switch (eventCode){
                    // 播放器尺寸改变
                    case OnPlayerEventListener.PLAYER_EVENT_ON_VIDEO_SIZE_CHANGE:
                        if(bundle!=null){
                            mVideoWidth = bundle.getInt(EventKey.INT_ARG1);
                            mVideoHeight = bundle.getInt(EventKey.INT_ARG2);
                            mVideoSarNum = bundle.getInt(EventKey.INT_ARG3);
                            mVideoSarDen = bundle.getInt(EventKey.INT_ARG4);
                            PLog.d(TAG,"onVideoSizeChange : videoWidth = " + mVideoWidth
                                    + ", videoHeight = " + mVideoHeight
                                    + ", videoSarNum = " + mVideoSarNum
                                    + ", videoSarDen = " + mVideoSarDen);
                            if(mRender!=null){
                                //update video size
                                mRender.updateVideoSize(mVideoWidth, mVideoHeight);
                                //update video sarNum,sarDen
                                mRender.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
                            }
                        }
                        break;
                    // 播放器旋转
                    case OnPlayerEventListener.PLAYER_EVENT_ON_VIDEO_ROTATION_CHANGED:
                        if(bundle!=null){
                            //if rotation change need update render.
                            mVideoRotation = bundle.getInt(EventKey.INT_DATA);
                            PLog.d(TAG,"onVideoRotationChange : videoRotation = " + mVideoRotation);
                            if(mRender!=null)
                                mRender.setVideoRotation(mVideoRotation);
                        }
                        break;
                    // 准备好绑定到SurfaceView上
                    case OnPlayerEventListener.PLAYER_EVENT_ON_PREPARED:
                        if(bundle!=null && mRender!=null){
                            mVideoWidth = bundle.getInt(EventKey.INT_ARG1);
                            mVideoHeight = bundle.getInt(EventKey.INT_ARG2);
                            mRender.updateVideoSize(mVideoWidth, mVideoHeight);
                        }
                        bindRenderHolder(mRenderHolder);
                        break;
                    // 缓存开始
                    case OnPlayerEventListener.PLAYER_EVENT_ON_BUFFERING_START:
                        isBuffering = true;
                        break;
                    // 缓存结束
                    case OnPlayerEventListener.PLAYER_EVENT_ON_BUFFERING_END:
                        isBuffering = false;
                        break;
                }
                if(mOnPlayerEventListener!=null)
                    mOnPlayerEventListener.onPlayerEvent(eventCode, bundle);
                //last dispatch event , because bundle will be recycle after dispatch.
                mSuperContainer.dispatchPlayEvent(eventCode, bundle);
            }
        };
    }
    
    public final class AVPlayer implements IPlayer{
        private OnPlayerEventListener mInternalPlayerEventListener =
                new OnPlayerEventListener() {
            @Override
            public void onPlayerEvent(int eventCode, Bundle bundle) {
                mTimerCounterProxy.proxyPlayEvent(eventCode, bundle);
                // 准备开始播放
                if(eventCode==OnPlayerEventListener.PLAYER_EVENT_ON_PREPARED){
                    //when prepared set volume value
                    if(mVolumeLeft >= 0 || mVolumeRight >= 0){
                        mInternalPlayer.setVolume(mVolumeLeft, mVolumeRight);
                    }
                // 播放结束
                }else if(eventCode==OnPlayerEventListener.PLAYER_EVENT_ON_PLAY_COMPLETE){
                    int duration = getDuration();
                    int bufferPercentage = getBufferPercentage();
                    //check valid data.
                    if(duration <= 0 && !isLive())
                        return;
                    onTimerUpdateEvent(duration, duration, bufferPercentage);
                }
                if(isPlayRecordOpen())
                    mRecordProxyPlayer.onPlayerEvent(eventCode, bundle);
                callBackPlayEventListener(eventCode, bundle);
            }
        };
    }
    

    再具体到播放和暂停两个事件的处理

    我们回到OnPlayerEventListener接口代码中:

    public interface OnPlayerEventListener {
        /**
         * when you call {@link IPlayer#start()}
         */
        int PLAYER_EVENT_ON_START = -99004;
    
        /**
         * when you call {@link IPlayer#pause()}
         */
        int PLAYER_EVENT_ON_PAUSE = -99005;
        void onPlayerEvent(int eventCode, Bundle bundle);
    }
    

    再ExoMediaPlayer 类中使用到了PLAYER_EVENT_ON_START和PLAYER_EVENT_ON_PAUSE两个参数。

    public class ExoMediaPlayer extends BaseInternalPlayer {
        @Override
        public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
            
            // 视频不处于正在准备状态
            if(!isPreparing){
                // 是否打开即播放
                if(playWhenReady){
                    updateStatus(IPlayer.STATE_STARTED);
                    // 提交恢复播放事件
                    submitPlayerEvent(OnPlayerEventListener.PLAYER_EVENT_ON_RESUME, null);
                }else{
                    updateStatus(IPlayer.STATE_PAUSED);
                    // 提交暂停播放事件
                    submitPlayerEvent(OnPlayerEventListener.PLAYER_EVENT_ON_PAUSE, null);
                }
            }
            // 视频处于正在准备状态
            if(isPreparing){
                switch (playbackState){
                    // 准备完毕
                    case Player.STATE_READY:
                        isPreparing = false;
                        Format format = mInternalPlayer.getVideoFormat();
                        Bundle bundle = BundlePool.obtain();
                        if(format!=null){
                            bundle.putInt(EventKey.INT_ARG1, format.width);
                            bundle.putInt(EventKey.INT_ARG2, format.height);
                        }
                        updateStatus(IPlayer.STATE_PREPARED);
                        // 提交准备播放事件
                        submitPlayerEvent(OnPlayerEventListener.PLAYER_EVENT_ON_PREPARED, bundle);
    
                        if(playWhenReady){
                            updateStatus(STATE_STARTED);
                            // 提交开始播放事件
                            submitPlayerEvent(OnPlayerEventListener.PLAYER_EVENT_ON_START, null);
                        }
    
                        if(mStartPos > 0){
                            mInternalPlayer.seekTo(mStartPos);
                            mStartPos = -1;
                        }
                        break;
                }
            }
        }
    
    }
    

    上述代码的核心方法BaseInternalPlayer#submitPlayerEvent():

    public abstract class BaseInternalPlayer implements IPlayer {
        private OnPlayerEventListener mOnPlayerEventListener;
        // 提交播放器事件
        protected final void submitPlayerEvent(int eventCode, Bundle bundle){
            if(mOnPlayerEventListener!=null)
                mOnPlayerEventListener.onPlayerEvent(eventCode, bundle);
        }
    }
    

    查看对于接口OnPlayerEventListener#onPlayerEvent()方法,对于PLAYER_EVENT_ON_START和PLAYER_EVENT_ON_PAUSE两种事件的具体反应。

    从播放/暂停按钮入手

    播放/暂停的drawable:selector_play_state.xml

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_selected="true">
            <bitmap android:src="@mipmap/ic_video_player_btn_play"/>
        </item>
        <item>
            <bitmap android:src="@mipmap/ic_video_player_btn_pause"/>
        </item>
    </selector>
    

    哪里使用了上述selector呢?layout_controller_cover.xml

            <ImageView
                android:id="@+id/cover_player_controller_image_view_play_state"
                android:layout_width="wrap_content"
                android:layout_height="16dp"
                android:paddingLeft="10dp"
                android:paddingRight="10dp"
                android:scaleType="centerInside"
                android:src="@drawable/selector_play_state"/>
    

    ControllerCover里面有一个播放/暂停按钮。

    public class ControllerCover extends BaseCover implements OnTimerUpdateListener, OnTouchGestureListener{
        @BindView(R.id.cover_player_controller_image_view_play_state)
        ImageView mStateIcon;
        public void onViewClick(View view){
            switch (view.getId()){
                case R.id.cover_player_controller_image_view_play_state:
                    boolean selected = mStateIcon.isSelected();
                    if(selected){
                        requestResume(null);
                    }else{
                        requestPause(null);
                    }
                    mStateIcon.setSelected(!selected);
                    break;
                case 
            }
        }
    }
    

    上述代码中requestResume()和requestPause()两个方法源自于BaseCover类:

    public abstract class BaseCover extends BaseReceiver implements
            ICover, ICoverHandle, View.OnAttachStateChangeListener {
        @Override
        public final void requestResume(Bundle bundle) {
            notifyReceiverEvent(InterEvent.CODE_REQUEST_RESUME, bundle);
        }
    
        @Override
        public final void requestSeek(Bundle bundle) {
            notifyReceiverEvent(InterEvent.CODE_REQUEST_SEEK, bundle);
        }
    }
    

    上述代码中notifyReceiverEvent()方法源自于类BaseReceiver:

    public abstract class BaseReceiver implements IReceiver, StateGetter {
    
        private Context mContext;
        private OnReceiverEventListener mOnReceiverEventListener;
    
        protected final void notifyReceiverEvent(int eventCode, Bundle bundle){
            if(mOnReceiverEventListener!=null)
                mOnReceiverEventListener.onReceiverEvent(eventCode, bundle);
        }
    }
    

    上述代码中的onReceiverEvent()方法源自于接口onReceiverEvent

    public interface OnReceiverEventListener {
        void onReceiverEvent(int eventCode, Bundle bundle);
    }
    

    返回寻找onReceiverEvent的实现类RelationAssist:

    public final class RelationAssist implements AssistPlay {
        private OnReceiverEventListener mOnReceiverEventListener;
    
        private OnAssistPlayEventHandler mOnEventAssistHandler;
    
        private OnReceiverEventListener mInternalReceiverEventListener =
                new OnReceiverEventListener() {
            @Override
            public void onReceiverEvent(int eventCode, Bundle bundle) {
                if(eventCode == InterEvent.CODE_REQUEST_NOTIFY_TIMER){
                    mPlayer.setUseTimerProxy(true);
                }else if(eventCode == InterEvent.CODE_REQUEST_STOP_TIMER){
                    mPlayer.setUseTimerProxy(false);
                }
                //if setting AssistEventHandler, call back it to handle.
                if(mOnEventAssistHandler !=null)
                    mOnEventAssistHandler.onAssistHandle(RelationAssist.this, eventCode, bundle);
                if(mOnReceiverEventListener!=null)
                    mOnReceiverEventListener.onReceiverEvent(eventCode, bundle);
            }
        };
    }
    

    事实上是通过OnAssistPlayEventHandler#onAssistHandle()方法实现播放/暂停:

    public abstract class BaseEventAssistHandler<T> implements OnEventAssistHandler<T> {
    
        @Override
        public void onAssistHandle(T assist, int eventCode, Bundle bundle) {
            switch (eventCode){
                case InterEvent.CODE_REQUEST_PAUSE:
                    requestPause(assist, bundle);
                    break;
                case InterEvent.CODE_REQUEST_RESUME:
                    requestResume(assist, bundle);
                    break;
            }
        }
    
    }
    
    
    

    类OnAssistPlayEventHandler源码:

    public class OnAssistPlayEventHandler extends BaseEventAssistHandler<AssistPlay> {
    
        @Override
        public void requestPause(BaseVideoView videoView, Bundle bundle) {
            if(isInPlaybackState(videoView)){
                videoView.pause();
            }else{
                videoView.stop();
            }
        }
    
        @Override
        public void requestResume(BaseVideoView videoView, Bundle bundle) {
            if(isInPlaybackState(videoView)){
                videoView.resume();
            }else{
                requestRetry(videoView, bundle);
            }
        }
    }
    

    上述代码播放/暂停事件流程图如下:


    暂停播放事件流程.png

    BaseVideoView中含有OnReceiverEventListener和OnVideoViewEventHandler

    public class BaseVideoView extends FrameLayout implements IVideoView, IStyleSetter {
    
        private OnReceiverEventListener mOnReceiverEventListener;
    
        private OnVideoViewEventHandler mEventAssistHandler;
    
        private OnReceiverEventListener mInternalReceiverEventListener =
                new OnReceiverEventListener() {
            @Override
            public void onReceiverEvent(int eventCode, Bundle bundle) {
                if(eventCode == InterEvent.CODE_REQUEST_NOTIFY_TIMER){
                    mPlayer.setUseTimerProxy(true);
                }else if(eventCode == InterEvent.CODE_REQUEST_STOP_TIMER){
                    mPlayer.setUseTimerProxy(false);
                }
                if(mEventAssistHandler!=null)
                    mEventAssistHandler.onAssistHandle(BaseVideoView.this, eventCode, bundle);
                if(mOnReceiverEventListener!=null)
                    mOnReceiverEventListener.onReceiverEvent(eventCode, bundle);
            }
        };
    }
    

    OnVideoViewEventHandler

    首先分析OnVideoViewEventHandler#onAssistHandle()方法。
    OnVideoViewEventHandler继承抽象类BaseEventAssistHandler实现接口OnEventAssistHandler

    接口OnEventAssistHandler源码:

    public interface OnEventAssistHandler<T> {
    
        void onAssistHandle(T assist, int eventCode, Bundle bundle);
    
        void requestPause(T assist, Bundle bundle);
        void requestResume(T assist, Bundle bundle);
    }
    

    抽象类BaseEventAssistHandler源码:

    public abstract class BaseEventAssistHandler<T> implements OnEventAssistHandler<T> {
    
        @Override
        public void onAssistHandle(T assist, int eventCode, Bundle bundle) {
            switch (eventCode){
                case InterEvent.CODE_REQUEST_PAUSE:
                    requestPause(assist, bundle);
                    break;
                case InterEvent.CODE_REQUEST_RESUME:
                    requestResume(assist, bundle);
                    break;
            }
        }
    
    }
    

    类OnVideoViewEventHandler 源码:

    public class OnVideoViewEventHandler extends BaseEventAssistHandler<BaseVideoView> {
    
        @Override
        public void requestPause(BaseVideoView videoView, Bundle bundle) {
            if(isInPlaybackState(videoView)){
                videoView.pause();
            }else{
                videoView.stop();
            }
        }
    
        @Override
        public void requestResume(BaseVideoView videoView, Bundle bundle) {
            if(isInPlaybackState(videoView)){
                videoView.resume();
            }else{
                requestRetry(videoView, bundle);
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:九、Android视频框架PlayerBase#事件处理流程

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