基於DM3730平臺的gstreamer音視頻傳輸調試


1、            Gstreamer基本概念

GStreamer 是一個開源的多媒體用的框架,採用了基於插件(plugin)和管道(pipeline)的體系結構,框架中的所有的功能模塊都被實現成可以插拔的組件, 並且在需要的時候能夠很方便地安裝到任意一個管道上,由於所有插件都通過管道機制進行統一的數據交換,因此很容易利用已有的各種插件“組裝”出一個功能完善的多媒體應用程序。

2、            Gstreamer基本組成

Gstreamer組成有四個基本單位,它們分別爲元件(element)、襯墊(Pads)、箱櫃(Bins)、管道(pipelines)。

A:元件(element):元件是Gstreamer中最重要的概念,它是組成整個gstreamer應用程序的基本單位,可以將多個相關功能的元件鏈接到一起組成一個管道,這樣就可以實現一個簡單的多媒體軟件了。常見的元件有音頻編解碼、視頻編解碼、文件讀取、網絡傳輸等。

B:襯墊(Pads):用於元件之間的鏈接,可以理解爲元件的插座或端口,襯墊分爲兩種類型:src爲輸出,sink爲輸入。一個元件可以既有src又有sink襯墊,也可以多個src或sink襯墊。例如:音頻編碼元件的輸入或輸出端、音頻播放元件的輸入端都屬於襯墊。

C: 箱櫃(Bins)、管道(pipelines):箱櫃是一個可以裝載元件的容器,將多個元件鏈接起來放入箱櫃中實現一個高級功能的單元。例如:將音頻解碼元件和音頻輸出元件鏈接起來可以組成一個音頻解碼播放模塊裝載到箱櫃中。管道是最高等級的箱櫃,是由多個元件或箱櫃組成的一個完整的功能單元。例如:一個音視頻文件的播放通道。

如下圖所示,一個簡單的ogg格式的播放器用gstreamer的方式去實現,就是將各相關功能的元件通過襯墊連接到一起組成一個管道,這樣就可以實現一個基本的ogg播放器了。


簡單的ogg播放器Gstreamer實現

3、            Gstreamer應用及實現功能


Gstreamer功能框架圖

GStreamer核心庫函數是一個處理插件、數據流和媒體操作的框架,gstremer的插件機制是其核心,所有的元件的都是以插件的形式綁定在管道中用來實現媒體處理的功能的。Gstreamer目前包含的插件已經超過了250個,包含音視頻的各種方式輸入輸出、編解碼、存儲、網絡傳輸、傳輸協議、音視頻編輯、格式轉換等方面的插件。

4、            基於gstreamer框架的軟件及功能

l        Rhythmbox是一個綜合的音樂管理軟件,屬於建築於網絡之上的播放器。可以直接下載歌曲,支持網絡電臺和播客。


Rhythmbox

l        Sound juicer是一種在Linux及其它Unix-Like等操作系統平臺上可將CD音軌轉檔的軟件,能透過GStreamer的插件來進行各種音效編碼。可轉換包括mp3、Ogg、FLAC、及PCM等不同格式。


Sound juicer

l        Monkey Bubble 是一個很有趣又很酷的GNOME下的一個遊戲軟件,它通過GStreamer播放音樂產生驚悚的或甜美的音響效果。  


Monkey Bubble

l        AviSynth是一個功能強大的視頻文件後期處理工具,提供了許多編輯和處理視頻文件的方法。能夠提供各種方式來合併和濾鏡處理影像文件。最獨特的就是AviSynth並不是一個孤立的影像處理程序,而是在影像文件和應用程序之間擔任“中間人”的角色。


AviSynth

l        Thoggen 是一個高效的 DVD 備份軟件,它基於GStreamer,擁有一個漂亮的 GTK+ 界面,功能強大且容易使用。

l        GNOME Media 是用GStreamer 來進行聲音控制、音頻錄製和CD播放。 

 

5、            DM3730平臺及環境搭建

DM3730是TI公司生產一款ARM+DSP雙核的處理器,該處理器集成了高達 1GHz的ARM Cortex™-A8內核及高達800MHz的具有高級數字信號處理的DSP核,並提供了豐富的外設接口。主要應用於便攜式數據終端、導航、自動化資訊娛樂、醫療設備、工業控制等產品中。

搭建DVSDK開發環境

DVSDK(DaVinci Software Development Kit)是TI公司爲了方便用戶開發和測試而提供的一系列的工具包。開發者可以利用DVSDK提供的工具測試DM3730的軟硬件性能,能夠評估ARM Linux的開發環境並且體驗到硬件多媒體編解碼的性能。

1、首先下載一個DM3730對應的DVSDK安裝包,我們這裏下載的是DVSDK4.03的版本。

2、DVSDK安裝推薦使用Ubuntu 10.04的版本,然後安裝DVSDK到ubuntu系統。

3、修改根目錄下的Rules.make文件,主要是修改對應的平臺、內核、編譯工具鏈等選項。

4、執行根目錄下的setup.sh腳本,主要是安裝tftp工具,創建文件系統目錄、配置串口和uboot環境參數。

5、執行make clean、make all和 make install進行完全編譯。make help 可參看make幫助信息。

6、編譯成功後就會生成目標文件系統targetfs,在targetfs/usr/share/ti文件夾裏面會有調試軟硬的各種工具。

CMEM和DSPLink

       DM3730爲ARM+DSP雙核機制的CPU,所以ARM和DSP之間的通信就顯得尤爲重要。CMEM和DSPLink對於DM3730來說是倆個非常重要的驅動,它們的主要功能就是爲了實現ARM和DSP之間的通信和數據交換。

CMEM:主要用於分配大片連續共享內存和數據交互。

DSPLink:雙核通信的基礎軟件,爲開發人員提供通用的API,用於ARM 與DSP之間通信。

內存分配

       由於ARM和DSP共享內存,爲了避免內存使用混亂,需要重新分配內存的使用範圍,下圖是DM3730的內存分配情況:


DM3730內存分配

從上圖可以看到Linux的內存被分配成了2個部分0x80000000-0x83700000,0x88000000-0xA0000000。所以uboot的啓動參數bootargs應該傳遞給linux內核內存的分配情況(mem=55M@0x80000000 mem=384M@0x88000000)。

系統啓動後需要安裝cmemk.ko和dsplinkk.ko。

> insmod cmemk.ko phys_start=0x83700000 phys_end=0x85900000 allowOverlap=1 useHeapIfPoolUnavailable=1
> insmod  dsplinkk.ko

6、            移植Gstreamer

DVSDK中的文件系統已經做好了對gstreamer的支持,當你編譯完dvsdk後,make install會將文件系統生成到Rules.make文件中EXEC_DIR變量所對應的目錄裏。然後你會在文件系統的usr/lib/gstreamer-0.10/看到gstreamer的庫文件。該版本的gstreamer使用過程中可能會出現庫的版本名稱不對或則丟失軟連接等問題,這些問題需要大家重命名或則手動創建軟連接即可解決。

 

7、            media-ctl移植

media-ctl是一個通過調用linux系統的MediaController API來實現對多媒體設備(DM3730默認爲/dev/media0)進行控制的指令,是一個開源的工具。它可以枚舉出系統各多媒體設備實體及實體的襯墊(pads),並可以將不同實體的襯墊連接到一起組成一個通道,從而控制視頻在前端採集時的流向。

由上圖可以看到,視頻採集過來的原始數據最終到達DM3730的ARM核,也就是可以被我們的程序得到是有很多條路徑可以選擇的。

Sensor->CCDC->Memory- (C)

Sensor->CCDC->Preview->Memory- (1), (4)

Sensor->CCDC->Preview->Resizer->Memory- (1), (2), (3)

此處參考網頁《CM-T3730: Linux: Camera

通過media-ctl –help可以看到該工具的使用方法,media-ctl –p可以列出各實體的參數和襯墊及連接狀態。如下所示:

Openingmedia device /dev/media0
Enumeratingentities
Found16 entities
Enumeratingpads and links
Devicetopology
-entity 1: OMAP3 ISP CCP2 (2 pads, 2 links)
            type V4L2 subdev subtype Unknown
            device node name /dev/v4l-subdev0
        pad0: Input [SGRBG10 4096x4096]
                <- 'OMAP3 ISP CCP2input':pad0 []
        pad1: Output [SGRBG10 4096x4096]
                -> 'OMAP3 ISP CCDC':pad0 []
 
-entity 2: OMAP3 ISP CCP2 input (1 pad, 1 link)
            type Node subtype V4L
            device node name /dev/video0
        pad0: Output
                -> 'OMAP3 ISP CCP2':pad0 []
 
-entity 3: OMAP3 ISP CSI2a (2 pads, 2 links)
            type V4L2 subdev subtype Unknown
            device node name /dev/v4l-subdev1
        pad0: Input [SGRBG10 4096x4096]
        pad1: Output [SGRBG10 4096x4096]
                -> 'OMAP3 ISP CSI2aoutput':pad0 []
                -> 'OMAP3 ISP CCDC':pad0 []
 
-entity 4: OMAP3 ISP CSI2a output (1 pad, 1 link)
            type Node subtype V4L
            device node name /dev/video1
        pad0: Input
                <- 'OMAP3 ISP CSI2a':pad1 []
 
-entity 5: OMAP3 ISP CCDC (3 pads, 9 links)
            type V4L2 subdev subtype Unknown
            device node name /dev/v4l-subdev2
        pad0: Input [SGRBG10 4096x4096]
                <- 'OMAP3 ISP CCP2':pad1 []
                <- 'OMAP3 ISP CSI2a':pad1 []
                <- 'ov5640 2-003c':pad0 []
        pad1: Output [SGRBG10 4096x4096]
                -> 'OMAP3 ISP CCDC output':pad0[]
                -> 'OMAP3 ISP resizer':pad0[]
        pad2: Output [SGRBG10 4096x4095]
                -> 'OMAP3 ISP preview':pad0[]
                -> 'OMAP3 ISP AEWB':pad0[IMMUTABLE,ACTIVE]
                -> 'OMAP3 ISP AF':pad0[IMMUTABLE,ACTIVE]
                -> 'OMAP3 ISPhistogram':pad0 [IMMUTABLE,ACTIVE]
 
-entity 6: OMAP3 ISP CCDC output (1 pad, 1 link)
            type Node subtype V4L
            device node name /dev/video2
        pad0: Input
                <- 'OMAP3 ISP CCDC':pad1 []
 
-entity 7: OMAP3 ISP preview (2 pads, 4 links)
            type V4L2 subdev subtype Unknown
            device node name /dev/v4l-subdev3
        pad0: Input [SGRBG10 4096x4096]
                <- 'OMAP3 ISP CCDC':pad2 []
                <- 'OMAP3 ISP previewinput':pad0 []
        pad1: Output [YUYV 4082x4088]
                -> 'OMAP3 ISP previewoutput':pad0 []
                -> 'OMAP3 ISP resizer':pad0[]
 
-entity 8: OMAP3 ISP preview input (1 pad, 1 link)
            type Node subtype V4L
            device node name /dev/video3
        pad0: Output
                -> 'OMAP3 ISP preview':pad0[]
 
-entity 9: OMAP3 ISP preview output (1 pad, 1 link)
            type Node subtype V4L
            device node name /dev/video4
        pad0: Input
                <- 'OMAP3 ISP preview':pad1[]
 
-entity 10: OMAP3 ISP resizer (2 pads, 4 links)
             type V4L2 subdev subtype Unknown
             device node name /dev/v4l-subdev4
        pad0: Input [YUYV 4095x4095(0,0)/4086x4082]
                <- 'OMAP3 ISP CCDC':pad1 []
                <- 'OMAP3 ISP preview':pad1[]
                <- 'OMAP3 ISP resizerinput':pad0 []
        pad1: Output [YUYV 4096x4095]
                -> 'OMAP3 ISP resizeroutput':pad0 []
 
-entity 11: OMAP3 ISP resizer input (1 pad, 1 link)
             type Node subtype V4L
             device node name /dev/video5
        pad0: Output
                -> 'OMAP3 ISP resizer':pad0[]
 
-entity 12: OMAP3 ISP resizer output (1 pad, 1 link)
             type Node subtype V4L
             device node name /dev/video6
        pad0: Input
                <- 'OMAP3 ISP resizer':pad1[]
 
-entity 13: OMAP3 ISP AEWB (1 pad, 1 link)
             type V4L2 subdev subtype Unknown
             device node name /dev/v4l-subdev5
        pad0: Input
                <- 'OMAP3 ISP CCDC':pad2[IMMUTABLE,ACTIVE]
 
-entity 14: OMAP3 ISP AF (1 pad, 1 link)
             type V4L2 subdev subtype Unknown
             device node name /dev/v4l-subdev6
        pad0: Input
                <- 'OMAP3 ISP CCDC':pad2[IMMUTABLE,ACTIVE]
 
-entity 15: OMAP3 ISP histogram (1 pad, 1 link)
             type V4L2 subdev subtype Unknown
             device node name /dev/v4l-subdev7
        pad0: Input
                <- 'OMAP3 ISP CCDC':pad2[IMMUTABLE,ACTIVE]
 
-entity 17: ov5640 2-003c (1 pad, 1 link)
             type V4L2 subdev subtype Unknown
             device node name /dev/v4l-subdev8
        pad0: Output [unknown 640x480(0,0)/640x480]
                -> 'OMAP3 ISP CCDC':pad0 []

從上面列表從可以看到entity17對應ov5640也就是視頻輸入源,輸出可以選擇OMAP3 ISP CCDC,我們要建立一個ov5640--> ISP CCDC-->memory的通道實現視頻採集功能,通過幫助我知道應該使用media-ctl –l來實現通道連接功能。

可以直接使用entity和pad的數字來進行連接,這樣上述通道可以表示爲:

media-ctl -l '17:0->5:0[1]', '5:1->6:0[1]'

“:”前面的數字代表entity的值,後面的數字爲該entity的pad值,“[]”裏面的數字代表狀態0爲不激活,1爲激活。

但是還是建議使用名稱來進行連接,這樣更加直觀一些,如下:

media-ctl -l '"ov56402-003c":0->"OMAP3 ISP CCDC":0[1], "OMAP3 ISPCCDC":1->"OMAP3 ISP CCDC output":0[1]'

除此之外還要對各pad的分辨率進行配置,使用media-ctl -v --set-format指令,這裏ov5640默認使用640x480的分辨率,設置如下:

media-ctl -v --set-format '"ov56402-003c":0 [UYVY 640x480]'
media-ctl -v --set-format '"OMAP3 ISPCCDC":0 [UYVY 640x480]'
media-ctl -v --set-format '"OMAP3 ISPCCDC":1 [UYVY 640x480]'

這樣可以看到ISP CCDC的輸出節點爲/dev/video2,以後程序就可以使用該節點獲取視頻數據和控制了。

如果你使用的TVP5150這樣AD芯片,其實實現方式也是相同的,只是名字和分辨率換換而已,如下所示:

media-ctl -r -l '"tvp51503-005d":0->"OMAP3 ISP CCDC":0[1], "OMAP3 ISPCCDC":1->"OMAP3 ISP CCDC output":0[1]'
media-ctl -v --set-format '"tvp51503-005d":0 [UYVY 720x576]'
media-ctl -v --set-format '"OMAP3 ISPCCDC":0 [UYVY 720x576]'
media-ctl -v --set-format '"OMAP3 ISPCCDC":1 [UYVY 720x576]'

另外。Media-ctl有好多版本,費很大勁才找到適合DM3730使用的,但還是有一個小bug,現在將我修改後使用的media-ctl源碼上傳上來了,需要的話可以去下載。當然如果通過MediaController API自己編程實現上述功能也是可以的。

調試過程中發現一個問題,文件系統存放在SD啓動時會生成/dev/media0設備,但是燒寫到NandFlash之後/dev/media0沒有了。後來發現原來是mdev的問題,於是將mdev替換爲udev後,問題就解決了,時間太長了具體原因忘記了,知道的朋友幫忙留一下言吧。

 Media-ctl.tar.gz

8、            DM3730音視頻gstreamer處理流程

DVSDK軟件包中提供了gstreamer的代碼並集成了針對於DM3730芯片的插件TI GStreamer Plugin,如下圖所示:


DM3730軟件系統框架圖

上圖綠色部分爲TI基於gstreamer框架實現的插件,裏面包含了基於DM3730的DSP音視頻編解碼算法、視頻顯示、DMA控制等插件。

我們想做一個類似於IPcamera的測試功能,通過採集音視頻並編碼打包,然後通過網絡傳輸出去,通過客戶端可以接收到數據並分別解包後顯示出來。具體實現方式將用到gstreamer內部提供的元件和TI提供的視頻編碼的插件。

DM3730音視頻處理的具體功能框圖如下圖所示:



 元件功能介紹:

l        v4l2src:從video4linux2設備(ov5640、tvp5150)中讀取視頻幀。支持rgb、yuv、jpeg、dv、mpegts等常見視頻格式。

l        alsasrc:通過ALSA接口聲卡設備中讀取音頻數據,支持8、16、24、32位的音頻數據。

l        ffmpegcolorspace:將視頻數據從一種顏色空間轉換成另一種。

l        audioconvert:音頻格式轉換。

l        TIVidenc1:TI提供的視頻編碼器插件。

l        alawenc:A率音頻編碼器。

l        mpegtsmux:混合多媒體到MPEG2-TS傳輸流(一種傳輸和存儲包含音效、圖像與通信協議各種數據的標準格式,用於數字電視廣播系統),主要實現音視頻的同步處理。

l        rtpmp2tpay:將有效的負載編碼MPEG2-TS傳輸流打包成RTP協議包,適合實時流媒體傳輸。

l        udpsink:通過以太網傳輸udp的數據。

 

gst-launch是gstreamer提供的快速建立多媒體處理管道的軟件,它可以通過指令來驗證整個軟件的實現的可能性。上述的功能我們可以通過該工具很方便的實現出來,具體指令如下所示:

gst-launch-v v4l2src device=/dev/video2 \
!ffmpegcolorspace \
!video/x-raw-yuv,format=\(fourcc\)UYVY,width=720, height=576 \
!TIVidenc1 codecName=h264enc engineName=codecServer \
!queue ! mux. \
alsasrc! audioconvert \
!'audio/x-raw-int,rate=44100,channels=1' ! faac \
!mux.mpegtsmux name=mux ! queue ! rtpmp2tpay ! udpsink port=8877 host=192.168.2.100

如果正常的話通過客戶端軟件就可以直接看到帶有伴音的圖像了,而且應該是音視頻同步的圖像。當然客戶端也可以通過gst-launch來進行實現,可以在電腦上安裝好gstreamer的環境,現在windows和linux均有支持,我沒有去研究如何用gst-launch來進行解碼顯示,因爲有更方便的工具可以實現這個功能,那就是VLC播放器,打開VLC選擇“文件”-->“打開網絡串流”在UDP/RTP輸入正確的端口號,點擊確定就可以正常播放網絡傳輸的音視頻了。

當然你如果僅僅想傳輸視頻也是可以的,通過如下指令即可實現視頻單獨傳輸:

gst-launch-v v4l2src device=/dev/video2 !\
ffmpegcolorspace! videoscale! videorate ! \
video/x-raw-yuv,format=\(fourcc\)UYVY,width=720, height=576, framerate=30/1!\
TIVidenc1rateControlPreset=3 codecName=h264enc engineName=codecServer !\
rtph264paypt=96 ! udpsink host=192.168.2.100 port=8877 sync=false async=false

客戶端解碼可以通過gst-launch實現,指令如下(windows下的指令,linux下未測試):

gst-launch udpsrc port=8877caps="application/x-rtp, media=(string)video, clock-rate=(int)90000 ,encoding-name=(string)H264, payload=(int)96" ! gstrtpjitterbuffer !rtph264depay ! ffdec_h264 ! ffmpegcolorspace ! videoscale !"video/x-raw-yuv" ! autovideosink

或則也可以通過VLC進行播放,需要先編寫一個.sdp的文件,如下:

v=0
m=video 8877 RTP/AVP 96
c=IN IP4 192.168.2.200
a=rtpmap:96 H264/9000

將上面內容保存爲rtph264.sdp文件,然後通過VLC打開即可接收並播放網絡傳輸的視頻流。

上面的參數大家可以自行研究,這裏就不贅述了。

上面的指令通過應用程序也是很方便實現的,前提是你掌握了gstreamer的編程方法。

這裏上傳一個非常有用的gstreamerAPI手冊,CHM格式的,是本人自己製作的,還是很實用的,而且查找函數和使用方法非常的方便,大家可以選擇下載。


GStreamer 1.0 Core Reference Manual




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章