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