還是基於Gstreamer的,在Linux下的比較簡單的媒體播放器,
相關閱讀:基於Gstreamer和Gtk的一個簡單的MP3播放器 http://www.linuxidc.com/Linux/2012-02/54982.htm
代碼如下:
main.c
[cpp]
- /*
- *main.c
- *Simple media player based on Gstreamer and GTK
- */
- #include <gst/gst.h>
- #include <gdk/gdkx.h>
- #include <gtk/gtk.h>
- #include <gst/interfaces/xoverlay.h>
- #include <string.h>
-
- #include "main.h"
-
- static GtkWidget *main_window;
- static GtkWidget *play_button;
- static GtkWidget *pause_button;
- static GtkWidget *stop_button;
- static GtkWidget *status_label;
- static GtkWidget *time_label;
- static GtkWidget *seek_scale;
- static GtkWidget *video_output;
- static gpointer window;
-
- static GstElement *play = NULL;
- static GstElement *bin;
-
- static guint timeout_source = 0;
- static char *current_filename = NULL;
- gboolean no_seek = FALSE;
- // 打開文件
- static void file_open(GtkAction *action)
- {
- GtkWidget *file_chooser = gtk_file_chooser_dialog_new(
- "Open File", GTK_WINDOW(main_window),
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
- NULL);
-
- if (gtk_dialog_run(GTK_DIALOG(file_chooser)) == GTK_RESPONSE_ACCEPT) {
- char *filename;
- filename = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(file_chooser));
- // g_signal_emit_by_name(G_OBJECT(stop_button), "clicked");
- if (current_filename) g_free(current_filename);
- current_filename = filename;
- if (load_file(filename))
- gtk_widget_set_sensitive(GTK_WIDGET(play_button), TRUE);
- }
-
- gtk_widget_destroy(file_chooser);
- }
- // 退出
- static void file_quit(GtkAction *action)
- {
- gtk_main_quit();
- }
- // 關於
- static void help_about(GtkAction *action)
- {
- GtkWidget *about_dialog = gtk_about_dialog_new();
- gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about_dialog), "MediaPlayer");
- gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about_dialog), "0.0.0");
- gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about_dialog), "Copyright @ 2011, Figo");
-
- gtk_dialog_run(GTK_DIALOG(about_dialog));
- gtk_widget_destroy(about_dialog);
- }
-
- static GtkActionEntry mainwindow_action_entries[] = {
- { "FileMenu", "NULL", "文件" },
- {
- "OpenFile",
- GTK_STOCK_OPEN,
- "打開(O)",
- "<control>O",
- "Open a file for playback",
- G_CALLBACK(file_open)
- },
- {
- "QuitPlayer",
- GTK_STOCK_QUIT,
- "退出(Q)",
- "<control>Q",
- "Quit the media player",
- G_CALLBACK(file_quit)
- },
-
- { "HelpMenu", "NULL", "幫助" },
- {
- "HelpAbout",
- GTK_STOCK_ABOUT,
- "關於",
- "",
- "About the media player",
- G_CALLBACK(help_about)
- }
- };
-
- static void play_clicked(GtkWidget *widget, gpointer data)
- {
- if (current_filename) {
- if (play_file()) {
- gtk_widget_set_sensitive(GTK_WIDGET(stop_button), TRUE);
- gtk_widget_set_sensitive(GTK_WIDGET(pause_button), TRUE);
- // g_print("Play was pressed\n");
- gui_status_update(STATE_PLAY);
- g_print("Play\n");
- }
- else {
- g_print("Failed to play\n");
- }
- }
- }
-
- static void pause_clicked(GtkWidget *widget, gpointer data)
- {
- if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
- {
- gst_element_set_state(play,GST_STATE_PAUSED);
- GstStateChangeReturn statechange;
- statechange = gst_element_set_state(play, GST_STATE_PAUSED);
- gui_status_update(STATE_PAUSE);
- g_print("Pause\n");
- // g_print("Pause was pressed\n");
- }
- else
- {
- // g_print("Pause was pressed\n");
- gst_element_set_state(play,GST_STATE_PLAYING);
- gui_status_update(STATE_PLAY);
- g_print("Resume to play\n");
- }
- }
-
- static void stop_clicked(GtkWidget *widget, gpointer data)
- {
- if (timeout_source)
- g_source_remove(timeout_source);
- timeout_source = 0;
-
- // g_print("Stop was pressed\n");
- gst_element_set_state(play,GST_STATE_NULL);
- // gst_object_unref(GST_OBJECT(play));//不用銷毀管道
- gui_status_update(STATE_STOP);
- g_print("Deleting pipeline\n");
- g_print("Stop\n");
- }
-
- /* Handler for user moving seek bar */
- static void seek_value_changed(GtkRange *range, gpointer data)
- {
- if (no_seek)
- return;
-
- gdouble val = gtk_range_get_value(range);
- seek_to(val);
- }
-
- GtkWidget *build_gui()
- {
- GtkWidget *main_vbox;
- GtkWidget *status_hbox;
- GtkWidget *controls_hbox;
- GtkWidget *saturation_controls_hbox;
-
- GtkActionGroup *actiongroup;
- GtkUIManager *ui_manager;
-
- actiongroup = gtk_action_group_new("MainwindowActiongroup");
- gtk_action_group_add_actions(actiongroup,
- mainwindow_action_entries,
- G_N_ELEMENTS(mainwindow_action_entries),
- NULL);
-
- ui_manager = gtk_ui_manager_new();
- gtk_ui_manager_insert_action_group(ui_manager, actiongroup, 0);
- gtk_ui_manager_add_ui_from_string(
- ui_manager,
- "<ui>"
- " <menubar name='MainMenu'>"
- " <menu action='FileMenu'>"
- " <menuitem action='OpenFile'/>"
- " <separator name='fsep1'/>"
- " <menuitem action='QuitPlayer'/>"
- " </menu>"
- " <menu action='HelpMenu'>"
- " <menuitem action='HelpAbout'/>"
- " </menu>"
- " </menubar>"
- "</ui>",
- -1,
- NULL);
-
-
- // 創建主 GtkVBOx. 其他所有都在它裡面
- // 0:各個構件高度可能不同,6:構件之間的間距為6 像素
- main_vbox = gtk_vbox_new(0, 0);
-
- // 添加菜單欄
- gtk_box_pack_start(
- GTK_BOX(main_vbox),
- gtk_ui_manager_get_widget(ui_manager, "/ui/MainMenu"),
- FALSE, FALSE, 0);
-
- /*
- // 視頻顯示區域
- video_output = gtk_drawing_area_new ();
- gtk_box_pack_start (GTK_BOX (main_vbox), video_output, TRUE, TRUE, 0);
- //gtk_widget_set_size_request (video_output, 0x200, 0x100);
- gtk_widget_set_size_request (video_output, 672, 378);
- gtk_widget_show (video_output);
- */
- // 滑動條控制
- seek_scale = gtk_hscale_new_with_range(0, 100, 1);
- gtk_scale_set_draw_value(GTK_SCALE(seek_scale), FALSE);
- gtk_range_set_update_policy(GTK_RANGE(seek_scale), GTK_UPDATE_DISCONTINUOUS);
- g_signal_connect(G_OBJECT(seek_scale), "value-changed", G_CALLBACK(seek_value_changed), NULL);
- gtk_box_pack_start(GTK_BOX(main_vbox), seek_scale, FALSE, FALSE, 0);
-
- // controls_hbox
- controls_hbox = gtk_hbox_new(TRUE, 6);
- gtk_box_pack_start_defaults(GTK_BOX(main_vbox), controls_hbox);
-
- // 播放按鈕
- play_button = gtk_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
- // 設置“敏感”屬性,FALSE 表示為灰色,不響應鼠標鍵盤事件
- gtk_widget_set_sensitive(play_button, FALSE);
- g_signal_connect(G_OBJECT(play_button), "clicked", G_CALLBACK(play_clicked), NULL);
- gtk_box_pack_start_defaults(GTK_BOX(controls_hbox), play_button);
-
- // 暫停按鈕,為使按下時停留在按下狀態,使用GtkToggleButton
- pause_button = gtk_toggle_button_new_with_label(GTK_STOCK_MEDIA_PAUSE);
- // 將按鈕設置為固化按鈕
- gtk_button_set_use_stock(GTK_BUTTON(pause_button), TRUE);
- gtk_widget_set_sensitive(pause_button, FALSE);
- g_signal_connect(G_OBJECT(pause_button), "clicked", G_CALLBACK(pause_clicked), NULL);
- gtk_box_pack_start_defaults(GTK_BOX(controls_hbox), pause_button);
-
- // 停止按鈕
- stop_button = gtk_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
- gtk_widget_set_sensitive(stop_button, FALSE);
- g_signal_connect(G_OBJECT(stop_button), "clicked", G_CALLBACK(stop_clicked), NULL);
- gtk_box_pack_start_defaults(GTK_BOX(controls_hbox), stop_button);
-
- // status_hbox
- status_hbox = gtk_hbox_new(TRUE, 0);
- gtk_box_pack_start(GTK_BOX(main_vbox), status_hbox, FALSE, FALSE, 0);
- // 狀態標簽
- status_label = gtk_label_new("<b>已停止</b>");
- gtk_label_set_use_markup(GTK_LABEL(status_label), TRUE);
- gtk_misc_set_alignment(GTK_MISC(status_label), 0.0, 0.5);
- gtk_box_pack_start(GTK_BOX(status_hbox), status_label, TRUE, TRUE, 0);
- // 時間標簽
- time_label = gtk_label_new("00:00:00");
- gtk_misc_set_alignment(GTK_MISC(time_label), 0.5, 1.0);
- gtk_box_pack_start(GTK_BOX(status_hbox), time_label, TRUE, TRUE, 0);
-
- return main_vbox;
- }
-
- /*
- void stop_playback()
- {
- if (timeout_source)
- g_source_remove(timeout_source);
- timeout_source = 0;
-
- if (play) {
- gst_element_set_state(play, GST_STATE_NULL);
- gst_object_unref(GST_OBJECT(play));
- play = NULL;
- }
- gui_status_update(STATE_STOP);
- }*/
-
- // destory main window
- static void destroy(GtkWidget *widget, gpointer data)
- {
- gtk_main_quit();
- }
- // 更新播放時間
- void gui_update_time(const gchar *time, const gint64 position, const gint64 length)
- {
- gtk_label_set_text(GTK_LABEL(time_label), time);
- if (length > 0) {
- no_seek = TRUE;
- gtk_range_set_value(GTK_RANGE(seek_scale), ((gdouble)position / (gdouble)length) * 100.0);
- no_seek = FALSE;
- }
- }
- // 更新播放狀態
- void gui_status_update(PlayerState state)
- {
- switch (state) {
- case STATE_STOP:
- gtk_widget_set_sensitive(GTK_WIDGET(stop_button), FALSE);
- gtk_widget_set_sensitive(GTK_WIDGET(pause_button), FALSE);
- gtk_label_set_markup(GTK_LABEL(status_label), "<b>已停止</b>");
- gtk_range_set_value(GTK_RANGE(seek_scale), 0.0);
- gtk_label_set_text(GTK_LABEL(time_label), "00:00:00");
- break;
- case STATE_PLAY:
- gtk_widget_set_sensitive(GTK_WIDGET(stop_button), TRUE);
- gtk_widget_set_sensitive(GTK_WIDGET(pause_button), TRUE);
- gtk_label_set_markup(GTK_LABEL(status_label), "<b>播放中</b>");
- break;
- case STATE_PAUSE:
- gtk_label_set_markup(GTK_LABEL(status_label), "<b>已暫停</b>");
- break;
- default:
- break;
- }
- }
-
- static gboolean bus_callback(GstBus *bus, GstMessage *message, gpointer data)
- {
- 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);
-
- gtk_main_quit();
- break;
- }
- case GST_MESSAGE_EOS:
- g_print("End of stream\n");
- // stop_playback();
- // stop_clicked(GtkWidget *widget, gpointer data);
- if (timeout_source)
- g_source_remove(timeout_source);
- timeout_source = 0;
- gst_element_set_state(play, GST_STATE_NULL);
- gui_status_update(STATE_STOP);
- break;
- default:
- break;
- }
-
- return TRUE;
- }
-
- static gboolean build_gstreamer_pipeline(const gchar *uri)
- {
- // 創建一個playbin 元素
- play = gst_pipeline_new ("Mediaplayer");
- bin = gst_element_factory_make ("playbin", "bin");
-
- gst_bin_add (GST_BIN (play), bin);
- {
- GstBus *bus;
- bus = gst_pipeline_get_bus (GST_PIPELINE (play));
- gst_bus_add_watch (bus, bus_callback, NULL);
- gst_object_unref (bus);
- }
-
- g_object_set (G_OBJECT (bin), "uri", uri, NULL);
-
- return TRUE;
- }
- // load file to play
- gboolean load_file(const gchar *uri)
- {
- if (build_gstreamer_pipeline(uri))
- return TRUE;
- return FALSE;
- }
-
- static gboolean update_time_callback(GstElement *pipeline)
- {
- GstFormat fmt = GST_FORMAT_TIME;
- gint64 position;
- gint64 length;
- gchar time_buffer[25];
-
- if (gst_element_query_position(pipeline, &fmt, &position)
- && gst_element_query_duration(pipeline, &fmt, &length)) {
- g_snprintf(time_buffer, 24, "%u:%02u:%02u", GST_TIME_ARGS(position));
- gui_update_time(time_buffer, position, length);
- }
-
- return TRUE;
- }
-
- gboolean play_file()
- {
- if (play) {
- /* Start playing */
- gst_element_set_state(play, GST_STATE_PLAYING);
- gui_status_update(STATE_PLAY);
- /* Connect a callback to trigger every 200 milliseconds to
- * update the GUI with the playback progress. We remember
- * the ID of this source so that we can remove it when we stop
- * playing */
- timeout_source = g_timeout_add(200, (GSourceFunc)update_time_callback, play);
- return TRUE;
- }
-
- return FALSE;
- }
-
- /* Attempt to seek to the given percentage through the file */
- void seek_to(gdouble percentage)
- {
- GstFormat fmt = GST_FORMAT_TIME;
- gint64 length;
-
- /* If it seems safe to attempt a seek... */
- if (play && gst_element_query_duration(play, &fmt, &length)) {
- /* ...calculate where to seek to */
- gint64 target = ((gdouble)length * (percentage / 100.0));
-
- /* ...and attempt the seek */
- if (!gst_element_seek(play, 1.0, GST_FORMAT_TIME,
- GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
- target, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
- g_print("Failed to seek to desired position\n");
- }
- }
-
- int main(int argc, char *argv[])
- {
- // 初始化 GTK+
- gtk_init(&argc, &argv);
- gst_init(&argc, &argv);
- // 創建窗口
- main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- // 設置窗口標題
- gtk_window_set_title(GTK_WINDOW(main_window), "MediaPlayer");
- // 主窗口銷毀句柄
- g_signal_connect(G_OBJECT(main_window), "destroy", G_CALLBACK(destroy), NULL);
- // 創建主窗口GUI
- gtk_container_add(GTK_CONTAINER(main_window), build_gui());
- // 顯示
- gtk_widget_show_all(GTK_WIDGET(main_window));
- // 開始主循環
- gtk_main();
-
- return 0;
- }
main.h
[cpp]
- /*
- * main.h
- */
-
- #ifndef MAIN_H
- #define MAIN_H
-
- #include <gtk/gtk.h>
-
- typedef enum {
- STATE_STOP,
- STATE_PLAY,
- STATE_PAUSE
- } PlayerState;
-
- void gui_status_update(PlayerState state);
- void gui_update_time(const gchar *time, const gint64 position, const gint64 length);
- // void gui_update_metadata(const gchar *title, const gchar *artist);
-
- gboolean load_file(const gchar *uri);
- void seek_to(gdouble percentage);
-
- #endif
MakiFile
[plain]
- CFLAGS=`pkg-config --cflags gtk+-2.0 gstreamer-0.10`
- LIBS=`pkg-config --libs gtk+-2.0 gstreamer-0.10`
-
- all: player
-
- player:
- gcc -o MediaPlayer main.c main.h $(LIBS) $(CFLAGS) -l gstinterfaces-0.10
-
- clean:
- rm *.o player
編譯,終端裡輸入:
[plain]
- make
生成可執行文件,運行:
[plain]
- ./MediaPlayer
運行界面: