Reference:
http://gstreamer.freedesktop.org/
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/manual.pdf
gstreamer SDK Tutorials
Android MediaCodec stuff
About GStreamer
GStreamer 是一個建立streaming media applications的 framework
GStreamer提供了
- an API for multimedia applications
- a plugin architecture
- a pipeline architecture
- a mechanism for media type handling/negotiation
- a mechanism for synchronization
- over 250 plug-ins providing more than 1000 elements
- a set of tools
Foundations
- Elements:每一個原件都有特定的功能,像是讀取檔案資料、decoding of this data or outputting this data to your sound card,將幾個element串聯起來就可以建立一個pipeline來執行特定任務
- Pads:當element連接各個element時,pad為elements的輸入和輸出,常被用於協商各elements之間的連結和資料串流在GStreamer中,Pads具有特定資料處理能力:
- 限制通過Pads的資料型態
- 資料型態的協商呼叫 caps negotiation 這個process,資料型態的描述為 GstCaps
- 打個比方。Pads類似於物理設備上的插頭或插孔。例如,一個家庭影院系統,包括一個放大器,一個DVD播放機的,和一個(無聲)視頻投影機。連結DVD播放機到放大器是允許的,因為這兩種設備有音頻插孔,以及投影機與DVD播放機連接是允許的,因為這兩種設備都兼容的視頻插孔。可能不會在投影機和放大器之間的聯繫,因為投影機和放大器具有不同類型的插孔。 GStreamer中的服務類似於在家庭影院系統的接口。
- Bins:蒐集所有elements的容器,可以改變bins的狀態來改變所有elements的狀態
- pipeline:為一個high-level的bin,它提供bus讓application與其子集合同步,當設定為PAUSED 或 PLAYING 狀態,資料流將會進行處理
- Communication:GStreamer提供一些機制讓pipeline和application來做溝通和資料交換
- buffers:各個elements 在pipeline 中傳輸資料流,總是從source到sink(downstream)
- events:各個elements 之間傳送 或是 application 傳給 pipeline。為downstream 和 upstream,downstream可以同步資料流
- messages :pipeline與application溝通之用。也常用於傳輸 errors、狀態交換等等資訊給application。
- queries:允許application 從pipeline中請求 duaration和 current playback position 等訊息。elemant也常使用queries 與對等element中來請求資訊。
Initializing GStreamer
- Simple initialization
- #include <gst/gst.h>
- int
- main (int argc, char *argv[])
- {
- const gchar *nano_str;
- guint major, minor, micro, nano;
- gst_init (&argc, &argv); //初始化gstreamer
- gst_version (&major, &minor, µ, &nano); //利用 gst_version 來獲得當前版本訊息
- if (nano == 1)
- nano_str = "(CVS)";
- else if (nano == 2)
- nano_str = "(Prerelease)";
- else
- nano_str = "";
- printf ("This program is linked against GStreamer %d.%d.%d %s\n",
- major, minor, micro, nano_str);
- return 0;
- }
- Initialisation using the GOption interface
- #include <gst/gst.h>
- int
- main (int argc,
- char *argv[])
- {
- gboolean silent = FALSE;
- gchar *savefile = NULL;
- GOptionContext *ctx;
- GError *err = NULL;
- GOptionEntry entries[] = {
- { "silent", 's', 0, G_OPTION_ARG_NONE, &silent,
- "do not output status information", NULL },
- { "output", 'o', 0, G_OPTION_ARG_STRING, &savefile,
- "save xml representation of pipeline to FILE and exit", "FILE" },
- { NULL }
- };
- ctx = g_option_context_new ("- Your application");
- g_option_context_add_main_entries (ctx, entries, NULL);
- g_option_context_add_group (ctx, gst_init_get_option_group ());
- if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
- g_print ("Failed to initialize: %s\n", err->message);
- g_error_free (err);
- return 1;
- }
- printf ("Run me with --help to see the Application options appended.\n");
- return 0;
- }
Element
所有(high-level)都源自 GstElement 物件。任何一个解碼器编码器、分離器、視頻/音頻输出元件都是一個 GstElement對象。Element 就像黑盒子,從Element 一端輸入數據,經過處理後,另外一端就會進行輸出。
- Source Element
- 用於為pipeline產生數據,如從音效卡讀取資料。
- 僅產生數據,不接收數據
- Filters(過濾器)、convertors(轉換器)、demuxers(分流器)、muxers(整流器)以及codecs(編解碼器)
3. Sink elements(接收元件)
- Creating a GstElement
- 建立elements:呼叫函數 gst_element_factory_make (),這個函数使用一個已存在的factory name和一個新的element name来建立element。建立完之後,你可以用新的element name在(bin)中查询得到這個element。
- 解除引用elements:呼叫 gst_object_unref () ,會使得一個element的引用數減少 1,任何element 在建立時其引用數為 1,當引用數為0時,element會銷毀。
- #include <gst/gst.h>
- int main (int argc, char *argv[])
- {
- GstElement *element;
- /* init GStreamer */
- gst_init (&argc, &argv);
- /* create element */
- element = gst_element_factory_make ("fakesrc", "source");
- if (!element) {
- g_print ("Failed to create element of type 'fakesrc'\n");
- return -1;
- }
- gst_object_unref (GST_OBJECT (element));
- return 0;
- }
gst_element_factory_find () 使用一個唯一的 factory name 来訪問一個 GstElementFactory 對象。
- #include <gst/gst.h>
- int main (int argc, char *argv[])
- {
- GstElementFactory *factory;
- GstElement * element;
- /* init GStreamer */
- gst_init (&argc, &argv);
- /* create element, method #2 */
- factory = gst_element_factory_find ("fakesrc");
- if (!factory) {
- g_print ("Failed to find factory of type 'fakesrc'\n");
- return -1;
- }
- element = gst_element_factory_create (factory, "source");
- if (!element) {
- g_print ("Failed to create element, even though its factory exists!\n");
- return -1;
- }
- gst_object_unref (GST_OBJECT (element));
- return 0;
- }
- Using an element as a GObject
使用 GObject 的方法可以對 GstElement 進行查詢、設置、獲取屬性的值。同樣的 GParamSpecs 也有支持。
每個 GstElement 都從其 GstObject 繼承了至少一個“名字"屬性
- gst_object_set_name:設定該屬性
- gst_object_get_name:取得一個對象名字屬性
- #include <gst/gst.h>
- int main (int argc, char *argv[])
- {
- GstElement *element;
- gchar *name;
- /* init GStreamer */
- gst_init (&argc, &argv);
- /* create element */
- element = gst_element_factory_make ("fakesrc", "source");
- /* get name */
- g_object_get (G_OBJECT (element), "name", &name, NULL);
- g_print ("The name of the element is '%s'.\n", name);
- g_free (name);
- gst_object_unref (GST_OBJECT (element));
- return 0;
- }
gst-inspect 是一個用來查詢特定element 特性(properties)的實用工具。它也提供了諸如函數簡短介紹、參數的類型及其支持的範圍等信息。
factory element 最有用處的功能為包含對element 所產生的pads 一個詳細描述及pads的功能(pads所支援的媒體類型)
- Linking elements
舉例來說,第一個為source,第二個為 ogg/vorbis 音頻解碼器,最終為音效卡。
- #include <gst/gst.h>
- int main (int argc, char *argv[])
- {
- GstElement *pipeline;
- GstElement *source, *filter, *sink;
- /* init */
- gst_init (&argc, &argv);
- /* create pipeline */
- pipeline = gst_pipeline_new ("my-pipeline");
- /* create elements */
- source = gst_element_factory_make ("fakesrc", "source");
- filter = gst_element_factory_make ("identity", "filter");
- sink = gst_element_factory_make ("fakesink", "sink");
- /* must add elements to pipeline before linking them */
- gst_bin_add_many (GST_BIN (pipeline), source, filter, sink, NULL);
- /* link */
- if (!gst_element_link_many (source, filter, sink, NULL)) {
- g_warning ("Failed to link elements!");
- }
- [..]
- }
- note:連結不同element前,需確保這些element都被加在同一個bin之中。
- Element States
element被建立之後不會執行任何操作,需要改變其狀態才能做事情
- GST_STATE_NULL:預設狀態。會回收所有被該element 佔用的資源
- GST_STATE_READY:預備狀態。會得到所需的global resource,這些global resource 將被通過該element 的資料流使用
- GST_STATE_PAUSED:暫停狀態。
- GST_STATE_PLAYING:播放狀態。
gst_element_set_state():改變element 的狀態
Bins
將一組有連接的element 組合成一個大的邏輯組件,不用對單個element 進行操作,只需要操作 bins
Bins可以對包含在其中的element 進行管理,會計算數據怎樣流入Bins ,並對其制定一個最佳計畫(Gstreamer最難的步驟之一)
pipeline:允許包含的element 進行 scheduling的普通容器
- Creating a bin
可用 gst_bin_new()和 gst_pipeline_new () 建立 bins
利用 gst_bin_add() 在bins中增加element 和 gst_bin_remove() 移除bins中的element
- #include <gst/gst.h>
- int main (int argc, char *argv[])
- {
- GstElement *bin, *pipeline, *source, *sink;
- /* init */
- gst_init (&argc, &argv);
- /* create */
- pipeline = gst_pipeline_new ("my_pipeline");
- bin = gst_bin_new ("my_bin");
- source = gst_element_factory_make ("fakesrc", "source");
- sink = gst_element_factory_make ("fakesink", "sink");
- /* First add the elements to the bin */
- gst_bin_add_many (GST_BIN (bin), source, sink, NULL);
- /* add the bin to the pipeline */
- gst_bin_add (GST_BIN (pipeline), bin);
- /* link the elements */
- gst_element_link (source, sink);
- [..]
- }
可以透過函數 gst_bin_get_list() 得到一個bins中所有element 的列表
- Custom bins
- int main (int argc, char *argv[])
- {
- GstElement *player;
- /* init */
- gst_init (&argc, &argv);
- /* create player */
- player = gst_element_factory_make ("oggvorbisplayer", "player");
- /* set the source audio file */
- g_object_set (player, "location", "helloworld.ogg", NULL);
- /* start playback */
- gst_element_set_state (GST_ELEMENT (player), GST_STATE_PLAYING);
- [..]
- }
BUS
採用自己的thread 機制將一個 pipeline thread 送到 application 之中,優點為使用 Gstreamer 時,application 不需要 thread-aware
每個pipeline都預設一個 Bus,所以application 不需要在另外建立。
使用Bus的兩種方法:
- 執行 GLib/Gtk+ loop,然後對Bus進行偵測,當有新Message 出現 Bus會通知你
- gst_bus_add_watch () :建立Messgae Hanlder 來偵測 pipeline,當pipeline 發消息到Bus 訊息處理器就會被觸發,檢測訊息信號類型決定哪些事件將被處理,當處理器刪除某個消息時,其返回值為TRUE
- gst_bus_add_signal_watch ()
- 使用 gst_bus_peek () 或 gst_bus_poll () 自己偵測 Bus 消息
- #include <gst/gst.h>
- static GMainLoop *loop;
- static gboolean my_bus_callback (GstBus *bus, GstMessage *message, gpointer data)
- {
- g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
- switch (GST_MESSAGE_TYPE (message)) {
- case GST_MESSAGE_ERROR: {
- GError *err;
- gchar *debug;
- gst_message_parse_error (message, &err, &debug);
- g_print ("Error: %s\n", err->message);
- g_error_free (err);
- g_free (debug);
- g_main_loop_quit (loop);
- break;
- }
- case GST_MESSAGE_EOS:
- /* end-of-stream */
- g_main_loop_quit (loop);
- break;
- default:
- /* unhandled message */
- break;
- }
- /* we want to be notified again the next time there is a message
- * on the bus, so returning TRUE (FALSE means we want to stop watching
- * for messages on the bus and our callback should not be called again) */
- return TRUE;
- }
- gint
- main (gint argc, gchar *argv[])
- {
- GstElement *pipeline;
- guint bus_watch_id;
- /* init */
- gst_init (&argc, &argv);
- /* create pipeline, add handler */
- pipeline = gst_pipeline_new ("my_pipeline");
- /* adds a watch for new message on our pipeline's message bus to
- * the default GLib main context, which is the main context that our
- * GLib main loop is attached to below
- */
- bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
- bus_watch_id = gst_bus_add_watch (bus, my_bus_callback, NULL);
- gst_object_unref (bus);
- [..]
- /* create a mainloop that runs/iterates the default GLib main context
- * (context NULL), in other words: makes the context check if anything
- * it watches for has happened. When a message has been posted on the
- * bus, the default main context will automatically call our
- * my_bus_callback() function to notify us of that message.
- * The main loop will be run until someone calls g_main_loop_quit() */
- loop = g_main_loop_new (NULL, FALSE);
- g_main_loop_run (loop);
- /* clean up */
- gst_element_set_state (pipeline, GST_STATE_NULL);
- gst_object_unref (pipeline);
- g_source_remove (bus_watch_id);
- g_main_loop_unref (loop);
- return 0;
- }
瞭解 message handler 在mainloop 中thread context是很重要的。因為在Bus上 pipeline和 application之前的交互是非同步的,所以上述方法無法用於real-time的情況。如果需要real-time 的要求,就需要Gstreamer plug-in。
note:如果使用預設的GLib主循環實現pipeline與application之間的交互,可以將"message"信號連結到Bus上。
- Message Type
Gstreamer 有幾種由Bus 傳遞的預定義 Message type。所有的 message 都有一個 message source、type和 timestamp
- Error, warning and information notifications:被各個element 用來在必要的時後告知用戶現在pipeline的狀態
- gst_message_parse_error ()、 _parse_warning () 和 _parse_info () 來提取訊息
- End-of-stream notification:
- Tags:
- State-changes:
- Buffering:
- Element messages:
- Application-specific messages:
沒有留言:
張貼留言