國 立 交 通 大 學
電信工程研究所
碩 士 論 文
適合影像處理的串流模組設計
Streaming Module Design for Video Processing
研究生:陳怡如
指導教授:張文鐘 博士
適合影像處理的串流模組設計
Streaming Module Design for Video Processing
研 究 生:陳怡如
Student:Yi-Ju Chen
指導教授:張文鐘
Advisor:Wen-Tong Chang
國 立 交 通 大 學
電信工程研究所
碩 士 論 文
A ThesisSubmitted to Institute of Communication Engineering College of Electrical Engineering and Computer Science
National Chiao Tung University in partial Fulfillment of the Requirements
for the Degree of Master
in
Communication Engineering
August 2010
Hsinchu, Taiwan, Republic of China
i
適合影像處理的串流模組設計
研究生:陳怡如
指導教授:張文鐘 博士
國立交通大學 電信工程研究所碩士班
摘要
本論文是以 TSSA ( Trimedia Streaming Software Architecture ) 軟體架構所建立的模 組結構以及其模組化的串流方式為探討的重點。模組化的概念是將不同性質的影像處理 程式區分開來,讓各模組具有單一化的執行功能,並且具備獨立的資料結構以及執行函 式。此外模組會以單純的介面函式來與應用程式以及系統連結,提供給外界簡易的操作 方式,而模組本身的影像處理內容,則是透過模組內部的函式來呼叫執行,不讓外部的 應用程式或者其它模組直接來操作,避免模組本身的資料內容遭到修改,給予模組多一 層的保護。TSSA 模組的串流方式是透過傳輸模組來運作。在兩兩影像處理模組之間會 連接一個傳輸模組,而傳輸模組上的傳輸條件以及傳送單位,則會根據前後連接的影像 處理模組特性來設定。當模組之間要傳送影像資訊時,會透過系統函式來取得傳輸模組 上的封包,提供給影像處理模組來讀取或寫入資料。這部分的運作機制會透過對應用程 式執行上實際的測試來了解,此外會再藉由於影像處理模組中增添新的函式功能,對模 組的運作方式做進一步的了解與應用。
ii
Streaming Module Design for Video Processing
Student: Yi-Ju Chen
Advisor:
Dr.
Wen-Thong
Chang
Institute of Communication Engineering
National Chiao Tung University
ABSTRACT
The primary issue of this thesis is the component architecture and streaming of TSSA ( Trimedia Streaming Software Architecture ). The concept of modular is separating different types of image processing programs into several parts each with its own data structures and functions. In addition, each component would be linked to the application program and system by some simple interfaces, which provide an easy way for users to operate. Meanwhile, components’ image processing procedure would be executed by the internal functions to avoid modifying from application programs or other components. The streaming of TSSA components is operating on the in-out descriptor, which is generalized as a connection component. The in-out descriptor is connected between two image processing components, and the transmitting conditions of in-out descriptor are based on the properties of components it’s connected. While the image processing components need to transmit data, the packets of in-out descriptor are provided via system functions. The mechanism of communication between components would be verified through the experiment of some programs and an additional function would be added into the component to further clarify the operations.
iii
誌 謝
時光荏苒,研究所兩年的歲月匆匆流逝,在這段期間裡最要感謝的人是我的指導教 授 張文鐘博士。不論在學業或生活上,老師都給予我相當多的指導與幫助,尤其在最 後這段整理論文以及準備口試的日子裡,老師更是抽出了寶貴的時間辛苦的待在實驗室, 指導我在研究上所需要加強的部分,並為我修改論文上的不足,對於老師的付出,內心 真的只有滿滿的感激。同時也要感謝口試委員黃仲陵教授、范國清教授以及余孝先博士, 在口試時給予我研究上與論文上的建議,有了您們的指導才使得這篇論文更趨完整。 很幸運能成為 821 實驗室的一員,在兩年實驗室的生涯裡,大家總是不吝惜對我的 關懷與照顧,讓我能感受到實驗室大家庭的溫暖。博班學長家豪,96 級學長琮壹,98 級與 99 級的學弟妹舒評、信妤、維哲、耀駿、詩倩,助理立杰,以及 97 級的好夥伴們 耀葦、明穎、雅嵐,感謝你們對我研究上以及生活上的幫助,有了你們的陪伴,我才能 夠順利走過這段研究所時光。 最後我要感謝我心愛的家人,父母親以及哥哥,謝謝你們對我的支持與關心,尤其 是媽媽每天都從電話裡關心我在這裡生活的一切,給予我最大的鼓勵,真的很感激你們 對我的付出。此外我也由衷的感謝男朋友以及男朋友家人對我的關懷與照顧,還有所有 關心我的好朋友們。有你們才有今天的我,再次的謝謝你們。 誌於 2010.夏 新竹。交大 怡如iv
目 錄
摘要... i ABSTRACT... ii 誌謝... iii 目錄... iv 圖目錄... vi 表目錄... viii 第一章 緒論... 1 1.1 研究背景... 1 1.2 論文架構... 2 第二章 TSSA 模組架構... 3 2.1 模組架構... 3 2.2 模組的資料結構... 6 2.2.1 Capabilities 資料結構... 6 2.2.2 Instance 資料結構... 8 2.3 模組的函式功能... 12 2.4 TSSA 模組應用... 17 第三章 傳輸模組 IOD... 20 3.1 IOD 架構概念... 20 3.2 IOD 的建立流程... 21 3.2.1 IOD 結構參數... 21 3.2.2 Default 層上 IOD 的建立... 25 3.2.3 IOD 的傳送端與接收端設定... 31 3.3 模組間資料串流... 32 第四章 輸入端與輸出端模組... 35 4.1 系統初始化設定... 35v 4.2 輸入端模組架構... 39 4.3 SVIP 模組... 42 4.3.1 SVIP Unit... 42 4.3.2 SVIP Stream... 47 4.4 輸出端模組架構... 52 第五章 實驗驗證... 55 5.1 傳輸數據驗證... 55 5.2 模組實驗... 61 5.2.1 In-Place 模組結構... 62 5.2.2 模組實驗結果... 64 第六章 結論... 67 參考文獻... 68
vi
圖
目
錄
圖 2.1 模組的分層結構... 4 圖 2.2 模組內的分層關係連結... 5 圖 2.3 Encoder 模組 Capabilities 資料結構... 7 圖 2.4 Instance 的結構組成關係... 9 圖 2.5 Encoder 模組 Instance 資料結構... 9 圖 2.6 設定 Capabilities 的函式流程... 13 圖 2.7 Open()函式的執行內容... 14 圖 2.8 Default 層 Start()函式執行流程... 15 圖 2.9 模組 AL 層上 Start 函式的內容... 16 圖 2.10 應用層程式全域變數的資料結構... 17 圖 2.11 TSSA 模組與分層架構圖... 18 圖 3.1 IOD 與影像處理模組之間的關係架構... 20 圖 3.2 IOD 資料結構在分層上的設定關係... 21 圖 3.3 複製 Setup 結構內容到 IOD 結構流程... 25 圖 3.4 Queue 的建構流程... 27 圖 3.5 Packet 的建構流程... 29 圖 3.6 tmPacket_ArrayCreate( )函式內容... 29 圖 3.7 Packet 的結構關係... 30 圖 3.8 buffer 的設定流程... 31 圖 3.9 傳送端與接收端模組的 IOD 設定... 31 圖 3.10 拿取空 packet 的函式流程... 32 圖 3.11 Release packet 的函式流程... 34 圖 4.1 tmMain()函式內容... 36 圖 4.2 tmbslCore 系統架構... 36vii
圖 4.3 BoardActivateList[]資料陣列... 37
圖 4.4 PCI Demo 板 A/D 晶片的註冊流程... 38
圖 4.5 輸入端分層與模組架構... 39 圖 4.6 tmVdecAna 模組存放硬體資訊的資料結構... 40 圖 4.7 tmVdecAna 模組取得硬體資訊的流程... 40 圖 4.8 Unit Capabilities 資料結構... 43 圖 4.9 SvipUnit_localInit()內容... 43 圖 4.10 取 unit 數的程式流程... 44 圖 4.11 Unit Capabilities 的結構關係... 45 圖 4.12 Unit 的 Instance 結構... 45 圖 4.13 Unit Open 函式內容... 46 圖 4.14 SVIP 結構... 48 圖 4.15 tmVcapSvip 模組 AL 層 Start()函式內容... 49 圖 4.16 svip_SetVidPacket()的函式內容... 50
圖 4.17 SVIP 的 Video Stream 處理... 50
圖 4.18 Buffer 位址與暫存器的設定關係... 51 圖 4.19 啟動影像擷取的暫存器設定... 51 圖 4.20 輸出端分層與模組架構... 52 圖 5.1 模組之間的傳輸架構... 56 圖 5.2 IOD、packet、buffer 的連結關係... 56 圖 5.3 queue、packet 與 buffer 的結構關係... 57 圖 5.4 應用程式 exH264Codec.c 模組架構... 60 圖 5.5 In-Place 模組結構... 62 圖 5.6 應用程式 exSvipDeinterlace.c 模組架構... 62 圖 5.7 ModifyPacket()中加入的程式內容... 65 圖 5.8 人臉偵測實驗結果... 66
viii
表
目
錄
表 2.1 tsaDefaultCapabilities 結構... 6 表 2.2 tsaDefaultInstanceSetup 結構... 10 表 3.1 tsaInOutDescriptorSetup 結構... 22 表 3.2 tsaInOutDescriptor 結構... 24 表 3.3 tmPacket_Setup 結構... 28 表 4.1 板子與使用的 A/D 晶片... 38 表 4.2 tmVdecAna 模組函式... 42 表 5.1 IOD 的傳輸單位設定... 58 表 5.2 packet與buffer位址... 59 表 5.3 packet位址的數據比對... 61 表 5.4 empty序列上儲存的packet資料結構位址... 63 表 5.5 In-Place模組的packet傳輸數據... 641
第一章 緒論
1.1 研究背景 目前,模組化的概念正廣泛的運用於軟體工程中,由於多媒體相關產品日益增加, 產品上軟體套件功能的擴充需求也會逐漸上升,因此透過模組化的概念應用,可直接將 所要擴充的功能模組新增到軟體套件上,於相同的軟體平台上運作。所以在整個軟體套 件的環境中,儲存了多個獨立的功能模組,提供給應用程式來操作使用,倘若在一個應 用程式上使用到了多個模組來執行,則每個獨立的模組之間就必須具備相同的介面以便 傳輸溝通。對於模組化的概念以及模組的運作與傳輸方式,在本論文中,以 PNX Lite PCI Demonstration 嵌入式平台為環境,探討於該裝置上所執行的程式架構。其中,PNX Lite PCI Demonstration 是一個簡易的嵌入式環境,以 PCI 介面連接於電 腦上,在此環境中具備了一組 DSP 晶片 PNX1005、一組類比數位轉換晶片 SAA7115、 一組處理高畫質影像輸入的晶片 TDA19978、一組數位類比轉換晶片 SAA7104、以及一 組處理高畫質影像輸出的換晶片 TDA9983。而主要探討的內容為應用於 DSP 晶片上的 軟體架構 TSSA ( Trimedia Streaming Software Architecture ),以及依據 TSSA 架構所建立 的軟體模組在設定與運作上流程,並於實作的部分對模組之間的資料傳輸方式進行測試, 同時在其中一個影像處理模組上新增了人臉偵測的功能,對模組的資料結構以及函式設 定上做進一步的應用。
在 TSSA 模組化的串流系統上,每個模組都是一個獨立的執行緒,這些執行緒會依 照順序串成一個執行的序列,以平行的方式共同存在於系統上,因此在 TSSA 架構上會 具備一個控管所有模組的系統核心,稱為 Default Layer。在 Default 系統核心上,首先 會為應用程式中所使用到的每個模組建立一個執行緒,當應用程式要開始執行運作時, 會依序呼叫模組的啟動函式,而 Default 系統在收到啟動模組的指令後,就會接著去啟 動該模組的執行緒。其中在每個執行緒上都會給予一個主要的執行程式,這個主要的執 行程式是包裝在模組的架構裡,所以當執行緒啟動後,就會進入到模組的執行程式裡不 斷的運算處理資料,直到使用者下達停止的指令為止。因此 TSSA 架構上定義了一套撰 寫模組的標準方式,內容包括了一個模組在運作上所需要的資料結構與運作函式,以及 提供給應用程式在模組的操控上所需要的 API。透過這些模組的 API,系統上管理執行
2 緒的核心函式,就會去建造每個模組在執行上所需要的環境。這部分模組的建立與運作 機制,會在論文的第二章裡進行更詳盡的說明。 應用程式上若使用到多個模組,系統上就會存在多個執行緒,而執行緒之間是以非 同步的方式來做資料交換,執行緒本身只負責資料的運算處理,並不會對資料交換所需 要的記憶體空間做管理,因此這部分會由系統核心來為兩兩相連接的執行緒,配置資料 交換所需要使用到的記憶體空間。由於資料交換為非同步的方式,所以需要配置多個記 憶體區塊,一次使用一個區塊來交換資料。在記憶體區塊上的管理方式,則會利用到兩 個 Queue 來分別記錄記憶體的使用狀態,一個記錄可使用的記憶體區域位址,另一個記 錄已使用記憶體區域位址。在論文的第三章裡,會針對模組之間資料傳輸的設定與運作 方式進行探討,並於第五章以模組之間所傳輸數據來分析並驗證模組的傳輸方式。 1.2 論文架構 在本論文中,會以 DSP 晶片上所執行的程式為主要探討的內容,因此在論文章節的 順序上,首先在第二章裡,會先針對以 TSSA 架構建立的影像處理模組進行探討,包括 了模組所必須具備的資料結構和函式內容,以及模組在執行上與系統之間的介面函式連 結關係;接下來在第三章裡,則會討論連結於影像處理模組之間的傳輸模組結構,並探 討其資料傳輸的設定流程以及傳輸方式;第四章裡所要討論的為輸入端與輸出端的模組, 由於這兩個模組在運作上會使用到 DSP 上的硬體資源,在結構上相較於一般純粹由軟 體來運算的模組會更複雜些,因此獨立於此章節中說明;第五章為實作驗證的部份,藉 由模組之間傳輸的數據來分析模組的傳輸機制,並將人臉偵測的功能函式應用於模組中; 最後第六章為本論文的結論。
3
第二章
TSSA 模組架構
本章以 TSSA 架構上的模組以及其運作方式為探討的重點,內容上主要會針對在每 個模組中必備的資料結構及執行函式來進行討論,並了解其相關的設定內容及運作流程; 接下來則會探討如何在一個應用程式上來使用模組,並且以 TSSA 的架構建立於 DSP 晶片上執行。而在章節的順序上,首先 2.1 節中,會先針對模組的組成架構來進行討論; 接下來在 2.2 節中,則會探討模組中的資料結構成員;而 2.3 節中,則是討論模組的相 關函式以及其功能;最後在 2.4 節中,會對於應用程式如何來使用模組以及整體的 TSSA 架構做進一步的探討。 2.1 模組架構 模組 ( Component ) 是一個具備某種特定功能的影像處理單元,例如影像擷取、影 像編碼、影像解碼、影像輸出……等,依據影像資料處理的類型來分成多個各具功能的 模組。由於在 TSSA 系統上支援多重程序執行 ( Multitasking ) 的作業方式,因此每個影 像處理模組都具備自己的執行緒 ( thread,在程式中稱之為 task ),而這些具備執行緒的 模組在 TSSA 架構上又稱為 Active Component,系統在執行上會依照各模組所設定的優 先順序來進行控制權的轉換。其中模組在架構上會具備兩大資料結構 Capabilities 以及 Instance,各模組的特性則 會藉由在這兩個資料結構上不同的設定值來描述;同時在模組上還必須具備相關的執行 函式,來設定或運算資料結構的內容,因此在模組中依據執行的內容來區分並定義了以 下八個函式:GetCapabilities( )、Open( )、GetInstanceSetup( )、InstanceSetup( )、Start( )、 InstanceConfig( )、Stop( )、Close( ),函式詳細的執行內容會在 2.3 節中做介紹。而在 TSSA 的架構上,具備一組操作所有模組的核心程式稱為 Default 層函式,各模組會以上述所 提及的八個函式做為模組的操作介面,來與 Default 層連結。為了讓程式在操作上能夠 更有系統,在模組上定義了兩層介面函式,分別提供給應用程式以及 Default 層函式來 連結,其中提供給應用程式操作的介面函式稱為 OL 層( Operation Layer )函式,提供給 Default 層操作的介面函式稱為 AL 層( Abstraction Layer )函式,層次之間的結構關係如 圖 2.1 所示。
4 接下來就以模組函式在收到應用程式傳入參數後所執行的程序,來探討模組的運作 流程,以及各層面的函式在模組運作上所執行的內容。首先在應用程式上,若要對模組 進行資料結構的設定或函式的操作時,就會將參數傳入模組所提供的 OL 層介面函式上, 交由各模組來進行處理。而在模組 OL 層上的函式通常不具備資料運算或處理的功能, 主要是做為模組在應用程式與 Default 層系統函式之間的溝通介面,模組實際處理影像 資料的部分會寫在 AL 層的函式裡。因此當模組 OL 層上的函式收到應用程式傳入的參 數時,就會接著將這些傳入的指標或設定值傳入 Default 層中,同時也會把該模組於 AL 層上的影像處理函式指標一併傳入,交由 Default 層函式來做一些預設的執行程序,例 如資料結構的初始值設定,並提供了 AL 層的介面函式位址來給 Default 層操作。 Default 層管理了在應用程式中使用到的所有模組,包括影像處理模組以及傳輸模組, 同時也定義了所有模組在運作上皆會使用到的資料結構以及函式,讓模組能夠以這些預 設好的資料結構或函式來設定參數,並提供模組在執行上一套固定的流程。因此當 Default 層在收到由模組 OL 層傳入的資料後,Default 層上的相關函式則會針對傳入的 指令來判斷所要執行的內容,若所要執行的內容是模組中特定的處理程序,則會利用 OL 層所提供的 AL 層函式位址,連結到模組 AL 層的函式上,來取得相關的資料結構設 定以及處理函式。 圖 2.1 模組的分層結構 Application 應用程式 Hardware 硬體層 Multitasking OS Device Layer Board Support Layer
軟體層
Operating Layer (OL)
Abstraction Layer (AL) OS Abstraction Layer Default Layer
5
而模組的 AL 層又可稱為訊號處理層( Signal Processing Layer ),是存放模組特定資 料結構的設定值以及影像處理函式所在的層面。模組中的 AL 層是一個純粹的影像處理 層面,不需要考量到排程以及作業系統的執行,只需要在該層的函式被呼叫時提供出資 料結構的設定值,或者對傳入的資料進行處理運算即可,因此可將 AL 層視為是模組的 一個資料庫。圖 2.2 為模組與 Default 層之間的連接關係,由於 Default 層中定義了所有 模組共同的運作程序,因此架構上的每個模組只需要編輯在 OL 層與 AL 層的程式內容, 即可透過 Default 層函式來傳輸處理。 若 Default 層系統函式執行到與 OS 相關的內容時,會透過架構上負責 OS 相關函式 運作的 OSAL 層 ( OS Abstraction Layer )來處理。其中 OSAL 層是建立於作業系統之上 的一層介面函式,當模組所要執行的內容牽涉到作業系統的運作時,就會透過 OSAL 層 的函式來與作業系統溝通。而模組中經由 OSAL 層來管理的內容包含了 Task 的運作、 Task-ISR 同步機制、傳輸序列( Queue )、計時器、Interrupts 的順序、Semaphores、 Mutexes……等。
而模組在資料處理上若有使用到硬體上資源,例如輸入端模組必須從硬體上來讀取 影像的資料,則會藉由硬體的操作介面 DL 層( Device Layer )以及 BSL 層( Board Support Library )來設定或拿取硬體上的資訊。其中 DL 層的內容主要是與 DSP 晶片上的硬體環 境相關,並藉由設定暫存器的值來操作硬體。而 BSL 層中的內容是對 DSP 晶片周邊的 硬體環境來描述,當模組執行的內容牽涉到周邊硬體的相關設定時,例如輸入端與輸出 端模組在訊號的傳輸上,必須取得連接於 DSP 晶片前後的硬體資訊,才能夠順利取得 或傳輸訊號,而在這樣的情況下,模組就會透過 BSL 層的函式來連結到周圍硬體環境 的資料庫,拿取硬體環境上相關的設定資訊。關於 DL 與 BSL 這部分詳細的內容會在第
Default Layer Function
Component A Component A Component B Component B Component C Component C OL 層 AL 層 Default 層 圖 2.2 模組內的分層關係連結
6 四章裡繼續討論。 2.2 模組的資料結構 在本節中將會針對模組的 Capabilities 以及 Instance 兩大資料結構進行討論,說明這 些資料結構在模組運作上所扮演的角色,並探討其組成的結構成員特性以及設定的參數 內容。在 2.2.1 小節中,會先對 Capabilities 資料結構進行討論;2.2.2 小節則是對 Instance 資料結構的探討。 2.2.1 Capabilities 資料結構 Capabilities 是用來標示模組特性的資料結構,包括了標明模組身分的 ID、模組在 傳輸上所支援的資料格式、以及在該模組的輸入與輸出端上可連接的模組數量……等, 因此在建立模組的過程中,會先將 Capabilities 的結構參數值設定好,並將資料存放於模 組的 AL 層中,而在需要用到 Capabilities 的設定資訊的狀況下,例如在設定模組的連接 關係上必須要以模組的代號來做為連接的依據,以及判斷相連接的模組在傳輸上格式是 否相容……等,應用程式就會透過函式到 AL 層中來拿取 Capabilities 的設定值。在 Capabilities 的結構上主要的結構成員為 Default 層所定義的 default Capabilities 資料結構, 也是在每個模組的 Capabilities 結構上都會具備的部分,default Capabilities 的結構成員 則如表 2.1 所示。
表 2.1 tsaDefaultCapabilities 結構 struct tsaDefaultCapabilities
componentClass numSupportedInstance receiverFormatSetup version numCurrentInstance olFuncs
capabilityFlags numberOfInputs inputPinCapabilities textmemoryRequirement inputFormats outputPinCapabilities datamemoryRequirement numberOfOutputs
processorRequirement OutputFormats
若模組在 default Capabilities 所定義的結構成員之外還有額外的結構參數需要設定, 則會將這些成員附加於 Capabilities 結構上,例如圖 2.3 所示的 H.264 Encoder 模組,在 default Capabilities 結構外,另外定義了 H264_Profiles、H264_Levels、H264_Complexity -Modes……等的結構成員,提供模組在運作上所需的參數設定。
7
接下來就針對模組 Capabilities 資料結構上,主要的 default Capabilities 結構成員來 進行討論。
- componentClass
架構上的所有模組都擁有自己的一組 ID,稱為 CID ( Component Identifier ),會在 模組建立的同時,到系統中管理各模組 ID 的資料庫中新增。 - version 由於在軟體的編譯上會不斷的修改程式內容並更新版本,因此在這部分利用到 majorVersion、minorVersion、buildVersion 等三個參數來標明模組的版本。 - capabilityFlags 旗標是用來標明模組的結構特性,例如模組的資料是透過快取記憶體 ( cache ) 傳 遞給記憶體,或者直接對記憶體區塊來讀寫;或者該模組是否支援多種影像格式的 輸入與輸出;以及模組在輸出端是否具備與多個模組連接的結構……等。而之後在 設定模組的連接關係時,則會依據旗標來判斷所要執行的內容。 - textmemoryRequirement、datamemoryRequirement 這兩個結構成員為模組在設定上所需要使用到的記憶體空間大小。textmemory- Requirement 為模組的程式碼資料庫所使用到的記憶體大小,同時也代表在應用層 中 include 一個模組所使用到的記憶體;datamemoryRequirement 則為模組在設定 Instance 資料結構時所使用到的記憶體大小。 - numSupportedInstance 模組中所支援的 Instance 數量。若模組有控制到硬體層結構,則會將該值設定為硬 體的單位數量;而一般純軟體沒有牽涉到硬體結構的模組,該值則會設定為 1。
typedef struct_tmalVencH264_Capabilities_t
{ // Default Capabilities 資料結構 ptsaDefaultCapabilities_t pDefCap; //由 H.264 Encoder 模組所增加的 Capabilities 結構成員 tmalVencH264_Profiles_t supportedProfiles; tmalVencH264_Levels_t supportedLevels; tmalVencH264_ComplexityModes_t supportedComplexityModes; tmalVencH264_BitrateControlModes_t supportedBitrateControlModes; tmalVencH264_BitStreamOutputModes_t supportedBitStreamOutputModes; }tmalVencH264_Capabilities_t, *ptmalVencH264_Capabilities_t; 圖 2.3 Encoder 模組 Capabilities 資料結構
8 - numCurrentInstance 在程式執行中該模組所設定的 Instance 數量,因此在這部分會將初始值的設定為零, 而之後會隨著程式的設定來做增減。 - inputFormats、OutputFormats 分別代表輸入以及輸出該模組的資料格式,而以下則列舉了主要幾個設定的資料格 式: z dataClass 標明傳輸資料的種類,例如影像訊號、聲音訊號或者是壓縮過後的資料封包。 z dataType 依據傳輸資料的種類再分類,例如影像訊號可再依照色彩的編碼方式分成 RGB 或 YUV……等。 z dataSupType 在經過 dataType 分類後,可依據影像畫面的取樣方式再進一步細部的區分,例 如 YUV 色彩的取樣方式有 4:4:4、4:2:2、4:2:0……等,而取樣出來的 YUV 成 分又可依據 Planar、SemiPlanar、Sequence……等方式來擺放。 z description 標明出影像畫面是以何種方式呈現,例如 Interlaced、Frame……等。 - numberOfInputs、numberOfOutputs 在模組與模組的連接上,有些模組可能會接收來自多個模組的輸出資料,或者將處 理完的資料傳給多個模組接收。因此會由 numberOfInputs 來標明該模組在輸入端所 支援與其它模組的連接數量;而 numberOfOutput 則代表模組的輸出端所支援與其 它模組的連接數量。 2.2.2 Instance 資料結構 Instance 資料結構的內容主要是設定模組運作時必要的參數或函式連結,在一個模 組的 Instance 結構中涵蓋了兩個部分,第一部分為 Instance 結構上提供給應用層來變更 設定的 InstanceSetup 子結構,而在 InstanceSetup 結構上的組成也可再分為兩個部分,其 一是由 Default 層所定義,提供給所有模組使用的 DefaultInstanceSetup 結構,其二則是 模組在 Default 層所提供的 Setup 結構成員外,需要由應用層來設定的特定結構參數;而 Instance 結構的另一部分則是不需透過應用層來設定的參數,通常包括了各模組特定的 一些變數,以及由 Default 層對模組在運作上所做的相關設定,Instance 的結構關係可參
9 照圖 2.4。
以 H.264 Encoder 模組的 Instance 資料結構為例,如圖 2.5 所示,在該模組的 Instance 結構上分成了可由應用程式來設定的 Instance Setup 結構,以及由 Default 層與 AL 層來 設定的結構參數兩部分。而在模組的 Instance Setup 結構這部分,除了由 Default 層所定 義的 Instance Setup 結構外,還包括了模組自行定義的 Setup 結構成員,皆是用來提供給 應用程式做參數上的設定。 圖 2.4 Instance 的結構組成關係 Application Layer Default、AL Layer *由應用層來設定 Instance 的 Setup 結構參數。 *將應用層設定好的 Setup 結構參數傳入 Default 層以及 AL 層,提供來設定模組的 Instance 結構。 DefaultInstanceSetup Specific Setup member I. InstanceSetup
II. Component Specific Variable
DefaultInstanceSetup Specific Setup member
InstanceSetup
Instance
typedef struct _tmalVencH264_InstVars_t
{ ptmalVencH264_InstanceSetup_t pInstSetup; //由 Default 層設定,應用於運作上的參數 tsaClockHandle_t *ClockHandle; tsaCompState_t componentState; tsaDatainFunc_tdatainFunc; tsaDataoutFunc_tdatainFunc; …… //由模組自訂的 Instance 成員 tmVencH264_Input_t inputModule; tmVencH264_Output_t outputModule; tmVencCoreH264_FrameBuffer_t currentFb; tmVencCoreH264_BitSreamBuffer_t currentBs; ……
//Default Instance Setup 結構
ptsaDefaultInstanceSetup_t pDefInstSetup; //模組自訂的 Instance Setup 成員 Int8 slice_alpha_c0_offest_div2; Int8 slice_beta_offest_div2; UInt32 iframeInterval; Bool useConstrainedIntraPredict; Bool enableExportMV; Bool frameSkipEnable; …… 圖 2.5 Encoder 模組 Instance 資料結構 //模組所定義的 Instance Setup 結構
10
接下來就針對在每個模組上都會具備的 Default Instance Setup 結構,其中幾個主要 的結構成員來做介紹,Default Instance Setup 的資料結構如表 2.2 所示。
表 2.2 tsaDefaultInstanceSetup 結構 struct tsaDefaultInstanceSetup
qualityLevel startPinFunc taskFlags errorFunc stopPinFunc createNoTask progressReprotFlags clockHandle taskStartArgument progressFunc *inputDescriptors powerState completionFunc *outputDescriptors debugFlags datainFunc parentId normalMmsp
dataoutFunc controlFunc sharedCacheableMmsp memalloc controlDescriptor sharedUncacheableMmsp memfreefunc priority *inputConnections getformatFunc taskName[16] *outputConnections installFormatFunc stackSize periodOfComponent tmalInstance unitNumber task
- qualityLevel 代表模組在執行中所能獲得處理器提供的品質高低,由數字 (1,2,3…) 來標示, 數字越大代表從處理器上獲得的資源越多,而通常模組在這部分的值皆設定為 0。 - errorFunc 當模組在串流的過程發生錯誤時所會呼叫的函式。而在 errorFunc 的函式中則會標 示目前是在哪個模組中出錯的訊息,提供偵錯上的使用。 - progressFunc 當模組執行的程序到某個段落時所會呼叫的函式,此函式會依據模組傳入的旗標, 標明出模組在串流資訊上所做的處理。 - completionFunc 當模組停止運作時所會呼叫的函式,並由函式標明出停止運作的模組名稱。 - tmalInstance 用來存放 Instance 結構在 AL 層的設定。由於 Default 層會在模組的 OL 層與 AL 層 之間做連結與設定,而在層與層之間的設定過程上可能會修改到相同的結構參數, 因此為了對 AL 層的設定值多一層保護,建立了 tmalInstance 結構,用來存放 Default
11 層與 AL 層之間傳遞的 Instance 設定參數。 - datainFunc 是負責處理模組輸入端資料傳輸的函式,而執行的內容主要是從模組輸入端所連接 的連接模組( IOD 1 )中拿取寫有資料的 packet,提供給模組來做運算處理,接著在 模組處理完畢後將 packet 的資料清空再放回 IOD 中。由於每個模組在輸入端運作 的模式都相同,因此在 Default 層中便定義一個 tsaDefaultDatainFunction( )函式,將 上述的運作方式寫入此函式中,提供給所有模組使用。 - dataoutFunc 是負責處理模組輸出端資料傳輸的函式,而這部分資料傳輸的方式是先從輸出端的 IOD 中拿取空的 packet,接著將模組處理好的資料寫入此 packet 中再放到 IOD 上。 與上述的 datainFunc 相同,在 Default 層中也定義了一個處理資料輸出的函式 tsaDefaultDataoutFunction( ),提供給所有模組使用。 - starPinFunc 在模組啟動後,會先將該模組輸入端與輸出端的 pin 腳皆設定為啟動的狀態,也就 是讓輸入端與輸出端可以開始傳輸資料。而在 Default 層中有定義了執行此功能的 函式 tsaDefaultStartPin( ),提供給所有的模組來使用。 - stopPinFunc 當模組的運作結束時,會將模組輸入端與輸出端的 pin 腳設定回停止的狀態,讓模 組停止對外的資料傳輸。而同樣的在 Default 層中也提供了執行此功能的函式 tsaDefaultStopPin( )來給所有模組使用。 - inputDescriptors 於模組輸入端所銜接的連接模組。當 IOD 建立完成後,會將此建立好的 IOD 結構 指標設定到模組的 inputDescriptors 中,讓模組取得輸入端 IOD 的資訊,使得在傳 輸資料的時候,模組可以辨認出要至哪個 IOD 中拿取。 - outputDescriptors 於模組輸出端所銜接的連接模組。設定方法與上述的 inputDescriptors 相同,此 outputDescriptors 則是讓模組得知要將處理完畢的資料寫到哪個 IOD 中。 _____________________ 1
IOD 為 TSSA 架構上另一個型態的模組 Connection Component,當兩個影像處理模組之間要傳 輸資料時,就會利用此連接模組來協助兩者資料的讀寫與傳輸,由於在連接模組上會描述影像處理 模組之間資料輸入與輸出的特性與設定,因此連接模組又可稱為 IOD ( In–Out Descriptors ),關於 IOD 詳細的內容會在第三章進行介紹。
12 - priority 模組執行緒的優先順序,是由應用層設定,提供給作業系統來操作模組之間在執行 運作上的順序。 - taskName[16] 模組執行緒的名稱,是由應用層所設定,當 Default 層在建立模組的執行緒時,可 將 taskName 傳入執行緒的建立函式提供命名使用。 - taskFlag
標明執行緒 task 的執行狀態,例如已經啟動的 task,在 task 的旗標上就會標明為 “tmosalTaskStarted",而正在等待記數中的 task,在 task 旗標上則會標明為 “tmosalTaskCounting"。 - task 當模組透過 Default 層到 OSAL 層中建立好執行緒後,便可將執行緒的指標回傳設 定到 task 中,讓每個模組的 Instance 結構裡都能具備自己的執行緒資料。 而在了解上述這些資料結構成員後,接下來所要討論的重點為模組如何拿取並設定 這些資料結構,以及模組從結構設定到執行運作的流程上所使用到的相關函式。 2.3 模組的函式功能 在 TSSA 架構中為每個模組定義了八個在運作上的相關函式,分別負責處理模組中 不同的程序設定,而這八個函式列舉如下:
‐ tm <Layer> <Component> GetCapbilities( )
‐ tm <Layer> <Component> Open( )
‐ tm <Layer> <Component> GetInstanceSetup( )
‐ tm <Layer> <Component> InstanceSetup( )
‐ tm <Layer> <Component> Start( )
‐ tm <Layer> <Component> Stop( )
‐ tm <Layer> <Component> Close( )
13 在每個模組中的 OL 層以及 AL 層上都會具備這些函式,因此在函式名稱上,<Layer> 代表函式所在的層面,< Component >則代表模組的名稱。而由於 Default 層是負責模組 OL 層與 AL 層的連結,因此在 Default 層中也具備了這八個函式,並以< tsaDefault >做 為函式名稱的開頭,例如 tsaDefaultGetCapabilities( )、tsaDefaultOpen( )……等。接下來 就針對這八個函式的執行內容來進行討論。 1. GetCapbilities( ) 由於 Capabilities 資料結構中儲存了模組的結構特性以及標示模組的代號,因此在模 組的執行程序上,首先必須取得 Capabilities 的資料設定。而 Capabilities 結構參數的 值設定於模組的 AL 層中,因此應用層會透過 OL 層以及 Default 層的連結來向 AL 層取得 Capabilities 的設定。函式的流程如圖 2.6 所示,首先在應用層上會呼叫模組 OL 層的 GetCapabilities( )函式,並傳入應用層中存放 Capabilities 結構的指標;接下 來在 OL 層中,會呼叫 Default 層的 GetCapabilities( )函式,將該模組 AL 層的函式指 標位址與存放 Capabilities 的指標一併傳入到 Default 層中,讓 Default 層取得 AL 層 運作的函式位址;最後,就由 Default 層連結到該模組 AL 層的 GetCapabilties( )函式, 並在該函式中,將存放 Capabilities 資料結構的位址設定到由上層傳入用來取得 Capabilities 設定的變數中,完成 Capabilities 的設定。
圖 2.6 設定 Capabilities 的函式流程
tmalComponentGetCapabilities(ptmalComponentCapabilities_t * cap)
{ //在 AL 層這部分則會將存放 Capabilities 結構的位址設定給傳入的指標。
*cap = &lcap; ……
AL Layer
tsaviAl_GetCapabilities (tmalFunc, &cap)
//在 Default 層中則會藉由巨集連結到模組 AL 層的 GetCapabilities 函式。
Default Layer
//在 OL 層中會呼叫 Default 層的 GetCapabilities 函式,並將模組 AL 層的 函式位址以及存放 Capabilities 結構的指標一併傳入到 Default 層中。
tsaDefaultGetCapabilities(&add_done, &Component_TmalFunc, (UInt32*) ppCap,);
OL Layer
//在應用層呼叫模組 OL 層 GetCapabilities 的介面函式,並傳入存放 Capabilities 的指標。
tmolComponentGetCapabilities(&ivp->ComponentCap);
Application Layer
14
2. Open( )
Open( )函式主要的功能是分配記憶體空間給 Instance 資料結構。由於接下來所要設 定的部分為模組的 Instance 結構,因此在各層的 Open( )函式裡會先分配記憶體空間 給 Instance 以及 Instance 的 Setup 資料結構,提供給模組一個新的設定環境,並且讓 模組在資料結構的設定上能夠避免被其它的模組修改到,也是對模組在設定上多一 層的保護。
圖 2.7 為 AL 層 Open( )函式的執行內容,由於各層 Open( )函式執行的內容類似,這 部分便以 AL 層為例。在 Open( )函式中,主要是藉由 TSSA 中所定義分配記憶體的 函式 tmDefault_Calloc( ),依據 Instance 以及 InstanceSetup 資料結構的大小來分配記 憶給模組的變數。其中在 Default 層的 Open( )函式裡,在做好記憶體區塊分配後, 還會針對 Instance 結構中部分的結構成員做初始值的設定。
3. GetInstanceSetup( )
GetInstanceSetup( )函式是去取得模組的 Instance Setup 結構,提供給應用層來設定。 而在取得模組 Instance Setup 結構的流程上,與前面所描述 GetCapabilities( )函式在 取得 Capabilities 結構的方法類似,都是先藉由 OL 層的函式將待設定的結構指標以 及 AL 層的函式位址傳入 Default 層中,再由 Default 層連結到 AL 層的函式上,取 得資料結構的位址。而應用層在獲得模組的 Instance Setup 結構時,便可針對模組在 運作上的需求來設定結構參數,而除了模組本身所具備特定的參數須要設定外,在 每個模組中都會設定到的結構成員包括了 errorFunc、progressFunc、completeFunc 等模組在運作上用來標示以及回報狀態的函式,模組的執行緒在作業系統上的優先 順訊 priority,模組輸入端所連接的傳輸模組 inputDescriptors,模組輸出端所連接的 傳輸模組 outputDescriptors……等。 圖 2.7 Open()函式的執行內容
tmalComponentOpen()
{ //依照 Instanc 結構的 Size,分配記憶體空間給 Instance 變數
ivp = tmDefault_Calloc (sizeof (ComponentInstance_t);
//依照 InstancSetup 結構的 Size,分配記憶體空間給 Instance Setup 變數
ivp->pSetup = tmDefault_Calloc (sizeof (ComponentInstanceSetup_t)); ……
15
4. InstanceSetup( )
而當應用層設定完上述的 Instance Setup 結構後,便透過 InstanceSetup( )函式將設定 好的 Setup 結構傳入下層,而在 Default 層以及 AL 層中則會將這些 Setup 結構的參 數一一設定到 Instance 結構上,完成模組 Instance 資料結構的設定。 5. Start( ) 當每個模組的資料結構參數都設定完成之後,便可透過 Start( )函式來啟動模組的運 做。模組啟動的流程同樣是透過 OL 層介面函式,連結到 Default 系統函式,並於 Default 層中建立以及啟動模組的執行緒,而模組主要的運算處理函式則會在系統啟 動執行緒時,一併傳入給 psos 系統,讓系統拿到一個啟動狀態的執行緒以及在此執 行緒上所要執行的函式。系統上的函式的流程如圖 2.8 所示,當 Default 層收到啟動 模組的指令後,首先 Default 層會呼叫 OSAL 層執行緒的建立函式 tmosalTaskCreate( ), 判斷該模組是否具備建立好的執行緒,若模組的執行緒尚未建立,則會藉由 psos 的 系統函式 t_create( )為模組建立一個執行緒。當模組的執行緒建立完成後,就會透過 psos 的系統函式 t_start( )來啟動執行緒。 圖 2.8 Default 層 Start()函式執行流程 defaultTaske() { ……//進入 task 的迴圈中,讓執行緒維持運作。 for (;;) { //將模組的輸入以及輸出端設定為“啟動"的狀態 startPins (divp); //連結到模組 AL 層的 Start()函式,開始處理模組的影像資料。 tsaviAl_Start (divp); //將模組的輸入輸出端設定為“停止"的狀態 stopPins (divp); …… } tmosalTaskCreate()
{ //由 OSAL 層呼叫 psos 的系統函式 t_start,並將 Default 層的 task 執行函 數傳入,交由 psos 系統來呼叫。
t_start (psosTask, T_PREEMPT | T_TSLICE , pStartFunction ,tArgs); ……
tsaDefaultStart( )
{ //呼叫 OSAL 層的 task 建立函式,並傳入 Default 層中管理模組 task 運作 的函式 defaultTask,以及模組上與 task 相關的設定參數。
tmosalTaskCreate ( defaultTask, divp, divp->priority, divp->stackSize, &tid, divp->taskName, divp->taskFlags | tmosalTaskStarted); ……
16
而在 OSAL 層呼叫 psos 系統函式 t_start( )執行的同時,會傳入一個 Default 層上所 定義的 root function 稱為 defaultTask( ),在這個函式裡將模組運作上所會執行的內 容寫在一個迴圈裡,包含了一開始要先將模組的輸入端與輸出端 pin 腳設定為啟動 的狀態,接著再呼叫該模組 AL 層上的執行運作函式,進入到模組影像處理的程式 部分。而在啟動模組之後,必須讓模組的函式保持在運作的狀態,才能不斷處裡輸 入的串流資料。因此在每個模組 AL 層 Start 函式的執行程序上,會定義一個無限迴 圈,將模組從拿取影像資料、運算處理、到儲存處理好的影像資料的流程,都寫在 這個迴圈裡,若模組一直保持在啟動的執行狀態,就會不斷的在這個迴圈裡執行運 算,直到收到停止的指令才會停止運算並跳出迴圈,圖 2.9 為 ProcessInPlace 模組 AL 層 Start( )函式的執行內容。當應用程式啟動所有的模組之後,系統上會取得每 一個模組的執行緒,以及執行緒上所要運作的函式,而每個執行緒這時候都會保持 在啟動的狀態,由系統依照執行緒的優先權來分配運作的先後順序。 6. InstanceConfig( ) 當所有模組皆開始運作後,某些應用程式或許會提供一些變更影像畫面的功能給使 用者來選擇,例如暫停影像畫面、取消影像 deinterlaced 的功能、或停止程式的運 作……等選項,而在使用者下達指令後,應用層就會透過 OL 層的 InstanceConfig( ) 函式將變更的部分傳入下層,並於 Default 層以及 AL 層的 InstanceConfig( )函式中去 更改 Instance 資料結構的設定。 7. Stop( ) 暫停模組中所有處理的程序,並變更標明模組狀態的旗標設定,將原本為“Running" 或者“Requesting"的狀態更改為“Stop"以及“Stop_Requesting"。而模組會在暫 停的狀態上停留,直到模組的 Start( )函式再度被呼叫時,才會恢復模組運作。
tmalProcessInPlaceStart(Intinstance)
{…… //進入模組的運算迴圈,讓模組能夠不斷的執行運算
while (ivp->componentState == tsaCompStateRunning) { //呼叫 datain function 讀取輸入影像資料
tsaviStreaming_DataIn ( );
//呼叫模組的影像處理函式來運算資料
modifyPacket (ivp->handle, ivp->packet);
//呼叫 dataout function 輸出模組處理完的影像資料
tsaviStreaming_DataOut ( );
…… } 圖 2.9 模組 AL 層上 Start 函式的內容
17
8. Close( )
結束整個模組的運作,並藉由 TSSA 中所定義釋放記憶體的函式 tmDefault_Free( ), 將前面在 Open( )以及 Start( )函式中所分配的記憶體空間釋放掉。
一個標準的 TSSA 軟體模組架構,就是藉由 Capabilities 以及 Instance 這兩大資料結 構在上述的這些函式中,搭配模組的分層機制來設定以及運作而構成的。 2.4 TSSA 模組應用 當一個影像處理模組具備了上述的資料結構與函式功能後,即可將模組儲存於 TSSA 的模組資料庫中,當應用程式在執行上需要使用到該影像處理功能時,就可以直 接到此資料庫中來拿取。而在應用程式拿取模組來使用的流程上,首先必須在執行程式 的 makefile 檔裡宣告需要的模組名稱以及函式資料庫名稱,接下來在應用層的程式上則 要對所使用的模組進行宣告,如圖 2.10 所示。 圖 2.10 應用層程式全域變數的資料結構
struct exSvipInstance // Global Structure
{ …… /*--- tmVdecAna ---*/ //A/D 晶片的操作模組 Int hVdecAna; tmbslVdecAnaVideoInSources_t VISources; …… /*--- tmVcapSvip ---*/ //影像擷取模組 Int hVcapSvipUnit;
Int hVcapSvipStream[MAX_NUMBER_STREAMS];
ptmolVcapSvipUnit_Capabilities_t pVcapSvipUnitCap;
ptmolVcapSvipUnit_InstanceSetup_t pVcapSvipUnitSetup;
ptmolVcapSvipStream_Capabilities_t pVcapSvipStreamCap[MAX_NUMBER_STREAMS];
ptmolVcapSvipStream_InstanceSetup_tpVcapSvipStreamSetup[MAX_NUMBER_STREAMS];
/*--- tmVideoProc ---*/ //影像處理模組 Int videoProc; ptmolProcessInPlaceCapabilities_t videoProcCap; ptmolProcessInPlaceInstanceSetup_t videoProcSetup; …… /*--- tmVrendGfxVo ---*/ //影像輸出模組 …… /*--- tmVencAna ---*/ // D/A 晶片的操作模組 …… /*--- IO Descriptors ---*/ //IOD 相關宣告 ptsaInOutDescriptor_t vcapSvipOd; ptsaInOutDescriptor_t videoProcOd; ……
18
在應用程式的一開始,會宣告一個全域的結構變數 ( Global Structure ),定義在此 程式中所會使用到的結構變數,而在該資料結構上,則會宣告此應用程式裡所有影像處 理模組以及傳輸模組 IOD 的變數。其中對於影像處理模組的宣告內容,包含了用來描述 模組特性的資料結構 Capabilities,以及維持模組運作所要設定的 Instance 資料結構,和 Instance 結構中提供給應用程式來設定的 InstanceSetup 資料結構;而傳輸模組 IOD 的宣 告內容,則是用來設定 IOD 架構的 Setup 資料結構。而在應用程式一開始所宣告的全域 資料結構中,每個結構成員的內容都還是空的,尚未設定任何的參數值,因此應用程式 在接下來所要執行的程序,就會利用到在 2.3 節裡所提到的模組函式,來取得各模組中 的結構參數預設值,並且對尚未有值的資料結構來做參數設定。而當各影像處理模組都 取得設定值,同時傳輸模組也建立完成之後,此應用程式即可開始執行運作。 而整個應用程式會以 TSSA 的架構來建立於 DSP 晶片上執行。由使用者的操作層面 至硬體環境之間,TSSA 架構會再以分層化 ( Layer ) 的模式,由上而下分成四個層面, 如圖 2.11 的模組分層架構所示。在最上層的 TSSA Application Layer 即為所要執行的應 用程式,也是使用者所操作編譯的部分。而第二層 TSSA Streaming Layer,為較高階的 軟體層,負責影像處理以及資料串流的功能,也是在前面幾個章節所描述的軟體模組主 要建構的層面。而圖 2.11 中該層面上的每一個方塊,代表的就是一個影像處理模組,而
圖 2.11 TSSA 模組與分層架構圖
VdecAna VCapSvip VrendGfxVo VencAna
TSSA Streaming Layer
PNX1005 Analog Video Decoder
(A/D)
Analog Video Encoder (D/A) SVIP SAA7115 Hardware Layer MBS QVCP SAA7104 應用程式 TSSA Application Layer dlSvip dlMbs dlQvcp bsl bsl LowLevel Software Layer
19
此圖是以一個處理即時影像的應用程式為例,使用到的模組包括了操作 A/D 訊號轉換晶 片的模組 tmVdecAna ( trimedia Video Decode Analog )、將影像資訊從硬體上擷取到軟體 層的輸入端模組 tmVcapSvip ( trimedia Video Capture Svip )、連接於輸入端與輸出端模組 之間的數個影像處理模組、將處理完的影像資訊傳入到硬體層輸出的影像輸出模組 tmVrenderGfxVo ( trimedia Video Renderer) 、 以 及 操 作 D/A 訊 號 轉 換 晶 片 的 模 組 tmVencAna ( trimedia Video Encode Analog )。這些獨立的模組,透過傳輸模組的連接因 而能夠互相溝通並且傳遞資料,至於傳輸模組的資料串流方式則會在第三章裡做詳細的 探討。 接下來第三層為較低階的軟體層,是提供給上層的軟體模組來操作硬體環境的一層 介面,提供的資訊包括了驅動 DSP 晶片 PNX1005 所需的 DL 層函式資料庫、以及支援 DSP 晶片周圍硬體環境的 BSL 層函式資料庫連結;而在分層結構中的最底層,即為上 述這些軟體程式運作的硬體環境,在硬體環境上主要包含了三個部分,分別為 DSP 晶 片 PNX1005,DSP 晶片輸入端所連結的類比轉換數位( Analog to Digital,A/D )晶片 SAA7115,以及連結於 DSP 晶片輸出端的數位轉換類比( Digital to Analog,D/A )晶片 SAA7104。其中在 PNX1005 上,還具備了多個硬體單元來處理影像訊號,例如負責影 像輸入的 SVIP ( Shared Video Input Processor ) 單元,以及調整影像畫面的 MBS ( Memory Scale Based ) 單元,與負責影像輸出的 QVCP ( Quality Video Composition Processor )單元,這些硬體環境的運用則會在第四章裡做進一步的探討與說明。
20
第三章 傳輸模組 IOD
本章所要探討的內容為 TSSA 架構上的傳輸模組 IOD ( In-Out Descriptor ),由於 IOD 是用來連接兩個影像處理模組,因此在與模組之間的連接設定以及資料的傳輸流程 都是在本章所要討論的重點。而在章節的順序上,首先 3.1 節會先針對 IOD 的架構進行 討論;接下來在 3.2 節中,則會討論 IOD 的建立流程,包含了 IOD 的資料結構設定以 及 IOD 相關函式的執行內容;最後在 3.3 節中,則會討論在影像處理模組上如何藉由 IOD 來傳輸資料。 3.1 IOD 架構概念
IOD 為 TSSA 架構上為連接模組( Connection Component ),是做為影像處理模組 ( Active Component )之間傳輸資料的橋梁。IOD 實際上為一個特定的記憶體區塊,是由 應用層在設定模組間的連接關係時所建立的,每兩個相連接的影像處理模組之間都會有 一個特定的 IOD,當前一級的模組處理完影像後,便會把資料寫入所連接的 IOD 中, 而下一級的模組則會到此 IOD 中拿取資料,在連接上的架構如圖 3.1 所示。
模組之間資料的傳輸是以封包( packet )為單位,一個 packet 通常用來傳送一張影 像畫面,而一個 packet 可具備一到多個 buffer,用來存放影像中不同的成分,例如同一 張影像的亮度( luminance )與彩度( chrominance )的資料就會分別放在不同的 buffer 裡來 傳送,packet 的這部分詳細的格式設定會在 3.2.2 小節中進一步討論。當模組之間要傳 輸資料時,如圖 3.1 中的傳送端( Sender )會至 IOD 的 packet 序列中拿取空的 packet 來 寫入處理完畢的影像資料;而接收端( Receiver )在需要影像資料時,則會到 IOD 的 packet 序列中拿取填有資料的 packet 來處理,當接收端處理完資料後,則會將此 packet 所傳送 的影像資訊清空,把空的 packet 放回 IOD 序列中,提供給傳送端模組寫入資料,形成
Sender
Active ComponentReceiver
Active Component IOD - Full Packet - Empty Packet 圖 3.1 IOD 與影像處理模組之間的關係架構21 一個循環式的傳輸方式。 3.2 IOD 的建立流程 由於 IOD 是用來串連兩個影像處理模組,因此當應用層在設定模組之間的連接關係 時,就會開始針對兩兩模組之間的 IOD 設定特定的結構參數,並且會直接呼叫 Default 層的函式來建立 IOD。在本節中,將會以程式上執行的流程來探討 IOD 的建立過程。 首先在 3.2.1 小節中,會先針對 IOD 的結構參數進行討論,並了解如何設定兩個模組之 間專屬的 IOD;接下來在 3.2.2 小節中,則會探討在 Default 層中的函式如何建立 IOD, 以及在該函式中對結構參數所做的設定;最後 3.2.3 小節,則是討論如何將建立好的 IOD 設定到 IOD 前後所連接的兩個模組中。 3.2.1 IOD 結構參數 當應用層要建立兩個模組之間的 IOD 時,首先必須將 IOD 前後所連接的模組資料 結構設定到 IOD 的結構參數中,讓 IOD 能夠確認前後模組的連接關係;而另一方面, 必須讓前後兩個模組也能夠辨認出之間所連接的 IOD,因此在 IOD 建立完成之後,會 將此 IOD 的指標設定到模組的 Instance 結構參數中,讓模組取得 IOD 的資料,使得雙 方都能夠確認連接的關係。
由於 IOD 實質上是由 Default 層來建立的,因此在 Default 層中定義了建立一個 IOD 所必須具備的資料結構,用來設定每個 IOD 特定的條件。其中,在這個資料結構上,部 分的結構參數要在應用層上設定,因此 Default 層便將這些參數成員獨立出來,定義了 另一個 IOD 的 Setup 資料結構,提供給應用層來設定。其 IOD 結構與 IOD Setup 結構在
應用層與 Default 層上的設定關係如圖 3.2 所示。 tsaInOutDescriptorSetup tsaInOutDescriptor tsaInOutDescriptorSetup Application Layer Default Layer *在應用層設定 IOD 的 Setup 資料結構 *將 IOD Setup 結構的內 容設定到 IOD 的資料結 構中,做為 Default 層建 立 IOD 的設定條件 圖 3.2 IOD 資料結構在分層上的設定關係
22 在應用層開始設定 IOD 的 Setup 結構參數之前,首先必須取得前後兩個模組的代號 以及處理的影像格式等資訊,而這部分的資訊主要設定在模組的 Capabilities 結構中,因 此應用層會先藉由模組的 GeaCapabilities()函式,取得模組的 Capabilities 資料結構設定, 再開始建立模組之間傳輸的 IOD。IOD 的 Setup 資料結構成員如表 3.1 所示,在應用層 上會以模組之間的傳輸條件來設定結構內容,接下來就以 Setup 結構中幾個主要的結構 成員來做說明。 表 3.1 tsaInOutDescriptorSetup 結構 struct tsaInOutDescriptorSetup
format receiverCap numofProperties flags senderIndex propertySetups fullQName receiverIndex connectionProxy emptyQName bufferMem numberOfBuffers queueFlags bufferProperty bufSize[N] queueSize packetBase senderCap numberOfPackets - format 標明在這個 IOD 上傳輸的資料格式,包含了目前所傳輸的資料類型為影像、音訊或 其他形態的訊號;若為影像資料,則會標明出影像的格式,例如 YUV、RGB、JPEG、 MPRG……等;接下來則更進一步標示出影像的取樣格式,例如 YUV 的影像有 4:4:4、 4:2:2、4:2:0……等多種的取樣格式,以及影像的取樣內容是以 sequence、planar 或 其他的方式排列擺放;此外,還會標示出目前每筆傳輸資料的大小,例如影像畫面 的長寬資訊。 - flags
旗標是用來標明此 IOD 的一些結構特性,例如標明此 IOD 是否具備 Tee1
的結構、 IOD 的 buffer 在記憶體空間上的分配是否要與快取記憶體( cache )區塊對齊、或是 要再額外配置一個記憶體空間來放置 IOD 的 buffer……等。而 Default 層在設定 IOD 結構參數時,則會依據旗標來判斷 IOD 所要設定的參數內容。
_____________________ 1
當有多個模組要接收來自同一個模組的輸出資料時,可透過建立 Tee 來複製資料。Tee 的結構就 像樹木一樣,具有主幹和分支( trunk & branch ),在程式的執行上會選定一個建立好的 IOD 當作主幹, 其餘做為分支的 IOD 則會複製主幹上的資料來傳輸。
23 - fullQName
當 Default 層在建立 IOD 的過程中,會建立兩個序列,一個為 fullQueue,排列 IOD 中填滿資料的 packet;另一個序列為 emptyQueue,排列 IOD 中空的 packet。因此 在序列的建立過程上,會需要一個序列名稱來標示,fullQName 即為 fullQueue 序列 的名稱。
- emptyQName
如同上述,emptyQName 即為 emptyQueue 序列的名稱。 - packetBase
在 IOD 上傳輸的每個 packet 都需要一個 id 編號,做為 packet 傳輸上的辨別,而 packetBase 則是標明此 IOD 中 packet 的起始編號,例如連接輸入端模組 tmVcapSvip IOD 的 packetBase 為 0x100,則此 IOD 的 packet 編號會從 256 開始算起,接下來為 257、258、259……逐一增加。
- senderCap
將 IOD 傳送端模組所取得的 Capabilities 資料結構設定到 senderCap 上,讓 IOD 取 得傳送端模組的 id 以及影像格式等相關資料。
- senderIndex
由於部分的模組在結構上會具備多支輸出 pin 腳,可以將處理好的影像資料往下傳 送給多個模組,因此在 IOD 的 senderIndex 上會標明要從傳送端模組的那一支 pin 腳來取得影像。
- receiverCap
將 IOD 接收端模組所取得的 Capabilities 資料結構設定到 receiverCap 上,讓 IOD 取 得接收端模組的 id 以及影像格式等相關資料。
- receiverIndex
用來標明 IOD 的接收端模組要以哪一支 pin 腳來接收資料。大部分模組在結構上都 只具備一個輸入的 pin 腳,只有在少部分的模組中( 例如 Render )具備多個輸入 pin 腳,可以接收來自不同 IOD 的資料,因此在 IOD 的設定上還是必須標明接收端的 pin 腳資訊,做為模組連接上的一個確認。 - numberOfPackets 在 IOD 上傳送的 packet 數量。由於每個模組在影像處理上的速度並不一致,因此 在存取 packet 的速度上也會不同,應用層則可以依據模組的特性來調整在 IOD 上 傳輸的 packet 數量,讓影像最後能夠流暢的輸出。
24 - numberOfBuffers
在每個 packet 中所具備的 buffer 數量。Buffer 的數量是依據影像的取樣以及排列格 式來設定的,例如傳輸 YUV422SemiPlanar 的影像,則代表影像的取樣方式為 4:2:2, 並將 Y 和 UV 放置到兩個不同的 plane,因此需要兩個 buffer 來存放這兩個不同的 成分;若影像經過壓縮的處理,則在 packet 上只需要設定一個 buffer 來存放資料。 - bufSize[N] 定義 packet 中每個 buffer 的大小。 當應用層將以上的 Setup 結構參數設定完畢之後,會把此設定好的 Setup 結構傳入 Default 層中,提供給 Default 層建立 IOD 使用。而 Default 層在拿到 Setup 結構後,會 將 Setup 結構中的參數設定到 IOD 的資料結構中,並依照 Setup 結構中設定的內容來建 立 IOD。 表 3.2 為 IOD 的資料結構成員,其中表格的第三欄即為和 Setup 資料結構一 致的部分,Default 層會根據這部分結構成員所設定的參數來設定其它結構成員的值,接 下來的 3.2.2 小節就開始探討 IOD 在 Default 層上的建立流程。
表 3.2 tsaInOutDescriptor 結構 struct tsaInOutDescriptor
senderState receiverStopped format
receiverState cmdFullWakeupSent flags
fullQueue cmdEmptyWakeupSent senderCap
emptyQueue mmspFlags receiverCap
*packetArray sleepOnStop senderIndex
fullsize clock receiverIndex
emptysize connectionProxy packetBase
lastFormat numofFullPackets numberOfpackets
waitsemaphore numofEmptyPackets bufferMem
bTee maxNumofFullPackets bufferProperty
bCopyData maxInUse queuesize
ioTeeing maxPacketInUse fullQueueName[16]
parent Mutex emptyQueueName[16]
25
3.2.2 Default層上IOD的建立
當 應 用 層 設 定 好 Setup 結 構 參 數 後 , 會 藉 由 Default 層 建 立 IOD 的 函 式 tsaDefaultInOutDescriptorCreate( )將Setup結構傳入Default層中,並開始執行該函式的內 容。在tsaDefaultInOutDescriptorCreate( )函式中,首先會將傳入的Setup結構參數複製到 IOD結構中,如圖 3.3所示。 當 Default 層取得 Setup 的設定之後,會將這些設定值傳入到下列的函式裡,藉由執 行這些函式來設定 IOD 結構中待設定的成員,而接下來則會針對這些函式執行的內容一 一探討。
‐
setInOutDescriptorFlags( )‐
tsaDefaultCheckCapabilitiesFormat( )‐
tsaDefaultInstallFormat( )‐
tmGeneralMutex_create( )‐
createQueue( )‐
tmPacket_create( )‐
Packet 與 Queue 的設定:tmPacket_SetBufferSize( )、tmPacket_SetBufferAddr( )、 tmosalQueueSend( )。1. setInOutDescriptorFlags( )
在這部分會依據 IOD 的傳送端以及接收端模組在 Capabilities 結構上旗標的設定,來 修改 IOD 結構中的旗標。首先,會確認傳送端以及接收端模組是否具備 Tee 的結構,
tsaDefaultInOutDescriptorCreate ( ptsaInOutDescriptor_t*create,
tsaInOutDescriptorSetup_t const*setup ); { //定義一個 Null 的 iod 結構
ptsaInOutDescriptor_t iod = Null; ……
//分配記憶體空間給 IOD 資料結構結構
iod = tmDefault_Calloc (sizeof *iod);
//依據 Setup 結構提供的參數來設定 IOD 資料結構
iod->flags = setup->flags;
iod->senderCap = setup->senderCap;
iod->receiverCap = setup->receiverCap;
iod->senderIndex = setup->senderIndex;
iod->receiverIndex = setup->receiverIndex;
……..
將應用層傳入的 Setup 結構設定給 IOD 的資料結構
26
若兩邊模組皆不具備的話,則會在 IOD 的旗標上加入(or , || )不支援 Tee 結構的旗標。 而接下來會確認接收端模組的旗標中是否有包含“tsaCapFlagCopybackDatain",此 旗標代表模組會直接向記憶體來拿取資料,而不用透過 cache 間接來跟記憶體取得資 料。若接收端模組的旗標中包含了這個旗標,則會在 IOD 的旗標中加入“tsaIODesc- SetupFlagCopybackDatain"的旗標,標明出此接收端模組特性。在檢視完接收端模組 後,會接著確認傳送端模組的旗標設定,若傳送端模組的旗標設定中包含了“tsaCap- FlagsInvalidateDataout",表示傳送端的資料是直接寫入記憶體中,不會透過 cache 來間接存取,而在 IOD 的旗標設定上會加入“tsaIODescSetupInvalidateDataout"旗 標,標明出此傳送端模組的特性。 在接下來要討論的 tsaDefaultInstallFormat( )以及 tsaDefaultInstallFormat( )兩個函式 裡,主要是針對 IOD 結構中的 format 來做設定。當應用層在設定 Setup 結構時,若有在 Setup 的結構成員 format 中設定特定的格式,則 Default 層在將 Setup 的 format 內容設 定到 IOD 結構中之前,會先針對設定的格式和傳送端模組以及接收端模組的格式設定做 比對,確認模組在資料傳輸上格式的相容。 2. tsaDefaultCheckCapabilitiesFormat( ) 在本函式裡,會比對 Setup 結構上的 format 設定與傳送端、接收端模組的格式設定 是否相符合,其中傳送端與接收端模組的格式內容是設定在 Capabilities 結構裡,因 此這部分會依序將傳送端模組的 Capabilities 結構以及 format 設定、接收端模組的 Capabilities 結構以及 format 設定傳入比對格式的函式 tmFormat_Negotiate( )中處理。 在 tmFormat_Negotiate( )函式中,主要判斷的格式設定包含了 dataClass、dataType、 dataSubtype,若 format 與 Capabilities 結構在這幾個參數上的設定不一致,則函式會 回傳錯誤的訊息給 Default 層,讓 Default 層停止 IOD 的建立。
3. tsaDefaultInstallFormat( )
當上述函式 tsaDefaultCheckCapabilitiesFormat( )執行完格式的比對後,若 Setup 結構 中的 format 設定與傳送接收端模組的格式相符合,則在本函式中,會將 Setup 結構 的 format 設定到 IOD 結構裡,完成 IOD 的 format 設定。
27
4. tmGeneralMutex_create( )
建立 IOD 的 Mutex。如同影像處理模組建立 Mutex 的過程,在這部分,做為連接模 組的 IOD 也會在 psos 上建立一個自己的 Mutex,提供給系統執行操作。
5. createQueue( )
在這個函式裡,會來建立 IOD 中傳送 packet 的序列:full queue、empty queue。而序 列是由 Default 層透過 OSAL 層的函式來跟系統要求建立,因此在執行的程序上,如 圖 3.4 所示,首先 Default 層會將序列的設定資訊傳入到 OSAL 層的 tmosalQueueName- Create( )函式裡,而這些傳入的參數包含了序列名稱、序列的大小、序列的旗標以及 序列編號,其中序列編號是一個待設值,會透過接下來要介紹的幾個 OSAL 層函式 來取得設定。當 OSAL 層取得這些設定後,會再將參數傳入 spOsalQueueNameCreate( ) 函式裡來執行建立序列的動作,這麼做的原因是為了因應不具備序列名稱的序列, 若目前所要建立的是一個未命名的序列,則會透過 OSAL 層的 tmosalQueueCreate( ) 函式將序列名稱設定為 Null 再傳入 spOsalQueueNameCreate( )函式裡。 圖 3.4 Queue 的建構流程 spOsalQueueNameCreate( ) { //取得 Queue 的 Index spOsalQueueGetIndex(pQueueHandle);
//呼叫 psos 的 system 函式來建立 Queue
q_vcreate( qName, Q_PRIOR|Q_LOCAL, maxPackets, maxPacketSize, &psosQueue );
//將系統建立的 Queue 設定到儲存序列的陣列中
gpSpOsalQueues[*pQueueHandle].psosQueue= psosQueue;
tmosalQueueNameCreate() { ……
spOsalQueueNameCreate(maxPackets, maxPacketSize, pQueueHandle, name, flags); //此函式是 OSAL 層中真正建立 Queue 的函式, 有命名的 Queue 會經由 tmosalQueueNameCreate()呼叫; 未命名的 Queue 則是經由 tmosalQueueCreate()呼叫。 OSAL Layer createQueues() { //呼叫 OSAL 層的函式來建立 fullQueue
tmosalQueueNameCreate(queueSize, sizeof (Int[4]), &queue, fullQName, flags); iod->fullQueue = queue;
//藉由同一個函式建立 emptyQueue
tmosalQueueNameCreate (queueSize, sizeof (Int[4]), &queue, emptyQName, flags); iod->emptyQueue = queue;
標明 Queue Index 的指標
28 在 spOsalQueueNameCreate( )函式的執行上,首先會透過一個取得序列編號的函式 spOsalQueueGetIndex( ),來向 OSAL 層中一個專門存放序列資料的陣列拿取序列的 編號。此陣列稱為 gpSpOsalQueues[ ],當系統建立了一個序列,會將序列的位址搭 配一個序列編號儲存到此陣列中,因此每個序列都具有一個獨一無二的序列編號。 而 spOsalQueueGetIndex( )函式在拿取序列編號時,會由陣列 0 開始檢查,若判斷出 該元素的值不等於零,則代表陣列中此元素已經存有序列資料了,則函式會再往下 一個元素來檢查,直到取得空的陣列元素為止,而此元素在陣列中的編號即為序列 編號。在設定好序列編號後,OSAL 層便呼叫 psos 的系統函式 q_vcreate( )來建立序 列,當系統函式執行完畢後會將所建立的序列位址回傳,而此位址便可以搭配前面 搜尋到的序列編號一起儲存到 gpSpOsalQueues[ ]陣列中,完成序列的建立。
6. tmPacket_create( )
這部分是來建立 IOD 上傳輸的 packet,在執行 tmPacket_create( )函式之前,會將 IOD Setup 結構中與 packet 相關的參數設定到 packet 的 Setup 結構中。packet 的 Setup 資 料結構成員如表 3.3 所示,包括了 packet 資料結構所要放置的記憶體空間、packet 上所具備的 buffer 數量、在此 IOD 上傳輸的 packet 起始編號、釋放 packet 資料內容 的函式、packet 特定條件設定的參數、以及此 packet 所屬的 IOD 指標……等,而在 設定好這些 packet 的 Setup 結構後,會將此結構傳入 tmPacket_create( )函式中,提供 給 packet 建立時的參數設定。
表 3.3 tmPacket_Setup 結構 tmPacket_Setup
mem packetBase numOfBuffers numOfProperties propertySetups releaseFunc
cookie
由於 tmPacket_Create( )函式在執行上一次只會設定一個 packet,因此 Default 層會依 據應用層在 Setup 結構中設定的 packet 數量來決定呼叫 tmPacket_Create( )的次數。 而傳入 tmPacket_Create( )的參數,除了已設定好的 packet Setup 結構外,還有一個待 設定的 packet 陣列,該陣列是用來存放在此 IOD 上傳輸的 packet 資料,因此在這部 分會將其傳入給 packet 的建立函式,讓函式能將建立好的 packet 存放到此陣列中。 建構 packet 的流程如圖 3.5 所示,在 tmPacket_Create( )函式中,會再透過一個建立
29
packet 陣列的函式 tmPacket_ArrayCreate( )來設定 packet 的結構,而 tmPacket_ ArrayCreate( )函式具有一次可以設定多個 packet 結構的功能,但由於在 Default 層上 已經將所要建立的 packet 數寫入迴圈中,設定好函式所要執行的次數,因此在這部 分會將 tmPacket_ ArrayCreate( )函式設定為一次建立一個 packet。
在 tmPacket_ArrayCreate( )函式建立 packet 的過程中,如圖 3.6 所示,首先會配置一 個記憶體空間,提供給 packet 存放資料結構的設定,接著會將傳入的 packet setup 參 數一一設定到 packet 的資料結構裡。當這部分的結構參數設定結束後,便完成了 packet 初步的建立,但是在 packet 的資料結構中仍有尚未設定的結構成員,因此接 下來會針對這部分結構成員的設定做進一步的討論。
7. Packet 與 Queue 的設定
圖 3.5 Packet 的建構流程
tmPacket_Create( ptmPacket_t*create, tmPacket_Setup_t const*setup)
{ /*呼叫建立 packet 陣列的函式,傳入值”1”代表建立陣列中的一個元素, 也就是建立一個 packet 的意思 */
tmPacket_ArrayCreate (create, 1, setup); ……
for (i=0; i!= iod->numberOfPackets; ++i)// numberOfPacket 即為所要建立的 packet 數
{
tmPacket_Create ( &iod->packetArray[i], &packetSetup ); ++packetSetup. packetBase;
//每建立完一個 packet,packetBase 加 1
}
設定好的 packet setup 結構 待設定的 packet 資料陣列
tmPacket_ArrayCreate(ptmPacket_tcreate[], Intn, tmPacket_Setup_t const *setup) { //配置記憶體區塊給 packet 結構設定參數使用
tmviMem_Calloc (setup->mem, &tmp, n*Packet_SIZE
(setup->numOfBuffers + setup->numOfProperties)); //將 packet setup 結構的參數設定到 packet 結構裡
create[0] = tmp;
create[0]->numOfBuffers = setup->numOfBuffers;
create[0]->numOfProperties = setup->numOfProperties;
create[0]->header->id = setup->packetBase;
create[0]->header->mem = setup->mem;
create[0]->header->releaseFunc = setup->releaseFunc; ……