myPlayerUI.c
#include "myType.h" #ifdef _DB #define Debug(format, ...) printf("--->> Debug .... LINE %-5d" format "\n", __LINE__, ##__VA_ARGS__); #else #define Debug(format, ...) #endif static void destroy(GtkWidget *widget, gpointer data ) { gtk_main_quit (); } static void widget_destroy(GtkWidget *widget, GtkWidget * destroy ) { gtk_widget_destroy ( destroy ); } static gboolean delete_event( GtkWidget *widget, GdkEvent *event, gpointer data ) { Debug ("delete event occurred"); return FALSE; //return TRUE; } static 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; } } static void player_disconstructor(void) { if(pst != STOPED && pst != PREPARING){ gtk_range_set_value(GTK_RANGE(seek_scale), 0.0); gtk_label_set_text(GTK_LABEL(time_label), "00:00:00"); if(play) gst_element_set_state(play, GST_STATE_NULL); if(x_overlay) gst_object_unref (x_overlay); pst = STOPED; } } static void player_constructor(gchar * const file_name) { player_disconstructor(); 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", file_name, NULL); x_overlay = gst_element_factory_make("ximagesink","video-sink"); g_object_set(G_OBJECT(bin), "video-sink", x_overlay, NULL); gst_x_overlay_set_window_handle(GST_X_OVERLAY(x_overlay), GDK_WINDOW_XID(boxImg->window)); playerControlCallback(NULL, (gpointer*)&open_file_data); if (play) { gst_element_set_state(play, GST_STATE_PLAYING); pst = PLAYING; g_timeout_add(200, (GSourceFunc)update_time_callback, play); } } static void selected_file_name (GtkWidget *widget, GtkFileSelection *fs) { Debug("The selected file is : %s", (gchar*)gtk_file_selection_get_filename( GTK_FILE_SELECTION (fs) )); gchar input_file_name[100]; memset(input_file_name, 0, 100); memset(pre_file_name, 0, 100); sprintf(input_file_name, "file://%s", (gchar*)gtk_file_selection_get_filename( GTK_FILE_SELECTION (fs) )); sprintf(pre_file_name, "file://%s", (gchar*)gtk_file_selection_get_filename( GTK_FILE_SELECTION (fs) )); open_file_data.type = OPENFILE; open_file_data.data = (gchar*)gtk_file_selection_get_filename( GTK_FILE_SELECTION (fs) ); player_constructor(input_file_name); } static void seek_button_action(callbackStruct seekData) { if(pst == SEEKING){ if(seekData.data == NULL){ if (!gst_element_seek(play, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { Debug("Failed to seek to desired position"); } gtk_range_set_value(GTK_RANGE(seek_scale), 0.0); gtk_label_set_text(GTK_LABEL(time_label), "00:00:00"); }else{ GstFormat fmt = GST_FORMAT_TIME; gint64 position; gint64 length; gchar time_buffer[25]; gint64 seek_time; gdouble val = gtk_range_get_value((GtkRange *)seek_scale); if (gst_element_query_position(play, &fmt, &position) && gst_element_query_duration(play, &fmt, &length)) { if(seekData.type == SEEKF){ seek_time = ((gdouble)length * (val / 100.0)) + 4 * length / 100; position += 400 / length; }else if(seekData.type == SEEKB){ seek_time = ((gdouble)length * (val / 100.0)) - 4 * length / 100; position -= 400 / length; } g_snprintf(time_buffer, 24, "%u:%02u:%02u", GST_TIME_ARGS(position)); gui_update_time(time_buffer, position, length); if (!gst_element_seek(play, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, seek_time, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) Debug("Failed to seek to desired position"); } } } } 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; } 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); Debug("Error: %s", err->message); g_error_free(err); g_free(debug); gtk_main_quit(); break; } case GST_MESSAGE_EOS: Debug("End of stream"); player_disconstructor(); break; default: break; } return TRUE; } static void file_selection( GtkWidget *widget, gpointer data ) { GtkWidget * file_select = gtk_file_selection_new ("Open file"); g_signal_connect (GTK_FILE_SELECTION (file_select)->ok_button, "clicked", G_CALLBACK (selected_file_name), (gpointer*)file_select); g_signal_connect (GTK_FILE_SELECTION (file_select)->ok_button, "clicked", G_CALLBACK (widget_destroy), (gpointer*)file_select); g_signal_connect (GTK_FILE_SELECTION (file_select)->cancel_button, "clicked", G_CALLBACK (widget_destroy), (gpointer*)file_select); gtk_widget_show (file_select); } /* for test set page size */ static void setPageSize( GtkAdjustment *get, GtkAdjustment *set ) { set->page_size = get->value * 100 / 30; set->page_increment = get->value * 100 / 30; gtk_adjustment_set_value (set, CLAMP(set->value, set->lower, (set->upper - set->page_size))); g_signal_emit_by_name(set, "changed"); } static int playerControlCallback(GtkWidget *widget, gpointer data) { if(data == NULL){ fprintf(stderr, "playerControlCallback input data %p\n", data); return -1; } callbackStruct *p = (callbackStruct*)data; switch (p->type){ case OPENFILE: /* player control */ Debug("Open file data : %s", p->data); pst = PLAYING; break; case PLAYPAUSE: if(pst != PLAYING){ if(pst == STOPED){ player_constructor(pre_file_name); }else if(pst == PREPARING){ file_selection(NULL, NULL); }else if(pst == PAUSED){ gst_element_set_state(play, GST_STATE_PLAYING); Debug("PAUSE to PLAYING data : %s", p->data); } pst = PLAYING; }else{ gst_element_set_state(play,GST_STATE_PAUSED); Debug("PLAYING to PAUSE data : %s", p->data); pst = PAUSED; } break; case STOP: if(pst != STOPED){ Debug("STOP data : %s", p->data); player_disconstructor(); pst = STOPED; } break; case SEEKF: if(pst != STOPED && pst != PREPARING){ pst = SEEKING; seek_button_action(*p); Debug("SEEKING data : %s", p->data); pst = SEEKCOMPLETE; }else{ Debug("Player NOT started! ....."); } break; case SEEKB: if(pst != STOPED && pst != PREPARING){ pst = SEEKING; seek_button_action(*p); Debug("SEEKING data : %s", p->data); pst = SEEKCOMPLETE; }else{ Debug("Player NOT started! ....."); } break; default: Debug("Undifined callback type"); return -1; } return 0; } static int getDuration(unsigned long long * duration) { *duration = 3600; return 0; } static void setVolume(gpointer * adj) { if(adj == NULL){ fprintf(stderr, "setVolume param adj == NULL !\n"); return; } gdouble volume = gtk_adjustment_get_value((GtkAdjustment*)adj); /* set volume here */ Debug("Current volume is %d", (gint)volume); } static void setSoundEffect(GtkWidget * item, soundEffectType type) { switch (type){ case SOUND_EFFECT_NORMAL: /* set sound effect here */ Debug("Sound effect : Normal"); break; case SOUND_EFFECT_CLASSICAL: Debug("Sound effect : Classical"); break; case SOUND_EFFECT_JAZZ: Debug("Sound effect : Jazz"); break; case SOUND_EFFECT_BASS: Debug("Sound effect : Bass"); break; default: Debug("Sound effect unknown"); } } static void seek_value_changed(GtkRange *range, gpointer data) { if (no_seek) return; gdouble val = gtk_range_get_value(range); GstFormat fmt = GST_FORMAT_TIME; gint64 length; if (play && gst_element_query_duration(play, &fmt, &length)) { gint64 target = ((gdouble)length * (val / 100.0)); 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)) Debug("Failed to seek to desired position"); } } static int buildPlayerControlItem(GtkWidget * window, unsigned long long duration) { if(window == NULL){ fprintf(stderr, "buildPlayerControlItem paramter windows == NULL !\n"); return -1; } buttonOpenFile = gtk_button_new_with_label ("Open File"); g_signal_connect (buttonOpenFile, "clicked", G_CALLBACK (file_selection), (gpointer*)&openData); gtk_widget_show (buttonOpenFile); buttonSeekBackward = gtk_button_new_with_label ("Seek"); g_signal_connect (buttonSeekBackward, "clicked", G_CALLBACK (playerControlCallback), (gpointer*)&seekBData); gtk_widget_show (buttonSeekBackward); buttonPlayPause = gtk_button_new_with_label ("Play/Pause"); g_signal_connect (buttonPlayPause, "clicked", G_CALLBACK (playerControlCallback), (gpointer*)&playData); gtk_widget_show (buttonPlayPause); buttonSeekForward = gtk_button_new_with_label ("Seek"); g_signal_connect (buttonSeekForward, "clicked", G_CALLBACK (playerControlCallback), (gpointer*)&seekFData); gtk_widget_show (buttonSeekForward); buttonStop = gtk_button_new_with_label ("Stop"); g_signal_connect (buttonStop, "clicked", G_CALLBACK (playerControlCallback), (gpointer*)&stopData); gtk_widget_show (buttonStop); 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_widget_show (seek_scale); time_label = gtk_label_new("00:00:00"); gtk_misc_set_alignment(GTK_MISC(time_label), 0.5, 1.0); gtk_widget_show (time_label); return 0; } static GtkWidget * buildSoundEfectMenu(void) { GtkWidget * soundEffect = gtk_option_menu_new (); GtkWidget * menu = gtk_menu_new (); GtkWidget * item = gtk_menu_item_new_with_label("Normal"); g_signal_connect (item, "activate", G_CALLBACK(setSoundEffect), GINT_TO_POINTER(SOUND_EFFECT_NORMAL)); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); item = gtk_menu_item_new_with_label("Classical"); g_signal_connect (item, "activate", G_CALLBACK(setSoundEffect), GINT_TO_POINTER(SOUND_EFFECT_CLASSICAL)); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); item = gtk_menu_item_new_with_label("Jazz"); g_signal_connect (item, "activate", G_CALLBACK(setSoundEffect), GINT_TO_POINTER(SOUND_EFFECT_JAZZ)); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); item = gtk_menu_item_new_with_label("Bass"); g_signal_connect (item, "activate", G_CALLBACK(setSoundEffect), GINT_TO_POINTER(SOUND_EFFECT_BASS)); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); gtk_option_menu_set_menu (GTK_OPTION_MENU (soundEffect), menu); gtk_widget_show(soundEffect); return soundEffect; } static GtkWidget * buildVolumeController() { GtkObject * adj1 = gtk_adjustment_new (12, 0, 30, 1, 1, 0); g_signal_connect (adj1, "value_changed", G_CALLBACK (setVolume), (gpointer*)adj1); GtkWidget * scale = gtk_hscale_new (GTK_ADJUSTMENT (adj1)); gtk_scale_set_digits (GTK_SCALE (scale), 0); gtk_widget_show (scale); /* //// test set page size GtkObject * adj2 = gtk_adjustment_new (0, 0, 100, 1, 1, 0); g_signal_connect (adj1, "value_changed", G_CALLBACK (setPageSize), (gpointer*)adj2); ///// test set page size GtkWidget * scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj2)); gtk_range_set_update_policy (GTK_RANGE (scrollbar), GTK_UPDATE_CONTINUOUS); gtk_table_attach_defaults (GTK_TABLE (table), scrollbar, 0, 260, 258, 259); gtk_widget_show (scrollbar); */ return scale; } static void showItems(GtkWidget * table) { gtk_table_attach_defaults (GTK_TABLE (table), seek_scale, 0, 260, 257, 258); gtk_table_attach_defaults (GTK_TABLE (table), time_label, 200, 230, 258, 259); gtk_table_attach (GTK_TABLE (table), buttonOpenFile, 0, 1, 259, 260, 10, 10, 0, 0); gtk_table_attach (GTK_TABLE (table), buttonSeekBackward, 1, 2, 259, 260, 10, 10, 0, 0); gtk_table_attach (GTK_TABLE (table), buttonPlayPause, 2, 3, 259, 260, 10, 10, 0, 0); gtk_table_attach (GTK_TABLE (table), buttonSeekForward, 3, 4, 259, 260, 10, 10, 0, 0); gtk_table_attach (GTK_TABLE (table), buttonStop, 4, 5, 259, 260, 10, 10, 0, 0); button = gtk_label_new ("SE"); gtk_table_attach (GTK_TABLE (table), button, 209, 210, 259, 260, 10, 10, 0, 0); gtk_widget_show (button); gtk_table_attach (GTK_TABLE (table), soundEffect, 210, 220, 259, 260, 10, 10, 0, 0); button = gtk_label_new ("Sound"); gtk_table_attach (GTK_TABLE (table), button, 220, 230, 259, 260, 10, 10, 0, 0); gtk_widget_show (button); gtk_table_attach_defaults (GTK_TABLE (table), volumeScale, 230, 260, 259, 260); } int main( int argc, char *argv[] ) { unsigned long long video_duration = 0ll; GtkWidget *window; gtk_init (&argc, &argv); gst_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (window, "delete-event", G_CALLBACK (delete_event), NULL); g_signal_connect (window, "destroy", G_CALLBACK (destroy), NULL); gtk_container_set_border_width (GTK_CONTAINER (window), 1); openData.type = OPENFILE; openData.data = "Open file"; playData.type = PLAYPAUSE; playData.data = "Just set PLAYPAUSE"; stopData.type = STOP; stopData.data = "try to stop"; seekFData.type = SEEKF; seekFData.data = "seek forward to ..... "; seekBData.type = SEEKB; seekBData.data = "seek backward to ..... "; //seekFData.data = NULL; //seekBData.data = NULL; pst = PREPARING; GtkWidget * table = gtk_table_new (260, 260, FALSE); boxImg = gtk_drawing_area_new (); gtk_widget_set_size_request (boxImg, 520, 408); gtk_table_attach_defaults (GTK_TABLE (table), boxImg, 0, 260, 0, 204); gtk_widget_show (boxImg); getDuration(&video_duration); if(buildPlayerControlItem(window, video_duration)){ return -1; } soundEffect = buildSoundEfectMenu(); volumeScale = buildVolumeController(); showItems(table); gtk_container_add(GTK_CONTAINER(window),table); gtk_widget_show (table); gtk_widget_show (window); gtk_main (); return 0; }
myType.h
#include <gst/gst.h> #include <gdk/gdkx.h> #include <gtk/gtk.h> #include <gst/interfaces/xoverlay.h> #include <string.h> #include <stdio.h> typedef enum{ OPENFILE, PREPARE, PLAYPAUSE, PAUSE, SEEKF, SEEKB, STOP, CLOSE, }callbackType; typedef enum{ STOPED, PLAYING, PAUSED, PREPARING, SEEKING, SEEKCOMPLETE, }playerStatus; typedef enum{ SOUND_EFFECT_NORMAL, SOUND_EFFECT_CLASSICAL, SOUND_EFFECT_JAZZ, SOUND_EFFECT_BASS, }soundEffectType; typedef struct{ callbackType type; char * data; void * reserved1; void * reserved2; }callbackStruct; playerStatus pst; gchar pre_file_name[100]; GtkWidget *button; GtkWidget *buttonPlayPause; GtkWidget *buttonStop; GtkWidget *buttonSeekBackward; GtkWidget *buttonSeekForward; GtkWidget *buttonOpenFile; GtkWidget *soundEffect; GtkWidget *volumeScale; GtkWidget *event_box; GtkWidget *label; GtkWidget *seek_scale; GtkWidget *time_label; GtkWidget *boxImg; callbackStruct playData; callbackStruct stopData; callbackStruct seekFData; callbackStruct seekBData; callbackStruct openData; callbackStruct open_file_data; gboolean no_seek = FALSE; static GstElement *play = NULL; static GstElement *x_overlay; static GstElement *bin; static void destroy(GtkWidget *widget, gpointer data); static void widget_destroy(GtkWidget *widget, GtkWidget * destroy ); static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data); static void gui_update_time(const gchar *time, const gint64 position, const gint64 length); static void player_disconstructor(void); static void player_constructor(gchar * const file_name); static void selected_file_name (GtkWidget *widget, GtkFileSelection *fs); static gboolean update_time_callback(GstElement *pipeline); static gboolean bus_callback(GstBus *bus, GstMessage *message, gpointer data); static void file_selection( GtkWidget *widget, gpointer data ); static void setPageSize(GtkAdjustment *get, GtkAdjustment *set); static int playerControlCallback(GtkWidget *widget, gpointer data); static int getDuration(unsigned long long * duration); static void setVolume(gpointer * adj); static void setSoundEffect(GtkWidget * item, soundEffectType type); static void seek_value_changed(GtkRange *range, gpointer data); static int buildPlayerControlItem(GtkWidget * window, unsigned long long duration); static GtkWidget * buildSoundEfectMenu(void); static GtkWidget * buildVolumeController(); static void showItems(GtkWidget * table);
Makefile
CFLAGS=`pkg-config --cflags gtk+-2.0 gstreamer-0.10`# -D_DB LIBS=`pkg-config --libs gtk+-2.0 gstreamer-0.10` myPlayerUI:myPlayerUI.c gcc -g -o myPlayerUI myPlayerUI.c $(CFLAGS) $(LIBS) -l gstinterfaces-0.10 clean: rm -rf myPlayerUI