【ARM-Linux開發】gstreamer教程及在DM3730上的應用

謝原文做者:goalie高義http://blog.csdn.net/goalietech/article/details/24887955

1 Gstreamer基本概念

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

2Gstreamer基本組成

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

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

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

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

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


簡單的ogg播放器Gstreamer實現編程

3 Gstreamer應用及實現功能


Gstreamer功能框架圖ubuntu

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

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

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


Rhythmbox

l        Sound juicer是一種在Linux及其它Unix-Like等操做系統平臺上可將CD音軌轉檔的軟件,能透過GStreamer的插件來進行各類音效編碼。可轉換包括mp三、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的開發環境而且體驗到硬件多媒體編解碼的性能。

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

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

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

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

五、執行make clean、make all和 make install進行徹底編譯。make help 可參看make幫助信息。

六、編譯成功後就會生成目標文件系統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 plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. > insmod cmemk.ko phys_start=0x83700000 phys_end=0x85900000 allowOverlap=1 useHeapIfPoolUnavailable=1  
  2. > insmod  dsplinkk.ko  
[plain]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  1.   

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 plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. Openingmedia device /dev/media0  
  2. Enumeratingentities  
  3. Found16 entities  
  4. Enumeratingpads and links  
  5. Devicetopology  
  6. -entity 1: OMAP3 ISP CCP2 (2 pads, 2 links)  
  7.             type V4L2 subdev subtype Unknown  
  8.             device node name /dev/v4l-subdev0  
  9.         pad0: Input [SGRBG10 4096x4096]  
  10.                 <- 'OMAP3 ISP CCP2input':pad0 []  
  11.         pad1: Output [SGRBG10 4096x4096]  
  12.                 -> 'OMAP3 ISP CCDC':pad0 []  
  13.    
  14. -entity 2: OMAP3 ISP CCP2 input (1 pad, 1 link)  
  15.             type Node subtype V4L  
  16.             device node name /dev/video0  
  17.         pad0: Output  
  18.                 -> 'OMAP3 ISP CCP2':pad0 []  
  19.    
  20. -entity 3: OMAP3 ISP CSI2a (2 pads, 2 links)  
  21.             type V4L2 subdev subtype Unknown  
  22.             device node name /dev/v4l-subdev1  
  23.         pad0: Input [SGRBG10 4096x4096]  
  24.         pad1: Output [SGRBG10 4096x4096]  
  25.                 -> 'OMAP3 ISP CSI2aoutput':pad0 []  
  26.                 -> 'OMAP3 ISP CCDC':pad0 []  
  27.    
  28. -entity 4: OMAP3 ISP CSI2a output (1 pad, 1 link)  
  29.             type Node subtype V4L  
  30.             device node name /dev/video1  
  31.         pad0: Input  
  32.                 <- 'OMAP3 ISP CSI2a':pad1 []  
  33.    
  34. -entity 5: OMAP3 ISP CCDC (3 pads, 9 links)  
  35.             type V4L2 subdev subtype Unknown  
  36.             device node name /dev/v4l-subdev2  
  37.         pad0: Input [SGRBG10 4096x4096]  
  38.                 <- 'OMAP3 ISP CCP2':pad1 []  
  39.                 <- 'OMAP3 ISP CSI2a':pad1 []  
  40.                 <- 'ov5640 2-003c':pad0 []  
  41.         pad1: Output [SGRBG10 4096x4096]  
  42.                 -> 'OMAP3 ISP CCDC output':pad0[]  
  43.                 -> 'OMAP3 ISP resizer':pad0[]  
  44.         pad2: Output [SGRBG10 4096x4095]  
  45.                 -> 'OMAP3 ISP preview':pad0[]  
  46.                 -> 'OMAP3 ISP AEWB':pad0[IMMUTABLE,ACTIVE]  
  47.                 -> 'OMAP3 ISP AF':pad0[IMMUTABLE,ACTIVE]  
  48.                 -> 'OMAP3 ISPhistogram':pad0 [IMMUTABLE,ACTIVE]  
  49.    
  50. -entity 6: OMAP3 ISP CCDC output (1 pad, 1 link)  
  51.             type Node subtype V4L  
  52.             device node name /dev/video2  
  53.         pad0: Input  
  54.                 <- 'OMAP3 ISP CCDC':pad1 []  
  55.    
  56. -entity 7: OMAP3 ISP preview (2 pads, 4 links)  
  57.             type V4L2 subdev subtype Unknown  
  58.             device node name /dev/v4l-subdev3  
  59.         pad0: Input [SGRBG10 4096x4096]  
  60.                 <- 'OMAP3 ISP CCDC':pad2 []  
  61.                 <- 'OMAP3 ISP previewinput':pad0 []  
  62.         pad1: Output [YUYV 4082x4088]  
  63.                 -> 'OMAP3 ISP previewoutput':pad0 []  
  64.                 -> 'OMAP3 ISP resizer':pad0[]  
  65.    
  66. -entity 8: OMAP3 ISP preview input (1 pad, 1 link)  
  67.             type Node subtype V4L  
  68.             device node name /dev/video3  
  69.         pad0: Output  
  70.                 -> 'OMAP3 ISP preview':pad0[]  
  71.    
  72. -entity 9: OMAP3 ISP preview output (1 pad, 1 link)  
  73.             type Node subtype V4L  
  74.             device node name /dev/video4  
  75.         pad0: Input  
  76.                 <- 'OMAP3 ISP preview':pad1[]  
  77.    
  78. -entity 10: OMAP3 ISP resizer (2 pads, 4 links)  
  79.              type V4L2 subdev subtype Unknown  
  80.              device node name /dev/v4l-subdev4  
  81.         pad0: Input [YUYV 4095x4095(0,0)/4086x4082]  
  82.                 <- 'OMAP3 ISP CCDC':pad1 []  
  83.                 <- 'OMAP3 ISP preview':pad1[]  
  84.                 <- 'OMAP3 ISP resizerinput':pad0 []  
  85.         pad1: Output [YUYV 4096x4095]  
  86.                 -> 'OMAP3 ISP resizeroutput':pad0 []  
  87.    
  88. -entity 11: OMAP3 ISP resizer input (1 pad, 1 link)  
  89.              type Node subtype V4L  
  90.              device node name /dev/video5  
  91.         pad0: Output  
  92.                 -> 'OMAP3 ISP resizer':pad0[]  
  93.    
  94. -entity 12: OMAP3 ISP resizer output (1 pad, 1 link)  
  95.              type Node subtype V4L  
  96.              device node name /dev/video6  
  97.         pad0: Input  
  98.                 <- 'OMAP3 ISP resizer':pad1[]  
  99.    
  100. -entity 13: OMAP3 ISP AEWB (1 pad, 1 link)  
  101.              type V4L2 subdev subtype Unknown  
  102.              device node name /dev/v4l-subdev5  
  103.         pad0: Input  
  104.                 <- 'OMAP3 ISP CCDC':pad2[IMMUTABLE,ACTIVE]  
  105.    
  106. -entity 14: OMAP3 ISP AF (1 pad, 1 link)  
  107.              type V4L2 subdev subtype Unknown  
  108.              device node name /dev/v4l-subdev6  
  109.         pad0: Input  
  110.                 <- 'OMAP3 ISP CCDC':pad2[IMMUTABLE,ACTIVE]  
  111.    
  112. -entity 15: OMAP3 ISP histogram (1 pad, 1 link)  
  113.              type V4L2 subdev subtype Unknown  
  114.              device node name /dev/v4l-subdev7  
  115.         pad0: Input  
  116.                 <- 'OMAP3 ISP CCDC':pad2[IMMUTABLE,ACTIVE]  
  117.    
  118. -entity 17: ov5640 2-003c (1 pad, 1 link)  
  119.              type V4L2 subdev subtype Unknown  
  120.              device node name /dev/v4l-subdev8  
  121.         pad0: Output [unknown 640x480(0,0)/640x480]  
  122.                 -> 'OMAP3 ISP CCDC':pad0 []  

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

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

[plain]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. media-ctl -l '17:0->5:0[1]', '5:1->6:0[1]'  

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

可是仍是建議使用名稱來進行鏈接,這樣更加直觀一些,以下:

[plain]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  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的分辨率,設置以下:

[plain]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. media-ctl -v --set-format '"ov56402-003c":0 [UYVY 640x480]'  
  2. media-ctl -v --set-format '"OMAP3 ISPCCDC":0 [UYVY 640x480]'  
  3. media-ctl -v --set-format '"OMAP3 ISPCCDC":1 [UYVY 640x480]'  

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

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

[plain]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. media-ctl -r -l '"tvp51503-005d":0->"OMAP3 ISP CCDC":0[1], "OMAP3 ISPCCDC":1->"OMAP3 ISP CCDC output":0[1]'  
  2. media-ctl -v --set-format '"tvp51503-005d":0 [UYVY 720x576]'  
  3. media-ctl -v --set-format '"OMAP3 ISPCCDC":0 [UYVY 720x576]'  
  4. 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接口聲卡設備中讀取音頻數據,支持八、1六、2四、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 plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. gst-launch-v v4l2src device=/dev/video2 \  
  2. !ffmpegcolorspace \  
  3. !video/x-raw-yuv,format=fourccUYVY,width=720, height=576 \  
  4. !TIVidenc1 codecName=h264enc engineName=codecServer \  
  5. !queue ! mux. \  
  6. alsasrc! audioconvert \  
  7. !'audio/x-raw-int,rate=44100,channels=1' ! faac \  
  8. !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 plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. gst-launch-v v4l2src device=/dev/video2 !\  
  2. ffmpegcolorspace! videoscale! videorate ! \  
  3. video/x-raw-yuv,format=fourccUYVY,width=720, height=576, framerate=30/1!\  
  4. TIVidenc1rateControlPreset=3 codecName=h264enc engineName=codecServer !\  
  5. rtph264paypt=96 ! udpsink host=192.168.2.100 port=8877 sync=false async=false  

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

[python]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. 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 plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. v=0  
  2. m=video 8877 RTP/AVP 96  
  3. c=IN IP4 192.168.2.200  
  4. a=rtpmap:96 H264/9000  

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

上面的參數你們能夠自行研究,這裏就不贅述了。

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

這裏上傳一個很是有用的gstreamerAPI手冊,CHM格式的,是本人本身製做的,仍是很實用的,並且查找函數和使用方法很是的方便,你們能夠選擇下載。


GStreamer 1.0 Core Reference Manual

[html]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. <pre code_snippet_id="324143" snippet_file_name="blog_20140503_10_3411737"></pre>  
  2. <pre></pre>  
  3. <pre></pre>
相關文章
相關標籤/搜索