首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >S7上的MediaCodec失败

S7上的MediaCodec失败
EN

Stack Overflow用户
提问于 2016-06-15 23:06:10
回答 3查看 2.5K关注 0票数 0

我设置了一系列类来解码来自服务器的H264流视频,并将其呈现在SurfaceView上。现在,这段代码在我尝试过的每个设备上都能完美地工作,包括模拟器,但是突然我给自己买了一个S7,在这个设备上它不能正常工作了。

奇怪的是,有时它会完美地工作,而另一些时候则会抛出这个错误:

代码语言:javascript
复制
06-15 16:41:40.249 13300-24605/cm.myapp E/ACodec: [OMX.Exynos.avc.dec] ERROR(0x90000012)
06-15 16:41:40.249 13300-24605/cm.myapp E/ACodec: signalError(omxError 0x90000012, internalError -2147483648)
06-15 16:41:40.249 13300-24604/cm.myapp E/MediaCodec: Codec reported err 0x90000012, actionCode 0, while in state 6
06-15 16:41:40.249 13300-24578/cm.myapp  W/MediaStreamerThread: Failed to draw media.

有时它会在dequeueInputBuffers调用中崩溃:

代码语言:javascript
复制
java.lang.IllegalStateException
                                                                                at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)
                                                                                at android.media.MediaCodec.dequeueOutputBuffer(MediaCodec.java:2379)

然后,在其他一些时候,它会抛出这个非常不同的错误:

代码语言:javascript
复制
06-15 16:34:57.239 13300-16625/cm.myapp W/System.err: java.lang.IllegalArgumentException: The surface has been released
06-15 16:34:57.239 13300-16625/cm.myapp W/System.err:     at android.media.MediaCodec.native_configure(Native Method)
06-15 16:34:57.239 13300-16625/cm.myapp W/System.err:     at android.media.MediaCodec.configure(MediaCodec.java:1778)
                                                                        java.lang.RuntimeException: Could not create h264 decoder

这些错误本身并不是很详细,因此我不知道问题出在哪里。

再说一次,我的代码在大多数设备上都运行得很好,但在这台设备上却失败了。这怎麽可能?有什么想法吗?

这是我的解码代码:

代码语言:javascript
复制
public class H264Decoder
{
    static private final long TIMEOUT_US = 10000L;

    private MediaCodec mDecoder;
    private Surface mSurface;

    private static final List<byte[]> EMPTY_ENCODE_RESULT = new ArrayList<>();
    public void init()
    {

                try
                {
                    mDecoder = MediaCodec.createDecoderByType( "video/avc" );

                    MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 640, 480);

                    mDecoder.configure(mediaFormat, mSurface, null, 0);
                    mDecoder.start();

                }
                catch(NoClassDefFoundError ex) {
                    ex.printStackTrace();
                    throw new RuntimeException("Could not create h264 decoder", ex);
                }        
    }

    public List<byte[]> offer(byte[] data)
    {
        List<byte[]> returnValue = new ArrayList<>();
        returnValue.add(decode(data, true));
        return returnValue; 
    }

    public void release()
    {
        assert mSurface != null;
        assert mDecoder != null;

        mDecoder.stop();
        mDecoder.release();
        mDecoder = null;
    }

    public H264Decoder(Surface surface)
    {
        mSurface = surface;
    }

    public byte[] decode(byte[] data, boolean updateRender)
    {
        if (mSurface == null)
        {
            return null;
        }
        // INPUT -----------------------------------------------------------------------------------

        int inputBufferIndex = mDecoder.dequeueInputBuffer(TIMEOUT_US);

        if (inputBufferIndex >= 0)
        {
            // Get an input buffer from the codec, fill it with data, give it back
            ByteBuffer inputBuffer = mDecoder.getInputBuffers()[inputBufferIndex];
            inputBuffer.put(data);
            mDecoder.queueInputBuffer(inputBufferIndex, 0, data.length, 0, 0 );
        }

        // OUTPUT ----------------------------------------------------------------------------------

        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        int outputBufferIndex = mDecoder.dequeueOutputBuffer(info, TIMEOUT_US);

        if ( outputBufferIndex >= 0 )
        {
            final ByteBuffer[] outputBuffer = mDecoder.getOutputBuffers();
            mDecoder.releaseOutputBuffer(outputBufferIndex, updateRender);

        }
        else if ( outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED )
        {
            //outputBuffers = codec.getOutputBuffers();
        }
        else if ( outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED )
        {
            MediaFormat format = mDecoder.getOutputFormat();
        }
        return null;
    }
}
EN

回答 3

Stack Overflow用户

发布于 2016-06-17 00:19:59

很难说会出什么问题。但有一件事是

代码语言:javascript
复制
mDecoder.releaseOutputBuffer(outputBufferIndex, updateRender);
if(!updateRender) {
    return outputBuffer[outputBufferIndex].array();
}

我不建议从输出缓冲区返回数组。According to documentation它声明

一旦输出缓冲区释放到编解码器,就不能使用它

如果您确实需要编码的样本,我最好创建一个输出缓冲区的副本,调用release,然后返回副本。

如果返回的字节数组被以某种方式处理,我建议将解码器的这个方法提取到循环中并处理字节缓冲区(输出缓冲区),然后调用释放输出缓冲区。为了获得更多参考,我将查看MediaCodec Synchronous Processing using Buffers

票数 1
EN

Stack Overflow用户

发布于 2017-01-12 17:41:24

对于三星S7,您必须确保插入解码器的第一个H264帧是I帧。

票数 0
EN

Stack Overflow用户

发布于 2019-08-17 16:31:09

在三星Galaxy S8上,我会在调用MediaCodec.configure()之后异步获取ERROR(0x90000012),然后再提供任何流输入。

获得ERROR(0x90000012)的一个可靠方法是使用AVCC格式的流(就像Apple Quicktime电影)。

事实上,似乎在许多安卓设备上,我们使用附件B格式的H264取得了更大的成功。

附件-b还意味着不需要使用MediaCodec.BUFFER_FLAG_CODEC_CONFIG或通过MediaFormat (csd-0csd-1密钥)配置的sps/pps传递带外额外数据。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37839215

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档