之前曾经写过用SurfaceView,TextureView+MediaPlayer 播放视频,和 ffmpeg avi 解码后SurfaceView播放视频 ,今天再给大家来一篇 OpenGL ES+MediaPlayer 来播放视频。
当年也曾呆过camera开发组近一年时间,可惜那时候没写博客的意识,没能给自己给大家留下多少干货分享。
上个效果图吧:
用 OpenGL 着色器实现黑白(灰度图)效果。
即 0.299,0.587,0.114 CRT中转灰度的模型
下面看具体实现的逻辑:
如果你曾用 OpenGL 实现过贴图,那么就容易理解多了。
和图片不同的是,视频需要不断地刷新,每当有新的一帧来时,我们都应该更新纹理,然后重新绘制。用 OpenGL 播放视频就是把视频贴到屏幕上。
对openGL不熟的同学先看这里:学 OpenGL 必知道的图形学知识
1.先写顶点着色器和片段着色器
顶点着色器:
attribute vec4 aPosition;//顶点位置
attribute vec4 aTexCoord;//S T 纹理坐标
varying vec2 vTexCoord;
uniform mat4 uMatrix;
uniform mat4 uSTMatrix;
void main() {
vTexCoord = (uSTMatrix * aTexCoord).xy;
gl_Position = uMatrix*aPosition;
}
片段着色器:
#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 vTexCoord;
uniform samplerExternalOES sTexture;
void main() {
gl_FragColor=texture2D(sTexture, vTexCoord);
}
对着色器语言不懂的同学看这里:http://blog.csdn.net/king1425/article/details/71425556
samplerExternalOES 代替贴图片时的 sampler2D ,作用就是和s urfaceTexture 配合进行纹理更新和格式转换。
2.MediaPlayer的输出
在 GLVideoRenderer 的构造函数中初始化 MediaPlayer :
mediaPlayer=new MediaPlayer();
try{
mediaPlayer.setDataSource(context, Uri.parse(videoPath));
}catch (IOException e){
e.printStackTrace();
}
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(true);
mediaPlayer.setOnVideoSizeChangedListener(this);
onSurfaceCreated函数中使用SurfaceTexture来设置MediaPlayer的输出。
我们要用SurfaceTexture 创建一个Surface,然后将这个Surface作为MediaPlayer的输出表面。
SurfaceTexture的主要作用就是,从视频流和相机数据流获取新一帧的数据,获取新数据调用的方法是updateTexImage。
需要注意的是MediaPlayer的输出往往不是RGB格式(一般是YUV),而GLSurfaceView需要RGB格式才能正常显示。
所以我们先在onSurfaceCreated中将生成纹理的代码改成这样:
textureId = textures[0];
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
ShaderUtils.checkGlError("ws-------glBindTexture mTextureID");
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES11Ext.GL_TEXTURE_EXTERNAL_OES的用处是什么?
之前提到视频解码的输出格式是YUV的(YUV4