实现视频缩放的基本思路是通过改变渲染纹理的顶点坐标和纹理坐标实现,其中OpenGL ES混合模式是一种可以较好地适应不同尺寸的方法。
具体实现方法如下:
- 初始化OpenGL ES环境,通过GLSurfaceView.Renderer的回调函数onSurfaceCreated实现。
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 初始化OpenGL环境
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
}
- 在每次视频图像被更新时,将纹理数据绑定到OpenGL ES纹理对象上,并更新顶点坐标和纹理坐标。在GLSurfaceView.Renderer的回调函数onDrawFrame实现。
@Override
public void onDrawFrame(GL10 gl) {
// 清空屏幕
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// 更新纹理数据
surfaceTexture.updateTexImage();
// 更新顶点坐标和纹理坐标
float[] vertexCoords = {...};
float[] textureCoords = {...};
// 绘制纹理
GLES20.glUseProgram(program);
GLES20.glEnableVertexAttribArray(aPositionLocation);
GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
GLES20.glEnableVertexAttribArray(aTextureCoordLocation);
GLES20.glVertexAttribPointer(aTextureCoordLocation, COORDS_PER_TEXTURE, GLES20.GL_FLOAT, false, textureStride, textureBuffer);
GLES20.glUniformMatrix4fv(uMVPMatrixLocation, 1, false, mvpMatrix, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[0]);
GLES20.glUniform1i(uTextureLocation, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);
// 解绑定纹理
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
}
可以看到,通过使用混合模式GLES20.GL_BLEND并设置混合函数GLES20.GL_SRC_ALPHA和GLES20.GL_ONE_MINUS_SRC_ALPHA,可以实现更加自然的缩放效果,避免图像出现锯齿和失真现象。
下面是两个示例:
示例1:将视频缓冲区填充整个GLSurfaceView区域
顶点坐标和纹理坐标定义如下:
private static final float[] FULL_RECTANGLE_VERTEX_COORDS = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
private static final float[] FULL_RECTANGLE_TEXTURE_COORDS = {
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};
顶点坐标和纹理坐标填充整个GLSurfaceView区域,使用混合模式GLES20.GL_BLEND,并设置混合函数GLES20.GL_SRC_ALPHA和GLES20.GL_ONE_MINUS_SRC_ALPHA。
示例2:将视频缓冲区按照宽高比例缩放
顶点坐标和纹理坐标定义如下:
private static final float[] CROP_RECTANGLE_VERTEX_COORDS = {
-1.0f, -aspectRatio,
1.0f, -aspectRatio,
-1.0f, aspectRatio,
1.0f, aspectRatio,
};
private static final float[] CROP_RECTANGLE_TEXTURE_COORDS = {
0.0f, 1 - texAspectRatio,
1.0f, 1 - texAspectRatio,
0.0f, 1.0f - (1 - texAspectRatio),
1.0f, 1.0f - (1 - texAspectRatio),
};
其中,aspectRatio为GLSurfaceView的宽高比,texAspectRatio为视频缓冲区的宽高比。可以看到,在顶点坐标和纹理坐标中,通过相除和相减的方式,实现了缩放的效果。同样使用混合模式GLES20.GL_BLEND,并设置混合函数GLES20.GL_SRC_ALPHA和GLES20.GL_ONE_MINUS_SRC_ALPHA。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:通过OpenGL ES混合模式缩放视频缓冲区来适应显示尺寸 - Python技术站