• 沒有找到結果。

第四章 輸入端與輸出端模組

4.3 SVIP 模組

4.3.2 SVIP Stream

Stream 為 tmVcapSvip 模組中用來處理影像串流設定的部分,建立在標準的 TSSA 架構之上,因此 Stream 這部分具備了 OL 層、AL 層以及 DL 層的執行函式,運作的程 序與一般模組相同,由上而下的函式呼叫以及資料結構設定。但由於 tmVcapSvip 模組 的輸入訊號是來自 DSP 晶片的外部,所以在模組輸入端這部分的設定上會與一般模組 不同,這裡會藉由設定硬體層上 SVIP 暫存器的值來操作影像的輸入。接下來就先探討 SVIP 上的結構,再來了解 Stream 這部分在函式上如何運作,並且是如何從 SVIP 取得

48 縮放(Scale)則是 SVIP 所提供的另一個功能,可以將影像的畫面尺寸縮放一半,給後續 的模組進行影像處理,當影像要輸出時,在輸出端再將畫面的尺寸復原;由於 SVIP 支 援八位元以及十位元的影像輸入,在這裡可以進行位元上的轉換(Dither),將十位元轉換 為八位元;最後則是寫入(Write)的動作,將擷取到的影像寫入記憶體中儲存。

Capture Decode

STR-_CTL0

Test pattern generation DV port 0

DV port 1

FMT_CTL0

Window Scale Dither Write

FMT_CTL1

Video Stream0 Video Stream1 Video Stream2 Video Stream3

Video Stream4 Video Stream5 Video Stream6 Video Stream7

圖 4.14 SVIP 結構

49

而這些暫存器的控制是由 DL 層的 Instance 來設定,但由於 tmVcapSvip 模組的架構 較為龐大,在 OL、AL、DL 層上的 Instance 結構組成不太一樣,所以在整個上下層的 前後設定步驟會較為繁複,因此接下來就直接以 tmVcapSvip 這個模組開始運作後,如 何擷取到影像的角度來探討 Instance 的設定問題。

模組的啟動是由模組中的 Start()函式來執行,所以當應用層呼叫了 OL 層的 Start() 函式時,會進而連結到 AL 層的 Start()函式,而在 AL 層的 Start()函式中則會執行兩個主 要的程序來開啟影像的擷取。首先必須先取得影像輸入後所要放置的記憶體空間位址,

也就是去取得 tmVcapSvip 模組與下一級模組之間連結的 IOD 位址,接著會將取得的空 間位址傳到 DL 層設定給 SVIP 的暫存器,讓暫存器取得記憶體的位址,如此一來在 SVIP 取得影像後,便可直接將影像寫入記憶體中;而下一個步驟則是藉由 DL 層啟動 Stream 的函式,更改 SVIP 暫存器中部分的設定值,讓 SVIP 開始執行影像擷取的動作。接下 來如圖 4.15 所示,為 AL 層 Start()函式中所執行的內容。

在這部分最主要的兩個函式如上圖所框起的部分,分別為設定 packet 位址到 SVIP 暫存器的 svip_SetVidPacket()函式,以及啟動影像擷取的 tmdlSvipStream_PrimStart()函式。

首先在 Start()函式的一開始,會藉由 svipDataOut()函式來取得影像從 tmVcapSvip 模組輸 出時所要放置的記憶體位址,接下來將取得的位址傳入 svip_SetVidPacket()函式。在 svip_SetVidPacket()函式中,會將傳入的 packet 位址依照影像儲存時資料的排列方式來 設定 buffer 的位址,例如影像所設定的 subtype 為 YUVSemiPlanar,則在 buffer 的設定 上會分配兩個 buffer 來存放影像,一個存放影像的 Y(Luminance)部分,另一個存放影像 的 UV(Chrominance)部分。svip_SetVidPacket()函式的流程內容如圖 4.16 所示,在設定 好存放影像的 buffer 位址後,即可把 buffer 的位址傳入 DL 層中,讓 DL 層的函式將 buffer

tmalVcapSvipStream_Start(Int instance) { ……

svipDataOut(); //取得tmVcapSvip 模組與下一級模組之間 IOD 的 packet 位址

……

svip_SetVidPacket(); //將 packet 位址設定到 DL 層

……

tmdlSvipStream_PrimStart(); //設定 SVIP 的暫存器,開始影像的擷取

……

圖 4.15 tmVcapSvip 模組 AL 層 Start()函式內容

50

的位址設定到暫存器的寫入埠(port)。

在 DL 層中負責將 buffer 位址設定到暫存器上的函式為 tmdlSvip_SetVidBuf(),這個 函式在 AL 層的 Instance Setup 過程中,會設定給 Instance 結構裡的成員 pSetBufAddr,

所以當 AL 層要將 buffer 位址傳入 DL 層時,只要將 buffer 位址傳給 pSetBufAddr 這個 結構成員即可。而 DL 層的 tmdlSvip_SetVidBuf()函式在接收到 AL 層傳入的 buffer 位址 後,則會開始將位址一一設定到 SVIP 上的寫入(Write)暫存器。

由於 SVIP 會將同一筆影像資料分成 Primary Stream、Auxiliary Stream、Ancillary Stream 等三種型態的 Stream 來處理,區分出 Stream 的流程如圖 4.17 所示。首先,SVIP 由外部所接收到的影像資訊在經過 Decode 暫存器解多工後,會分出一到八筆的影像資 料,視所連接的攝影機數目而定,而每一筆的影像資料都會具有 Video Stream 以及 Ancillary Stream 兩種型態的 Stream,Video Stream 即為攝影機所攝錄到的影像訊息,而 Ancillary Stream 則是儲存於影像畫面上的一些資訊。主要的 Video Stream 會再經過 Window、Scale、Dither 等三個暫存器對影像的畫面做調整,若應用層上有設定要在同

圖 4.17 SVIP 的 Video Stream 處理

Video Stream

Ancillary Stream

Window Scale Dither Write

Auxiliary Video Stream

Primary Video Stream

圖 4.16 svip_SetVidPacket()的函式內容

//在 AL 層的 Instance Setup 中已將 DL 層的 tmdlSvip_SetVidBuf()函式設定給 Instance 的成員 pSetBufAddr。

ivp->primStreamInfo.pSetBufAddr = tmdlSvip_SetVidBuf;

svip_SetVidPacket() { ……

case vdfYUV422SemiPlanar:

tmPacket_GetBufferAddr(pPacket,0,((Pointer *)&vidBuf.buffer1));

//buffer 1 存放影像的 Y 部分

tmPacket_GetBufferAddr(pPacket,1,((Pointer *)&vidBuf.buffer2));

//buffer 2 存放影像的 UV 部分

(pStreamInfo->pSetBufAddr)(ivp->dlStreamInst,&vidBuf); //將 buffer 位址傳入 DL 層

51

一個畫面中取得另一個大小的視窗,則 Window 暫存器會從影像上擷取出一個次要的視 窗,即為 Auxiliary Stream,並與原始大小的畫面資訊 Primary Stream 一起傳送出去。

由於 Primary Stream 與 Auxiliary Stream 皆為 YUV 所組成的影像畫面,因此在寫入 記憶體時需要不同的寫入埠來將 YUV 分配到所要儲存的 buffer 裡面,加上前面所提到 的 Ancillary Stream 這筆資料也需要一個獨立的寫入埠來寫入 buffer,所以在 Write 暫存 器中具有五個寫入埠來分別處理這些影像資料。而在一般執行的程式上,通常只會選擇 Primary Stream 這筆資料來處理,因此在寫入暫存器的設定上會將由 AL 層傳入的 buffer 位址設定到其中幾個寫入埠上,設定關係如圖 4.18 所示。

當 SVIP 的暫存器取得影像要寫入的記憶體位址後,會回傳一個確認值給 AL 層的 Start()函式,讓 Start()函式可以往下繼續執行影像擷取的動作,而接下來所呼叫的函式 為 DL 層的 tmdlSvipStream_PrimStart(),在這個函式裡會將暫存器中的啟動位元值設定 為啟動的狀態,如圖 4.19 所示。這部分有變更到啟動位元的暫存器,包含了寫入(Write) 暫存器以及擷取(Capture)暫存器,在寫入暫存器上會設定所用到的寫入埠啟動位元,開 啟暫存器寫入的功能;而擷取暫存器的啟動位元一變更為啟動狀態,則會開始將外部輸 入的影像擷取進 SVIP 上。

圖 4.18 Buffer 位址與暫存器的設定關係

tmdlSvip_SetVidBuf ()

{ // 寫入暫存器 Port 0 的位址設定為存放 Y 資訊的 buffer1 位址

pSvipRegs->psuWrCtl[WRITE_PORT_0][streamIndex].psuWrBaseAddr.u32 = pPhysBuffer->buffer1;

……

// 寫入暫存器 Port 1 的位址設定為存放 UV 資訊的 buffer2 位址

pSvipRegs->psuWrCtl[WRITE_PORT_1][streamIndex].psuWrBaseAddr.u32 = pPhysBuffer->buffer2;

……

圖 4.19 啟動影像擷取的暫存器設定

tmdlSvipStream_PrimStart() { ……

svipPsuWrCtl.u32 = pSvipRegs->psuWrCtl[WRITE_PORT_0][streamIndex].psuWrCtl.u32;

svipPsuWrCtl.bits.valid0 = True; //設定寫入暫存器的 Port 0 啟動的位元 ……

svipPsuWrCtl.u32 = pSvipRegs->psuWrCtl[WRITE_PORT_1][streamIndex].psuWrCtl.u32;

svipPsuWrCtl.bits.valid0 = True; //設定寫入暫存器的 Port 1 啟動的位元 ……

pSvipRegs->ctl.u32 |= 1; //將 Capture 暫存器的啟動位元 Enable,開始影像的擷取 ……

52

輸入端模組的結構參數設定以及影像擷取的啟動設定,大致上到此告一段落,而接 下來為輸出端模組的討論。