openGL ES 在android中通过MediaCodec RGB的buffer转换MP4代码例子
时间: 2024-02-26 21:57:19 浏览: 144
FFmpeg+OpenGL ES+OpenSL ES打造Android视频播放器
以下是一个基本的示例代码,展示了如何使用OpenGL ES和MediaCodec API将RGB数据转换为MP4格式:
```java
public class EncoderThread extends Thread {
private static final String TAG = "EncoderThread";
private static final String MIME_TYPE = "video/avc";
private static final int FRAME_RATE = 30;
private static final int I_FRAME_INTERVAL = 1;
private static final int TIMEOUT_USEC = 10000;
private Surface mSurface;
private EGLContext mEGLContext;
private MediaCodec mEncoder;
private MediaMuxer mMuxer;
private int mTrackIndex;
private boolean mMuxerStarted;
public EncoderThread(Surface surface, EGLContext context) {
mSurface = surface;
mEGLContext = context;
}
@Override
public void run() {
try {
prepareEncoder();
prepareEGL();
loop();
releaseEncoder();
releaseEGL();
} catch (Exception e) {
Log.e(TAG, "Encoder thread error: " + e);
}
}
private void prepareEncoder() throws IOException {
MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, width, height);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, I_FRAME_INTERVAL);
mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mSurface = mEncoder.createInputSurface();
mEncoder.start();
mMuxer = new MediaMuxer(outputFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
mMuxerStarted = false;
mTrackIndex = -1;
}
private void prepareEGL() {
EGLDisplay display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
int[] version = new int[2];
EGL14.eglInitialize(display, version, 0, version, 1);
int[] attribList = {
EGL14.EGL_RED_SIZE, 8,
EGL14.EGL_GREEN_SIZE, 8,
EGL14.EGL_BLUE_SIZE, 8,
EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
EGL14.EGL_NONE
};
EGLConfig[] configs = new EGLConfig[1];
int[] numConfigs = new int[1];
EGL14.eglChooseConfig(display, attribList, 0, configs, 0, configs.length, numConfigs, 0);
EGLConfig config = configs[0];
int[] attribList2 = {
EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
EGL14.EGL_NONE
};
EGLContext context = EGL14.eglCreateContext(display, config, mEGLContext, attribList2, 0);
EGLSurface surface = EGL14.eglCreateWindowSurface(display, config, mSurface, attribList2, 0);
EGL14.eglMakeCurrent(display, surface, surface, context);
}
private void loop() {
while (true) {
GLES20.glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
EGLSurface eglSurface = EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW);
mEncoder.getInputSurface().swapBuffers();
drainEncoder();
if (mIsEndOfStream) {
signalEndOfInputStream();
break;
}
}
}
private void releaseEncoder() {
if (mEncoder != null) {
mEncoder.stop();
mEncoder.release();
mEncoder = null;
}
if (mMuxer != null) {
mMuxer.stop();
mMuxer.release();
mMuxer = null;
}
}
private void releaseEGL() {
EGLDisplay display = EGL14.eglGetCurrentDisplay();
EGLSurface surface = EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW);
EGLContext context = EGL14.eglGetCurrentContext();
EGL14.eglMakeCurrent(display, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
EGL14.eglDestroySurface(display, surface);
EGL14.eglDestroyContext(display, context);
EGL14.eglTerminate(display);
}
private void drainEncoder() {
ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers();
while (true) {
int encoderStatus = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
break;
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
encoderOutputBuffers = mEncoder.getOutputBuffers();
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
if (mMuxerStarted) {
throw new RuntimeException("Format changed twice");
}
MediaFormat newFormat = mEncoder.getOutputFormat();
mTrackIndex = mMuxer.addTrack(newFormat);
mMuxer.start();
mMuxerStarted = true;
} else if (encoderStatus < 0) {
Log.e(TAG, "unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);
} else {
ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
if (encodedData == null) {
throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null");
}
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
mBufferInfo.size = 0;
}
if (mBufferInfo.size != 0) {
if (!mMuxerStarted) {
throw new RuntimeException("muxer hasn't started");
}
encodedData.position(mBufferInfo.offset);
encodedData.limit(mBufferInfo.offset + mBufferInfo.size);
mMuxer.writeSampleData(mTrackIndex, encodedData, mBufferInfo);
}
mEncoder.releaseOutputBuffer(encoderStatus, false);
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
mIsEndOfStream = true;
break;
}
}
}
}
}
```
这个示例代码包括了几个关键的步骤,包括:
1. 创建一个MediaCodec编码器,并配置它的参数。
2. 创建一个OpenGL ES渲染器,并将渲染的图像数据绘制到屏幕上。
3. 将渲染的图像数据传递给MediaCodec编码器进行压缩。
4. 将编码后的视频数据写入一个MP4文件中。
5. 在循环中不断地从编码器的输出缓冲区中获取压缩数据,并将其写入MP4文件中。
需要注意的是,这个示例代码只是一个基本的框架,实际上还需要处理许多细节,例如处理OpenGL ES渲染器的生命周期、设置编码器的参数、处理编码器的输出缓冲区等。
阅读全文