简体   繁体   English

MediaCodec.Callback句柄来自MediaExtractor的IllegalStateException

[英]MediaCodec.Callback handle IllegalStateException from MediaExtractor

I am using MediaCodec in asynchronous mode to transcode a video based on the example by mstorsjo . 我基于mstorsjo的示例,以异步模式使用MediaCodec对视频进行转码。 With some video files I am getting IllegalStateException 's thrown when I call either MediaExtractor.advance() or MediaExtractor.getSampleTime() . 对于某些视频文件,调用MediaExtractor.advance()MediaExtractor.getSampleTime()时会IllegalStateException Eg in my audio decoder: 例如在我的音频解码器中:

MediaCodec decoder = MediaCodec.createDecoderByType(type);
decoder.setCallback(new MediaCodec.Callback() {
    public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {
        ByteBuffer decoderInputBuffer = codec.getInputBuffer(index);
        while (!mExtractorDone) {
            int size = mExtractor.readSampleData(decoderInputBuffer, 0);
            long presentationTimeUs = mExtractor.getSampleTime();
            boolean queuedInputBuffer = false;
            if (size >= 0) {
                codec.queueInputBuffer(
                        index,
                        0,
                        size,
                        presentationTimeUs,
                        mExtractor.getSampleFlags());
                queuedInputBuffer = true;
            }
            mExtractorDone = !mExtractor.advance();
            if (mExtractorDone) {
                queueEOS();
            }
            if (queuedInputBuffer) {
                    break;
            }
        }
    }
    ...
});
decoder.configure(inputFormat, null, null, 0);
decoder.start();

And similarly in my video decoder, which is run in a separate HandlerThread . 同样,在我的视频解码器中,该视频解码器在单独的HandlerThread中运行。

Is there a way I can catch all exceptions thrown in the MediaCodec.Callback and pass them back to the main awaitEncode function, so I can close everything and exit nicely? 有没有一种方法可以捕获MediaCodec.Callback引发的所有异常,并将它们传递回主awaitEncode函数,以便我可以关闭所有内容并正常退出? Should I be putting try catch s around every callback and then notify the main processing thread? 我是否应该在每个回调中加入try catch ,然后notify主处理线程?

It would be great to figure out what is causing the original IllegalStateException , but I would also feel more comfortable knowing all problems with my video transcoder were being caught and explained to the user. 弄清楚是什么原因导致了最初的IllegalStateException ,这将是非常不错的选择,但我也很高兴知道视频转码器的所有问题都已被捕获并向用户解释了。

My best solution so far is to just wrap everything in a try catch block. 到目前为止,我最好的解决方案是将所有内容包装在try catch块中。 I use a utility class that extends MediaCodec.Callback : 我使用扩展MediaCodec.Callback的实用程序类:

public abstract class SafeMediaCodecCallback extends MediaCodec.Callback {

    private final OnExceptionListener exceptionListener;

    public SafeMediaCodecCallback(OnExceptionListener exceptionListener) {
        this.exceptionListener = exceptionListener;
    }

    @Override
    public final void onInputBufferAvailable(@NonNull MediaCodec mediaCodec, int i) {
        try {
            onInputBufferAvailableSafe(mediaCodec, i);
        } catch (Exception exception) {
            handleException(exception);
        }
    }

    @Override
    public final void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec, int i, @NonNull MediaCodec.BufferInfo bufferInfo) {
        try {
            onOutputBufferAvailableSafe(mediaCodec, i, bufferInfo);
        } catch (Exception exception) {
            handleException(exception);
        }
    }

    @Override
    public final void onError(@NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
        handleException(e);
    }

    @Override
    public final void onOutputFormatChanged(@NonNull MediaCodec mediaCodec, @NonNull MediaFormat mediaFormat) {
        try {
            onOutputFormatChangedSafe(mediaCodec, mediaFormat);
        } catch (Exception exception) {
            handleException(exception);
        }
    }

    private void handleException(Exception e) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (e instanceof CodecException) {
                CodecException codecExc = (CodecException) e;

                if (codecExc.isTransient()) {
                    // We'll let transient exceptions go
                    return;
                }
            }
        }

        exceptionListener.onException(e);
    }

    public abstract void onInputBufferAvailableSafe(@NonNull MediaCodec mediaCodec, int i);

    public abstract void onOutputBufferAvailableSafe(@NonNull MediaCodec mediaCodec, int i, @NonNull MediaCodec.BufferInfo bufferInfo);

    public abstract void onOutputFormatChangedSafe(@NonNull MediaCodec mediaCodec, @NonNull MediaFormat mediaFormat);

}

And then I can bubble exceptions back up to the top thread, and if we can't recover, kill all the threads, tidy up, and throw the original Exception . 然后,我可以将异常冒泡回到顶部线程,如果我们无法恢复,请杀死所有线程,整理一下并抛出原始Exception

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM