在我尝试使用 MediaCodec 连接视频的过程中,我尝试使用两个MediaExtractor
s,每个都与 s 配对MediaCodec
作为解码器。我尝试本地化提取器和解码器循环,使它们看起来像这样:
private void videoExtractorLoop(MediaExtractor localVideoExtractor, MediaCodec destinationDecoder, ByteBuffer[] destinationDecoderInputBuffers)
{
boolean localExtractorIsOrig = (localVideoExtractor == videoExtractor);
boolean localDoneIndicator = localExtractorIsOrig ? videoExtractorDone : videoExtractorAppendDone;
while (mCopyVideo && !localDoneIndicator && (encoderOutputVideoFormat == null || muxing)) {
int decoderInputBufferIndex = destinationDecoder.dequeueInputBuffer(TIMEOUT_USEC);
if (decoderInputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
if (VERBOSE)
Log.d(TAG, "no video decoder input buffer");
break;
}
if (VERBOSE) {
Log.d(TAG, "video decoder: returned input buffer: "
+ decoderInputBufferIndex);
}
ByteBuffer decoderInputBuffer = destinationDecoderInputBuffers[decoderInputBufferIndex];
int size = localVideoExtractor.readSampleData(decoderInputBuffer, 0);
long presentationTime = localVideoExtractor.getSampleTime();
if (VERBOSE) {
Log.d(TAG, (localVideoExtractor == videoExtractor) + " video extractor: returned buffer of size "
+ size);
Log.d(TAG, (localVideoExtractor == videoExtractor) + " video extractor: returned buffer for time "
+ presentationTime);
}
if (size >= 0) {
if(localExtractorIsOrig)firstDecoderFinalFrameTimestamp = presentationTime;
destinationDecoder.queueInputBuffer(decoderInputBufferIndex, 0, size, presentationTime, localVideoExtractor.getSampleFlags());
}
if(localExtractorIsOrig)
{videoExtractorDone = !localVideoExtractor.advance();}
else
{
videoExtractorAppendDone = !localVideoExtractor.advance();
}
if (videoExtractorDone) {
if (VERBOSE)
Log.d(TAG, "video extractor: EOS");
if(localExtractorIsOrig && destinationDecoder == videoDecoder){destinationDecoder.queueInputBuffer(decoderInputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);}
else if(!localExtractorIsOrig && destinationDecoder == videoDecoderAppend){destinationDecoder.queueInputBuffer(decoderInputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);}
//videoDecoder.queueInputBuffer(decoderInputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
}
videoExtractedFrameCount++;
break;
}
//Video Extractor code end
}
private void localizedVideoDecoderLoop(MediaCodec localVideoDecoder, OutputSurface localVidDecoderOutputSurface, InputSurface dstEncoderInputSurface, ByteBuffer[] locDecoderOutputBuffers)
{
boolean localDecoderIsOrig = (localVideoDecoder == videoDecoder);
boolean localDoneIndicator = localDecoderIsOrig ? videoDecoderDone : videoDecoderAppendDone;
MediaFormat localDecoderOutFormat = localDecoderIsOrig ? decoderOutputVideoFormat : decoderOutputAppendVideoFormat;
Log.i("check_local_decoder", localDecoderIsOrig+"");
MediaCodec.BufferInfo localDecoderOutBufInfo = localDecoderIsOrig ? videoDecoderOutputBufferInfo : videoDecoderAppendOutputBufferInfo;
//Video Decoder code begin
while (mCopyVideo && !localDoneIndicator && (encoderOutputVideoFormat == null || muxing)) {
int decoderOutputBufferIndex = localVideoDecoder.dequeueOutputBuffer(localDecoderOutBufInfo, TIMEOUT_USEC);
if (decoderOutputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
if (VERBOSE)
Log.d(TAG, "no video decoder output buffer");
break;
}
if (decoderOutputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
if (VERBOSE)
Log.d(TAG, "video decoder: output buffers changed");
if(localDecoderIsOrig){videoDecoderOutputBuffers = localVideoDecoder.getOutputBuffers();}
else {videoDecoderAppendOutputBuffers = localVideoDecoder.getOutputBuffers();}
break;
}
if (decoderOutputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
if(localDecoderIsOrig){decoderOutputVideoFormat = localVideoDecoder.getOutputFormat();}
else{decoderOutputAppendVideoFormat = localVideoDecoder.getOutputFormat();}
Log.i("decoder_vid_out_format", localDecoderOutFormat+"");
if (VERBOSE) {
Log.d(TAG, "video decoder: output format changed: "
+ localDecoderOutFormat);
}
break;
}
if (VERBOSE) {
Log.d(TAG, "video decoder: returned output buffer: "
+ decoderOutputBufferIndex);
Log.d(TAG, "video decoder: returned buffer of size "
+ localDecoderOutBufInfo.size);
Log.d(TAG, "video decoder: returned buffer for time "
+ localDecoderOutBufInfo.presentationTimeUs);
}
ByteBuffer decoderOutputBuffer = locDecoderOutputBuffers[decoderOutputBufferIndex];
if ((localDecoderOutBufInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
if (VERBOSE)
Log.d(TAG, "video decoder: codec config buffer");
localVideoDecoder.releaseOutputBuffer(decoderOutputBufferIndex,
false);
break;
}
if (VERBOSE) {
Log.d(TAG, "video decoder: returned buffer for time "
+ localDecoderOutBufInfo.presentationTimeUs);
}
boolean render = localDecoderOutBufInfo.size != 0;
localVideoDecoder.releaseOutputBuffer(decoderOutputBufferIndex,
render);
if (render) {
renderingFrameSection(localVidDecoderOutputSurface, dstEncoderInputSurface, localDecoderOutBufInfo.presentationTimeUs);
}
videoDecodedFrameCount++;
if ((localDecoderOutBufInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
if (VERBOSE)
Log.d(TAG, "video decoder: EOS");
if(localDecoderIsOrig){videoDecoderDone = true;}
else{videoDecoderAppendDone = true;}
if(!localDecoderIsOrig){videoEncoder.signalEndOfInputStream();}
}
break;
}
//Video Decoder code end
}
我在通常的 ExtractDecodeEditEncodeTest 中使用这些函数分别代替了 Extractor 代码和 Decoder 代码。我只是传入我想要使用MediaExtractor
的解码器,我希望该函数使用所述提取器和解码器执行通常的提取/解码循环。MediaCodec
当我将这些函数用于第一个提取器-解码器对时,它们运行良好。但是,当我在第一个工作完成后立即将它们用于第二个提取器-解码器对时,我从该行中得到以下异常destinationDecoder.queueInputBuffer(decoderInputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
:
W/System.err: android.media.MediaCodec$CodecException: Error 0xfffffff3
编辑:
我仔细查看了堆栈跟踪,发现了这些:
10-07 10:37:39.697 3061-25956/? I/EXYNOS_BASE_COMP: [0xf1459700][Exynos_OMX_ComponentStateSet] current:(OMX_StateLoaded) dest:(OMX_StateIdle)
10-07 10:37:39.697 23904-25949/com.picmix.mobile I/ACodec: [OMX.Exynos.avc.dec] Now Loaded->Idle
10-07 10:37:39.707 23904-25949/com.picmix.mobile D/SurfaceUtils: set up nativeWindow 0x7f76e82010 for 400x224, color 0x105, rotation 0, usage 0x2900
10-07 10:37:39.707 23904-25949/com.picmix.mobile I/ACodec: [OMX.Exynos.avc.dec] configureOutputBuffersFromNativeWindow setBufferCount : 7, minUndequeuedBuffers : 5
10-07 10:37:39.707 3061-25956/? D/libexynosv4l2: try node: /dev/video6
10-07 10:37:39.707 3061-25956/? I/libexynosv4l2: node found for device s5p-mfc-dec: /dev/video6
10-07 10:37:39.707 23904-25929/com.picmix.mobile I/check_local_decoder: false
10-07 10:37:39.707 3061-25956/? I/libexynosv4l2: open video device /dev/video6
10-07 10:37:39.717 3061-25956/? I/EXYNOS_BASE_COMP: [0xf1459700][Exynos_OMX_ComponentStateSet]:567 OMX_EventCmdComplete
10-07 10:37:39.717 3061-25956/? I/EXYNOS_BASE_COMP: [0xf1459700][Exynos_OMX_ComponentStateSet] current:(OMX_StateIdle) dest:(OMX_StateExecuting)
10-07 10:37:39.717 3061-25956/? I/EXYNOS_BASE_COMP: [0xf1459700][Exynos_OMX_ComponentStateSet]:567 OMX_EventCmdComplete
10-07 10:37:39.717 23904-25949/com.picmix.mobile I/ACodec: [OMX.Exynos.avc.dec] Now Idle->Executing
10-07 10:37:39.717 23904-25949/com.picmix.mobile I/ACodec: [OMX.Exynos.avc.dec] Now Executing
10-07 10:37:39.717 3061-25979/? E/libexynosv4l2: failed to ioctl: VIDIOC_S_CTRL (22)
10-07 10:37:39.717 3061-25979/? E/EXYNOS_H264_DEC: Failed to set buffer process type(not supported)
10-07 10:37:39.717 3061-25979/? E/libexynosv4l2: failed to ioctl: VIDIOC_G_CTRL (22 - Invalid argument)
我需要在解码器设置中更改什么?