Skip to content

Simple usage

贾俊辉 edited this page Sep 19, 2020 · 1 revision

基本组件使用

使用BaseVideoView对象,可写入xml布局中,也可用代码创建。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.kk.taurus.playerbase.widget.BaseVideoView
        android:id="@+id/videoView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

添加组件设置数据

mVideoView = findViewById(R.id.videoView);
mVideoView.setOnPlayerEventListener(this);
mVideoView.setOnReceiverEventListener(this);

ReceiverGroup receiverGroup = new ReceiverGroup();
receiverGroup.addReceiver(KEY_LOADING_COVER, new LoadingCover(context));
receiverGroup.addReceiver(KEY_CONTROLLER_COVER, new ControllerCover(context));
receiverGroup.addReceiver(KEY_COMPLETE_COVER, new CompleteCover(context));
receiverGroup.addReceiver(KEY_ERROR_COVER, new ErrorCover(context));
mVideoView.setReceiverGroup(receiverGroup);

//设置一个事件处理器
mVideoView.setEventHandler(new OnVideoViewEventHandler());

//设置DataSource
mVideoView.setDataSource(new DataSource("url...."));
mVideoView.start();

AVPlayer的使用

如果您想直接使用AVPlayer自己进行处理播放,那么大致步骤如下:
1.初始化一个AVPlayer对象。
2.初始化一个SuperContainer对象,将ReceiverGroup设置到SuperContainer中。
3.使用SuperContainer设置一个渲染视图Render,然后自己处理RenderCallBack并关联解码器。

代码如下:

SuperContainer mSuperContainer = new SuperContainer(context);
ReceiverGroup receiverGroup = new ReceiverGroup();
receiverGroup.addReceiver(KEY_LOADING_COVER, new LoadingCover(context));
receiverGroup.addReceiver(KEY_CONTROLLER_COVER, new ControllerCover(context));
receiverGroup.addReceiver(KEY_COMPLETE_COVER, new CompleteCover(context));
receiverGroup.addReceiver(KEY_ERROR_COVER, new ErrorCover(context));
mSuperContainer.setReceiverGroup(receiverGroup);

final RenderTextureView render = new RenderTextureView(mAppContext);
render.setTakeOverSurfaceTexture(true);
//....

mPlayer.setOnPlayerEventListener(new OnPlayerEventListener() {
    @Override
    public void onPlayerEvent(int eventCode, Bundle bundle) {
        if(eventCode==OnPlayerEventListener.PLAYER_EVENT_ON_VIDEO_SIZE_CHANGE){
            mVideoWidth = bundle.getInt(EventKey.INT_ARG1);
            mVideoHeight = bundle.getInt(EventKey.INT_ARG2);
            mVideoSarNum = bundle.getInt(EventKey.INT_ARG3);
            mVideoSarDen = bundle.getInt(EventKey.INT_ARG4);
            render.updateVideoSize(mVideoWidth, mVideoHeight);
            render.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
        }else if(eventCode==OnPlayerEventListener.PLAYER_EVENT_ON_VIDEO_ROTATION_CHANGED){
            mVideoRotation = bundle.getInt(EventKey.INT_DATA);
            render.setVideoRotation(mVideoRotation);
        }else if(eventCode==OnPlayerEventListener.PLAYER_EVENT_ON_PREPARED){
            bindRenderHolder(mRenderHolder);
        }
        //将事件分发给子视图
        mSuperContainer.dispatchPlayEvent(eventCode, bundle);
    }
});
mPlayer.setOnErrorEventListener(new OnErrorEventListener() {
    @Override
    public void onErrorEvent(int eventCode, Bundle bundle) {
        //将事件分发给子视图
        mSuperContainer.dispatchErrorEvent(eventCode, bundle);
    }
});
mSuperContainer.setOnReceiverEventListener(mInternalReceiverEventListener);
render.setRenderCallback(new IRender.IRenderCallback() {
    @Override
    public void onSurfaceCreated(IRender.IRenderHolder renderHolder, int width, int height) {
        mRenderHolder = renderHolder;
        bindRenderHolder(mRenderHolder);
    }
    @Override
    public void onSurfaceChanged(IRender.IRenderHolder renderHolder, int format, int width, int height) {

    }
    @Override
    public void onSurfaceDestroy(IRender.IRenderHolder renderHolder) {
        mRenderHolder = null;
    }
});
mSuperContainer.setRenderView(render.getRenderView());
mPlayer.setDataSource(dataSource);
mPlayer.start();

接入其他播放器

具体参见项目代码 IjkPlayer。
使用前做如下配置:

PlayerConfig.addDecoderPlan(new DecoderPlan(1, IjkPlayer.class.getName(), "IjkPlayer"));
PlayerConfig.setDefaultPlanId(1);

解码器的切换

int PLAN_ID_IJK = 1;
mVideoView.switchDecoder(PLAN_ID_IJK);
mVideoView.setDataSource(dataSource);
mVideoView.start();

组件视图

demo示例代码演示接入了Loading组件、Controller组件、CompleteCover组件。
这些组件均继承自父类BaseCover(覆盖层基类)

自定义覆盖层cover组件

public class CustomCover extends BaseCover{
	
    public CustomCover(Context context) {
        super(context);
    }

    @Override
    public void onPlayerEvent(int eventCode, Bundle bundle) {
        //...
    }
    
    @Override
    public void onErrorEvent(int eventCode, Bundle bundle) {
        //...
    }

    @Override
    public void onReceiverEvent(int eventCode, Bundle bundle) {
	//...
    }

    @Override
    public View onCreateCoverView(Context context) {
        return View.inflate(context, R.layout.layout_custom_cover, null);
    }
    //......	
}

自定义组件的使用。

ReceiverGroup receiverGroup = new ReceiverGroup();
receiverGroup.addReceiver("loading_cover", new CustomCover(context));
mPlayer.setReceiverGroup(receiverGroup);

无缝续播的使用

类似于今日头条等应用的列表播放效果,在列表中播放时无缝续播进入详情页或者无缝进入全屏页面。

原理:解码器动态关联不同的渲染视图(RenderView),比如使用MediaPlayer动态关联SurfaceView,就如同一个电脑主机不断连接不同的显示器。

版本3.2.0之后增加了关联助手,让无缝续播的使用更加简单化。使用关联播放时,您需要提供一个播放视图的容器。比如您要把正在view1容器中播放的画面切换到view2容器中,那么您只需要把view2的容器关联到助手即可。如下示例:

public class TestActivity extends AppcompatActivity{

	RelationAssist mAssist;
	ViewGroup view2;

	public void onCreate(Bundle saveInstance){
		super.onCreate(saveInstance);
		 
		//...
		 
		mAssist = new RelationAssist(this);
		mAssist.setEventAssistHandler(eventHandler);
		mReceiverGroup = ReceiverGroupManager.get().getLiteReceiverGroup(this);
		mAssist.setReceiverGroup(mReceiverGroup);
		DataSource dataSource = new DataSource();
		dataSource.setData("http://...");
		dataSource.setTitle("xxx");
		mAssist.setDataSource(dataSource);
		mAssist.attachContainer(mVideoContainer);
		mAssist.play();
		    
		//...
		switchPlay(view2);
	}
	
	private void switchPlay(ViewGroup container){
		 mAssist.attachContainer(container);
	}

}

更加详细的操作请参见项目demo。

Window模式播放

框架提供了一个WindowVideoView,如果您并不需要对Window进行无缝切播的话,请使用这个WindowVideoView,使用很简单,如下代码示例:

public class WindowVideoViewActivity extends AppCompatActivity {

    WindowVideoView mWindowVideoView;

    DataSource mDataSource;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_window_video_view);
        int width = 640;
        int height = 360;
        mWindowVideoView = new WindowVideoView(this,
                new FloatWindowParams()
                        .setX(100)
                        .setY(100)
                        .setWidth(width)
                        .setHeight(height)
                        .setGravity(Gravity.TOP | Gravity.LEFT));
        mWindowVideoView.setBackgroundColor(Color.BLACK);
		 //...
        mWindowVideoView.setReceiverGroup(receiverGroup);

        mDataSource = new DataSource();
        mDataSource.setData("http://...");
        mDataSource.setTitle("xxx");
    }

    public void activeWindowVideoView(View view){
        if(mWindowVideoView.isWindowShow()){
            mWindowVideoView.close();
        }else{
            mWindowVideoView.show();
            mWindowVideoView.setDataSource(mDataSource);
            mWindowVideoView.start();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mWindowVideoView.close();
        mWindowVideoView.stopPlayback();
    }
}

如果您需要在Window模式下使用无缝续播,那么请将FloatWindow和RelationAssist二者结合使用。 此处不做代码展示,如需要可进入项目参见WindowSwitchPlayActivity中的代码示例。

数据提供者DataProvider的接入

数据提供者的定义是为了更好的进行播控统一的完整性而设计的。比如Server端给你的是id,你需要用id再去请求某个接口取播放的url,这时我们可以把由id到url这个过程统一的做一个处理,就由DataProvider来完成这个对接过程。

public class MonitorDataProvider extends BaseDataProvider {
    
    @Override
    public void handleSourceData(DataSource sourceData) {
        //callback start
        onProviderDataStart(sourceData);
        loadData();
    }
    
    private void loadData(DataSource dataSource){
        //...
        if(sucess){
            Bundle bundle = BundlePool.obtain();
            bundle.putSerializable(EventKey.SERIALIZABLE_DATA, mDataSource);
            //callback success
            onProviderMediaDataSuccess(bundle);
        }else{
            //callback error
            onProviderError(IDataProvider.PROVIDER_CODE_DATA_PROVIDER_ERROR, null);
        }
    }

    @Override
    public void cancel() {
        //...
    }

    @Override
    public void destroy() {
        cancel();
    }
}