一个基于Gstreamer的Linux下的简单媒体播放器


还是基于Gstreamer的,在Linux下的比较简单的媒体播放器,

相关阅读:基于Gstreamer和Gtk的一个简单的MP3播放器

代码如下:

main.c

[cpp]
  1. /* 
  2. *main.c  
  3. *Simple media player based on Gstreamer and GTK 
  4. */  
  5. #include <gst/gst.h>   
  6. #include <gdk/gdkx.h>   
  7. #include <gtk/gtk.h>   
  8. #include <gst/interfaces/xoverlay.h>   
  9. #include <string.h>   
  10.   
  11. #include "main.h"   
  12.   
  13. static GtkWidget *main_window;  
  14. static GtkWidget *play_button;  
  15. static GtkWidget *pause_button;  
  16. static GtkWidget *stop_button;  
  17. static GtkWidget *status_label;  
  18. static GtkWidget *time_label;  
  19. static GtkWidget *seek_scale;  
  20. static GtkWidget *video_output;  
  21. static gpointer window;  
  22.   
  23. static GstElement *play = NULL;  
  24. static GstElement *bin;  
  25.   
  26. static guint timeout_source = 0;  
  27. static char *current_filename = NULL;  
  28. gboolean no_seek = FALSE;  
  29. // 打开文件   
  30. static void file_open(GtkAction *action)  
  31. {  
  32.     GtkWidget *file_chooser = gtk_file_chooser_dialog_new(  
  33.         "Open File", GTK_WINDOW(main_window),  
  34.         GTK_FILE_CHOOSER_ACTION_OPEN,  
  35.         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,  
  36.         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,  
  37.         NULL);  
  38.   
  39.     if (gtk_dialog_run(GTK_DIALOG(file_chooser)) == GTK_RESPONSE_ACCEPT) {  
  40.         char *filename;  
  41.         filename = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(file_chooser));  
  42.         // g_signal_emit_by_name(G_OBJECT(stop_button), "clicked");   
  43.         if (current_filename) g_free(current_filename);  
  44.         current_filename = filename;  
  45.         if (load_file(filename))  
  46.             gtk_widget_set_sensitive(GTK_WIDGET(play_button), TRUE);  
  47.     }  
  48.   
  49.     gtk_widget_destroy(file_chooser);  
  50. }  
  51. // 退出   
  52. static void file_quit(GtkAction *action)  
  53. {  
  54.     gtk_main_quit();  
  55. }  
  56. // 关于   
  57. static void help_about(GtkAction *action)  
  58. {  
  59.     GtkWidget *about_dialog = gtk_about_dialog_new();  
  60.     gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about_dialog), "MediaPlayer");  
  61.     gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about_dialog), "0.0.0");  
  62.     gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about_dialog), "Copyright @ 2011, Figo");  
  63.   
  64.     gtk_dialog_run(GTK_DIALOG(about_dialog));  
  65.     gtk_widget_destroy(about_dialog);  
  66. }  
  67.   
  68. static GtkActionEntry mainwindow_action_entries[] = {  
  69.     { "FileMenu""NULL""文件" },  
  70.     {  
  71.         "OpenFile",  
  72.         GTK_STOCK_OPEN,  
  73.         "打开(O)",  
  74.         "<control>O",  
  75.         "Open a file for playback",  
  76.         G_CALLBACK(file_open)  
  77.     },  
  78.     {  
  79.         "QuitPlayer",  
  80.         GTK_STOCK_QUIT,  
  81.         "退出(Q)",  
  82.         "<control>Q",  
  83.         "Quit the media player",  
  84.         G_CALLBACK(file_quit)  
  85.     },  
  86.     
  87.     { "HelpMenu""NULL""帮助" },  
  88.     {  
  89.         "HelpAbout",  
  90.         GTK_STOCK_ABOUT,  
  91.         "关于",  
  92.         "",  
  93.         "About the media player",  
  94.         G_CALLBACK(help_about)  
  95.     }  
  96. };  
  97.   
  98. static void play_clicked(GtkWidget *widget, gpointer data)  
  99. {  
  100.     if (current_filename) {  
  101.         if (play_file()) {  
  102.             gtk_widget_set_sensitive(GTK_WIDGET(stop_button), TRUE);  
  103.             gtk_widget_set_sensitive(GTK_WIDGET(pause_button), TRUE);  
  104.             // g_print("Play was pressed\n");     
  105.                     gui_status_update(STATE_PLAY);  
  106.                     g_print("Play\n");    
  107.         }  
  108.         else {  
  109.             g_print("Failed to play\n");  
  110.         }  
  111.     }  
  112. }  
  113.   
  114. static void pause_clicked(GtkWidget *widget, gpointer data)  
  115. {           
  116.     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))  
  117.     {  
  118.             gst_element_set_state(play,GST_STATE_PAUSED);  
  119.             GstStateChangeReturn statechange;  
  120.             statechange = gst_element_set_state(play, GST_STATE_PAUSED);  
  121.             gui_status_update(STATE_PAUSE);  
  122.             g_print("Pause\n");  
  123.             // g_print("Pause was pressed\n");   
  124.     }  
  125.     else  
  126.     {  
  127.             // g_print("Pause was pressed\n");   
  128.             gst_element_set_state(play,GST_STATE_PLAYING);  
  129.             gui_status_update(STATE_PLAY);  
  130.             g_print("Resume to play\n");  
  131.     }                
  132. }  
  133.   
  134. static void stop_clicked(GtkWidget *widget, gpointer data)  
  135. {        
  136.     if (timeout_source)  
  137.         g_source_remove(timeout_source);  
  138.     timeout_source = 0;  
  139.    
  140.     // g_print("Stop was pressed\n");     
  141.     gst_element_set_state(play,GST_STATE_NULL);  
  142.         // gst_object_unref(GST_OBJECT(play));//不用销毁管道   
  143.         gui_status_update(STATE_STOP);  
  144.     g_print("Deleting pipeline\n");  
  145.     g_print("Stop\n");      
  146. }  
  147.   
  148. /* Handler for user moving seek bar */  
  149. static void seek_value_changed(GtkRange *range, gpointer data)  
  150. {  
  151.     if (no_seek)   
  152.         return;  
  153.           
  154.     gdouble val = gtk_range_get_value(range);  
  155.     seek_to(val);  
  156. }  
  157.   
  158. GtkWidget *build_gui()  
  159. {  
  160.     GtkWidget *main_vbox;  
  161.     GtkWidget *status_hbox;  
  162.     GtkWidget *controls_hbox;  
  163.     GtkWidget *saturation_controls_hbox;  
  164.   
  165.     GtkActionGroup *actiongroup;  
  166.     GtkUIManager *ui_manager;  
  167.   
  168.     actiongroup = gtk_action_group_new("MainwindowActiongroup");  
  169.     gtk_action_group_add_actions(actiongroup,  
  170.         mainwindow_action_entries,  
  171.         G_N_ELEMENTS(mainwindow_action_entries),  
  172.         NULL);  
  173.   
  174.     ui_manager = gtk_ui_manager_new();  
  175.     gtk_ui_manager_insert_action_group(ui_manager, actiongroup, 0);  
  176.     gtk_ui_manager_add_ui_from_string(  
  177.         ui_manager,  
  178.         "<ui>"  
  179.         "    <menubar name='MainMenu'>"  
  180.         "        <menu action='FileMenu'>"  
  181.         "            <menuitem action='OpenFile'/>"  
  182.         "            <separator name='fsep1'/>"  
  183.         "            <menuitem action='QuitPlayer'/>"  
  184.         "        </menu>"  
  185.         "        <menu action='HelpMenu'>"  
  186.         "            <menuitem action='HelpAbout'/>"  
  187.         "        </menu>"         
  188.         "    </menubar>"  
  189.         "</ui>",  
  190.         -1,  
  191.         NULL);  
  192.       
  193.   
  194.     // 创建主 GtkVBOx. 其他所有都在它里面   
  195.     // 0:各个构件高度可能不同,6:构件之间的间距为6 像素   
  196.     main_vbox = gtk_vbox_new(0, 0);  
  197.   
  198.     // 添加菜单栏   
  199.     gtk_box_pack_start(  
  200.         GTK_BOX(main_vbox),  
  201.         gtk_ui_manager_get_widget(ui_manager, "/ui/MainMenu"),  
  202.         FALSE, FALSE, 0);  
  203.   
  204.         /* 
  205.         // 视频显示区域 
  206.     video_output = gtk_drawing_area_new (); 
  207.     gtk_box_pack_start (GTK_BOX (main_vbox), video_output, TRUE, TRUE, 0); 
  208.     //gtk_widget_set_size_request (video_output, 0x200, 0x100); 
  209.     gtk_widget_set_size_request (video_output, 672, 378); 
  210.     gtk_widget_show (video_output); 
  211.     */     
  212.     // 滑动条控制   
  213.     seek_scale = gtk_hscale_new_with_range(0, 100, 1);  
  214.     gtk_scale_set_draw_value(GTK_SCALE(seek_scale), FALSE);  
  215.     gtk_range_set_update_policy(GTK_RANGE(seek_scale), GTK_UPDATE_DISCONTINUOUS);  
  216.     g_signal_connect(G_OBJECT(seek_scale), "value-changed", G_CALLBACK(seek_value_changed), NULL);  
  217.     gtk_box_pack_start(GTK_BOX(main_vbox), seek_scale, FALSE, FALSE, 0);  
  218.   
  219.     // controls_hbox   
  220.     controls_hbox = gtk_hbox_new(TRUE, 6);  
  221.     gtk_box_pack_start_defaults(GTK_BOX(main_vbox), controls_hbox);  
  222.   
  223.     // 播放按钮   
  224.     play_button = gtk_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);  
  225.     // 设置“敏感”属性,FALSE 表示为灰色,不响应鼠标键盘事件   
  226.     gtk_widget_set_sensitive(play_button, FALSE);  
  227.     g_signal_connect(G_OBJECT(play_button), "clicked", G_CALLBACK(play_clicked), NULL);  
  228.     gtk_box_pack_start_defaults(GTK_BOX(controls_hbox), play_button);  
  229.       
  230.     // 暂停按钮,为使按下时停留在按下状态,使用GtkToggleButton   
  231.     pause_button = gtk_toggle_button_new_with_label(GTK_STOCK_MEDIA_PAUSE);  
  232.     // 将按钮设置为固化按钮   
  233.     gtk_button_set_use_stock(GTK_BUTTON(pause_button), TRUE);  
  234.     gtk_widget_set_sensitive(pause_button, FALSE);  
  235.     g_signal_connect(G_OBJECT(pause_button), "clicked", G_CALLBACK(pause_clicked), NULL);  
  236.     gtk_box_pack_start_defaults(GTK_BOX(controls_hbox), pause_button);  
  237.   
  238.     // 停止按钮   
  239.     stop_button = gtk_button_new_from_stock(GTK_STOCK_MEDIA_STOP);  
  240.     gtk_widget_set_sensitive(stop_button, FALSE);  
  241.     g_signal_connect(G_OBJECT(stop_button), "clicked", G_CALLBACK(stop_clicked), NULL);  
  242.     gtk_box_pack_start_defaults(GTK_BOX(controls_hbox), stop_button);       
  243.       
  244.     // status_hbox   
  245.     status_hbox = gtk_hbox_new(TRUE, 0);  
  246.     gtk_box_pack_start(GTK_BOX(main_vbox), status_hbox, FALSE, FALSE, 0);  
  247.     // 状态标签   
  248.     status_label = gtk_label_new("<b>已停止</b>");  
  249.     gtk_label_set_use_markup(GTK_LABEL(status_label), TRUE);  
  250.     gtk_misc_set_alignment(GTK_MISC(status_label), 0.0, 0.5);  
  251.     gtk_box_pack_start(GTK_BOX(status_hbox), status_label, TRUE, TRUE, 0);  
  252.     // 时间标签      
  253.     time_label = gtk_label_new("00:00:00");  
  254.     gtk_misc_set_alignment(GTK_MISC(time_label), 0.5, 1.0);  
  255.     gtk_box_pack_start(GTK_BOX(status_hbox), time_label, TRUE, TRUE, 0);  
  256.      
  257.     return main_vbox;  
  258. }  
  259.   
  260. /* 
  261. void stop_playback() 
  262. { 
  263.     if (timeout_source) 
  264.         g_source_remove(timeout_source); 
  265.     timeout_source = 0; 
  266.  
  267.     if (play) { 
  268.         gst_element_set_state(play, GST_STATE_NULL); 
  269.         gst_object_unref(GST_OBJECT(play)); 
  270.         play = NULL; 
  271.     } 
  272.     gui_status_update(STATE_STOP); 
  273. }*/  
  274.   
  275. // destory main window   
  276. static void destroy(GtkWidget *widget, gpointer data)  
  277. {  
  278.     gtk_main_quit();  
  279. }  
  280. // 更新播放时间   
  281. void gui_update_time(const gchar *time, const gint64 position, const gint64 length)  
  282. {  
  283.     gtk_label_set_text(GTK_LABEL(time_label), time);  
  284.     if (length > 0) {  
  285.         no_seek = TRUE;  
  286.         gtk_range_set_value(GTK_RANGE(seek_scale), ((gdouble)position / (gdouble)length) * 100.0);  
  287.         no_seek = FALSE;  
  288.     }  
  289. }  
  290. // 更新播放状态   
  291. void gui_status_update(PlayerState state)  
  292. {  
  293.     switch (state) {  
  294.         case STATE_STOP:  
  295.             gtk_widget_set_sensitive(GTK_WIDGET(stop_button), FALSE);  
  296.             gtk_widget_set_sensitive(GTK_WIDGET(pause_button), FALSE);             
  297.             gtk_label_set_markup(GTK_LABEL(status_label), "<b>已停止</b>");  
  298.             gtk_range_set_value(GTK_RANGE(seek_scale), 0.0);        
  299.             gtk_label_set_text(GTK_LABEL(time_label), "00:00:00");  
  300.             break;  
  301.         case STATE_PLAY:  
  302.             gtk_widget_set_sensitive(GTK_WIDGET(stop_button), TRUE);  
  303.             gtk_widget_set_sensitive(GTK_WIDGET(pause_button), TRUE);              
  304.             gtk_label_set_markup(GTK_LABEL(status_label), "<b>播放中</b>");  
  305.             break;  
  306.         case STATE_PAUSE:             
  307.             gtk_label_set_markup(GTK_LABEL(status_label), "<b>已暂停</b>");  
  308.             break;  
  309.         default:  
  310.             break;  
  311.     }  
  312. }  
  313.   
  314. static gboolean bus_callback(GstBus *bus, GstMessage *message, gpointer data)  
  315. {  
  316.     switch (GST_MESSAGE_TYPE(message)) {  
  317.         case GST_MESSAGE_ERROR:  
  318.         {  
  319.             GError *err;  
  320.             gchar *debug;  
  321.       
  322.             gst_message_parse_error(message, &err, &debug);  
  323.             g_print("Error: %s\n", err->message);  
  324.             g_error_free(err);  
  325.             g_free(debug);  
  326.       
  327.             gtk_main_quit();  
  328.             break;  
  329.         }  
  330.         case GST_MESSAGE_EOS:  
  331.             g_print("End of stream\n");  
  332.             // stop_playback();   
  333.             // stop_clicked(GtkWidget *widget, gpointer data);   
  334.             if (timeout_source)  
  335.                     g_source_remove(timeout_source);  
  336.                     timeout_source = 0;  
  337.                         gst_element_set_state(play, GST_STATE_NULL);     
  338.             gui_status_update(STATE_STOP);  
  339.             break;          
  340.         default:  
  341.             break;  
  342.     }  
  343.   
  344.     return TRUE;  
  345. }  
  346.   
  347. static gboolean build_gstreamer_pipeline(const gchar *uri)  
  348. {  
  349.     // 创建一个playbin 元素    
  350.     play = gst_pipeline_new ("Mediaplayer");  
  351.     bin  = gst_element_factory_make ("playbin""bin");  
  352.       
  353.     gst_bin_add (GST_BIN (play), bin);  
  354.     {  
  355.         GstBus *bus;  
  356.         bus = gst_pipeline_get_bus (GST_PIPELINE (play));  
  357.         gst_bus_add_watch (bus, bus_callback, NULL);  
  358.         gst_object_unref (bus);  
  359.     }  
  360.   
  361.     g_object_set (G_OBJECT (bin), "uri", uri, NULL);  
  362.       
  363.     return TRUE;  
  364. }  
  365. // load file to play   
  366. gboolean load_file(const gchar *uri)  
  367. {  
  368.     if (build_gstreamer_pipeline(uri))  
  369.         return TRUE;  
  370.     return FALSE;  
  371. }  
  372.   
  373. static gboolean update_time_callback(GstElement *pipeline)  
  374. {  
  375.     GstFormat fmt = GST_FORMAT_TIME;  
  376.     gint64 position;  
  377.     gint64 length;  
  378.     gchar time_buffer[25];  
  379.   
  380.     if (gst_element_query_position(pipeline, &fmt, &position)  
  381.         && gst_element_query_duration(pipeline, &fmt, &length)) {  
  382.         g_snprintf(time_buffer, 24, "%u:%02u:%02u", GST_TIME_ARGS(position));  
  383.         gui_update_time(time_buffer, position, length);  
  384.     }  
  385.   
  386.     return TRUE;  
  387. }  
  388.   
  389. gboolean play_file()  
  390. {  
  391.     if (play) {  
  392.         /* Start playing */  
  393.         gst_element_set_state(play, GST_STATE_PLAYING);  
  394.         gui_status_update(STATE_PLAY);  
  395.         /* Connect a callback to trigger every 200 milliseconds to 
  396.          * update the GUI with the playback progress. We remember 
  397.          * the ID of this source so that we can remove it when we stop 
  398.          * playing */  
  399.         timeout_source = g_timeout_add(200, (GSourceFunc)update_time_callback, play);  
  400.         return TRUE;  
  401.     }  
  402.   
  403.     return FALSE;  
  404. }  
  405.   
  406. /* Attempt to seek to the given percentage through the file */  
  407. void seek_to(gdouble percentage)  
  408. {  
  409.     GstFormat fmt = GST_FORMAT_TIME;  
  410.     gint64 length;  
  411.   
  412.     /* If it seems safe to attempt a seek... */  
  413.     if (play && gst_element_query_duration(play, &fmt, &length)) {  
  414.         /* ...calculate where to seek to */  
  415.         gint64 target = ((gdouble)length * (percentage / 100.0));  
  416.   
  417.         /* ...and attempt the seek */  
  418.         if (!gst_element_seek(play, 1.0, GST_FORMAT_TIME,  
  419.             GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,  
  420.             target, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))  
  421.         g_print("Failed to seek to desired position\n");  
  422.     }  
  423. }  
  424.   
  425. int main(int argc, char *argv[])  
  426. {  
  427.     // 初始化 GTK+   
  428.     gtk_init(&argc, &argv);  
  429.     gst_init(&argc, &argv);  
  430.     // 创建窗口   
  431.     main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);  
  432.     // 设置窗口标题   
  433.     gtk_window_set_title(GTK_WINDOW(main_window), "MediaPlayer");  
  434.     // 主窗口销毁句柄   
  435.     g_signal_connect(G_OBJECT(main_window), "destroy", G_CALLBACK(destroy), NULL);  
  436.     // 创建主窗口GUI   
  437.     gtk_container_add(GTK_CONTAINER(main_window), build_gui());  
  438.     // 显示   
  439.     gtk_widget_show_all(GTK_WIDGET(main_window));     
  440.     // 开始主循环   
  441.     gtk_main();  
  442.   
  443.     return 0;  
  444. }  

main.h

[cpp]
  1. /* 
  2.  * main.h 
  3.  */  
  4.   
  5. #ifndef MAIN_H   
  6. #define MAIN_H   
  7.   
  8. #include <gtk/gtk.h>   
  9.   
  10. typedef enum {  
  11.     STATE_STOP,  
  12.     STATE_PLAY,  
  13.     STATE_PAUSE  
  14. } PlayerState;  
  15.   
  16. void gui_status_update(PlayerState state);  
  17. void gui_update_time(const gchar *time, const gint64 position, const gint64 length);  
  18. // void gui_update_metadata(const gchar *title, const gchar *artist);   
  19.   
  20. gboolean load_file(const gchar *uri);  
  21. void seek_to(gdouble percentage);  
  22.   
  23. #endif  
MakiFile

[plain]
  1. CFLAGS=`pkg-config --cflags gtk+-2.0 gstreamer-0.10`  
  2. LIBS=`pkg-config --libs gtk+-2.0 gstreamer-0.10`  
  3.   
  4. all: player  
  5.   
  6. player:   
  7.     gcc -o MediaPlayer main.c main.h $(LIBS) $(CFLAGS) -l gstinterfaces-0.10  
  8.   
  9. clean:  
  10.     rm *.o player  
编译,终端里输入:

[plain]
  1. make  
生成可执行文件,运行:

[plain]
  1. ./MediaPlayer   

运行界面:

一个基于Gstreamer的Linux下的简单媒体播放器

相关内容