感謝原文作者:goalie高義http://blog.csdn.net/goalietech/article/details/24887955
1 Gstreamer基本概念
GStreamer 是一個開源的多媒體用的框架,采用了基于插件(plugin)和管道(pipeline)的體系結構,框架中的所有的功能模塊都被實現成可以插拔的組件, 并且在需要的時候能夠很方便地安裝到任意一個管道上,由于所有插件都通過管道機制進行統一的數據交換,因此很容易利用已有的各種插件“組裝”出一個功能完善的多媒體應用程序。
2Gstreamer基本組成
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。
[plain]?view plaincopy
>?insmod?cmemk.ko?phys_start=0x83700000?phys_end=0x85900000?allowOverlap=1?useHeapIfPoolUnavailable=1?? >?insmod??dsplinkk.ko??
[plain]?view plaincopy
??
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可以列出各實體的參數和襯墊及連接狀態。如下所示:
[plain]?view plaincopy
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的數字來進行連接,這樣上述通道可以表示為:
[plain]?view plaincopy
media-ctl?-l?'17:0->5:0[1]',?'5:1->6:0[1]'??
“:”前面的數字代表entity的值,后面的數字為該entity的pad值,“[]”里面的數字代表狀態0為不激活,1為激活。
但是還是建議使用名稱來進行連接,這樣更加直觀一些,如下:
[plain]?view plaincopy
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的分辨率,設置如下:
[plain]?view plaincopy
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芯片,其實實現方式也是相同的,只是名字和分辨率換換而已,如下所示:
[plain]?view plaincopy
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提供的快速建立多媒體處理管道的軟件,它可以通過指令來驗證整個軟件的實現的可能性。上述的功能我們可以通過該工具很方便的實現出來,具體指令如下所示:
[python]?view plaincopy
gst-launch-v?v4l2src?device=/dev/video2?\?? !ffmpegcolorspace?\?? !video/x-raw-yuv,format=fourccUYVY,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輸入正確的端口號,點擊確定就可以正常播放網絡傳輸的音視頻了。
當然你如果僅僅想傳輸視頻也是可以的,通過如下指令即可實現視頻單獨傳輸:
[python]?view plaincopy
gst-launch-v?v4l2src?device=/dev/video2?!\?? ffmpegcolorspace!?videoscale!?videorate?!?\?? video/x-raw-yuv,format=fourccUYVY,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下未測試):
[python]?view plaincopy
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的文件,如下:
[plain]?view plaincopy
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
[html]?view plaincopy
<pre?code_snippet_id="324143"?snippet_file_name="blog_20140503_10_3411737"></pre>?? <pre></pre>?? <pre></pre>??
總結
以上是生活随笔為你收集整理的gstreamer教程及在DM3730上的应用的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。