六、Android视频框架PlayerBase#IRender
2019-09-23 本文已影响0人
YongtaoHuang
上一篇: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);
}