您好,登錄后才能下訂單哦!
這篇文章主要介紹了C語言多媒體框架GStreamer如何使用的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇C語言多媒體框架GStreamer如何使用文章都會有所收獲,下面我們一起來看看吧。
GStreamer是GNOME桌面環境下用來創建流媒體應用的多媒體框架,其基本設計思想來自于俄勒岡(Oregon)研究生學院有關視頻管道的創意,同時也借鑒了DirectShow的設計思想。
GStreamer是用c語言實現的,使用了面向對象的思維。GStreamer框架是基于插件和管道的,所有的插件都能夠被鏈接到任意的已經定義的數據流管道中,數據通過管道機制進行統一交換。GStreamer的很多優點來源于其框架的模塊化,使得新的插件能夠無縫合并。
GStreamer能夠處理任意類型的數據流,其目標是要簡化音/視頻應用程序的開發,其最顯著的用途是在構建音視頻播放器、編輯音視頻文件、音視頻格式轉換和流媒體服務上,GStreamer已經能夠被用來處理像 MP3、Ogg、MPEG1、MPEG2、AVI、Quicktime 等多種格式的多媒體數據。
GStreamer核心庫函數是一個處理插件、數據流和媒體操作的框架。另外,其還提供了一套API,用于程序員使用其它插件來編寫他所需要的應用程序時使用。但是,由于追求模塊化和高效率,使得GStreamer在整個框架上變的復雜,也同時因為復雜度的提高,使得開發一個新的應用程序顯得不是那么的簡單。
元件是GStreamer的核心,是具有一定功能的基本單元,可將其描述為一個具有特定屬性的黑盒子。其在代碼里面的類型是GstElement,可以理解為Gstreamer里面的基類。Gstreamer默認安裝了很多有用的元件,按照功能上的差異,element分為以下幾類:
(1)source element 數據源元件,只有輸出端,用來產生供管道消費的數據,例如,音頻捕捉單元,它從聲卡讀取原始音頻數據,供其它模塊用;
(2)filter(/filter-like) element 中間元件,包括過濾器、轉換器、復用器、解復用器、編解碼器等,其既有輸入端又有輸出端,從輸入端獲得相應數據,經過處理之后傳遞給輸出端,有的element可能有一個source pad多個sink pads(demux),有的可能有多個source pads一個sink pad(mux),有的有一個source pad一個sink pad,例如,音頻編碼單元,它從外界獲得音頻數據之后,根據壓縮算法編碼后,給其它模塊使用;
(3)sink elements 接收器元件,只有輸入端,僅有消費數據的能力,是整條媒體管道的終端,例如,音頻回放單元,負責將接收到的數據寫到聲卡上;
由多個基本單元組成的一個高級的功能單元,是裝載元件的容器,可以通過改變一個Bin的狀態來改變其內部所有元件的狀態,Bin可以發送總線消息(bus message)給其子集元件。
Bin和pipeline的區別就是pipeline肯定是bin,但bin不一定是pipeline,bin就像一個盒子,里面放了什么東西,功能具體是怎么實現的,用戶可以不關心,bin是元件的集合,而pipeline更強調應用的可執行性。
最高等級的Bin,是一種允許對所包含的元件進行安排(scheduling)的普通容器。頂層(toplevel)箱柜必須為一個管道,因此每個GStreamer應用程序都至少需要一個管道。當應用程序啟動后,管道會自動運行在后臺線程中,下面是一個典型的pipeline示例:
不同Elements之間的鏈接點,數據流在元件之間流動就是依靠Pads。Pads有處理特殊數據的能力,也就是其支持特定媒體類型的能力,一個Pads能夠限制數據流類型的通過,鏈接成功的條件是,兩個Pads允許通過的數據類型一致時才能建立(數據類型協商)。
Pads按照數據導向,可分為source pads(element的輸出),sink pads(element 的輸入),按照時效性可分為,永久型(always)、隨機型(sometimes)、請求型(on request),三種時效性的意義顧名思義: 永久型的襯墊一直會存在,隨機型的襯墊只在某種特定的條件下才存在(會隨機消失的襯墊也屬于隨機型),請求型的襯墊只在應用程序明確發出請求時才出現。
Pads通過GstCaps對象進行描述,一個GstCaps對象包括一個或者多個GstStructure對象,一個GstStructure描述一種媒體類型,其結構中只包含功能集中規定的固定值。
Pad的屬性描述,例如:
SRC template: 'src'
Availability: Always
Capabilities:
audio/x-raw-float
rate: [ 8000, 50000 ]
channels: [ 1, 2 ]
endianness: 1234
width: 32
buffer-frames: 0
SINK template: 'sink'
Availability: Always
Capabilities:
audio/x-vorbis
bin本身沒有pad,所以就沒有辦法把兩個bin鏈接起來。但可以用bin中的一個元件的pad構造一個代理pad,這樣bin就有一個代理pad了。這個pad實際指向被代理的那個單元的pad,示例如下:
Bus采用自己的線程機制,負責pipeline線程和應用程序程序之間的通信。每個pipeline缺省創建一個Bus,應用程序在總線上設置一個類似于對象的信號處理的消息處理器,當主循環運行的時候,總線將會輪詢這個消息處理器是否有新的消息,當消息被采集到后,總線將呼叫相應的回調函數來完成相關操作。
應用程序有兩種方法使用Bus,第一種是使用 GLib/Gtk+ main loop及gst_bus_add_watch () or gst_bus_add_signal_watch()事件回調函數機制,第二種是程序通過gst_bus_peek () /gst_bus_poll ()主動檢查Bus中的消息;
管道的數據流由一組緩沖區和事件組成,緩沖區包括實際的管道數據,事件包括控制信息,如尋找信息和流的終止信號。所有這些數據流在運行的時候自動的流過管道。
緩沖區包含了你創建的管道里的數據流,通常一個源元件會創建一個新的緩沖區,同時元件還將會把緩沖區的數據傳遞給下一個元件。一個緩沖區主要由以下一個組成:
(1)指向某塊內存的指針;
(2)內存的大小;
(3)緩沖區的時間戳;
(4)一個引用計數,指出了緩沖區所使用的元件數。沒有元件可引用的時候,這個引用將用于銷毀緩沖區。
buffer的創建有2種方式,一種是由當前的element自己創建,然后把這個buffer傳遞給下一個element;另外一種方式就是dwonstream-allocated buffers,就是由下一個element來創建要求大小的buffer,并提供buffer操作函數,當前element通過調用buffer操作函數將數據寫入這個buffer中完成buffer數據傳遞。其區別在于buffer的創建是在數據傳輸的源端element創建還是在數據接收端element來創建。
元件必須封裝在插件中才能被使用,一個插件是一塊可以加載的代碼,通常被稱為共享對象文件(shared object file)或動態鏈接庫(dynamically linked library),一個插件中可以包含一個或若干element。
GStreamer core、Plugins以及依賴的第三方開源庫的架構關系,如下圖所示,
Gstreamer的組成結構如下圖所示:
Gstreamer的通信機制示意圖及解釋如下:
pipeline用來主動向外報告自己的運行狀態。這些Message被發送到一個消息隊列,也就是pipeline的Bus,應用程序可以從Bus中獲取Message,并作出自定義的反應。Message是GST提供的,屬于異步操作;
pipeline中插件之間進行通信的機制,分為下行事件,上行事件和雙向事件。也可以由應用程序直接向某一個插件發送事件,但起作用的前提是:該插件定義了該事件的響應操作。 通過事件可以控制整個pipeline的運行狀態。
下行事件是由source插件向sink插件方向傳輸,例如,
GST_EVENT_EOS (流的終止信號)
GST_EVENT_NEWSEGMENT
上行事件是由sink插件向source插件方向傳輸,用于改變管道中數據流的狀態,例如:
GST_EVENT_QOS
GST_EVENT_SEEK(查找)
雙向事件,例如:
GST_EVENT_FLUSH_START
GST_EVENT_FLUSH_STOP
應用程序控制某一插件的運行狀態,signal可以看做Glib對象的一個屬性,是由Gobject系統提供的,屬于同步操作,與linux中的系統信號有差別。通過信號可以讓某個插件做一些對插件本身變量的操作,比如增加或者刪除一些維護信息等等。
應用程序可以通過探針Probe來探測某個插件的pad中流過的數據,比如:在audioconert 插件的src pad 加一個探針,每當有buf到達時,就調用callback_have_data(),這里這個函數只是打印一下buf的大小,統計一下buf流過的個數;
//main GstPad *m_pad_concert_src = gst_element_get_static_pad(m_gst_convert, "src"); gst_pad_add_buffer_probe(m_pad_concert_src, G_CALLBACK(callback_have_data), NULL); gst_object_unref(m_pad_concert_src); /*******Callback handler when probe date received***********/ static gboolean callback_have_data(GstPad *padsrc, GstBuffer *buffer, gpointer data) { gint iBufSize = 0; gchar* pBuffer = NULL; iBufSize = GST_BUFFER_SIZE(buffer); pBuffer = (gchar*)GST_BUFFER_DATA(buffer); static gint numBuf = 0; g_print("\rBUF %d Size=%d ", numBuf++, iBufSize); return TRUE; }
應用程序可以查詢pipline當前的運行狀態,比如:以下代碼用來查詢當前播放的位置,和總的播放時間。
GstFormat m_format = GST_FORMAT_TIME; gint64 m_position , m_length; if( gst_element_query_position(pipeline, &m_format,&m_position) && gst_element_query_duration(pipeline, &m_format, &m_length)) { g_print("Current: %"GST_TIME_FORMAT" Total: %" GST_TIME_FORMAT "\r", GST_TIME_ARGS(m_position),GST_TIME_ARGS(m_length)); }
一個元件在被創建后,它不會執行任何操作,通過改變元件的狀態,才能使它做某些事情。元件有四種狀態,每種狀態都有其特定的意義,具體如下:
GST_STATE_NULL 默認狀態:沒有分配任何資源,沒有載入插件,不能處理數據;
GST_STATE_READY 預備狀態:分配或載入所有與流無關的資源(非硬件資源),所有數據流的位置信息應該自動置0,如果數據流先前被打開過,它應該被關閉,并且其位置信息、特性信息應該被重新置為初始狀態;
GST_STATE_PAUSED 暫停狀態:準備好全部資源,接受數據流,只是sink element暫停,收到數據不處理,只是block;
GST_STATE_PLAYING 播放狀態:準備好全部資源,接受并處理數據流;其實這個狀態除了當前運行時鐘外,其它與PAUSED狀態一樣,可以通過gst_element_set_state()來改變一個元件的狀態,當元件處于GST_STATE_PLAYING狀態,管道會開始自動處理數據。
元件通過caps來描述其能處理的媒體格式,元件之間交互數據流通過caps協商,caps是一個mime類型或者一些特性集的組合。
一個加載進系統的元件必須提供其源襯墊和接收襯墊支持的mime類型。通過Gstreamer注冊中心可以知道目前注冊的不同的元件,以及他們所期望得到的與他們能夠產生的媒體類型,下圖顯示了管道中每個Pads所處理的MIME類型。
通常當加載一個新的媒體流時,媒體的類型并不明了。這意味著選擇一條管道來對媒體流進行解碼之前,首先需要檢測媒體流的類型。 GStreamer 使用了類型檢測 (typefinding) 來達到此目的。類型檢測是構建管道所必經的步驟。
首先它會一直讀取數據流,在此期間,它會把數據提供給所有的實現了類型檢測器 (typefinder) 的插件,當其中任何一個類型檢測器識別出數據流,這個類型檢測器元件將會發送一個信號,并開始像一個關卡 (passthrough)模塊一樣工作。如果數據流的類型沒有被任何類型檢測器識別出來,管道會發送一個錯誤信息,并終止所有正在處理該數據流的動作。一旦類型檢測元件找到一個類型,應用程序將會使用該元件作為管道的一部分來解碼媒體流。
探測是襯墊監聽器的形象比喻,從技術上,探針僅僅是一個可以依附于襯墊的回調信號。這些信號默認是沒有被發射(fired)的(不然的話會降低性能),但是可以通過附加探針調用gst_pad_add_data_probe() 或類似的函數被激活,這些函數附加了信號處理器,并激活實際信號的發射。
同樣地,你可以用 gst_pad_remove_data_probe () 或相關函數來刪除信號處理器,也可以只是監聽時間或緩沖區。 探針在管道的線程context運行,所以回調不應該阻塞,而且通常不能有異常的阻塞,否則會降低管道的性能,如果出現這樣的缺陷,會導致死鎖甚至崩潰。
如下圖所示,基于插件的程序,其工作原理本質上都是通過讀取動態庫實現的,只需要每個動態庫中實現某一個特定的接口就可以了,比如XX_init等,這里就是plugin_init。里面會有個像注冊表一樣的數據結構會存儲所有的插件的信息。
利用GStreamer框架提供的組件,來實現一個簡單的MP3播放器。數據源元件負責從磁盤上讀取數據,過濾器元件負責對數據進行解碼,而接受器元件則負責將解碼后的數據寫入聲卡,示例代碼和注釋如下:
#include <gst/gst.h> #include <glib.h> //定義消息處理函數, static gboolean bus_call(GstBus *bus,GstMessage *msg,gpointer data) { GMainLoop *loop = (GMainLoop *) data;//主循環的指針,接受EOS消息時退出 switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_EOS: g_print("End of stream\n"); g_main_loop_quit(loop); break; case GST_MESSAGE_ERROR: { gchar *debug; GError *error; gst_message_parse_error(msg,&error,&debug); g_free(debug); g_printerr("ERROR:%s\n",error->message); g_error_free(error); g_main_loop_quit(loop); break; } default: break; } return TRUE; } int main(int argc,char *argv[]) { GMainLoop *loop; GstElement *pipeline,*source,*decoder,*sink;//定義組件 GstBus *bus; gst_init(&argc,&argv); //初始化gstreamer loop = g_main_loop_new(NULL,FALSE);//創建主循環,在執行 g_main_loop_run后正式開始循環 if(argc != 2) { g_printerr("Usage:%s <mp3 filename>\n",argv[0]); return -1; } //創建管道和元件 pipeline = gst_pipeline_new("audio-player"); //管道用來容納元件 source = gst_element_factory_make("filesrc","file-source");//數據源元件 decoder = gst_element_factory_make("mad","mad-decoder");//過濾器元件 sink = gst_element_factory_make("autoaudiosink","audio-output");//接收器元件 if(!pipeline||!source||!decoder||!sink){ g_printerr("One element could not be created.Exiting.\n"); return -1; } //設置 source的location 參數,即文件地址. g_object_set(G_OBJECT(source),"location",argv[1],NULL); //得到管道的消息總線 bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); //添加消息監視器 gst_bus_add_watch(bus,bus_call,loop); gst_object_unref(bus); //把元件添加到管道中。管道是一個特殊的組件,可以更好的讓數據流動 gst_bin_add_many(GST_BIN(pipeline),source,decoder,sink,NULL); //通過襯墊依次連接元件 gst_element_link_many(source,decoder,sink,NULL); //啟動管道,開始播放 gst_element_set_state(pipeline,GST_STATE_PLAYING); g_print("Running\n"); //開始循環 g_main_loop_run(loop); g_print("Returned,stopping playback\n"); //終止管道,釋放資源 gst_element_set_state(pipeline,GST_STATE_NULL); gst_object_unref(GST_OBJECT(pipeline)); return 0; }
編譯運行
gcc-Wall$(pkg-config--cflags--libsgstreamer-0.10)-gtest2.c-otest2
./test2/home/phinecos/test.mp3
關于“C語言多媒體框架GStreamer如何使用”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“C語言多媒體框架GStreamer如何使用”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。