Android MediaCodec将原始视频编码为h264
我正在尝试将手机摄像头输出转换为.h264 es格式,但MediaCodec编码器仍处于启用状态,请稍后在第一帧后重试输出缓冲区状态。摄像头预览设置为NV21 这里是摄像机到编码器:Android MediaCodec将原始视频编码为h264,android,encoding,h.264,android-mediacodec,Android,Encoding,H.264,Android Mediacodec,我正在尝试将手机摄像头输出转换为.h264 es格式,但MediaCodec编码器仍处于启用状态,请稍后在第一帧后重试输出缓冲区状态。摄像头预览设置为NV21 这里是摄像机到编码器: mCamera.setPreviewCallback(new Camera.PreviewCallback() { private long timestamp=0; @Override public void onPreviewFra
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
private long timestamp=0;
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
byte[] buffer = new byte[data.length];
encode(data);
}
});
编码器初始化:
private void initCodec() {
try {
mBufferInfo = new MediaCodec.BufferInfo();
mMediaCodec = MediaCodec.createEncoderByType("video/avc");
} catch (IOException e) {
e.printStackTrace();
}
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc",
1920,
1080);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 125000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
mMediaCodec.configure(mediaFormat,
null,
null,
MediaCodec.CONFIGURE_FLAG_ENCODE);
mMediaCodec.start();
}
和编码器本身:
private synchronized void encode(byte[] data) {
inputBuffers = mMediaCodec.getInputBuffers();// here changes
outputBuffers = mMediaCodec.getOutputBuffers();
int inputBufferIndex = mMediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(data);
mMediaCodec.queueInputBuffer(inputBufferIndex, 0, data.length, 0, 0);
} else {
return;
}
int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(mBufferInfo, 10000);
do {
if (outputBufferIndex >= 0) {
ByteBuffer outBuffer = outputBuffers[outputBufferIndex];
System.out.println("buffer info-->" + mBufferInfo.offset + "--"
+ mBufferInfo.size + "--" + mBufferInfo.flags + "--"
+ mBufferInfo.presentationTimeUs);
byte[] outData = new byte[mBufferInfo.size];
outBuffer.get(outData);
if (mBufferInfo.offset != 0) {
byte[] offsettedData;
offsettedData = Arrays.copyOfRange(outData, mBufferInfo.offset, outData.length-1);
pushFrame(offsettedData, offsettedData.length);
} else {
pushFrame(outData, outData.length);
}
mMediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mMediaCodec.dequeueOutputBuffer(mBufferInfo,
0);
} 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);
}
为什么输出缓冲区阻塞?请稍后重试(-1)?所有输入数据似乎都有效(来自摄像头) 您可以在bigflake()和Grafika()中找到一些示例。如果您选择使用YUV数据缓冲区,则可能需要执行颜色转换()。@fadden,我正在研究此链接中的源代码,但确定我的方法也没有完全错误(不完全错误,因为它只在第一帧上工作,没有其他帧)。另外,我没有找到如何将纹理传递到MediaCodec或从纹理获取表面。