美文网首页
六、Android视频框架PlayerBase#IRender

六、Android视频框架PlayerBase#IRender

作者: YongtaoHuang | 来源:发表于2019-09-23 14:28 被阅读0次

上一篇:https://www.jianshu.com/p/52b1246f6787

下一篇:
https://www.jianshu.com/p/e5d8ec6bfca3

IRender接口

IRender (渲染)接口:有两种渲染方式:TextureView和SurfaceView。内部接口IRendrHolder的bindPlayer方法是用来让播放器绑定在View上。

// 框架渲染视图
public interface IRender {
    //use TextureView for render
    int RENDER_TYPE_TEXTURE_VIEW = 0;
    //use SurfaceView for render
    int RENDER_TYPE_SURFACE_VIEW = 1;
    // 回调函数
    void setRenderCallback(IRenderCallback renderCallback);
    // 设置视频旋转,多用于屏幕旋转
    void setVideoRotation(int degree);
    // 设置采样
    void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen);
    // 更新视图尺寸
    void updateAspectRatio(AspectRatio aspectRatio);
    // 更新视频尺寸
    void updateVideoSize(int videoWidth, int videoHeight);
    // 获取渲染视图
    View getRenderView();
    // 释放资源
    void release();
    // 接口IRenderHolder负责将解码器与呈现视图相关联。
    interface IRenderHolder{
        void bindPlayer(IPlayer player);
    }
    // 回调接口
    interface IRenderCallback{
        void onSurfaceCreated(IRenderHolder renderHolder, int width, int height);
        void onSurfaceChanged(IRenderHolder renderHolder, int format, int width, int height);
        void onSurfaceDestroy(IRenderHolder renderHolder);
    }
}
TextureView优缺点:
  • 优点
    动画支持良好,可以获取视频截图
    视图不可见时可以保留当前帧不黑屏

  • 缺点
    必须开启硬件加速,否则无画面,占用内存比SurfaceView高,在5.0以前在主线程渲染,5.0以后有单独的渲染线程。

SurfaceView优缺点:
  • 优点
    可以在一个独立的线程中进行绘制,不会影响主线程使用双缓冲机制,播放视频时画面更流畅
  • 缺点
    Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换

RenderSurfaceView

RenderSurfaceView继承了SurfaceView,是IRender 的实现类。

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());
            }
        }
    }
    
}

RenderTextureView

RenderTextureView继承了TextureView,是IRender 的实现类。

public class RenderTextureView extends TextureView implements IRender {
    private static final class InternalRenderHolder implements IRenderHolder{

        private WeakReference<Surface> mSurfaceRefer;
        private WeakReference<RenderTextureView> mTextureRefer;

        public InternalRenderHolder(RenderTextureView textureView, SurfaceTexture surfaceTexture){
            mTextureRefer = new WeakReference<>(textureView);
            mSurfaceRefer = new WeakReference<>(new Surface(surfaceTexture));
        }

        RenderTextureView getTextureView(){
            if(mTextureRefer!=null){
                return mTextureRefer.get();
            }
            return null;
        }

        @Override
        public void bindPlayer(IPlayer player) {
            RenderTextureView textureView = getTextureView();
            if(player!=null && mSurfaceRefer!=null && textureView!=null){
                SurfaceTexture surfaceTexture = textureView.getOwnSurfaceTexture();
                SurfaceTexture useTexture = textureView.getSurfaceTexture();
                boolean isReleased = false;
                //check the SurfaceTexture is released is Android O.
                if(surfaceTexture!=null && Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
                    isReleased = surfaceTexture.isReleased();
                }
                boolean available = surfaceTexture!=null && !isReleased;
                //When the user sets the takeover flag and SurfaceTexture is available.
                if(textureView.isTakeOverSurfaceTexture()
                        && available
                        && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN){
                    //if SurfaceTexture not set or current is null, need set it.
                    if(!surfaceTexture.equals(useTexture)){
                        textureView.setSurfaceTexture(surfaceTexture);
                        PLog.d("RenderTextureView","****setSurfaceTexture****");
                    }else{
                        Surface surface = textureView.getSurface();
                        //release current Surface if not null.
                        if(surface!=null){
                            surface.release();
                        }
                        //create Surface use update SurfaceTexture
                        Surface newSurface = new Surface(surfaceTexture);
                        //set it for player
                        player.setSurface(newSurface);
                        //record the new Surface
                        textureView.setSurface(newSurface);
                        PLog.d("RenderTextureView","****bindSurface****");
                    }
                }else{
                    Surface surface = mSurfaceRefer.get();
                    if(surface!=null){
                        player.setSurface(surface);
                        //record the Surface
                        textureView.setSurface(surface);
                        PLog.d("RenderTextureView","****bindSurface****");
                    }
                }
            }
        }

    }
}

IRender的实际使用

还是得回到BaseVideoView中看IRender、RenderSurfaceView和RenderTextureView的使用。它不仅和播放器内核相关联(bindPlayer方法),还和SuperContainer关联紧密。
mRender.setRenderCallback(mRenderCallback); // 添加RenderCallback回调

public class BaseVideoView extends FrameLayout implements IVideoView, IStyleSetter {
    
    // 渲染视图 RenderTextureView或者RenderSurfaceView
    private IRender mRender;
    // IRenderHolder负责将解码器与呈现视图相关联。
    private IRender.IRenderHolder mRenderHolder;    

    @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); // 添加RenderCallback回调
        //update some params
        mRender.updateVideoSize(mVideoWidth, mVideoHeight);
        mRender.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
        //update video rotation
        mRender.setVideoRotation(mVideoRotation);
        //add to container
        mSuperContainer.setRenderView(mRender.getRenderView());
    }
    
    //on render holder ready ,bind the player.
    private void bindRenderHolder(IRender.IRenderHolder renderHolder){
        if(renderHolder!=null)
            renderHolder.bindPlayer(mPlayer); // 此处调用接口IRender#接口IRenderHolder#bindPlayer()方法
    }
    // mRender.setRenderCallback(mRenderCallback); // 添加RenderCallback回调    
    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) {
            //not handle some...
        }
        @Override
        public void onSurfaceDestroy(IRender.IRenderHolder renderHolder) {
            //on surface destroy detach player
            mRenderHolder = null;
        }
    };  

}

与SuperContainer关联

public class BaseVideoView extends FrameLayout implements IVideoView, IStyleSetter {
    @Override
    public void setRenderType(int renderType) {
        // ....
        //add to container
        mSuperContainer.setRenderView(mRender.getRenderView());
    }
}
// 调用了SuperContainer#setRenderView()方法==================================
    public final void setRenderView(View view){
        removeRender();
        //must set WRAP_CONTENT and CENTER for render aspect ratio and measure.
        LayoutParams lp = new LayoutParams(
                LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT,
                Gravity.CENTER);
        mRenderContainer.addView(view,lp);
    }

相关文章

网友评论

      本文标题:六、Android视频框架PlayerBase#IRender

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