GStreamer基礎教程01 - Hello World


摘要

在面對一個新的軟件庫時,第一步通常實現一個“hello world”程序,來了解庫的用法。對於GStreamer,我們可以實現一個極簡的播放器,來了解GStreamer的使用。

 

環境配置

為了快速掌握Gstreamer相關的知識,我們優先選擇Ubuntu作為我們的開發環境,其他平台的開發會在后續文章單獨介紹。如果還沒有Ubuntu虛擬機,可以在OSBoxes中直接下載Ubuntu 18.04的VirtualBox或VMware鏡像文件,節省安裝時間。

安裝編譯工具及庫

我們在基本介紹中提到,gstreamer的框架及插件位於不同的源碼包中,所以我們需要安裝多個軟件包:

$ 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

 

Hello World

我們首先使用官方的HelloWorld作為我們的第一個應用:basic-tutorial-1.c

#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;
}

通過下面的命令編譯得到可執行程序

$ 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應用是如何工作的。


GStreamer初始化

  /* Initialize GStreamer */
  gst_init (&argc, &argv);

首先我們調用了gstreamer的初始化函數,該初始化函數必須在其他gstreamer接口之前被調用,gst_init會負責以下資源的初始化:

  • 初始化GStreamer庫
  • 注冊內部element
  • 加載插件列表,掃描列表中及相應路徑下的插件
  • 解析並執行命令行參數

在不需要gst_init處理命令行參數時,我們可以講NULL作為其參數,例如:gst_init(NULL, NULL);

 

創建Pipeline

/* 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。

gst_parse_launch

在基本介紹中我們了解了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的測試。

playbin

我們知道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文檔,來決定我們是否需要對返回的對象進行釋放。

 

總結

在本教程中,我們掌握了:

  • 如何中Ubuntu下搭建GStreamer的開發環境。
  • 如何通過gst_init()初始化GStreamer。
  • 如何通過gst_parse_launch()快速構建一個pipeline。
  • 如何使用playbin自動播放文件。
  • 如何使用gst_element_set_state()來控制pipeline開始播放。
  • 如何通過bus等待播放結束。

在下一篇文章中,我們將繼續介紹GStreamer的基本概念,以及pipeline的另一種構造方式。

 

引用

https://gstreamer.freedesktop.org/documentation/tutorials/basic/hello-world.html
https://gstreamer.freedesktop.org/documentation/installing/on-linux.html

 

作者: John.Leng
本文版權歸作者所有,歡迎轉載。商業轉載請聯系作者獲得授權,非商業轉載請在文章頁面明顯位置給出原文連接.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM