美文网首页
十、Android视频框架PlayerBase#渲染流程

十、Android视频框架PlayerBase#渲染流程

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

上一篇:https://www.jianshu.com/p/3f39c4652d5b

IPlayer接口中的两个渲染方法

public interface IPlayer {
    void setDisplay(SurfaceHolder surfaceHolder);
    void setSurface(Surface surface);
}

两个渲染方法分别使用了SurfaceHolder和Surface,位于/android/view/。
具体实现类AVPlayer:

public final class AVPlayer implements IPlayer{
    private BaseInternalPlayer mInternalPlayer;
    // 调用BaseInternalPlayer内置的setDisplay和setSurface方法来操作。
    @Override
    public void setDisplay(SurfaceHolder surfaceHolder) {
        if(isPlayerAvailable())
            mInternalPlayer.setDisplay(surfaceHolder);
    }

    @Override
    public void setSurface(Surface surface) {
        if(isPlayerAvailable())
            mInternalPlayer.setSurface(surface);
    }
}

上述代码调用BaseInternalPlayer内置的setDisplay和setSurface方法来操作,如果采用ExoMediaPlayer:

public class ExoMediaPlayer extends BaseInternalPlayer {
    private SimpleExoPlayer mInternalPlayer;

    // 调用SimpleExoPlayer 内置的setDisplay和setSurface方法来操作,再往下走就进入EXO源码了
    @Override
    public void setDisplay(SurfaceHolder surfaceHolder) {
        mInternalPlayer.setVideoSurfaceHolder(surfaceHolder);
        submitPlayerEvent(OnPlayerEventListener.PLAYER_EVENT_ON_SURFACE_HOLDER_UPDATE, null);
    }

    @Override
    public void setSurface(Surface surface) {
        mInternalPlayer.setVideoSurface(surface);
        submitPlayerEvent(OnPlayerEventListener.PLAYER_EVENT_ON_SURFACE_UPDATE, null);
    }
}

上述代码调用了调用SimpleExoPlayer 内置的setDisplay和setSurface方法来操作,再往下走就进入EXO源码了,setDisplay将在下述的IRender接口中调用。

接口IRender

public interface IRender {
    interface IRenderHolder{
        void bindPlayer(IPlayer player);
    }
}

举RenderSurfaceView为例子分析,RenderTextureView流程一样:

public class RenderSurfaceView extends SurfaceView implements IRender {

    private static final class InternalRenderHolder implements IRenderHolder{

        private WeakReference<SurfaceHolder> mSurfaceHolder;

        public InternalRenderHolder(SurfaceHolder surfaceHolder){
            this.mSurfaceHolder = new WeakReference<>(surfaceHolder);
        }

        @Override
        public void bindPlayer(IPlayer player) {
            if(player!=null && mSurfaceHolder.get()!=null){
                player.setDisplay(mSurfaceHolder.get());
            }
        }
    }
}

RenderSurfaceView中调用了player#setDisplay()方法。

回到BaseVideoView

public class MyVideoViewActivity extends AppCompatActivity {

    private BaseVideoView mVideoView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_video_view);
        mVideoView = findViewById(R.id.myBaseVideoView);
        
        DataSource dataSource = new DataSource(DataUtils.VIDEO_URL_09);
        dataSource.setTitle("音乐和艺术如何改变世界");
        mVideoView.setDataSource(dataSource);

        mVideoView.start();
    }

}

进入BaseVideoView#setDataSource()方法:

public class BaseVideoView extends FrameLayout implements IVideoView, IStyleSetter {
    @Override
    public void setDataSource(DataSource dataSource) {
        //init AudioManager
        requestAudioFocus();
        //release render on data change.
        releaseRender();
        //Reconfigure the rendering view each time the resource is switched
        // 每次切换资源时重新配置呈现视图
        setRenderType(mRenderType);
        //set data to player
        mPlayer.setDataSource(dataSource);
    }
}

继续进入BaseVideoView#setRenderType()方法,每次切换资源时重新配置呈现视图:

public class BaseVideoView extends FrameLayout implements IVideoView, IStyleSetter {
    @Override
    public void setRenderType(int renderType) {
        boolean renderChange = mRenderType!=renderType;
        if(!renderChange && mRender!=null && !mRender.isReleased())
            return;
        releaseRender();
        switch (renderType){
            case IRender.RENDER_TYPE_SURFACE_VIEW:
                mRenderType = IRender.RENDER_TYPE_SURFACE_VIEW;
                mRender = new RenderSurfaceView(getContext());
                break;
            default:
            case IRender.RENDER_TYPE_TEXTURE_VIEW:
                mRenderType = IRender.RENDER_TYPE_TEXTURE_VIEW;
                mRender = new RenderTextureView(getContext());
                ((RenderTextureView)mRender).setTakeOverSurfaceTexture(true);
                break;
        }
        //clear render holder
        mRenderHolder = null;
        mPlayer.setSurface(null);
        mRender.updateAspectRatio(mAspectRatio);
        // 设置渲染回调方法
        mRender.setRenderCallback(mRenderCallback);
        //update some params
        mRender.updateVideoSize(mVideoWidth, mVideoHeight);
        mRender.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
        //update video rotation
        mRender.setVideoRotation(mVideoRotation);
        //add to container
        mSuperContainer.setRenderView(mRender.getRenderView());
    }
}

关于BaseVideoView#mRenderCallback源码如下,设置渲染回调方法:

    //on render holder ready ,bind the player.
    private void bindRenderHolder(IRender.IRenderHolder renderHolder){
        if(renderHolder!=null)
            renderHolder.bindPlayer(mPlayer);
    }

    private IRender.IRenderCallback mRenderCallback = new IRender.IRenderCallback() {
        @Override
        public void onSurfaceCreated(IRender.IRenderHolder renderHolder, int width, int height) {
            //on surface create ,try to attach player.
            mRenderHolder = renderHolder;
            bindRenderHolder(mRenderHolder);
        }
        @Override
        public void onSurfaceChanged(IRender.IRenderHolder renderHolder,
                                     int format, int width, int height) {
        }
        @Override
        public void onSurfaceDestroy(IRender.IRenderHolder renderHolder) {

        }
    };

其中onSurfaceCreated()方法中bindRenderHolder(mRenderHolder)中的renderHolder.bindPlayer(mPlayer),那么什么地方调用onSurfaceCreated()方法?位于RenderSurfaceView的内部类InternalSurfaceHolderCallback,mRenderCallback.onSurfaceCreated(new InternalRenderHolder(holder),0,0);

public class RenderSurfaceView extends SurfaceView implements IRender {

    public RenderSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mRenderMeasure = new RenderMeasure();
        getHolder().addCallback(new InternalSurfaceHolderCallback());
    }

    private IRenderCallback mRenderCallback;


    private static final class InternalRenderHolder implements IRenderHolder{

        private WeakReference<SurfaceHolder> mSurfaceHolder;

        public InternalRenderHolder(SurfaceHolder surfaceHolder){
            this.mSurfaceHolder = new WeakReference<>(surfaceHolder);
        }

        @Override
        public void bindPlayer(IPlayer player) {
            if(player!=null && mSurfaceHolder.get()!=null){
                player.setDisplay(mSurfaceHolder.get());
            }
        }
    }

    private class InternalSurfaceHolderCallback implements SurfaceHolder.Callback{

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            if(mRenderCallback!=null){
                mRenderCallback.onSurfaceCreated(new InternalRenderHolder(holder),0,0);
            }
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
        }

    }
}

此处还是用了InternalSurfaceHolderCallback继承了SurfaceHolder.Callback。
综上,可总结为渲染流程图如下:


渲染流程.png

下面我们来具体分析Android#Surface及其相关类。

Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback

(1)Surface
Surface是原始图像缓冲区(raw buffer)的一个句柄,而原始图像缓冲区是由屏幕图像合成器(screen compositor)管理的。
原生缓冲区(raw buffer)存储着当前窗口的像素数据。
当得到一个Surface对象时,同时会得到一个Canvas(画布)对象。
Surface本身的作用类似一个句柄,得到了这个句柄就可以得到其中的Canvas、原生缓冲器以及其它方面的内容。

public class Surface implements Parcelable {
    private final Canvas mCanvas = new CompatibleCanvas();
}

(2)SurfaceView
SurfaceView,顾名思义就是Surface的View,通过SurfaceView就可以看到Surface的部分或者全部的内容。
Surface是用通过SurfaceView才能展示其中的内容。从这个意思上来说,SurfaceView中的View之确切的含义应该是viewport即“视口”的意思。
另一方面,SurfaceView是Android中View的子类。事实上,在Android中所有用于界面展示的类皆为View的子类,包括那些不可见的、各种各样的Layout。
所以说,SurfaceView中的View有两个含义:
1、视口(viewport)的意思
2、SurfaceView是View的派生类

**(3)SurfaceHolder **
从设计模式的高度来看,Surface、SurfaceView和SurfaceHolder实质上就是广为人知的MVC,即Model-View-Controller。Model就是模型的意思,或者说是数据模型,或者更简单地说就是数据,也就是这里的Surface;View即视图,代表用户交互界面,也就是这里的SurfaceView;SurfaceHolder很明显可以理解为MVC中的Controller(控制器)。这样看起来三者之间的关系就清楚了很多。
M:Surface.java 用于存放数据模型
V:SurfaceView.java 用来显示视图
C:SurfaceHolder.java 作为控制器的存在

(4)SurfaceHolder.Callback
前面已经讲到SurfaceHolder是一个接口,它通过回调方法的方式,让我们可以感知到Surface的创建、销毁或者改变。其实这一点是通过其内部的静态子接口SurfaceHolder.Callback来实现的。

SurfaceHolder.Callback中定义了三个接口方法:

    public interface Callback {

        public void surfaceCreated(SurfaceHolder holder);

        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height);

        public void surfaceDestroyed(SurfaceHolder holder);
    }

1、public void surfaceChanged(SurfaceHolderholder, int format, int width, int height)
当surface发生任何结构性的变化时(格式或者大小),该方法就会被立即调用。
2、public void surfaceCreated(SurfaceHolderholder)
当surface对象创建后,该方法就会被立即调用。
3、 public void surfaceDestroyed(SurfaceHolderholder)
当surface对象在将要销毁前,该方法会被立即调用。

相关文章

网友评论

      本文标题:十、Android视频框架PlayerBase#渲染流程

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