openGL ES 在android中通过MediaCodec RGB的buffer转换MP4例子
时间: 2024-02-24 19:55:51 浏览: 101
以下是一个基本的示例,演示如何使用OpenGL ES和MediaCodec将RGB图像数据转换为MP4视频:
1. 首先,需要创建一个OpenGL ES上下文并设置它的表面为MediaCodec的输入表面。这可以通过使用EGL库和MediaCodec的createInputSurface()方法来完成。以下是一个示例代码片段:
```java
EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
int[] version = new int[2];
EGL14.eglInitialize(eglDisplay, version, 0, version, 1);
int[] configAttribs = {
EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT,
EGL14.EGL_RED_SIZE, 8,
EGL14.EGL_GREEN_SIZE, 8,
EGL14.EGL_BLUE_SIZE, 8,
EGL14.EGL_ALPHA_SIZE, 8,
EGL14.EGL_NONE
};
EGLConfig[] configs = new EGLConfig[1];
int[] numConfigs = new int[1];
EGL14.eglChooseConfig(eglDisplay, configAttribs, 0, configs, 0, 1, numConfigs, 0);
int[] surfaceAttribs = {
EGL14.EGL_WIDTH, inputWidth,
EGL14.EGL_HEIGHT, inputHeight,
EGL14.EGL_NONE
};
EGLSurface surface = EGL14.eglCreatePbufferSurface(eglDisplay, configs[0], surfaceAttribs, 0);
EGLContext context = EGL14.eglCreateContext(eglDisplay, configs[0], EGL14.EGL_NO_CONTEXT, new int[] {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE}, 0);
EGL14.eglMakeCurrent(eglDisplay, surface, surface, context);
MediaCodec codec = MediaCodec.createEncoderByType("video/avc");
MediaFormat format = MediaFormat.createVideoFormat("video/avc", inputWidth, inputHeight);
format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval);
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
Surface inputSurface = codec.createInputSurface();
```
2. 接下来,需要将RGB图像数据传递到OpenGL ES渲染管道中,并使用MediaCodec的输入表面将渲染结果作为视频帧发送到编码器。以下是一个示例代码片段:
```java
// 将RGB数据传递到纹理中
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
int textureId = textures[0];
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, inputWidth, inputHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(rgbData));
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
// 渲染帧
int vertexShader = ShaderUtils.loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER);
int fragmentShader = ShaderUtils.loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER);
int program = ShaderUtils.createProgram(vertexShader, fragmentShader);
int positionHandle = GLES20.glGetAttribLocation(program, "position");
int textureHandle = GLES20.glGetUniformLocation(program, "texture");
int matrixHandle = GLES20.glGetUniformLocation(program, "matrix");
GLES20.glViewport(0, 0, inputWidth, inputHeight);
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(program);
float[] vertices = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f
};
ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
vertexBuffer.order(ByteOrder.nativeOrder());
FloatBuffer floatBuffer = vertexBuffer.asFloatBuffer();
floatBuffer.put(vertices);
floatBuffer.position(0);
GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, floatBuffer);
GLES20.glEnableVertexAttribArray(positionHandle);
Matrix.setIdentityM(matrix, 0);
Matrix.scaleM(matrix, 0, -1f, 1f, 1f);
Matrix.rotateM(matrix, 0, 270, 0, 0, 1);
GLES20.glUniformMatrix4fv(matrixHandle, 1, false, matrix, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
GLES20.glUniform1i(textureHandle, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
// 将渲染结果发送到编码器
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, TIMEOUT_US);
if (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferIndex);
outputBuffer.position(bufferInfo.offset);
outputBuffer.limit(bufferInfo.offset + bufferInfo.size);
videoTrackIndex = muxer.addTrack(format);
muxer.writeSampleData(videoTrackIndex, outputBuffer, bufferInfo);
codec.releaseOutputBuffer(outputBufferIndex, false);
}
```
3. 最后,需要在完成所有帧的渲染后释放OpenGL ES上下文和MediaCodec资源。以下是一个示例代码片段:
```java
EGL14.eglDestroySurface(eglDisplay, surface);
EGL14.eglDestroyContext(eglDisplay, context);
EGL14.eglTerminate(eglDisplay);
codec.stop();
codec.release();
muxer.stop();
muxer.release();
```
注意:这只是一个基本示例,你需要根据你的具体情况进行修改。例如,你需要在每一帧之间等待编码器的输出缓冲区,以确保数据正确输出。
阅读全文