如何使用 Android MediaCodec 编码相机数据(YUV420sp)
Posted
技术标签:
【中文标题】如何使用 Android MediaCodec 编码相机数据(YUV420sp)【英文标题】:How to use Android MediaCodec encode Camera data(YUV420sp) 【发布时间】:2013-06-18 10:07:21 【问题描述】:感谢您的关注! 我想使用 android MediaCodec APIs 对从相机获取的视频帧进行编码, 不幸的是,我没有成功做到这一点!我对 MediaCodec API 还是不熟悉。 以下是我的代码,我需要你的帮助来弄清楚我应该做什么。
1、相机设置:
Parameters parameters = mCamera.getParameters();
parameters.setPreviewFormat(ImageFormat.NV21);
parameters.setPreviewSize(320, 240);
mCamera.setParameters(parameters);
2、设置编码器:
private void initCodec()
try
fos = new FileOutputStream(mVideoFile, false);
catch (FileNotFoundException e)
e.printStackTrace();
mMediaCodec = MediaCodec.createEncoderByType("video/avc");
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc",
320,
240);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 125000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
mMediaCodec.configure(mediaFormat,
null,
null,
MediaCodec.CONFIGURE_FLAG_ENCODE);
mMediaCodec.start();
inputBuffers = mMediaCodec.getInputBuffers();
outputBuffers = mMediaCodec.getOutputBuffers();
private void encode(byte[] data)
int inputBufferIndex = mMediaCodec.dequeueInputBuffer(0);
if (inputBufferIndex >= 0)
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(data);
mMediaCodec.queueInputBuffer(inputBufferIndex, 0, data.length, 0, 0);
else
return;
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0);
Log.i(TAG, "outputBufferIndex-->" + outputBufferIndex);
do
if (outputBufferIndex >= 0)
ByteBuffer outBuffer = outputBuffers[outputBufferIndex];
System.out.println("buffer info-->" + bufferInfo.offset + "--"
+ bufferInfo.size + "--" + bufferInfo.flags + "--"
+ bufferInfo.presentationTimeUs);
byte[] outData = new byte[bufferInfo.size];
outBuffer.get(outData);
try
if (bufferInfo.offset != 0)
fos.write(outData, bufferInfo.offset, outData.length
- bufferInfo.offset);
else
fos.write(outData, 0, outData.length);
fos.flush();
Log.i(TAG, "out data -- > " + outData.length);
mMediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo,
0);
catch (IOException e)
e.printStackTrace();
else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
outputBuffers = mMediaCodec.getOutputBuffers();
else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)
MediaFormat format = mMediaCodec.getOutputFormat();
while (outputBufferIndex >= 0);
我猜是编码器方法的问题,该方法会在Camera Preview Callback中使用,比如
initCodec();
//mCamera.setPreviewCallback(new MyPreviewCallback());
mCamera.setPreviewCallback(new PreviewCallback()
@Override
public void onPreviewFrame(byte[] data, Camera camera)
encode(data);
);
我只是不知道如何正确使用 MediaCodec API。你能给我一些建议或链接吗?
谢谢!
【问题讨论】:
你是用它来录制没有音频的视频吗,我想知道如何使用它和MediaMuxer一起录制视频和音频 【参考方案1】:我已经解决了问题。如下:
private synchronized void encode(byte[] data)
inputBuffers = mMediaCodec.getInputBuffers();// here changes
outputBuffers = mMediaCodec.getOutputBuffers();
int inputBufferIndex = mMediaCodec.dequeueInputBuffer(-1);
Log.i(TAG, "inputBufferIndex-->" + inputBufferIndex);
//......
接下来,你会发现你的编码视频颜色不对,更多信息请到这里MediaCodec and Camera: colorspaces don't match
【讨论】:
我得到了这个错误。如何解决这个 pblm....java.lang.NoClassDefFoundError: android.media.MediaCodec 错误指出这一行:mMediaCodec = MediaCodec.createEncoderByType("video/avc" ); @Aravi 看来您尝试在具有 API 的 Android 上使用 MediaCodec 【参考方案2】:摄像机输出的 YUV420 格式与 MediaCodec AVC 编码器接受的格式不兼容。在最好的情况下,它本质上是 NV12 与 NV21(U 和 V 平面颠倒),需要手动重新排序。在最坏的情况下,从 Android 4.2 开始,编码器输入格式可能是特定于设备的。
您最好使用MediaRecorder 将相机硬件连接到编码器。
更新:
现在可以将相机的 Surface 预览传递给 MediaCodec
,而不是使用 ByteBuffer
中的 YUV 数据。这更快,更便携。请参阅 CameraToMpegTest 示例 here。
【讨论】:
谢谢你的帮助。我录制了一个视频文件,但是文件数据不正确。开始数据是正确的,它们是h.264帧数据,但是大约三帧之后,h .264帧数据全部填充0。可能是文件缓冲区错误,我认为,但它不能是0 嗨,@fadden。关于“您最好使用 MediaRecorder 将相机硬件连接到编码器。”,是否有任何示例代码?谢谢。 MediaRecorder,Surface 不允许在录制前处理帧,为什么你认为它更快?我认为作者知道 MediaRecord,但正如您所见,他询问了相机框架以上是关于如何使用 Android MediaCodec 编码相机数据(YUV420sp)的主要内容,如果未能解决你的问题,请参考以下文章
Android 音视频 - MediaCodec 编解码音视频
Android 音视频编解码 -- 视频编码和H264格式原理讲解
Android 音视频编解码 -- 视频编码和H264格式原理讲解