我使用Android的MediaCodec API编写了H264流编码器.我在大约十个不同处理器的不同设备上进行了测试,除了Snapdragon 800驱动的设备(谷歌Nexus 5和索尼Xperia Z1)之外,它在所有设备上都有效.在这些设备上,我得到了SPS和PPS以及第一个Keyframe,但之后mEncoder.dequeueOutputBuffer(mBufferInfo,0)只返回MediaCodec.INFO_TRY_AGAIN_LATER.我已经尝试过不同的超时,比特率,分辨率和其他配置选项,但无济于事.结果总是一样的.
我使用以下代码初始化编码器:
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); } }
谢谢你的帮助!