本文介紹如何使用GStreamer 編寫(xiě)一個(gè)簡(jiǎn)單的MP3播放器。
1,需要使用mad解碼插件,因此需要先安裝gstreamer0.10-plugins-ugly
2,編寫(xiě)mp3播放器
下面來(lái)看看如何利用GStreamer框架提供的組件,來(lái)實(shí)現一個(gè)簡(jiǎn)單的MP3播放器。數據源元件負責從磁盤(pán)上讀取數據,過(guò)濾器元件負責對數據進(jìn)行解碼,而接受器元件則負責將解碼后的數據寫(xiě)入聲卡。
如果想要在程序中應用GStreamer提供的各種功能,首先必須在主函數中調用gst_init()來(lái)完成相應的初始化工作,以便將用戶(hù)從命令行輸入的參數傳遞給GStreamer函數庫。一個(gè)典型的GStreamer應用程序的初始化如下所示:
#include <gst/gst.h>
int main (int argc, char *argv[])
{
gst_init (&argc, &argv);
/* */
}
接下去需要創(chuàng )建三個(gè)元件并連接成管道,由于所有GStreamer元件都具有相同的基類(lèi)GstElement,因此能夠采用如下方式進(jìn)行定義:
GstElement *pipeline, *filesrc, *decoder, *audiosink;
管道在GStreamer框架中是用來(lái)容納和管理元件的,下面的代碼將創(chuàng )建一條名為pipeline的新管道:
/* 創(chuàng )建用來(lái)容納元件的新管道 */
pipeline = gst_pipeline_new ("pipeline");
數據源元件負責從磁盤(pán)文件中讀取數據,它具有名為location的屬性,用來(lái)指明文件在磁盤(pán)上的位置。使用標準的GObject屬性機制可以為元件設置相應的屬性:
/* 創(chuàng )建數據源元件 */
filesrc = gst_element_factory_make ("filesrc", "disk_source");
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
過(guò)濾器元件負責完成對MP3格式的數據進(jìn)行解碼,最簡(jiǎn)單的辦法是安裝mad這一插件,借助它來(lái)完成相應的解碼工作:
/* 創(chuàng )建過(guò)濾器元件 */
decoder = gst_element_factory_make ("mad", "decoder");
接收器元件負責將解碼后的數據利用聲卡播放出來(lái):
/* 創(chuàng )建接收器元件 */
audiosink = gst_element_factory_make ("audiosink", "play_audio")
已經(jīng)創(chuàng )建好的三個(gè)元件需要全部添加到管道中,并按順序連接起來(lái):
/* 添加元件到管道中 */
gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
/* 通過(guò)襯墊連接元件 */
gst_element_link_many (filesrc, decoder, audiosink, NULL);
所有準備工作都做好之后,就可以通過(guò)將管道的狀態(tài)切換到PLAYING狀態(tài),來(lái)啟動(dòng)整個(gè)管道的數據處理流程:
/* 啟動(dòng)管道 */
gst_element_set_state (pipeline, GST_STATE_PLAYING);
這里加入一個(gè)消息處理函數bus_call來(lái)監視產(chǎn)生的消息
/* 終止管道 */
gst_element_set_state (pipeline, GST_STATE_NULL);
/* 釋放資源 */
gst_object_unref (GST_OBJECT (pipeline));
3,完整的源代碼如下所示:
#include <gst/gst.h>
#include <glib.h>
//定義消息處理函數,
static gboolean bus_call(GstBus *bus,GstMessage *msg,gpointer data)
{
GMainLoop *loop = (GMainLoop *) data;//這個(gè)是主循環(huán)的指針,在接受EOS消息時(shí)退出循環(huán)
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);
loop = g_main_loop_new(NULL,FALSE);//創(chuàng )建主循環(huán),在執行 g_main_loop_run后正式開(kāi)始循環(huán)
if(argc != 2)
{
g_printerr("Usage:%s <mp3 filename>\n",argv[0]);
return -1;
}
//創(chuàng )建管道和組件
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);
//得到 管道的消息總線(xiàn)
bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
//添加消息監視器
gst_bus_add_watch(bus,bus_call,loop);
gst_object_unref(bus);
//把組件添加到管道中.管道是一個(gè)特殊的組件,可以更好的讓數據流動(dòng)
gst_bin_add_many(GST_BIN(pipeline),source,decoder,sink,NULL);
//依次連接組件
gst_element_link_many(source,decoder,sink,NULL);
//開(kāi)始播放
gst_element_set_state(pipeline,GST_STATE_PLAYING);
g_print("Running\n");
//開(kāi)始循環(huá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;
}
4,編譯運行
gcc -Wall $(pkg-config --cflags --libs gstreamer-0.10) -g test2.c -o test2
./test2 /home/phinecos/test.mp3