Android Media Codec视频解码 [英] Android Media Codec video decoding

查看:159
本文介绍了Android Media Codec视频解码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的第一个问题,所以请让我知道是否错过了任何事情!

This is my first question so please let me know if I missed anything!

使用Android API 16的新Media Codec实现尝试对视频进行解码,以便我可以发送要用作纹理的帧(纹理部分已经完成).因此,我想出了下面的代码,并提供了一些堆栈帮助,但是在runOutputBuffer()中,我的outputBufIndex返回了-1(或者在无限循环中,因为我提供了-1作为超时),任何人都可以提供帮助和/或提供有关从那里去哪里的任何建议?

Using Android API 16's new Media Codec implementation to try and decode a video so that I can send frames to be applied as a texture (the texture part is already done). So I have come up with the following code with some help off stack but in runOutputBuffer() my outputBufIndex is coming back -1 (or in an infinite loop as I have provided -1 as a timeout) can anyone help with this, and/or provide any advice on where to go from there?

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

Thanks for your help and here is my code:

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 ) );
    }

}

}

推荐答案

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

James, welcome to Stack Overflow (as a questioner)!

我曾尝试使用MediaCodec类来玩,但它的局限性极强,而且文献记载也很少.但是,请查看塞德里克·冯(Cedric Fung)撰写的这篇漂亮的坚实的帖子(及其链接的github).他的github项目应该可以在API-17(JellyBean 4.2)+设备上直接使用.

I have tried to toy with the MediaCodec class, it is terribly limited and poorly documented. However, check out this pretty solid post (and his linked github) by Cedric Fung. His github project should just work out of the box on an API-17 (JellyBean 4.2)+ device.

我确定您可以从那里确定需要更改的内容,尽管正如我之前提到的那样,在此方面,使用当前的API级别,您的灵活性有限.

I'm sure you can determine what you need to change from there, although as I alluded to before, you have limited flexibility here with the current level of the API.

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

Regarding your specific problem, I think you are locking the UI with your media decoder calls, which is not recommended, You should be taking a threaded approach, and rather than setting -1 as your timeout, have a timeout of say 10000 and allow it to be called multiple times until it is active.

希望这会有所帮助(尽管距您提出问题已有数月之久了)!

Hope this helps (although it has been months since you asked the question)!

这篇关于Android Media Codec视频解码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆