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

2019-09-24  本文已影响0人  YongtaoHuang

上一篇: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);
        }
    }
}
上一篇 下一篇

猜你喜欢

热点阅读