Netra(DM8168)處理器是個多核處理器,每個核之間相互獨立卻又相互關聯,如何高效簡潔地利用每個核完成一套系統功能是非常關鍵的,RDK這套軟件平臺就是針對這種多核平臺設計的一套多通道視頻應用方案,主要用于DVR、NVR、IPNC之類的產品。
? ? ? ? 這個軟件框架結構允許用戶創建不同的多路數據流來實現視頻的采集、視頻處理(DEI、Noise Filter、Encode、Decode、SwMs、Merge等)和視頻播放功能,其框架設計非常值得學習。
以下為相關縮寫解釋:
*****************************************************************************************************
HDVPSS:High Definition Video Processing Subsystem
HDVICP:High Definition Video and Image CoProcessor
Ducati:Dual Core M3 Processors controlling HDVPSS and HDVICP hardware engines
Video M3:ARM Cortex M3 Core(inside Ducati subSystem)controlling HDVICP codecs
VPSS M3:ARM Cortex M3 Core(inside Ducati subSystem)controlling HDVPSS,also called DSS M3
DEI:Deinterlacer
McFW:Multi Channel Framework
IPC:Inter Processor Communication
******************************************************************************************************
1、Rdk平臺軟件框架圖
? ? ?在Rdk平臺軟件中做了很好的分層,如下圖所示:
注意:上圖中核間通過Syslink/IPC通信,任意2個核之間都可以直接通信,是一個星型網絡,上圖畫的連接關系描述的是對等層次的概念。
上圖中相關層的功能及相關描述如下表所示:
層 | 處理器 | 描述 | 相關TI軟件包 |
Linux | HOST?A8 | Linux?OS,?includes,?filesystems, SATA,?Ethernet,?USB?and?other IO?drivers | Linux?PSP |
BIOS6 | VPSS?M3 Video?M3 DSP | BIOS?RTOS?used?as?OS?on Video-M3,?VPSS-M3,?DSP. Provides?features?like?threads, semaphores,?interrupts. Queues?and?message?passing between?links?is?implemented using?BIOS?semaphores. | BIOS XDC?(used?for?BIOS?and other?configuration) |
Syslink?/?IPC | HOST?A8 VPSS?M3 Video?M3 DSP | Software?APIs?used?for communicating?between processors.?Provides?features like?processor?loading?and booting,?multiprocessor?heaps, multiprocessor?linked?list (ListMP),?message?queues,?notify etc | Syslink IPC |
HDVPSS Drivers | VPSS?M3 | HDVPSS?drivers?like?capture, display,?deinterlacer,?scaling based?on?FVID2?interface?to control?and?configure?the HDVPSS?HW | HDVPSS |
Video Encode/Decode | Video?M3 | Video?encode?/?decode?APIs based?on?XDM?/?XDIAS?interface. Uses?framework?components?for?resource?allocation | XDIAS Framework?components IVAHD?HDVICP2?API H264?decoder H264?encoder |
Links | Links?HOST?A8 VPSS?M3 Video?M3 DSP | Implementation?of?individual links.?Some?links?are?specific?to a?processor?while?some?links?are?common?across?processors | DVR?RDK |
Link?API | HOST?A8 | The?link?API?allows?users?to create?,?connect,?and?control links?on?HOSTA8,?VPSS?M3, Video?M3?and?DSP. Link?API?is?used?to?create?a?chain?of?links?which?forms ?a?user?defined?use-case. The?connection?of?links?to?each other?is?platform?dependant. | McFW |
McFW?API | HOST?A8 | Multi-Channel?FrameWork?API. Multi-Channel?Application specific?API?which?allows?user?to?setup?and?control?pre-defined application?specific?chains?for DVR,?NVR,?using?a?single?simplified?API?interface. This?allows?users?to?directly?use the?links?without?having?to understand?the?detailed?link?API. The?McFW?API?is?platform independent?and?same?API?will work?on?DM816x,?DM814x, DM810x | McFW |
User Application | HOST?A8 | Typically?GUI?and?other application?specific?components like?file?read/write,?network streaming. | Customer?specific |
2、基于Rdk框架的實例
? ? ? ? ? ? ? ? Capture (YUV422I) 16CH D1 60fps
? ? ? ? ? ? ? ? ? ?|
? ? ? ? ? ? ? ? ? NSF (YUV420SP)
? ? ? ? ? ? ? ? ? ?|
? ? ? ? ? ? ? ? ? dup1---->IPCM3OUT(VPS) -> IPCM3IN(VID) -> ENC ->?IPC_BITS_OUT_M3 ->?IPC_BITS_IN_A8 -> fwrite() - Write to filesystem
? ? ? ? ? ? ? ? ? ?|? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?!
? ? ? ? ? ? ? ? ? ?| ? ? ? ? ? ? ? ? ? ? ??? ? ? ? ? ? ? ? ? ? ? ? ? ! ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ?+-<----IPCM3IN(VPS) <- IPCM3OUT(VID) -> DEC <-?IPC_BITS_IN_M3?<-?IPC_BITS_OUT_A8 <-?fread() - read from harddisk
? ? ? ? ? ? ? ? ? ?|
? ? ? ? ? ? ? ? ?MERGE
? ? ? ? ? ? ? ? ? ?|
? ? ? ? ? ? ? ? ? DUP2
? ? ? ? ? ? ? ? ? |||
? ? ? ? ?+--------+|+------------+
? ? ? ? ?| ? ? ? ? | ? ? ??? ? ? |? ? ? ?
? ? ? ? ?| ? ? ? ? ? ? ? ?| ? ? ? ? ? ? |
? ? ? SW Mosaic ? ? ? SW Mosaic ? ? ? ?SW Moasic
? ? ? (DEIH YUV422I) ?(DEI YUV422I) ? ?(SC5 YUV422I)
? ? ? ? ?| ? ? ? ? ? ? ? ?| ? ? ? ? ? ? |
?GRPX0 ? | ? ? ? GRPX1,2 ?| ? ? ? ? ? ? |
? ? | ? ?| ? ? ? ? ? | ? ?| ? ? ? ? ? ? |
? ? On-Chip HDMI ? ?Off-Chip HDMI ?SDTV (NTSC)
? ? ? 1080p60 ? ? ? ? 1080p60 ? ? ? ?480i60
3、Link Api機制
3.1 link api的概念
? ? link在上圖中的視頻數據流中是最基本的單元模塊,每個link中包含了一個基于BIOS6/Linux的任務、線程、消息盒(使用操作系統的信號量實現)。由于每個link運行一個獨立的線程,因此link之間可以并行運行。消息盒是關聯用戶指定的link,讓link之間有個互相對話的機制,用來傳遞信令。而對于視頻流數據、幀數據的傳遞link實現了專門的接口來實現,只傳遞指針,而不是數據。
? ? 在實現上節所介紹的數據流可以通過將多個link連接來實現chain,link API允許用戶Create、Start、Stop、Delete、Control各個link。在Rdk中TI基于link API進行再次封裝,用于特定的應用場合,其各種參數均是為特定的產品定制,可以是相關業務的開發更迅速。
3.2 link內部結構
3.3 link的特性
- 視頻處理的工作量可以均衡到每個核心上去執行,如下表:
Processor | OS | Used?for |
HOST?A8 | Linux | System?setup?and?control,?GUI,?IO?peripheral?control?like?SATA,?Ethernet,?USB,?Audio |
VPSS?M3 | BIOS6 | HDVPSS?control?for?video?capture,?video?display,?scaling,?deInterlacing?… |
Video?M3 | BIOS6 | HDVICP2?Video?compression?/?decompression?(H264?encode,?H264?decode) |
DSP | BIOS6 | SW?OSD,?custom?video?processing?algorithms |
- 每個link都有自己獨立的任務/線程用于完成視頻采集或播放等處理;
- 每個link都可以處理來自多個通道的視頻幀數據,每個通道的視頻寬高和數據格式都可以不同;
- A8作為HOST可以用來連接多個link形成數據流的鏈并對其進行控制;
- 數據鏈被建立并啟動時,數據鏈中的每個link將和它的下游link進行幀數據的交互;
- links之間的幀數據交互可以在多個核心之間進行,并且并不需要A8 HOST的干涉,從而降低A8的開銷;
- ?在數據鏈運行過程中用戶可以發送控制信令給任意link來動態設置相關的link參數;
3.4 link接口
? ? link接口可以分成以下幾類:
- link API——被用戶調用來配置和控制link的接口;
- Inter link API——被其他links調用來交換幀數據的接口;
- link output queue——被其他links通過Inter Link API接口實用的幀buffer隊列;
3.5 link間的消息傳遞
? ? 每個Link通過一個32位的該LinkId來識別,ID高4位標識了這個Link是在哪個核上運行,低24位標識了該Link的名稱:
Bits | Description |
[0..27] | Link ID |
[28..31] | Processor ID on which this link runs 0:DSP 1:Video M3 2:VPSS M3 3:A8 |
每個Link?API都需要這個LinkID參數來發送消息,當用戶發送消息到一個Link時,根據這ID函數內部判斷這個消息是發給本地的Link還是遠端核心的Link;如果是本地的直接調用BIOS/LINUX?API函數,否則就通過Syslink模塊的MessageQ發送這個消息到指定的核心,讓對端的核心調用對應的函數處理。
3.6 link API
? ? 下面將通過表格的形式來看看link API的部分接口及相關功能:
API | Description |
System_linkCreate | Creates?a?link?——allocates?driver,?codec,?memory?resources. |
System_linkGetInfo | Get?information?about?a?link?like?number?of?channels,?properties?of?each?channel.?MUST?be?called?after?System_linkCreate()?for?a?link |
System_linkStart | Start?the?link?——starts?the?driver?or?codec |
System_linkControl | Send?a?link?specific?control?command?with?optional?arguments |
System_linkStop | Stop?the?link?——?stops?the?driver?or?codec |
System_linkDelete | Deletes?a?link?——?free’s?driver,?codec,?memory?resources |
3.7 Inter link API
? ? 下面的表格介紹了在link內部實現的交換幀數據的API,對于用戶來說,這部分API是不需要關心的:
API | Description |
System_GetLinkInfoCb | Function?to?return?information?about?a?link?like?number?of?channels,?properties?of?each?channel |
System_LinkGetOutputFramesCb | Function?to?return?captured?or?generated?or output?frames?to?the?caller?(another?link) |
System_LinkPutEmptyFramesCb | Function?to?release?consumed?frames?back?to?the?original?link?for?reuse |
System_LinkGetOutputBitBufsCb | Function?to?return?generated?or?output?bitstream?frame?to?the?caller?(another?link)?–Valid?only?for?Encode?Link |
System_LinkPutEmptyBitBufsCb | Function?to?release?consumed?bitstream?frames?back?to?the?original?link?for?reuse?–Valid?only?for?Encode?Link |
? ? 在每個link中必須實現一些函數并在初始化時注冊這些函數指針給link管理的核心模塊,用于幀數據的獲取、釋放、dump相關狀態等。
? ? 對于任一個link想從它的上游link獲取幀數據都需要調用link管理核心函數System_getLinksFullFrames(),該函數內部會發送消息到對應的上游link,觸發該link向管理模塊注冊的回調函數System_LinkGetOutputFramesCb()將幀數據傳遞給該link;
? ? 同樣的,在當一個link想釋放處理完畢的幀buffer給上游link時需要調用link管理核心函數System_putLinksEmptyFrames(),該函數內部會發送消息到對應的上游link,觸發它注冊的回調函數System_LinkPutEmptyFramesCb()將幀buffer回收,用于后續的數據處理;
? ? 建立chain時,你肯定還會關注一個信息,那就是上游link的相關參數如何傳遞給下游的link,從源程序仔細琢磨琢磨就可以看出來,和上面的處理類似,所有有下游link的link都會注冊一個System_GetLinkInfoCb()的回調函數,在下游link的driver中會在創建driver時調用System_linkGetInfo()函數來獲取上游link的相關參數。
? ? 通過上述的方法,對于一個link來說就不需要關心和它交互的是哪一個link,所有的尋址都通過linkID來自動查找,并且同一個link實現可以和不同的link交互,而不需要改變函數的實現。
3.8 Link Output Queues 的管理
? ??一個Link可以有一個或多個輸出隊列用來存放采集到的或處理完畢的幀數據,每個Link的輸出隊列內存由自己分配;
? ??大多數Links只有一個輸出隊列,但是有些link有多個,從而可以實現多路不同的輸出數據流滿足不同的應用需求,例如,Noise?filter?Link可以輸出16路幀數據到2個輸出隊列,每個輸出隊列輸出8路通道數據跟別給2個DEI?Links模塊處理。
? ??一個輸出隊列中可以有多個視頻channels的數據,每個channel可以有不同的大小和數據格式;
? ??數據結構?FVID2_Frame是在VPSS驅動中定義的,Links之間就通過該結構參數傳遞幀數據的信息,如幀數據的Buf指針,而幀數據本身并不會被拷貝,從而節省內存開銷;
? ? 當一個Link采集完或處理完一幀數據后會發送一個消息“SYSTEM_CMD_NEW_DATA”給下游的Link,從而通知它有數據可取;當下游Link收到該消息后會調用System_getLinksFullFrames()函數來獲取對用的幀數據,處理完后再調用System_putLinksEmptyFrames()函數來歸還給上游Link繼續使用。
因此一個Link需要知道:
- 上游Link的LinkID和QueID,從而從該隊列里面獲取幀數據
- 下游LinkID,從而在有新數據產生時通知下游Link來取
3.9 IPC link核間幀數據交互
IPC?Link,是用來多核之間的幀數據傳遞的。
如VPSS上的采集Link想把幀數據發送給Video?Link處理,先將幀數據傳遞給本地的IPC?Link,然后IPC?Link再通過Syslink/IPC發送到Video?Link上的IPC?Link,然后再轉發給Video?Link,這樣的話對于采集Link的實現來說就非常清晰簡單,它的實現都是發送給本地的另一個Link;
IPC?Link的實現有點復雜,因為它涉及的幀數據傳遞是在多個核之間,這里面就牽扯到cache的一致性問題,考慮到每個核的特性以及高效性,總共設計了3個內部Links用于幀數據的傳遞機制:
- Intra-processor?links
? ? ?即同一核心內部的link,如采集與降噪之間的幀數據傳遞,這種內部的link間傳遞幀數據都是在VPSS?M3內部完成,因此采用簡單且高效的隊列機制實現。
- Inter?M3?(Video?/?VPSS)?links
? ? ?即M3內部核心之間的link,由于Video和Vpss所在的2個M3核心是同屬于一個雙核M3處理器,它們的cache是共享的;如降噪模塊(VPSS?NF)到編碼模塊(VIDEO?Enc)之間傳遞幀數據,帶有Notify的IPC?ListMP機制被用來在這2個M3核心之間傳遞幀信息(FVID2_Frame),該過程中不需要任何cache操作和地址轉換。
- Inter?processor?(M3?to?A8?or?DSP)
? ? 即處理器內部核心之間,如編碼(VideoM3)到BitStream?In(HostA8)之間傳遞幀數據,同樣使用帶Notify的IPC?ListMP機制在2個核心之間傳遞幀信息(FVID2_Frame),但該過程中需要做cache同步和地址轉換操作。
4、chain數據鏈路的建立
? ? 一個Chain是由多個links按照一定的應用需求按順序連接成一條視頻處理的數據流。
? ? 一個Chain可以銷毀后重新按照新的需求組成新的Chain,不需要重啟系統。
?Chain創建是特別需要相關link的順序
- 通過System_linkCreate()函數按照由source>>sink?的順序創建需要的Links,Source?Link即沒有上游Link的Link,如:視頻采集;Sink?Link是沒有下游Link的Link,如:視頻播放;這個創建順序是非常重要的,因為一個Link創建時它會查詢上游Link的一些信息,如上游Link需要的channel的個數和屬性,從而按照這些參數配置自己。
- 下一步調用System_linkStart()函數啟動每個Link,啟動順序一般從Sink?Link往前到Sorce?Link,當然你也可以不按照這個順序,不過不推薦,因為這樣可以保證每個Link在它的上游Link啟動前準備好接收數據,避免過多的緩沖引入額外的時延。
- 當一個Chain運行后控制命令就可以發送到各個Links來控制它,如調用System_linkControl()函數發送改變畫面合成風格的命令給相應的Link,具體的命令定義由每個Link的功能實現來決定;
- 注意:一般來說System_linkControl()函數是在System_linkCreate()創建了Link之后才能調用,不過有些控制命令可以在System_linkCreate()調用之前調用,以完成Link創建之前必須的一些初始化,如復位;
- 當Chain工作完成或銷毀時可以調用System_linkStop()函數先停止每個Link,注意:停止的順序必須從Source開始依次到Sink結束;因為一個Link可能阻塞著等待下游Link釋放當前Link的輸出Buffer,如果下游Link先停止的話當前Link可能會出于wait?for?ever的狀態而永久退不出來,因此上游Link必須先停止,之后才能停止下游Link;
- 最后等所有Link全部停止后,可以調用System_linkDelete()函數刪除所有Links,刪除順序沒有要求;
- 當Chain銷毀后就可以按照之前的順序重新創建一個新的Chain來完成另一個工作了。