我已經使用Android的MediaCodec API編寫了H264 Stream Encoder。我使用不同的處理器在大約十種不同的設備上進行了測試,它在所有這些設備上都能正常工作,Snapdragon 800處理器(Google Nexus 5和Sony Xperia Z1)除外。在這些設備上,我獲得了SPS和PPS以及第一個關鍵幀,但在此之後,mEncoder.dequeueOutputBuffer(mBufferInfo,0)僅返回MediaCodec.INFO_TRY_AGAIN_LATER。我已經嘗試過使用不同的超時,比特率,分辨率和其他配置選項,但無濟於事。結果總是一樣的。MediaCodec H264編碼器無法在Snapdragon 800設備上工作
我用下面的代碼來初始化編碼器:
mBufferInfo = new MediaCodec.BufferInfo();
encoder = MediaCodec.createEncoderByType("video/avc");
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 640, 480);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 768000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, mEncoderColorFormat);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
encoder.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
在選擇的顏色格式是:
MediaCodecInfo.CodecCapabilities capabilities = mCodecInfo.getCapabilitiesForType(MIME_TYPE);
for (int i = 0; i < capabilities.colorFormats.length && selectedColorFormat == 0; i++)
{
int format = capabilities.colorFormats[i];
switch (format) {
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar:
selectedColorFormat = format;
break;
default:
LogHandler.e(LOG_TAG, "Unsupported color format " + format);
break;
}
}
我做
ByteBuffer[] inputBuffers = mEncoder.getInputBuffers();
ByteBuffer[] outputBuffers = mEncoder.getOutputBuffers();
int inputBufferIndex = mEncoder.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0)
{
// fill inputBuffers[inputBufferIndex] with valid data
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(rawFrame);
mEncoder.queueInputBuffer(inputBufferIndex, 0, rawFrame.length, 0, 0);
LogHandler.e(LOG_TAG, "Queue Buffer in " + inputBufferIndex);
}
while(true)
{
int outputBufferIndex = mEncoder.dequeueOutputBuffer(mBufferInfo, 0);
if (outputBufferIndex >= 0)
{
Log.d(LOG_TAG, "Queue Buffer out " + outputBufferIndex);
ByteBuffer buffer = outputBuffers[outputBufferIndex];
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0)
{
// Config Bytes means SPS and PPS
Log.d(LOG_TAG, "Got config bytes");
}
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0)
{
// Marks a Keyframe
Log.d(LOG_TAG, "Got Sync Frame");
}
if (mBufferInfo.size != 0)
{
// adjust the ByteBuffer values to match BufferInfo (not needed?)
buffer.position(mBufferInfo.offset);
buffer.limit(mBufferInfo.offset + mBufferInfo.size);
int nalUnitLength = 0;
while((nalUnitLength = parseNextNalUnit(buffer)) != 0)
{
switch(mVideoData[0] & 0x0f)
{
// SPS
case 0x07:
{
Log.d(LOG_TAG, "Got SPS");
break;
}
// PPS
case 0x08:
{
Log.d(LOG_TAG, "Got PPS");
break;
}
// Key Frame
case 0x05:
{
Log.d(LOG_TAG, "Got Keyframe");
}
//$FALL-THROUGH$
default:
{
// Process Data
break;
}
}
}
}
mEncoder.releaseOutputBuffer(outputBufferIndex, false);
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0)
{
// Stream is marked as done,
// break out of while
Log.d(LOG_TAG, "Marked EOS");
break;
}
}
else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
{
outputBuffers = mEncoder.getOutputBuffers();
Log.d(LOG_TAG, "Output Buffer changed " + outputBuffers);
}
else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)
{
MediaFormat newFormat = mEncoder.getOutputFormat();
Log.d(LOG_TAG, "Media Format Changed " + newFormat);
}
else if(outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER)
{
// No Data, break out
break;
}
else
{
// Unexpected State, ignore it
Log.d(LOG_TAG, "Unexpected State " + outputBufferIndex);
}
}
由於獲取數據您的幫助!
當輸出停止時,有多少輸入幀排隊? (我想確保它不是簡單的輸入。)有沒有什麼可疑的東西在logcat中看? (編解碼器傾向於噴灑Log.e,這可能很難說)。正在選擇什麼顏色格式? (QCOM格式?)「原始幀」的大小是否與輸入緩衝區的容量完全相同? (如果不是......爲什麼不呢?) – fadden
@fadden我讓它運行了多長時間並不重要,但它似乎總是在輸入緩衝區中有5幀。它在創建時的輸出是:'I/OMXClient(11245):使用客戶端OMX mux。 I/ACodec(11245):setupVideoEncoder succeeded'選擇的顏色格式在兩種情況下都是'MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar'(如果我查詢所有格式,它只有兩個,上述和一個常數爲2130708361,如果選中則崩潰。)原始幀和輸入緩衝區不相同(原始幀大小始終較小,輸入緩衝區容量始終爲282624) – lowtraxx
五個幀是典型的 - 聽起來像它不處理輸入,因此沒有輸出。我假設你在調用'encoder.start()'? YUV420SemiPlanar很好; 2130708361僅用於表面輸入。 YUV420緩衝區的大小應該是'width * height * 1.5',或460800字節,所以我對你的緩衝區大小有點困惑。你在日誌文件中看到你的「媒體格式改變」信息,如果有,它說什麼? – fadden