【问题标题】:Android Media Codec video decodingAndroid Media Codec 视频解码
【发布时间】:2012-11-14 02:09:03
【问题描述】:

这是我的第一个问题,如果我遗漏了什么,请告诉我!

使用 Android API 16 的新媒体编解码器实现来尝试解码视频,以便我可以发送帧以作为纹理应用(纹理部分已经完成)。因此,我在堆栈外提供了一些帮助,但在runOutputBuffer() 中,我的outputBufIndex 回来了-1 (或者在我提供-1 作为超时的无限循环中)任何人都可以帮忙这个,和/或提供任何关于从那里去哪里的建议?

感谢您的帮助,这是我的代码:

public MediaDecoder( BPRenderView bpview )
{

    surface = bpview;
    extractor = new MediaExtractor( );
    extractor.setDataSource( filePath );
    format = extractor.getTrackFormat( 0 );
    mime = format.getString( MediaFormat.KEY_MIME );
    createDecoder( );
    runInputBuffer( );

}

public void createDecoder( )
{

    codec = MediaCodec.createDecoderByType( "video/avc" );
    // format =extractor.getTrackFormat( 0 );
    Log.d( LOG_TAG, "Track Format: " + mime );
    // format.setInteger( MediaFormat.KEY_BIT_RATE, 125000 );
    // format.setInteger( MediaFormat.KEY_FRAME_RATE, 15 );
    // format.setInteger( MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar );
    // format.setInteger( MediaFormat.KEY_I_FRAME_INTERVAL, 5 );
    codec.configure( format, null, null, 0 );
    codec.start( );

    codecInputBuffers = codec.getInputBuffers( );
    codecOutputBuffers = codec.getOutputBuffers( );
    extractor.selectTrack( 0 );
}

public void runInputBuffer( )
{
    // This should take in the entire video and put it in the input buffer
    int inputBufIndex = codec.dequeueInputBuffer( -1 );
    if( inputBufIndex >= 0 )
    {
        ByteBuffer dstBuf = codecInputBuffers[ inputBufIndex ];

        int sampleSize = extractor.readSampleData( dstBuf, 0 );
        Log.d( "Sample Size", String.valueOf( sampleSize ) );
        long presentationTimeUs = 0;
        if( sampleSize < 0 )
        {
            sawInputEOS = true;
            sampleSize = 0;
        }
        else
        {
            presentationTimeUs = extractor.getSampleTime( );
        }
        Log.d( LOG_TAG, "Input Buffer" );
        Log.d( "InputBufIndex:", String.valueOf( inputBufIndex ) );
        Log.d( "PresentationTimeUS", String.valueOf( presentationTimeUs ) );
        codec.queueInputBuffer( inputBufIndex, 0, // offset
                sampleSize, presentationTimeUs, sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0 );
        if( !sawInputEOS )
        {
            Log.d( "Extractor", " Advancing" );
            extractor.advance( );

        }
    }
    runOutputBuffer( );
}

public void runOutputBuffer( )
{
    BufferInfo info = new BufferInfo( );

    final int res = codec.dequeueOutputBuffer( info, -1 );

    Log.d( "RES: ", String.valueOf( res ) );
    if( res >= 0 )
    {
        int outputBufIndex = res;
        ByteBuffer buf = codecOutputBuffers[ outputBufIndex ];
        final byte[ ] chunk = new byte[ info.size ];
        buf.get( chunk ); // Read the buffer all at once
        buf.clear( ); // ** MUST DO!!! OTHERWISE THE NEXT TIME YOU GET THIS SAME BUFFER BAD THINGS WILL HAPPEN

        if( chunk.length > 0 )
        {
            Log.d( "Chunk: ", String.valueOf( chunk.length ) );

            surface.setTexture( chunk, 320, 240 );

            // mAudioTrack.write( chunk, 0, chunk.length );
            // do the things
        }
        codec.releaseOutputBuffer( outputBufIndex, false /* render */);

        if( ( info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM ) != 0 )
        {
            sawOutputEOS = true;
        }
    }
    else if( res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED )
    {
        codecOutputBuffers = codec.getOutputBuffers( );
    }
    else if( res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED )
    {
        final MediaFormat oformat = codec.getOutputFormat( );
        Log.d( LOG_TAG, "Output format has changed to " + oformat );
        // mAudioTrack.setPlaybackRate( oformat.getInteger( MediaFormat.KEY_SAMPLE_RATE ) );
    }

}

}

【问题讨论】:

    标签: android video media codec decoding


    【解决方案1】:

    James,欢迎来到 Stack Overflow(作为提问者)!

    我试图玩弄 MediaCodec 类,它非常有限且文档记录不充分。但是,请查看 Cedric Fung 的这个漂亮的 solid post(和他链接的 github)。他的 github 项目应该可以在 API-17 (JellyBean 4.2)+ 设备上开箱即用。

    我确信您可以从那里确定您需要更改的内容,尽管正如我之前提到的,您在 API 的当前级别上的灵活性有限。

    关于您的具体问题,我认为您正在使用媒体解码器调用锁定 UI,不建议这样做,您应该采用线程方法,而不是将 -1 设置为超时,而将超时设置为 10000并允许它被多次调用,直到它被激活。

    希望这会有所帮助(尽管您问这个问题已经有几个月了)!

    【讨论】:

    • 您好 Korc 感谢您的回答。是的,我现在把它修好了,而且效果很好,但是这个类有很多问题,特别是,正如你所说,它的灵活性。幸运的是,我们的应用程序主要用于 S3,但如果您要在多个设备(和 API)上使用此类,考虑到您必须允许的编解码器数量,它或多或少无用,尤其是当您尝试进行一些后期处理时在数据上,你不知道你会得到什么缓冲区(YUV420 等),直到你在设备上尝试它!疯狂!
    • 是的!对于后处理(我正在探索 MediaCodec 类的原因之一),我开始工作的一个解决方案是将缓冲区直接写入表面(类似于 Cedric 的代码),除了使用 TextureView 而不是 @ 987654325@(我可以指导您使用可让您执行此操作的代码)。一旦你有了它,你就可以使用 TextureView 的漂亮的“getBitmap”操作来填充一个 Android Bitmap 对象——它具有你可以设置的已知格式,通常是ARGB_8888——你可以对其进行操作。它没有那么高效或优雅,但可以完成工作。
    • MediaCodec 在 4.3 (API 18) 中有所改进。一些示例代码从这里链接:bigflake.com/mediacodec
    • kOrc 能否提供一个使用 TextureView 的示例的链接?
    • 其他一些示例,在 API 18 SDK 应用程序(包括使用 TextureView 的视频播放器)中:github.com/google/grafika
    猜你喜欢
    • 1970-01-01
    • 2013-09-30
    • 2017-09-16
    • 1970-01-01
    • 2020-06-30
    • 1970-01-01
    • 1970-01-01
    • 2016-10-07
    • 2018-12-25
    相关资源
    最近更新 更多