1. 程式人生 > >Android Multimedia框架總結(十二)CodeC部分之OMXCodec與OMX事件回撥流程

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乾貨,原始碼分析,歡迎關注我的微信公眾號,掃一掃下方二維碼或者長按識別二維碼,即可關注。

這裡寫圖片描述

如果你覺得好,隨手點贊,也是對筆者的肯定,也可以分享此公眾號給你更多的人,原創不易