close
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最后输出到硬件层。)
全站熱搜