close
 

Stagefright,omx与Component的交互

分类: android 140人阅读 评论(0) 收藏 举报

 

Stagefright中的Extractor/Writer分别对应多媒体播放流程中的Demux/Remux,而Component对应Encoder/Decoder。本文以解码为例介绍Extractor如何工作,以及Stagefright和Component之间如何通过与OMX层对接,完成track分离及解码工作。

(之前的调用流程为:java层 -> jni -> mediaplayerservice -> stagefrightplayer -> awesomeplayer)

一、Extractor的工作:
    不管同步或异步,setDataSource() 最后会调用 AwesomePlayer::finishSetDataSource_l()
    finishSetDataSource_l 调用 MediaExtractor::Create()创建相应的Extractor(MP3Extrator、MPEG4Extractor etc.)
    每一个Extractor提供countTrack, getTrack等接口。
    其中getTrack返回一个XXXSource的实例,其提供read函数,作为回调接口,为后续的decode提供数据源
    Extractor就这么些活儿。


(值得注意的是,不是所有格式的播放都走完后面的decode流程,比如FLAC,FLACSource中返回的是已经解过码的数据,即MEDIA_MIMETYPE_AUDIO_RAW,将直接通过AudioTrack直接进行输出)

                

二、Stagefright、OMX、Component

    一)omx相关的封装
        1、OMXCodec    Stagefright封装此类作为解码后的数据源使用,即Awesomeplayer的mVideoSource/mAudioSource,播放时Awesomeplayer/Audioplayer直接使用mVideoSource/mAudioSource的read读取数据。具体解码工作由OMXCodec完成。
        
        2、OMXClient, OMX, OMXMaster                Stagefright和Component在不同的系统模块中(可理解为这俩甚至不同进程),通过OMX进行对接并交互,Stagefright作为客户端与服务端MediaPlayerService通过binder进行通信并建立omx模型,通过名字即可知道,OMXClient为客户端,OMX为服务端,实际上OMX把最后工作交给OMXMaster完成。
        最后Stagefright通过mClient(即OMXClient类的obj)调用服务端OMXMaster,实现对Component的发号施令。
        
        3、OMXNodeInstance
        Stagefright与Component的通信必须是双工的,才能完成任务交互,OMXNodeInstance可理解为一个信使。
        它通过handle、callback、owner完成交互工作:
            owner:nodeinstance由Stagefright建立,它的owner即Awesomeplayer
            callback:component 的最后初始化由instance完成,初始化时传入callback,component将由此回调instance,instance转交给owner。
            handle: Component提供,awesomeplayer的命令由instance通过handle转给component。
        具体调用参考后面的分析。
        
    二)OMXCodec的创建
        不管同步或异步,prepare() 最后会调用 AwesomePlayer::onPrepareAsyncEvent()
        onPrepareAsyncEvent 调用 initAudioDecoder和initVideoDecoder,这两个初始化函数里分别创建相应的 OMXCodec
            mAudioSource = OMXCodec::Create()
            mVideoSource = OMXCodec::Create()

    三)OMX交互模型建立,及Component的注册
        这是在AwsomePlayer初始化的时候进行的,关键代码如下:
        AwsomePlayer()
        => mClient->connect()
        = => mOMX = service->getOMX();
        
        MediaPlayerService::getOMX
        => mOMX = new OMX
        = => mMaster = new OMXMaster
        = = => addPlugin(new SoftOMXPlugin);
        = = => addVendorPlugin();

        每一个Plugin可包含多个Component:
        while ((err = plugin->enumerateComponents))
            mPluginByComponentName.add(name8, plugin);

    四)Component的实例化:
        OMXCodec创建的同时,进行了Component实例化,关键代码如下:
        AwesomePlayer::initAudioDecoder()
        => OMXCodec::Create()
            {
                componentName = findMatchingCodecs()
                omx->allocateNode(componentName, observer, &node);     // --- omx is mClient
                codec = new OMXCodec(node);
                    => mNode = node;
                return codec;
            }
        = => OMX::allocateNode
            {
                instance = new OMXNodeInstance(this, observer); // 
                // 1、这里引用传参,component返回handle
                // 2、传入callback函数,component通过callback进行回调
                mMaster->makeComponentInstance(instance, &OMXNodeInstance::kCallbacks, &handle)
                // handle保存到instance中,后面 OMXNodeInstance::sendCommand() 的时候使用这个handle
                instance.setHandle(handle);
            }
        = = => OMXMaster::makeComponentInstance(callbacks, handle)
                {
                    plugin->makeComponentInstance
                }
        = = = => SoftOMXPlugin::makeComponentInstance(callbacks, handle)
        = = = = = > 最后调用软解的createSoftOMXComponent,或vendor硬解的createOMXComponent
            
                
    五)给Component发消息:
        OMXCodec::onStateChange()
        => mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
        = => findInstance(node)->sendCommand(cmd, param);
        = = =>OMX_SendCommand(mHandle, cmd, param, NULL);
                // 这是一个宏定义,最后就变成:
                mHandle->SendCommand(cmd, param, NULL);

    六)Component回调:
        回调函数:OMXNodeInstance::kCallbacks = {&OnEvent, &OnEmptyBufferDone, &OnFillBufferDone }
        OMXNodeInstance::OnEvent(appData)
        {
            instance = static_cast<OMXNodeInstance *>(pAppData);
            instance->owner()->OnEvent()
        }
        // NodeInstance作为pAppData在createSoftOMXComponent的时候传递给component,
        // component回调的时候带回来
        // instance的owner即AwsomePlayer的omx实例
        // 最后消息发回AwsomePlayer
        
三、解码流程
    一)OMXCodec => Component
    
    // 流程由OMXCodec发起
    OMXCodec::read()
    {
        => drainInputBuffer(); // 请Component解码buffer里的数据
        = => mOMX->emptyBuffer() 
        = ... => OMX_EmptyThisBuffer()
        = ... = => mHandle->EmptyThisBuffer()
    
        => fillOutputBuffer(); 请Component把解码后的数据写到buffer里
        = ... = => mHandle->FillThisBuffer()
    }
    
    // 相应的回调:
    OMXCodec::on_message()
    {
        case omx_message::EMPTY_BUFFER_DONE:
            drainAnyInputBuffer(); // next buffer please
        case omx_message::FILL_BUFFER_DONE: {
            // output
            mFilledBuffers.push_back();
            mBufferFilled.signal();
            // next buffer
            fillOutputBuffer(info);
        }
    }
    
    二)Component => OMXCodec
    
    // e.g. soft decode
    SimpleSoftOMXComponent::onMessageReceived
    {
        case kWhatEmptyThisBuffer:
        case kWhatFillThisBuffer:
        {
            onQueueFilled(portIndex);
        }
    }
    XXXOMXComponent::onQueueFilled()
    {
        decode()
        => SoftOMXComponent::notifyFillBufferDone()
        = => mCallbacks->FillBufferDone()
        = = => OMXNodeInstance::OnFillBufferDone()
        = ... => OMXCodec::on_message()
    }
    
四、buffer流
    前面提到Stagefright和Component在不同的系统模块中,事实上,它俩还是在同一个进程里的(即mediaserver进程),从buffer内存管理上来看也说明了这点。OMX中数据使用的是Tunnel的概念,即一个in port, 一个out port。Stagefright遵循这一概念,内存是在Component中创建的,创建命令依然是由OMXCodec在初始化的时候发起:
    OMXCodec::allocateBuffers() 
    {
        mOMX->allocateBuffer(&buffer) // 注意这里引用传递,返回创建的buffer链表地址
        info.mBuffer = buffer
        mPortBuffers[portIndex].push(info); // 后续OMXCodec将使用mPortBuffers进行buffer链表的操作,而Buffer数据块则是在XXXSource::read()中分配的
    }
    => mOMX->allocateBuffer()
    = => OMXNodeInstance::allocateBuffer()
    = = => OMX_AllocateBuffer()
    
    // Component中创建buffer链表:
    SimpleSoftOMXComponent::allocateBuffer(buffer)
    => SimpleSoftOMXComponent::useBuffer
    = => port->mBuffers.push();
    
    // Component中使用buffer
    while (!inQueue.empty() && !outQueue.empty()) {
        BufferInfo *inInfo = *inQueue.begin();
        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
        inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
        ...
    }
    

(之后,解码数据通过mVideoRenderer及mAudioSink/mAudioTrack最后输出到硬件层。)

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 丘猴子 的頭像
    丘猴子

    轉貼部落格

    丘猴子 發表在 痞客邦 留言(0) 人氣()