Android Multimedia框架總結(十二)CodeC部分之OMXCodec與OMX事件回撥流程
前言:上篇文中分析到AwesomePlayer到OMX服務,曾介紹到,OMX服務主要完成三個任務: NodeInstance列表的管理,NodeInstance的操作, 事件的處理。最後這個事件處理就是今天放大看的內容。要一步一步一Codec,事件傳遞必不可少,看下今天的Agenda:
- OMXCodec與OMX callback事件的處理時序圖
- 如何從OMX中dispatch到OMXCodec(附時序圖)
- 緩衝區更新過程
- onMessage回撥
OMXCodec與OMX callback事件的處理時序圖
OMXCodec與OMX callback事件的處理時序圖:
從時序圖看,首先我們要建立個OMXCodecObserver,該類是OMXCodec的內部類,在create函式中被建立,並把對應的OMXCodec加入都自己的觀察範圍內,具體程式碼如下:
framework/base/media/libstagefright/OMXCodec.cpp
其次初始化它的callback事件和事件的派發處理函式
OMX主要的callback事件有哪些呢?
在framework/base/media/libstagefright/omx/OMXNodeInstance.cpp中的kCallbacks函式有如下定義:
callback在哪定義呢?
看framework/base/media/libstagefright/omx/OMX.cpp中的
即每個component對應一組callback事件。
這些callback由哪些函式返回呢?具體的定義在framework/base/media/libstagefright/openmax/OMX_Core.h
有了callback事件,如何dispatch呢?其實我們在allocateNote函式已經定義好了我們的dispatch函式
mDispatchers.add(*node, new CallbackDispatcher(instance));
如何從OMX中dispatch到OMXCodec
有了oberser, callback event , callbackdispatcher,那麼一個callback event 如何從OMX傳到OMXCodec呢?
下面我們以emptybuffer流程來具體看下,時序圖如下:
從時序圖上看:首先mVideoSource->read,實際上就是呼叫了OMXCodec::read,對應程式碼如下:
接著呼叫drainInputBuffer,把輸入通道中的所有輸入快取區,逐個傳遞給drainInputBuffer,即先把inputbuffer都讀滿,
然後一次性送給具體的component,讓其慢慢解碼,drainInputBuffer的實現如下:
以上程式碼總結為:
- 第一次執行OMXCodec::read時的操作。
- 當整個編解碼流程執行起來之後,會面臨著一個輸入\輸出緩衝區更新的問題。
緩衝區更新過程
輸入緩衝區更新過程:
如果一個輸入緩衝區資料被讀取完了,OpenMAX會觸發事件omx_message::EMPTY_BUFFER_DONE通知上層,
在這個事件處理流程中,會根據傳送來的bufferid找到對應的輸入緩衝區,
然後把這個緩衝區傳遞給drainInputBuffer,繼續往下執行。
如下:
輸出緩衝區更新過程:
- 解碼完畢後,OpenMAX元件觸發omx_message::FILL_BUFFER_DONE,
輸出緩衝區會被傳出交給上層使用(傳遞給surfaceflinger來顯示),使用完後需要把這個快取區重新交給OpenMax, - 上層使用完輸出緩衝區後會呼叫MediaBuffer::release進行銷燬,在這個介面中會把輸出緩衝區的引用計數減1,
- 然後呼叫signalBufferReturned,實際對應OMXCodec::signalBufferReturned介面,
- 最後再下一層呼叫fillOutputBuffer,把這個緩衝區重新交給openMAX。
總結:這樣就是通過第一次呼叫drainInputBuffers觸發openMAX,然後後面依靠openMAX的事件驅動來完成資料的讀取、解碼操作。
下面我們用輸出緩衝區為例,再放大下上面分析的流程:
openmax component解碼完一幀之後,
會呼叫ppCallbacks->FillBufferDone,也就是呼叫了之前初始化好的OMX::OnFillBufferDone
接著看下CallbackDispatcher的post函式
接下來把這個msg開始分發出去
onMessage回撥
在onMessage方法中,進行通知回去
通過呼叫OMXCodecObserver把msg通過onMessage函式接著傳給OMXCodec。
程式碼如下:
通過上面的分析可以看到,雖然在OMX框架中 Input/OutPutPort上的buffer的生產和消費是非同步,但是還是通過了一個Condition mBufferFilled來做同步。通過訊號量機制來達到同步的目的。本質上是一個生產者/消費者模型。
第一時間獲得部落格更新提醒,以及更多android乾貨,原始碼分析,歡迎關注我的微信公眾號,掃一掃下方二維碼或者長按識別二維碼,即可關注。
如果你覺得好,隨手點贊,也是對筆者的肯定,也可以分享此公眾號給你更多的人,原創不易