當前位置:
首頁 > 最新 > OpenMAX編程-音視頻等組件介紹

OpenMAX編程-音視頻等組件介紹

導讀:

本文著重介紹不同類型組件的具體構成(參數類型、特性設置等),包括audio、video、image等組件。另外對OpenMAX的一些擴展用法以及以前文章當中的缺漏進行補充。

音頻組件-audio domain

從spec裡面截取一張圖,如下所示:

audio應用舉例

第一個流程圖展示了來自不同輸入源的音頻經過混合送入耳機播放的流程,其中一路是MP3,與另一路經過均衡器調節的MIDI格式的音頻同時送入音頻混合組件進行混合處理,最後經過立體聲效果增強,輸送給耳機播放。流程圖中的每一個節點都可以作為一個組件存在,當然也可以組合其中幾個作為一個組件(比如MP3與MIDI作為同一個組件,內部區分輸入文件格式)、mix加立體聲效果增強作為一個組件,音頻播放作為一個組件。更甚者,將它們全部合併在同一個組件裡面進行實現都是可以的。

應用場景:用作不同格式的音頻混合,比如在不同的物理環境下錄製一段不同格式的音頻文件,然後使用軟體將其混合起來。

第二個流程圖中分有兩路輸入與兩路輸出,其中一路是下行音頻數據流(經過編碼壓縮的),輸入給音頻解碼組件進行解碼,然後一路給喇叭外放,另一路與麥克風輸入音頻組合進行迴音消除,然後經過編碼生成上行音頻數據流進行傳輸。

應用場景:對講設備,比如微信或者QQ語音聊天,雙方可以同時講話,從第一視角來看,下行數據流指的就是對方講的話經過通訊設備(手機等)採集編碼之後網路傳輸過來的音頻信息,需要經過解碼在自己的通訊設備上面播放(這樣才能聽到對方講話)。同時自己說的話需要與下行音頻數據流組合進行迴音消除(試想沒有迴音消除,自己說的話傳過去,對面外放的同時又被對面的通訊設備採集再次發送過來,不斷循環就會導致回聲問題,需要與下行音頻數據流組合的原因就是需要其做分析進行回聲消除),然後經過編碼形成上行音頻數據流傳遞給對方。


未壓縮數據的最小載入大小

對於所有的未經過壓縮的音頻數據流類型,OpenMAX規定了其最小的數據載入包大小。對於PCM audio來說最小數據載入大小是5ms,此時音頻組件的輸出埠一次產生的數據包最小得是5ms的,另外此限制僅針對PCM格式(例如OMX_AUDIO_CodingADPCM格式)。

MIDI格式的全文件緩衝

所有的MIDI格式媒體文件都會包含多個並行音軌,但是在文件裡面是以串列的方式進行存放的,存放順序並不是實時播放時候的交錯順序。(也就是說文件存放是按照音軌1、音軌2來順序存放的,而不是音軌1與2內容交叉存放)。並且MIDI格式下,音頻播放的狀態只有在從文件頭部處理的時候才是確定的,如果需要進行跳播的話仍然需要處理一部分文件頭部的內容,猜測需要這樣做的原因是在文件頭部會存放音頻的各個信息,比如全音符,四分之一音符的持續長度等等,由於音軌串列排列並且位元組是變長存儲的,所以需要在OMX_AUDIO_PARAM_MIDITYPE結構體的nFileSize成員中存放整個文件的大小。


OMX_AUDIO_CODINGTYPE

用來標識不同的編碼格式,具體有PCM、AMR等等,該枚舉變數用在組件的port結構體定義與參數定義當中,可以通過set parameter回調介面進行設置,也可以在組件內部指定(不同的埠可以處理不同格式的音頻數據,使用該枚舉類型進行標識)。

audio埠

如[02 - OpenMAX編程-數據結構]一文中有關埠部分描述所講,一個組件的埠會由幾個結構體來共同描述,大致有(描述埠數量、起始埠號等),(埠定義),還有特定類型埠的參數結構體描述,例如,等。後面兩種類型的結構體通常是數組形式的,兩者一一對應,用來描述一個埠。

OMX_AUDIO_PORTDEFINITIONTYPE:音頻類型的埠定義,作為一個共用體成員存在於結構體內部,使用的時候通常直接初始化一個類型的結構體變數。

:顧名思義,該結構體描述了埠支持的音頻流數據格式,它是一個枚舉類型。支持使用來獲取、設置埠的格式。的值範圍是0~N-1,N就是該埠所支持的格式數量,IL Client可以通過枚舉所有支持的格式來獲知N的大小(枚舉過程以返回為結束)。

Param與config

:該結構體是格式特定的參數描述,有PCM、MP3等等,每一種格式的參數描述都不同,都有與之對應的結構體類型。其內容就不再一一描述,都是與特定格式有關的。該種類型的參數都可以用來進行獲取、設置。

:這些是與配置相關的結構體類型,有音量、通道音量、均衡等等,該種類型的參數都可以用來進行獲取、設置。

視頻圖像組件-audio&image domain


該部分介紹視頻、圖像通用的一些Config與Param設置,這部分類型定義在頭文件中可以找到。

未壓縮的數據格式

這部分使用一個枚舉類型來描述,包括RGB的8、16、32位未壓縮格式與YUV格式極其子格式等的枚舉。未壓縮數據格式有最小載入大小的要求,由視頻或者圖像埠定義結構體中的與成員共同決定,兩個成員前者表示「跨度」、後者表示「切片」,這個在不同的場合有不同的解釋。例如:對於一個YUV圖像來說,「跨度」就可以理解為圖像實際的大小加上擴展內容,如下圖所示:

image stride

stride可能會有正值有負值,正值表示從左至右、從上至下掃描,負值表示從左至右、從下至上掃描。「切片」就是切片編碼(如H264,該編碼有條帶的概念)時使用到的高度,可以簡單的使用(nSliceHeight * nStride)(條帶大小)的絕對值來作為最小傳輸大小。

未壓縮數據格式的要求

每一個image或者video組件對於未壓縮的數據緩衝區都有一些要求,這些要求是為了使得不同供應商之間的數據能夠正常地被處理。比如這些數據有以下幾種要求:

每一個非空的數據緩衝區都應該包含至少一個完整的slice,除非是遇到數據的結尾(比如未對齊的情況下:圖像高度100,要求slice 16,那麼最後一個slice就只有4,稱之為遇到數據的結尾)

每一個非空的數據緩衝區都應該包含有整數倍數個slice高度

當未壓縮的數據格式是平面(planar)模式的話,來自兩個平面的數據不能保存在同一個緩衝區內。比如YUV420有平面模式的格式(如NV21),它有兩個平面,那麼在兩個平面的交界處就不能夠使用同一個緩衝區來存放跨越交界處的平面數據

對於YUV420、YUV422、YUV411(YUV420)格式pack類型的數據來說,每一個緩衝區內部的slice都包含有Y、U、V的plane,其中YUV分量都是按照順序來排列的。前面說過的指明了Y分量的slice高度值,剩下的UV分量所佔據的空間大小就根據YUV的格式以及Y分量的高度值來決定。比如YUV420格式下為16,就表明有16個跨度的Y分量,加上合起來8個跨度的UV分量,合計16+8個跨度(註:有關YUV格式可以去看相關的spec)。這可以使得埠同時處理slice內的三個分量數據,而不用緩衝一整張image圖片之後才去進行處理。

parameter與config

該部分的內容眾多,這裡就不再把所有的條目都列出來了。

OMX_IndexParamCommonDeblocking:操作對象是結構體,用於決定是否使能編解碼模塊的去除塊狀偽影功能(編碼時編碼塊之間的邊緣偽影,編碼時塊之間沒有平滑過渡導致的編碼出現邊緣不一致問題)。

OMX_IndexParamCommonSensorMode:操作對象是結構體,用於設置sensor的幀率、解析度。

OMX_IndexConfigCommonColorFormatConversion:操作對象是結構體。用於做格式轉換,在需要從RGB轉為YUV格式時用到。

剩下的還有很多,需要結合spec文檔來進行梳理解析。


通用枚舉類型

OMX_VIDEO_CodingUnused:未實現編碼功能

OMX_VIDEO_CodingAutoDetect:自動檢測編碼類型(組件內部完成)

OMX_VIDEO_CodingMPEG2:MPEG2格式編碼

OMX_VIDEO_CodingH263:H263格式編碼

OMX_VIDEO_CodingMPEG4:MPEG4格式編碼

OMX_VIDEO_CodingWMV:WMV格式編碼

OMX_VIDEO_CodingRV:RV格式

OMX_VIDEO_CodingAVC:H264格式

OMX_VIDEO_CodingMJPEG:MJPEG格式

:標識視頻的一幀

OMX_VIDEO_PictureTypeI:通用I幀

OMX_VIDEO_PictureTypeP:通用P幀

OMX_VIDEO_PictureTypeB:通用B幀

OMX_VIDEO_PictureTypeSI:H.263的SI幀

OMX_VIDEO_PictureTypeSP:H.263的SP幀

OMX_VIDEO_PictureTypeEI:H.264的EI幀

OMX_VIDEO_PictureTypeEP:H.264的EP幀

OMX_VIDEO_PictureTypeS:MPEG-4的S幀

視頻幀的標識可以加在編碼後的幀信息裡面以供後續解碼或者mux進行使用。編碼格式需要在port埠的屬性裡面進行設置。

index以及對應的參數結構體

video組件實例

上圖中第一個框圖是一個圖像採集編碼、預覽一體化的video組件實例,從camera硬體採集圖像數據,經過圖像過濾器,然後經由一個分發器輸出一路視頻給video顯示組件進行預覽,一路送由H263編碼組件編碼最終寫入到文件裡面。

下面的一幅圖可以看作一個簡單的視頻通話通路。首先是上行數據通路:從camera硬體採集數據經過分發器分出一路給H263編碼,然後送給網路上行鏈路傳輸給對方,另一路與下行數據解碼之後的未壓縮視頻數據混合(就是聊天時的大圖與小圖,一個是對方的相機圖像,一個是本機的圖像,大小圖可以切換,混合就是將兩路視頻流疊放在一塊的過程)之後送由顯示組件顯示到本機上面。

埠相關結構體

:埠的定義結構體,該結構體用來描述一個埠,如果需要額外參數的話可以添加額外的結構體用於描述埠屬性,比如結構體用以描述埠的bit率。使用這個index可以獲取/設置埠的屬性。成員中需要注意的是與兩個,這兩個成員在前面也提到過。

:用以描述埠所支持的格式,這部分與音頻對應的結構體意義幾乎一樣,結構體成員的意義可以參考音頻部分的描述。

與音頻相同,視頻組件也有很多TYPE類型結構體用以描述一些video屬性,例如等,這些結構體都可以通過Set/GetParameter來進行設置獲取,這裡就不一一詳述,spec上面描述的很清楚。值得注意的是,不是所有的video組件都能用得上所有的TYPE的,比如video sink就用不著與編碼相關的TYPE,所以細分的video組件可能僅僅會使用到其中部分TYPE,這個要視組件細分類型而定。


image相關的定義在頭文件中描述。下圖描述了image相關的param參數類型:

index以及對應的參數結構體

image組件舉例

如上圖中框圖所描述的,這裡給出了類似video組件第一種用法的場景。camera獲取圖像經由image過濾器,然後由分發器分出一路顯示圖像,一路編成H263然後寫入到文件。糾正:spec這裡畫錯了,H.263 encode應該是jpeg encode,所以是編成jpeg格式圖像寫入文件。況且單幅圖像也發揮不出H.263編碼的特性。

埠相關的結構體如下:

:埠定義(與video的極為相似,不再贅述),其中不同細分類型組件的輸入輸出埠數量也是不一樣的。

輸入組件(source組件)沒有input,有一個output

分發組件有一個input與多個output

處理單元只有一個input一個output

mix組件有多個input,一個output

輸出組件(sink組件/顯示)有一個input,沒有output

注意這裡說的沒有input指的是沒有更上游的組件來提供輸入,該組件(輸入組件)的input就來自於camera的硬體驅動,沒有output也同理,是指的是沒有下游組件再來接收數據,該組件(輸出組件)的output就是屏硬體驅動。再者,input與output的數量並不是嚴格界定的,而是根據具體的使用場景有具體的數量設置。

:與video的一樣。

參數控制

image有些比較特殊的參數類型(TYPE),比如:

:該結構體參數就是用來控制閃光燈的(拍照的閃光燈功能),其中成員可以設置閃光燈常亮、關閉、自動、紅眼消除(拍照時的干擾,平時黑暗的地方手機拍照就可能出現人眼球部分是紅色的,參考google相關解釋)。

:聚焦,用於焦距調節。成員可以指定手動調焦、關閉調焦、自動調焦、自動鎖定目標焦距等等。

其餘的與video的很類似,在spec中可以看到比較詳細的描述。

組件擴展API與通用組件


很多時候,組件內部標準的API並不能滿足需求,此時就需要添加自定義的API,OpenMax也允許這種擴展,新加的API就稱之為extensions。如果需要添加自定義的index,就在OMX_INDEXTYPE中預留的空間範圍內增加(~之間)。

新增的index也會有與之對應的結構體成員來作為index的參數,它可以是屬於image、video、audio、other四個domain或者自定義的domain,(自定義的domain需要自己去實現)。這些自定義的index需要有與之對應的字元串類型的描述,IL Client可以使用來根據index的屬性獲取到index的索引值,通過該索引值可以使用OMX_Get/SetParameter或者OMX_Get/SetConfig來進行相關的數據參數存取。

回調函數

該宏專門用於獲取擴展的index索引值,該回調函數最終會傳入一個字元串給特定的組件,組件會根據字元串去找到對應的索引值返回給調用者,對於組件來說,OpenMax已有的標準的index可以不必實現該回調函數。該回調函數指向的的定義如下:

如前所述,每一個自定義的index都會與一個結構體或者指向結構體參數描述的地址相關聯,使用者需要定義一個頭文件把這些結構體描述包含進去,然後組件可以使用這些頭文件來實現特定的結構體參數讀寫。如果有些index對應的參數描述僅僅用一個指針來指定,那麼使用者與組件需要約定好如何去管理這部分數據,最好在一份擴展API文檔裡面能夠有這些描述信息。下面是spec文檔裡面給出的兩個使用的例子:


seeking組件

可以理解為是跳播組件,也就是手機播放器上面快進、點擊拖動到指定的位置播放,該種組件的播放源可以是本地的文件,也可以是遠程的文件(在線視頻文件),除了提供跳播功能之外,IL Client也會有獲取文件當前播放位置的需求,所以組件也要提供該種功能。

seeking配置

該參數對應的結構體描述是,IL Client可以通過該索引來獲取/設置組件的時間戳控制文件的播放。

seek模式設置,如果是模式的話表明是快速跳播,意思就是儘可能的快速切換到所要跳播的位置,即使最終跳播到的位置並不是精確的跳播位置(速度優先)。模式的話表明是以精確度為優先,及時因此導致跳播耗時較長也在所不惜。

數據流中的任意跳播請求會指向任意的目標位置,該位置的數據可能會依賴於前面的數據。比如跳播時指定的時間點對應整個數據流的某一幀,而該幀要解碼必須依賴於前面若干數量幀(需要重建解碼數據結構),那麼Fast模式就指的是從能夠解碼的第一幀開始顯示(該幀極大概率會比實際請求跳播的那一幀要靠前),此為犧牲跳播的精度。如果是Accurate模式則是等待整個解碼結構體重建完畢,直到解碼到真正請求的那一幀開始顯示,此為精度優先,可能會犧牲跳播時間。

seeking緩衝區標誌

緩衝區標誌用於sekking組件告訴下游組件傳遞給它的buffer的具體作用,通常情況下,需要加flag的buffer都是一個緩衝區單元裡面的第一個邏輯數據幀,就比如上面說的重建解碼結構體需要的數據幀,該部分的幀就需要加上一個flag。

只解碼標誌,還記得上面說的Accurate模式嗎?在該模式下,用於重建解碼結構體的幀(非跳播指定的幀)就需要加上該flag,當負責顯示的組件接收到帶有該flag的幀的時候就不能再去顯示這些幀。

該flags表明該幀數據攜帶整個播放數據流的開始時間戳,對於Fast模式來說就是重建解碼結構體需要的第一幀數據,對於Accurate模式來說就是跳播位置所在的第一幀。當一個時鐘組件的客戶端(使用時鐘組件的組件,例如video render組件)收到帶有該flag的buffer,就會調用SetConfig使用索引來設置時鐘組件,該索引表明客戶端的數據已經準備好要播放。

seek事件的產生步驟

該步驟是由IL Client來完成的:

使用索引來設置的成員為,停止組件的media clock。

使用索引來設置需要跳轉的時間戳。

刷新所有的組件。

使用索引來設置的成員為或者狀態。

對於Running狀態,在seeking操作結束之後,clock組件就立即開始media clock的流動,這個方法雖然比轉換到Waiting狀態要簡單,但是它忽略了stream的開始時間(seek之後的開始時間),並且它也沒有等待所有的組件都準備完畢(或者說沒法保證所有被刷新的組件都處於準備完畢的狀態),這就可能會造成同步的問題。

對於Waiting狀態,在seekin操作結束之後,clock組件會等待其麾下所有的組件都回復完配置之後,選擇最早回復的組件設置的時間戳來運行media clock。這樣的話就能夠確保以下兩點:

所有的組件都準備好處理數據了,消除組件之間的初始化漂移。

media clock開始時間會根據所有的Client組件的反饋值來進行確認,達到準確性、適應性的要求。

最後,seeking組件並不一定或者大部分時間並不是一個獨立的組件,而是指的是具有seeking功能的組件,比如音頻解碼、視頻解碼組件,seeking作為一個功能模塊嵌入到具體的組件內部實現。

這一章就講這些組件類型相關的內容,下一章會對clock組件做一個詳細的介紹,會對音視頻的同步問題做一個詳細的剖析,同步問題(不限於音視頻的同步)一直是一個非常大的問題。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 YellowMax 的精彩文章:

TAG:YellowMax |