硬件解碼視頻(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();
}
});