GTK Gstreamer media player

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


你可能感兴趣的:(GTK Gstreamer media player)