[置顶] OpenGL ES总结(四)OpenGL 渲染视频画面
2017-03-18 00:13
417 查看
转载请把头部出处链接和尾部二维码一起转载,本文出自:http://blog.csdn.net/hejjunlin/article/details/62976457
前一篇介绍是渲染一张图片,今天是在MediaPlayer播放过程中,渲染视频,看下Agenda:
与渲染图片的区别
创建SurfaceTexture
设置shader(着色器)
建立纹理坐标
UV坐标介绍
UV纹理坐标设定与贴图规则是什么?
视频播放
创建一个纹理时,视频的每一帧都可以看成图片,也就是要不断的更新纹理
主要的原因是,MediaPlayer的输出往往不是RGB格式(一般是YUV),而GLSurfaceView需要RGB格式才能正常显示,另外,获取每一帧的数据并没有那么方便。
所以,我们创建的纹理应该稍有不同,SurfaceTexture在《Android Multimedia框架总结(三)MediaPlayer中创建到setDataSource过程》就曾详细介绍过,这里贴出来:
SurfaceTexture: SurfaceTexture是从Android3.0(API 11)加入的一个新类。这个类跟SurfaceView很像,可以从video decode里面获取图像流(image stream)。但是,和SurfaceView不同的是,SurfaceTexture在接收图像流之后,不需要显示出来。SurfaceTexture不需要显示到屏幕上,因此我们可以用SurfaceTexture接收来自decode出来的图像流,然后从SurfaceTexture中取得图像帧的拷贝进行处理,处理完毕后再送给另一个SurfaceView用于显示即可。
在onDrawFrame中
其中mTarget是 GLES11Ext.GL_TEXTURE_EXTERNAL_OES,GLES11Ext.GL_TEXTURE_EXTERNAL_OES的到底是做什么的?
我们知道视频解码的输出格式是YUV的(YUV420sp),那么这个扩展纹理的作用就是实现YUV格式到RGB的自动转化,我们就不需要再为此写YUV转RGB的代码。
我们用上面的textureId是构造时传入的,
这个textureId是用于去创建一个SurfaceTexture,然后用surfaceTexture去创建一个Surface ,再把surface送给mediaPlayer进行输出。
updateTexImage,就是来更新纹理,其中getTransformMatrix的目的,是让新的纹理和纹理坐标系能够正确的对应,mSTMatrix的定义是和mMVPMatrix完全一样的。
其中vextex_oes.glsl
frag_oes.glsl
其中有X,Y,Z,还有U,V,那么什么是UV坐标?
对于三维模型,有两个最重要的坐标系统,一是顶点的位置(X,Y,Z)坐标,另一个就是UV坐标。什么是UV?简单的说,就是贴图影射到模型表面的依据。 完整的说,其实应该是UVW(因为XYZ已经用过了,所以另选三个字母表示)。U和V分别是图片在显示器水平、垂直方向上的坐标,取值一般都是0~1,也就是(水平方向的第U个像素/图片宽度,垂直方向的第V个像素/图片高度)。那W呢?贴图是二维的,何来三个坐标?嗯嗯,W的方向垂直于显示器表面,一般 用于程序贴图或者某些3D贴图技术(记住,确实有三维贴图这种概念!),对于游戏而言不常用到,所以一般我们就简称UV了。
所有的图象文件都是二维的一个平面。水平方向是U,垂直方向是V,通过这个平面的,二维的UV坐标系。我们可以定位图象上的任意一个象素。但是一个问题是如何把这个二维的平面贴到三维的NURBS表面和多边形表面呢? 对于NURBS表面。由于他本身具有UV参数,尽管这个UV值是用来定位表面上的点的参数,但由于它也是二维的,所以很容易通过换算把表面上的点和平面图象上的象素对应起来。所以把图象贴带NURBS是很直接的一件事。但是对于多变形模型来讲,贴图就变成一件麻烦的事了。所以多边形为了贴图就额外引进了一个UV坐标,以便把多边形的顶点和图象文件上的象素对应起来,这样才能在多边形表面上定位纹理贴图。所以说多边形的顶点除了具有三维的空间坐标外。还具有二维的UV坐标。
UV” 这里是指u,v纹理贴图坐标的简称(它和空间模型的X, Y, Z轴是类似的). 它定义了图片上每个点的位置的信息. 这些点与3D模型是相互联系的, 以决定表面纹理贴图的位置. UV就是将图像上每一个点精确对应到模型物体的表面. 在点与点之间的间隙位置由软件进行图像光滑插值处理. 这就是所谓的UV贴图.
那为什么用UV坐标而不是标准的投影坐标呢? 通常给物体纹理贴图最标准的方法就是以planar(平面),cylindrical(圆柱), spherical(球形),cubic(方盒)坐标方式投影贴图.
Planar projection(平面投影方式)是将图像沿x,y或z轴直接投影到物体. 这种方法使用于纸张, 布告, 书的封面等 - 也就是表面平整的物体.平面投影的缺点是如果表面不平整, 或者物体边缘弯曲, 就会产生如图A的不理想接缝和变形. 避免这种情况需要创建带有alpha通道的图像, 来掩盖临近的平面投影接缝, 而这会是非常烦琐的工作. 所以不要对有较大厚度的物体和不平整的表面运用平面投影方式. 对于立方体可以在x, y方向分别进行平面投影, 但是要注意边缘接缝的融合. 或者采用无缝连续的纹理, 并使用cubic投影方式. 多数软件有图片自动缩放功能, 使图像与表面吻合. 显然, 如果你的图像与表面形状不同, 自动缩放就会改变图像的比例以吻合表面. 这通常会产生不理想的效果, 所以制作贴图前先测量你的物体尺寸.
uv纹理坐标设定与贴图规则是什么?
当opengl对一个四方形进行贴图时,会定义纹理贴图坐标,一串数组。
当纹理映射启动后绘图时,你必须为OpenGL ES提供其他数据,即顶点数组中各顶点的纹理坐标。纹理坐标定义了图像的哪一部分将被映射到多边形。
最后效果图:
第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。
如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易
前一篇介绍是渲染一张图片,今天是在MediaPlayer播放过程中,渲染视频,看下Agenda:
与渲染图片的区别
创建SurfaceTexture
设置shader(着色器)
建立纹理坐标
UV坐标介绍
UV纹理坐标设定与贴图规则是什么?
视频播放
与渲染图片的区别
渲染视频画面和渲染图片不同,视频需要不断地刷新,每当有新的一帧来时,我们都应该更新纹理,然后重新绘制。我们使用SurfaceTexture来设置MediaPlayer的setSurface.创建一个纹理时,视频的每一帧都可以看成图片,也就是要不断的更新纹理
主要的原因是,MediaPlayer的输出往往不是RGB格式(一般是YUV),而GLSurfaceView需要RGB格式才能正常显示,另外,获取每一帧的数据并没有那么方便。
所以,我们创建的纹理应该稍有不同,SurfaceTexture在《Android Multimedia框架总结(三)MediaPlayer中创建到setDataSource过程》就曾详细介绍过,这里贴出来:
SurfaceTexture: SurfaceTexture是从Android3.0(API 11)加入的一个新类。这个类跟SurfaceView很像,可以从video decode里面获取图像流(image stream)。但是,和SurfaceView不同的是,SurfaceTexture在接收图像流之后,不需要显示出来。SurfaceTexture不需要显示到屏幕上,因此我们可以用SurfaceTexture接收来自decode出来的图像流,然后从SurfaceTexture中取得图像帧的拷贝进行处理,处理完毕后再送给另一个SurfaceView用于显示即可。
创建SurfaceTexture
public VideoTexture(Context context, int textureId) { mContext = context; mTexureId = textureId; mSurfaceTexture = new SurfaceTexture(textureId); mSurface = new Surface(mSurfaceTexture); // 初始化顶点坐标与着色数据 initVertexData(); // 初始化着色器 initShader(); }
在onDrawFrame中
mSurfaceTexture.updateTexImage(); checkGlError("onDrawFrame start"); mSurfaceTexture.getTransformMatrix(mSTMatrix); GLES30.glUseProgram(mProgram); checkGlError("glUseProgram"); GLES30.glActiveTexture(GLES30.GL_TEXTURE0); GLES30.glBindTexture(mTarget, mTexId);
其中mTarget是 GLES11Ext.GL_TEXTURE_EXTERNAL_OES,GLES11Ext.GL_TEXTURE_EXTERNAL_OES的到底是做什么的?
我们知道视频解码的输出格式是YUV的(YUV420sp),那么这个扩展纹理的作用就是实现YUV格式到RGB的自动转化,我们就不需要再为此写YUV转RGB的代码。
我们用上面的textureId是构造时传入的,
// 生成纹理ID int[] textures = new int[2]; GLES20.glGenTextures(// 2, // 产生的纹理id的数量 textures, // 纹理id的数组 0 // 偏移量 ); mVideoTexture = new VideoTexture(mContext, textures[0]);
这个textureId是用于去创建一个SurfaceTexture,然后用surfaceTexture去创建一个Surface ,再把surface送给mediaPlayer进行输出。
updateTexImage,就是来更新纹理,其中getTransformMatrix的目的,是让新的纹理和纹理坐标系能够正确的对应,mSTMatrix的定义是和mMVPMatrix完全一样的。
private float[] mMVPMatrix = new float[16]; private float[] mSTMatrix = new float[16];
设置shader(着色器):
public void initShader() { // 加载顶点着色器的脚本内容 String mVertexShader = ShaderUtil.readRawTextFile(mContext, R.raw.vertex_oes); // 加载片元着色器的脚本内容 String mFragmentShader = ShaderUtil.readRawTextFile(mContext, R.raw.frag_oes); // 基于顶点着色器与片元着色器创建程序 mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader); // 获取程序中顶点位置属性引用id maPositionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition"); // 获取程序中顶点纹理坐标属性引用id maTextureCoordHandle = GLES30.glGetAttribLocation(mProgram, "aTextureCoord"); // 获取程序中总变换矩阵引用id muMVPMatrixHandle = GLES30.glGetUniformLocation(mProgram, "uMVPMatrix"); muSTMatrixHandle = GLES30.glGetUniformLocation(mProgram, "uSTMatrix"); }
其中vextex_oes.glsl
uniform mat4 uMVPMatrix; //总变换矩阵 uniform mat4 uSTMatrix; attribute vec4 aPosition; //顶点位置 attribute vec4 aTextureCoord; //顶点纹理坐标 varying vec2 vTextureCoord; //用于传递给片元着色器的变量 void main() { gl_Position = uMVPMatrix * aPosition; //根据总变换矩阵计算此次绘制此顶点位置 vTextureCoord = (uSTMatrix * aTextureCoord).xy;//将接收的纹理坐标传递给片元着色器 }
frag_oes.glsl
#extension GL_OES_EGL_image_external : require precision mediump float; varying vec2 vTextureCoord; //接收从顶点着色器过来的参数 uniform samplerExternalOES sTexture;//纹理内容数据 void main() { //给此片元从纹理中采样出颜色值 gl_FragColor = texture2D(sTexture, vTextureCoord); }
建立纹理坐标:
private final float[] mTriangleVerticesData = { // X, Y, Z, U, V -3.2f, -1.5f, 0, 0.f, 0.f, // 3.2f, -1.5f, 0, 1.f, 0.f, // -3.2f, 1.5f, 0, 0.f, 1.f, // 3.2f, 1.5f, 0, 1.f, 1.f, // };
其中有X,Y,Z,还有U,V,那么什么是UV坐标?
对于三维模型,有两个最重要的坐标系统,一是顶点的位置(X,Y,Z)坐标,另一个就是UV坐标。什么是UV?简单的说,就是贴图影射到模型表面的依据。 完整的说,其实应该是UVW(因为XYZ已经用过了,所以另选三个字母表示)。U和V分别是图片在显示器水平、垂直方向上的坐标,取值一般都是0~1,也就是(水平方向的第U个像素/图片宽度,垂直方向的第V个像素/图片高度)。那W呢?贴图是二维的,何来三个坐标?嗯嗯,W的方向垂直于显示器表面,一般 用于程序贴图或者某些3D贴图技术(记住,确实有三维贴图这种概念!),对于游戏而言不常用到,所以一般我们就简称UV了。
所有的图象文件都是二维的一个平面。水平方向是U,垂直方向是V,通过这个平面的,二维的UV坐标系。我们可以定位图象上的任意一个象素。但是一个问题是如何把这个二维的平面贴到三维的NURBS表面和多边形表面呢? 对于NURBS表面。由于他本身具有UV参数,尽管这个UV值是用来定位表面上的点的参数,但由于它也是二维的,所以很容易通过换算把表面上的点和平面图象上的象素对应起来。所以把图象贴带NURBS是很直接的一件事。但是对于多变形模型来讲,贴图就变成一件麻烦的事了。所以多边形为了贴图就额外引进了一个UV坐标,以便把多边形的顶点和图象文件上的象素对应起来,这样才能在多边形表面上定位纹理贴图。所以说多边形的顶点除了具有三维的空间坐标外。还具有二维的UV坐标。
UV” 这里是指u,v纹理贴图坐标的简称(它和空间模型的X, Y, Z轴是类似的). 它定义了图片上每个点的位置的信息. 这些点与3D模型是相互联系的, 以决定表面纹理贴图的位置. UV就是将图像上每一个点精确对应到模型物体的表面. 在点与点之间的间隙位置由软件进行图像光滑插值处理. 这就是所谓的UV贴图.
那为什么用UV坐标而不是标准的投影坐标呢? 通常给物体纹理贴图最标准的方法就是以planar(平面),cylindrical(圆柱), spherical(球形),cubic(方盒)坐标方式投影贴图.
Planar projection(平面投影方式)是将图像沿x,y或z轴直接投影到物体. 这种方法使用于纸张, 布告, 书的封面等 - 也就是表面平整的物体.平面投影的缺点是如果表面不平整, 或者物体边缘弯曲, 就会产生如图A的不理想接缝和变形. 避免这种情况需要创建带有alpha通道的图像, 来掩盖临近的平面投影接缝, 而这会是非常烦琐的工作. 所以不要对有较大厚度的物体和不平整的表面运用平面投影方式. 对于立方体可以在x, y方向分别进行平面投影, 但是要注意边缘接缝的融合. 或者采用无缝连续的纹理, 并使用cubic投影方式. 多数软件有图片自动缩放功能, 使图像与表面吻合. 显然, 如果你的图像与表面形状不同, 自动缩放就会改变图像的比例以吻合表面. 这通常会产生不理想的效果, 所以制作贴图前先测量你的物体尺寸.
uv纹理坐标设定与贴图规则是什么?
当opengl对一个四方形进行贴图时,会定义纹理贴图坐标,一串数组。
当纹理映射启动后绘图时,你必须为OpenGL ES提供其他数据,即顶点数组中各顶点的纹理坐标。纹理坐标定义了图像的哪一部分将被映射到多边形。
视频播放
try { mMediaPlayer = new MediaPlayer(); mMediaPlayer.setSurface(mSurface); mMediaPlayer.setLooping(true); String url = Environment.getExternalStorageDirectory() + "/节目.mp4"; Log.w("videoTexture", " datasource file url " + url); mMediaPlayer.setDataSource(mContext, Uri.parse(url)); mMediaPlayer.prepare(); mMediaPlayer.start(); } catch (Exception e) { e.printStackTrace(); }
最后效果图:
第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。
如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易
相关文章推荐
- OpenGL ES总结(四)OpenGL 渲染视频画面
- [置顶] OpenGL ES总结(二)OpenGL坐标变换之平移及旋转
- openGL ES进阶教程(四)用openGL ES+MediaPlayer 渲染播放视频+滤镜效果
- [置顶] OpenGL ES总结(一)OpenGL 初识
- [置顶] OpenGL ES总结(三)OpenGL通过计算纹理坐标来显示一张图片
- [置顶] 基于iOS的网络音视频实时传输系统(六)- AudioQueue播放音频,OpenGL渲染显示图像
- Cocos2d-x3.2与OpenGL渲染总结(一)Cocos2d-x3.2的渲染流程
- Cocos2d-x3.2与OpenGL渲染总结(一)Cocos2d-x3.2的渲染流程
- Cocos2d-x3.2与OpenGL渲染总结(一)Cocos2d-x3.2的渲染流程
- Cocos2d-x3.2与OpenGL渲染总结(一)Cocos2d-x3.2的渲染流程
- Android OpenGL ES零基础系列(三):OpenGL ES的渲染管道及VertexShader与FragmentShader
- OpenGL ES 2.0总结(1)-VBO与渲染
- Cocos2d-x3.2与OpenGL渲染总结和渲染流程
- 用jni实现基于opengl的yuv格式的视频渲染
- [置顶] Android Multimedia框架总结(二)MediaPlayer框架及播放网络视频案例
- 基于Surface的视频编解码与OpenGL ES渲染
- qt视频渲染画面闪烁
- 用jni实现基于opengl的yuv格式的视频渲染
- OpenGL渲染管线总结
- Cocos2d-x3.2与OpenGL渲染总结Cocos2d-x3.2的渲染流程