default: TRESPASS(); break; } }
显然这是一个消息的处理函数,对于 kWhatEmptyThisBuffer, kWhatFillThisBuffer这类消息都会进入到
onQueueFilled(i)函数,这个 onQueueFilled函数相当于是OMX软件编解码组件的一个入口,函数显示如下:
void SoftMPEG4::onQueueFilled(OMX_U32 portIndex) { ?...
Bool success = PVInitVideoDecoder(
mHandle, vol_data, &vol_size, 1, mWidth, mHeight, mode);
?...
MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
PVSetPostProcType((VideoDecControls *) mHandle, 0); notifyEmptyBufferDone(inHeader); ?...
PVSetReferenceYUV(mHandle, outHeader->pBuffer);
if (PVDecodeVideoFrame(mHandle, &bitstream, ×tamp, &tmp, &useExtTimestamp,
outHeader->pBuffer) != PV_TRUE) {
notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; return; }
?...
notifyFillBufferDone(outHeader); }
上面的函数只保留了几个关键的函数调用,可以看到在这个onQueueFilled函数中会通过一些类似与 PVDecodeVideoFrame
进入到OMX 框架中软件编解码的部分。可以看到通过 PVDecodeVideoFrame之后的yuv数据会保存在outHeader->pBuffer
字段中。然后通过notifyEmptyBufferDone(inHeader); 或者notifyFillBufferDone(outHeader);来向组件OMX
外部通知已经从inPutPort消费了一个buffer或者已经向outPutPort填充了一个buffer。
简单说来,当notifyEmptyBufferDone的时候,OMX会记录已经被消费的buffer的索引,然后继续在该索引对应
的buffer上 drainInputBuffer,当notifyFillBufferDone时候最终会通过OMX的消息机制走到OMXCodec::
on_message中进入case omx_message::FILL_BUFFER_DONE:主要工作是,记录这个已经填充的buffer的索引号,然后 将这个索引号保存在
mFilledBuffers.push_back(i); mBufferFilled.signal();
看到mBufferFilled这个Condition被signal了,那么谁wait在这个Condition上呢?看上OMXCodec::read函数中我
红色标注的部分。原来在OMXCodec::read函数的后半段中会一直 while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
if ((err = waitForBufferFilled_l()) != OK) { return err; } }
那么FILL_BUFFER_DONE之后,在OMXCodec::read函数中被返回给AwesomePlayer的mVideoBuffer就是在 OMX框架中outPutPort上的buffer。
通过上面的分析可以看到,虽然在OMX框架中 Input/OutPutPort上的buffer的生产和消费是异步,但是还是通过了一个
Condition mBufferFilled来做同步。这个生产者消费者的问题,来用一个信号量做同步,还是比较好的。
原文三:
Android_ics openmax in stagefright 学习记录------1
链接:http://blog.csdn.net/mci2004/article/details/7753741
这几篇文章是之前学习openmax的输出,记录在这里,希望不要误导菜鸟的同时又能得到牛牛们的指导。
android_ics openmax_in_stagefright 再次学习 /*
*在学习android源代码的工程中,一点要时刻牢记C/S架构 *任何时刻都要搞清除,这个时候的代码是运行在客户端, *还是服务端,这个对象来之,客户端还是服务端的代理。 */
<---以下的讨论,目的都在于弄清楚,stagefright框架内,OpenMaXIL和各个编解码的组件是如何通信的--->
At first:
OpenMax是事实上的标准,也是android上多媒体编解码框架未来的趋势。
分析的比较凌乱,后面在做整理。
///////////////////////////////////////////// //1,OMX 从何开始?
////////////////////////////////////////////
看下awesomeplayer的构造函数
AwesomePlayer::AwesomePlayer() : mQueueStarted(false), ...
mTextPlayer(NULL) {
/*mClient是一个OMXClient类型的成员变量*/ CHECK_EQ(mClient.connect(), (status_t)OK); DataSource::RegisterDefaultSniffers();
mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent); ...
mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate); mVideoEventPending = false;
mCheckAudioStatusEvent = new AwesomeEvent( this, &AwesomePlayer::onCheckAudioStatus); ... }
/*connect函数的定义*/
status_t OMXClient::connect() {
sp
sp
interface_cast
CHECK(service.get() != NULL);
mOMX = service->getOMX(); CHECK(mOMX.get() != NULL);
return OK; }
上面的函数,通过binder取请求MediaPlayerService的getOmx然后反回一个OMX实例,事实上这个时候在awesomePlayer
中的mOMX是一个来之服务端的实例。打通了一条Client->Service的通道。个人认为这就是OpenMax框架的入口。
/*OMX的构造函数如下,@OMX.cpp*/
OMX::OMX():mMaster(new OMXMaster),mNodeCounter(0) { }
-------------------------以下是插曲,首次看请忽略--------------------------------------------------------->
/*下面完整的贴出OMX的结构,其中有些成员的作用,在后面的学习中,会慢慢的揭开其真面目*/
class OMX : public BnOMX, public IBinder::DeathRecipient { public: OMX();
virtual bool livesLocally(pid_t pid);
virtual status_t listNodes(List
virtual status_t allocateNode(
const char *name, const sp
virtual status_t freeNode(node_id node);
virtual status_t sendCommand(
node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param);
virtual status_t getParameter( node_id node, OMX_INDEXTYPE index, void *params, size_t size);
virtual status_t setParameter( node_id node, OMX_INDEXTYPE index,