在面對一個新的軟件庫時,第一步一般實現一個「hello world」程序,來了解庫的用法。對於GStreamer,咱們能夠實現一個極簡的播放器,來了解GStreamer的使用。html
爲了快速掌握Gstreamer相關的知識,咱們優先選擇Ubuntu做爲咱們的開發環境,其餘平臺的開發會在後續文章單獨介紹。若是尚未Ubuntu虛擬機,能夠在OSBoxes中直接下載Ubuntu 18.04的VirtualBox或VMware鏡像文件,節省安裝時間。linux
咱們在基本介紹中提到,gstreamer的框架及插件位於不一樣的源碼包中,因此咱們須要安裝多個軟件包:git
$ sudo apt-get install gcc build-essential libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools \
gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-qt5 gstreamer1.0-pulseaudio
咱們首先使用官方的HelloWorld做爲咱們的第一個應用:basic-tutorial-1.cweb
#include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *pipeline; GstBus *bus; GstMessage *msg; /* Initialize GStreamer */ gst_init (&argc, &argv); /* Build the pipeline */ pipeline = gst_parse_launch ("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm", NULL); /* Start playing */ gst_element_set_state (pipeline, GST_STATE_PLAYING); /* Wait until error or EOS */ bus = gst_element_get_bus (pipeline); msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS); /* Free resources */ if (msg != NULL) gst_message_unref (msg); gst_object_unref (bus); gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); return 0; }
經過下面的命令編譯獲得可執行程序ubuntu
$ gcc basic-tutorial-1.c -o basic-tutorial-1 `pkg-config --cflags --libs gstreamer-1.0`
編譯成功後,咱們能夠獲得可執行文件,執行 basic-tutorial-1,會在彈出的窗口中,自動讀取服務器上的sintel_trailer-480p.webm視頻文件並播放。若是網絡環境不理想,在播放的過程當中會常常處理緩衝狀態,形成播放卡頓。也能夠先下載媒體文件,將uri的http路徑替換爲本地uri(例如: uri=file:///home/john/sintel_trailer-480p.webm)避免網絡的影響。服務器
經過上面的代碼,咱們達到了播放一個視頻文件的目的,接下來經過分析這個簡短的程序來了解gstreamer應用是如何工做的。網絡
/* Initialize GStreamer */ gst_init (&argc, &argv);
首先咱們調用了gstreamer的初始化函數,該初始化函數必須在其餘gstreamer接口以前被調用,gst_init會負責如下資源的初始化:框架
在不須要gst_init處理命令行參數時,咱們能夠講NULL做爲其參數,例如:gst_init(NULL, NULL);函數
/* Build the pipeline */ pipeline = gst_parse_launch ("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm", NULL);
這一行是示例中的核心邏輯,展現瞭如何經過gst_parse_launch 建立一個playbin的pipeline,並設置播放文件的uri。工具
在基本介紹中咱們瞭解了Pipeline的概念,在pipeline中,首先經過「source」 element獲取媒體數據,而後經過一個或多個element對編碼數據進行解碼,最後經過「sink」 element輸出聲音和畫面。一般在建立較複雜的pipeline時,咱們須要經過gst_element_factory_make來建立element,而後將其加入到GStreamer Bin中,並鏈接起來。當pipeline比較簡單而且咱們不須要對pipeline中的element進行過多的控制時,咱們能夠採用gst_parse_launch 來簡化pipeline的建立。
這個函數可以巧妙的將pipeline的文本描述轉化爲pipeline對象,咱們也常常須要經過文本方式構建pipeline來查看GStreamer是否支持相應的功能,所以GStreamer提供了gst-launch-1.0命令行工具,極大的方便了pipeline的測試。
咱們知道pipeline中須要添加特定的element以實現相應的功能,在本例中,咱們經過gst_parse_launch建立了只包含一個element的Pipeline。
咱們剛提到pipeline須要有「source」、「sink」 element,爲何這裏只須要一個playbin就夠了呢?是由於playbin element內部會根據文件的類型自動去查找所須要的「source」,「decoder」,」sink」並將它們鏈接起來,同時提供了部分接口用於控制pipeline中相應的element。
在playbin後,咱們跟了一個uri參數,指定了咱們想要播放的媒體文件地址,playbin會根據uri所使用的協議(「https://」,「ftp://」,「file://」等)自動選擇合適的source element(此例中經過https方式)獲取數據。
/* Start playing */ gst_element_set_state (pipeline, GST_STATE_PLAYING);
這一行代碼引入了一個新的概念「狀態」(state)。每一個GStreamer element都有相應都狀態,咱們目前能夠簡單的把狀態與播放器的播放/暫停按鈕聯繫起來,只有當狀態處於PLAYING時,pipeline纔會播放/處理數據。
這裏gst_element_set_state經過pipeline,將playbin的狀態設置爲PLAYING,使playbin開始播放視頻文件。
/* Wait until error or EOS */ bus = gst_element_get_bus (pipeline); msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
這幾行會等待pipeline播放結束或者播放出錯。咱們知道GStreamer框架會經過bus,將所發生的事件通知到應用程序,所以,這裏首先取得pipeline的bus對象,經過gst_bus_timed_pop_filtered 以同步的方式等待bus上的ERROR或EOS(End of Stream)消息,該函數收到消息後纔會返回。
咱們會在下一篇文章中繼續介紹消息相關的內容。
到目前爲止,GStreamer會處理視頻播放的全部工做(數據獲取,解碼,音視頻同步,輸出)。當到達文件末端(EOS)或出錯(直接關閉播放窗口,斷開網絡)時,播放會自動中止。咱們也能夠在終端經過ctrl+c中斷程序的執行。
/* Free resources */ if (msg != NULL) gst_message_unref (msg); gst_object_unref (bus); gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline);
這裏咱們將再也不使用的msg,bus對象進行銷燬,並將pipeline狀態設置爲NULL(在NULL狀態時GStreamer會釋放爲pipeline分配的全部資源),最後銷燬pipeline對象。因爲GStreamer是繼承自GObject,因此須要經過gst_object_unref 來減小引用計數,當對象的引用計數爲0時,函數內部會自動釋放爲其分配的內存。
不一樣接口會對返回的對象進行不一樣的處理,咱們須要詳細的閱讀API文檔,來決定咱們是否須要對返回的對象進行釋放。
在本教程中,咱們掌握了:
在下一篇文章中,咱們將繼續介紹GStreamer的基本概念,以及pipeline的另外一種構造方式。
https://gstreamer.freedesktop.org/documentation/tutorials/basic/hello-world.html
https://gstreamer.freedesktop.org/documentation/installing/on-linux.html