第十八节、关于硬解与软解

硬件解码视频(MediaCodec)、软件解码视频(FFMpeg)
硬件解码视频: 我们知道AVPacket中存放的是视频的压缩数据,在获取到AVPacket后,直接将AVPacket中的data传递到上层交给MediaCodec,
MediaCodec完成解码交给opengl es
软件解码视频: 软件解码需要FFMpeg解码出AVFrame后,将AVFrame中的data(yuv数据)传递到上层交给opengl es
opengl es渲染yuv纹理 vertex_base.glsl

attribute vec4 av_Position; //定点坐标,应用传入 attribute vec2 af_Position; //采样纹理坐标,应用传入 varying vec2 v_texPo; //把获取的纹理坐标传入fragment里面 void main() { v_texPo = af_Position; gl_Position = av_Position; }

片元着色器
fragment_yuv.glsl
precision mediump float; varying vec2 v_texPo; uniform sampler2D sampler_y; uniform sampler2D sampler_u; uniform sampler2D sampler_v; void main() { float y,u,v; y = texture2D(sampler_y,v_texPo).x; u = texture2D(sampler_u,v_texPo).x- 128./255.; v = texture2D(sampler_v,v_texPo).x- 128./255.; vec3 rgb; rgb.r = y + 1.403 * v; rgb.g = y - 0.344 * u - 0.714 * v; rgb.b = y + 1.770 * u; //黑白滤镜 //float gray = rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114; //gl_FragColor = vec4(gray, gray, gray, 1); //原始效果 gl_FragColor = vec4(rgb,1); }

【第十八节、关于硬解与软解】这种情况下,在FFMpeg解码获取到AVFrame中的yuv数据后,直接传递给surfaceView即可
public void setFrameData(int w, int h, byte[] y, byte[] u, byte[] v) { if(wlGlRender != null) { wlGlRender.setFrameData(w, h, y, u, v); requestRender(); } }

opengl es渲染MediaCodec解码后的数据 顶点着色器
vertex_base.glsl
attribute vec4 av_Position; //定点坐标,应用传入 attribute vec2 af_Position; //采样纹理坐标,应用传入 varying vec2 v_texPo; //把获取的纹理坐标传入fragment里面 void main() { v_texPo = af_Position; gl_Position = av_Position; }

片元着色器
fragment_mediacodec.glsl
#extension GL_OES_EGL_image_external : require precision mediump float; varying vec2 v_texPo; uniform samplerExternalOES sTexture; void main() { gl_FragColor=texture2D(sTexture, v_texPo); //lowp vec4 textureColor = texture2D(sTexture, v_texPo); //float gray = textureColor.r * 0.299 + textureColor.g * 0.587 + textureColor.b * 0.114; //gl_FragColor = vec4(gray, gray, gray, textureColor.w); }

在编写Render的时候注意实现SurfaceTexture.OnFrameAvailableListener接口
/** * Callback interface for being notified that a new stream frame is available. */ public interface OnFrameAvailableListener { void onFrameAvailable(SurfaceTexture surfaceTexture); }

就是当surface中有可用的数据的时候,就会被回调,我们在回调中通知
surfaceView,进行刷新(调用surfaceView的requestRender())
wlGlRender.setWlOnRenderRefreshListener(new WlOnRenderRefreshListener() { @Override public void onRefresh() { requestRender(); } });

    推荐阅读