中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C語言多媒體框架GStreamer如何使用

發布時間:2022-07-19 17:08:14 來源:億速云 閱讀:226 作者:iii 欄目:開發技術

這篇文章主要介紹了C語言多媒體框架GStreamer如何使用的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇C語言多媒體框架GStreamer如何使用文章都會有所收獲,下面我們一起來看看吧。

1、GStreamer簡介

GStreamer是GNOME桌面環境下用來創建流媒體應用的多媒體框架,其基本設計思想來自于俄勒岡(Oregon)研究生學院有關視頻管道的創意,同時也借鑒了DirectShow的設計思想。

GStreamer是用c語言實現的,使用了面向對象的思維。GStreamer框架是基于插件和管道的,所有的插件都能夠被鏈接到任意的已經定義的數據流管道中,數據通過管道機制進行統一交換。GStreamer的很多優點來源于其框架的模塊化,使得新的插件能夠無縫合并。

GStreamer能夠處理任意類型的數據流,其目標是要簡化音/視頻應用程序的開發,其最顯著的用途是在構建音視頻播放器、編輯音視頻文件、音視頻格式轉換和流媒體服務上,GStreamer已經能夠被用來處理像 MP3、Ogg、MPEG1、MPEG2、AVI、Quicktime 等多種格式的多媒體數據。

GStreamer核心庫函數是一個處理插件、數據流和媒體操作的框架。另外,其還提供了一套API,用于程序員使用其它插件來編寫他所需要的應用程序時使用。但是,由于追求模塊化和高效率,使得GStreamer在整個框架上變的復雜,也同時因為復雜度的提高,使得開發一個新的應用程序顯得不是那么的簡單。

2、GStreamer基本概念

2.1、元件(Element)

元件是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 接收器元件,只有輸入端,僅有消費數據的能力,是整條媒體管道的終端,例如,音頻回放單元,負責將接收到的數據寫到聲卡上;

2.2、箱柜(Bin)

由多個基本單元組成的一個高級的功能單元,是裝載元件的容器,可以通過改變一個Bin的狀態來改變其內部所有元件的狀態,Bin可以發送總線消息(bus message)給其子集元件。

Bin和pipeline的區別就是pipeline肯定是bin,但bin不一定是pipeline,bin就像一個盒子,里面放了什么東西,功能具體是怎么實現的,用戶可以不關心,bin是元件的集合,而pipeline更強調應用的可執行性。

2.3、管道(Pipeline)

最高等級的Bin,是一種允許對所包含的元件進行安排(scheduling)的普通容器。頂層(toplevel)箱柜必須為一個管道,因此每個GStreamer應用程序都至少需要一個管道。當應用程序啟動后,管道會自動運行在后臺線程中,下面是一個典型的pipeline示例:

C語言多媒體框架GStreamer如何使用

2.4、襯墊(Pad)

不同Elements之間的鏈接點,數據流在元件之間流動就是依靠Pads。Pads有處理特殊數據的能力,也就是其支持特定媒體類型的能力,一個Pads能夠限制數據流類型的通過,鏈接成功的條件是,兩個Pads允許通過的數據類型一致時才能建立(數據類型協商)。

Pads按照數據導向,可分為source pads(element的輸出),sink pads(element 的輸入),按照時效性可分為,永久型(always)、隨機型(sometimes)、請求型(on request),三種時效性的意義顧名思義: 永久型的襯墊一直會存在,隨機型的襯墊只在某種特定的條件下才存在(會隨機消失的襯墊也屬于隨機型),請求型的襯墊只在應用程序明確發出請求時才出現。

Pads通過GstCaps對象進行描述,一個GstCaps對象包括一個或者多個GstStructure對象,一個GstStructure描述一種媒體類型,其結構中只包含功能集中規定的固定值。

2.5、能力集(Caps)

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

2.6、幽靈pad(ghost pad)

bin本身沒有pad,所以就沒有辦法把兩個bin鏈接起來。但可以用bin中的一個元件的pad構造一個代理pad,這樣bin就有一個代理pad了。這個pad實際指向被代理的那個單元的pad,示例如下:

C語言多媒體框架GStreamer如何使用

2.7、Bus

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中的消息;

2.8、緩沖區(Buffer)

管道的數據流由一組緩沖區和事件組成,緩沖區包括實際的管道數據,事件包括控制信息,如尋找信息和流的終止信號。所有這些數據流在運行的時候自動的流過管道。

緩沖區包含了你創建的管道里的數據流,通常一個源元件會創建一個新的緩沖區,同時元件還將會把緩沖區的數據傳遞給下一個元件。一個緩沖區主要由以下一個組成:

(1)指向某塊內存的指針;

(2)內存的大小;

(3)緩沖區的時間戳;

(4)一個引用計數,指出了緩沖區所使用的元件數。沒有元件可引用的時候,這個引用將用于銷毀緩沖區。

buffer的創建有2種方式,一種是由當前的element自己創建,然后把這個buffer傳遞給下一個element;另外一種方式就是dwonstream-allocated buffers,就是由下一個element來創建要求大小的buffer,并提供buffer操作函數,當前element通過調用buffer操作函數將數據寫入這個buffer中完成buffer數據傳遞。其區別在于buffer的創建是在數據傳輸的源端element創建還是在數據接收端element來創建。

2.9、插件(Plugin)

元件必須封裝在插件中才能被使用,一個插件是一塊可以加載的代碼,通常被稱為共享對象文件(shared object file)或動態鏈接庫(dynamically linked library),一個插件中可以包含一個或若干element。

3、GStreamer基本架構

GStreamer core、Plugins以及依賴的第三方開源庫的架構關系,如下圖所示,

C語言多媒體框架GStreamer如何使用

Gstreamer的組成結構如下圖所示:

C語言多媒體框架GStreamer如何使用

4、GStreamer通信機制

Gstreamer的通信機制示意圖及解釋如下:

C語言多媒體框架GStreamer如何使用

4.1、Message

pipeline用來主動向外報告自己的運行狀態。這些Message被發送到一個消息隊列,也就是pipeline的Bus,應用程序可以從Bus中獲取Message,并作出自定義的反應。Message是GST提供的,屬于異步操作;

4.2、Event

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

4.3、Signal

應用程序控制某一插件的運行狀態,signal可以看做Glib對象的一個屬性,是由Gobject系統提供的,屬于同步操作,與linux中的系統信號有差別。通過信號可以讓某個插件做一些對插件本身變量的操作,比如增加或者刪除一些維護信息等等。

4.4、Probe

應用程序可以通過探針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;
}

4.5、Quary

應用程序可以查詢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));
}

5、GStreamer元件狀態

一個元件在被創建后,它不會執行任何操作,通過改變元件的狀態,才能使它做某些事情。元件有四種狀態,每種狀態都有其特定的意義,具體如下:

GST_STATE_NULL 默認狀態:沒有分配任何資源,沒有載入插件,不能處理數據;

GST_STATE_READY 預備狀態:分配或載入所有與流無關的資源(非硬件資源),所有數據流的位置信息應該自動置0,如果數據流先前被打開過,它應該被關閉,并且其位置信息、特性信息應該被重新置為初始狀態;

GST_STATE_PAUSED 暫停狀態:準備好全部資源,接受數據流,只是sink element暫停,收到數據不處理,只是block;

GST_STATE_PLAYING 播放狀態:準備好全部資源,接受并處理數據流;其實這個狀態除了當前運行時鐘外,其它與PAUSED狀態一樣,可以通過gst_element_set_state()來改變一個元件的狀態,當元件處于GST_STATE_PLAYING狀態,管道會開始自動處理數據。

6、GStreamer中的幾個關鍵概念

6.1、識別流的MIME類型

元件通過caps來描述其能處理的媒體格式,元件之間交互數據流通過caps協商,caps是一個mime類型或者一些特性集的組合。

C語言多媒體框架GStreamer如何使用

一個加載進系統的元件必須提供其源襯墊和接收襯墊支持的mime類型。通過Gstreamer注冊中心可以知道目前注冊的不同的元件,以及他們所期望得到的與他們能夠產生的媒體類型,下圖顯示了管道中每個Pads所處理的MIME類型。

6.2、媒體流類型檢測(typefind)

通常當加載一個新的媒體流時,媒體的類型并不明了。這意味著選擇一條管道來對媒體流進行解碼之前,首先需要檢測媒體流的類型。 GStreamer 使用了類型檢測 (typefinding) 來達到此目的。類型檢測是構建管道所必經的步驟。

首先它會一直讀取數據流,在此期間,它會把數據提供給所有的實現了類型檢測器 (typefinder) 的插件,當其中任何一個類型檢測器識別出數據流,這個類型檢測器元件將會發送一個信號,并開始像一個關卡 (passthrough)模塊一樣工作。如果數據流的類型沒有被任何類型檢測器識別出來,管道會發送一個錯誤信息,并終止所有正在處理該數據流的動作。一旦類型檢測元件找到一個類型,應用程序將會使用該元件作為管道的一部分來解碼媒體流。

6.3、數據探測

探測是襯墊監聽器的形象比喻,從技術上,探針僅僅是一個可以依附于襯墊的回調信號。這些信號默認是沒有被發射(fired)的(不然的話會降低性能),但是可以通過附加探針調用gst_pad_add_data_probe() 或類似的函數被激活,這些函數附加了信號處理器,并激活實際信號的發射。

同樣地,你可以用 gst_pad_remove_data_probe () 或相關函數來刪除信號處理器,也可以只是監聽時間或緩沖區。 探針在管道的線程context運行,所以回調不應該阻塞,而且通常不能有異常的阻塞,否則會降低管道的性能,如果出現這樣的缺陷,會導致死鎖甚至崩潰。

6.4、插件加載流程

如下圖所示,基于插件的程序,其工作原理本質上都是通過讀取動態庫實現的,只需要每個動態庫中實現某一個特定的接口就可以了,比如XX_init等,這里就是plugin_init。里面會有個像注冊表一樣的數據結構會存儲所有的插件的信息。

C語言多媒體框架GStreamer如何使用

7、GStreamer開發示例-MP3文件播放器

利用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如何使用”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

绥宁县| 射阳县| 双峰县| 洮南市| 江川县| 莎车县| 洛南县| 广河县| 桓仁| 含山县| 西林县| 汉阴县| 咸丰县| 靖西县| 汾阳市| 景德镇市| 集安市| 陆良县| 鄂尔多斯市| 蓝田县| 凤城市| 三亚市| 云阳县| 正安县| 体育| 松江区| 安化县| 永川市| 青铜峡市| 灯塔市| 安平县| 鲜城| 望都县| 微博| 黄大仙区| 元氏县| 麟游县| 潮州市| 永吉县| 策勒县| 宁德市|