diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/gtk-vlc-player/Makefile.am | 7 | ||||
-rw-r--r-- | lib/gtk-vlc-player/gtk-vlc-player.c | 272 | ||||
-rw-r--r-- | lib/gtk-vlc-player/gtk-vlc-player.h | 61 | ||||
-rw-r--r-- | src/Makefile.am | 3 |
7 files changed, 347 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 0a47a01..3c2694f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = src doc +SUBDIRS = lib src doc diff --git a/configure.ac b/configure.ac index 306a9fa..80b9b08 100644 --- a/configure.ac +++ b/configure.ac @@ -117,6 +117,7 @@ case $host in esac AC_CONFIG_FILES([Makefile \ + lib/Makefile lib/gtk-vlc-player/Makefile \ src/Makefile \ doc/Makefile doc/Doxyfile]) AC_OUTPUT diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..743e585 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,2 @@ + +SUBDIRS = gtk-vlc-player diff --git a/lib/gtk-vlc-player/Makefile.am b/lib/gtk-vlc-player/Makefile.am new file mode 100644 index 0000000..83742d1 --- /dev/null +++ b/lib/gtk-vlc-player/Makefile.am @@ -0,0 +1,7 @@ +AM_CFLAGS = -Wall + +lib_LTLIBRARIES = libgtk-vlc-player.la + +libgtk_vlc_player_la_SOURCES = gtk-vlc-player.c gtk-vlc-player.h + +include_HEADERS = gtk-vlc-player.h diff --git a/lib/gtk-vlc-player/gtk-vlc-player.c b/lib/gtk-vlc-player/gtk-vlc-player.c new file mode 100644 index 0000000..82c33ac --- /dev/null +++ b/lib/gtk-vlc-player/gtk-vlc-player.c @@ -0,0 +1,272 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> + +#include <gtk/gtk.h> +#ifdef __WIN32__ +#include <gdk/gdkwin32.h> +#else +#include <gdk/gdkx.h> +#include <X11/Xlib.h> +#endif + +#include <vlc/vlc.h> + +#include <gtk-vlc-player.h> + +static void gtk_vlc_player_class_init(GtkVlcPlayerClass *klass); +static void gtk_vlc_player_init(GtkVlcPlayer *klass); + +static void widget_on_realize(GtkWidget *widget, gpointer data); +static gboolean widget_on_click(GtkWidget *widget, GdkEventButton *event, gpointer data); + +static void vlc_time_changed(const struct libvlc_event_t *event, void *userdata); +static void vlc_length_changed(const struct libvlc_event_t *event, void *userdata); + +GType +gtk_vlc_player_get_type(void) +{ + static GType type = 0; + + if (!type) { + /* FIXME: destructor needed */ + const GTypeInfo info = { + sizeof(GtkVlcPlayerClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)gtk_vlc_player_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(GtkVlcPlayer), + 0, /* n_preallocs */ + (GInstanceInitFunc)gtk_vlc_player_init, + }; + + type = g_type_register_static(GTK_TYPE_DRAWING_AREA, + "GtkVlcPlayer", &info, 0); + } + + return type; +} + +enum { + TIME_CHANGED_SIGNAL, + LENGTH_CHANGED_SIGNAL, + LAST_SIGNAL +}; + + +static guint gtk_vlc_player_signals[LAST_SIGNAL] = {0, 0}; + +static void +gtk_vlc_player_class_init(GtkVlcPlayerClass *klass) +{ +#if 0 + gtk_vlc_player_signals[CLICKED_SIGNAL] = + g_signal_new("clicked", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(GtkVlcPlayerClass, clicked), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +#endif + + gtk_vlc_player_signals[TIME_CHANGED_SIGNAL] = + g_signal_new("time-changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(GtkVlcPlayerClass, time_changed), + NULL, NULL, + g_cclosure_marshal_VOID__LONG, G_TYPE_NONE, + 1, G_TYPE_INT64); + + gtk_vlc_player_signals[LENGTH_CHANGED_SIGNAL] = + g_signal_new("length-changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(GtkVlcPlayerClass, length_changed), + NULL, NULL, + g_cclosure_marshal_VOID__LONG, G_TYPE_NONE, + 1, G_TYPE_INT64); +} + +static void +gtk_vlc_player_init(GtkVlcPlayer *klass) +{ + GdkColor color; + libvlc_event_manager_t *evman; + + gdk_color_parse("black", &color); + gtk_widget_modify_bg(GTK_WIDGET(klass), GTK_STATE_NORMAL, &color); + + g_signal_connect(G_OBJECT(klass), "realize", + G_CALLBACK(widget_on_realize), NULL); + + /* FIXME: must probably do via vlc events */ + gtk_widget_add_events(GTK_WIDGET(klass), GDK_BUTTON_PRESS_MASK); + g_signal_connect(G_OBJECT(klass), "button-press-event", + G_CALLBACK(widget_on_click), NULL); + + klass->vlc_inst = libvlc_new(0, NULL); + klass->media_player = libvlc_media_player_new(klass->vlc_inst); + + /* sign up for time updates */ + evman = libvlc_media_player_event_manager(klass->media_player); + + libvlc_event_attach(evman, libvlc_MediaPlayerTimeChanged, + vlc_time_changed, klass); + libvlc_event_attach(evman, libvlc_MediaPlayerLengthChanged, + vlc_length_changed, klass); + + klass->isFullscreen = FALSE; + klass->fullscreen_window = NULL; + klass->orig_parent = NULL; +} + +static void +widget_on_realize(GtkWidget *widget, gpointer data __attribute__((unused))) +{ + GtkVlcPlayer *player = GTK_VLC_PLAYER(widget); + GdkWindow *window = gtk_widget_get_window(widget); + +#ifdef __WIN32__ + libvlc_media_player_set_hwnd(player->media_player, GDK_WINDOW_HWND(window)); +#else + libvlc_media_player_set_xwindow(player->media_player, GDK_WINDOW_XID(window)); +#endif +} + +/* FIXME: might have to use libvlc events */ +static gboolean +widget_on_click(GtkWidget *widget, GdkEventButton *event, + gpointer user_data __attribute__((unused))) +{ + GtkVlcPlayer *player = GTK_VLC_PLAYER(widget); + + if (event->type != GDK_2BUTTON_PRESS || event->button != 1) + return TRUE; + + //DEBUG("player_widget double-click"); + + if (player->isFullscreen) { + assert(player->fullscreen_window != NULL); + assert(player->orig_parent != NULL); + + gtk_window_unfullscreen(GTK_WINDOW(player->fullscreen_window)); + gtk_widget_reparent(widget, player->orig_parent); + gtk_widget_hide(player->fullscreen_window); + + player->isFullscreen = FALSE; + } else { + if (player->fullscreen_window == NULL) + player->fullscreen_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + player->orig_parent = gtk_widget_get_parent(widget); + + gtk_widget_show(player->fullscreen_window); + gtk_widget_reparent(widget, player->fullscreen_window); + gtk_window_fullscreen(GTK_WINDOW(player->fullscreen_window)); + + player->isFullscreen = TRUE; + } + + return TRUE; +} + +/* + * VLC callbacks are invoked from another thread! + */ +static void +vlc_time_changed(const struct libvlc_event_t *event, void *userdata) +{ + GtkVlcPlayer *player = GTK_VLC_PLAYER(userdata); + + assert(event->type == libvlc_MediaPlayerTimeChanged); + + gdk_threads_enter(); + g_signal_emit(player, gtk_vlc_player_signals[TIME_CHANGED_SIGNAL], 0, + (gint64)event->u.media_player_time_changed.new_time); + gdk_threads_leave(); +} + +static void +vlc_length_changed(const struct libvlc_event_t *event, void *userdata) +{ + GtkVlcPlayer *player = GTK_VLC_PLAYER(userdata); + + assert(event->type == libvlc_MediaPlayerLengthChanged); + + gdk_threads_enter(); + g_signal_emit(player, gtk_vlc_player_signals[LENGTH_CHANGED_SIGNAL], 0, + (gint64)event->u.media_player_length_changed.new_length); + gdk_threads_leave(); +} + +/* + * API + */ + +GtkWidget * +gtk_vlc_player_new(void) +{ + return GTK_WIDGET(g_object_new(GTK_TYPE_VLC_PLAYER, NULL)); +} + +gboolean +gtk_vlc_player_load(GtkVlcPlayer *player, const gchar *uri) +{ + libvlc_media_t *media; + + media = libvlc_media_new_location(player->vlc_inst, (const char *)uri); + libvlc_media_parse(media); + libvlc_media_player_set_media(player->media_player, media); + + /* NOTE: media was parsed so get_duration works */ + g_signal_emit(player, gtk_vlc_player_signals[LENGTH_CHANGED_SIGNAL], 0, + (gint64)libvlc_media_get_duration(media)); + g_signal_emit(player, gtk_vlc_player_signals[TIME_CHANGED_SIGNAL], 0, 0); + + libvlc_media_release(media); + + return FALSE; +} + +void +gtk_vlc_player_play(GtkVlcPlayer *player) +{ + libvlc_media_player_play(player->media_player); +} + +void +gtk_vlc_player_pause(GtkVlcPlayer *player) +{ + libvlc_media_player_pause(player->media_player); +} + +gboolean +gtk_vlc_player_toggle(GtkVlcPlayer *player) +{ + if (libvlc_media_player_is_playing(player->media_player)) + gtk_vlc_player_pause(player); + else + gtk_vlc_player_play(player); + + return (gboolean)libvlc_media_player_is_playing(player->media_player); +} + +void +gtk_vlc_player_stop(GtkVlcPlayer *player) +{ + gtk_vlc_player_pause(player); + libvlc_media_player_stop(player->media_player); + + g_signal_emit(player, gtk_vlc_player_signals[TIME_CHANGED_SIGNAL], 0, 0); +} + +void +gtk_vlc_player_seek(GtkVlcPlayer *player, gint64 time) +{ + libvlc_media_player_set_time(player->media_player, (libvlc_time_t)time); +} diff --git a/lib/gtk-vlc-player/gtk-vlc-player.h b/lib/gtk-vlc-player/gtk-vlc-player.h new file mode 100644 index 0000000..217371c --- /dev/null +++ b/lib/gtk-vlc-player/gtk-vlc-player.h @@ -0,0 +1,61 @@ +#ifndef __GTK_VLC_PLAYER_H +#define __GTK_VLC_PLAYER_H + +#include <glib-object.h> +#include <gtk/gtk.h> + +#include <vlc/vlc.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_VLC_PLAYER \ + (gtk_vlc_player_get_type()) +#define GTK_VLC_PLAYER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_VLC_PLAYER, GtkVlcPlayer)) +#define GTK_VLC_PLAYER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_VLC_PLAYER, GtkVlcPlayerClass)) +#define GTK_IS_VLC_PLAYER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_VLC_PLAYER)) +#define GTK_IS_VLC_PLAYER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_VLC_PLAYER)) +#define GTK_VLC_PLAYER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_VLC_PLAYER, GtkVlcPlayerClass)) + +typedef struct _GtkVlcPlayer { + GtkDrawingArea parent_instance; + + libvlc_instance_t *vlc_inst; + libvlc_media_player_t *media_player; + + gboolean isFullscreen; + + GtkWidget *fullscreen_window; + GtkWidget *orig_parent; +} GtkVlcPlayer; + +typedef struct _GtkVlcPlayerClass { + GtkDrawingAreaClass parent_class; + + void (*time_changed) (GtkVlcPlayer *self, gint64 new_time, gpointer user_data); + void (*length_changed) (GtkVlcPlayer *self, gint64 new_length, gpointer user_data); +} GtkVlcPlayerClass; + +GType gtk_vlc_player_get_type(void); + +/* + * API + */ +GtkWidget *gtk_vlc_player_new(void); +gboolean gtk_vlc_player_load(GtkVlcPlayer *player, const gchar *uri); + +void gtk_vlc_player_play(GtkVlcPlayer *player); +void gtk_vlc_player_pause(GtkVlcPlayer *player); +gboolean gtk_vlc_player_toggle(GtkVlcPlayer *player); +void gtk_vlc_player_stop(GtkVlcPlayer *player); + +void gtk_vlc_player_seek(GtkVlcPlayer *player, gint64 time); + + +G_END_DECLS + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index eecbba3..17dbd2c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,6 @@ +AM_CFLAGS = -Wall +AM_CPPFLAGS = -I$(top_srcdir)/lib/gtk-vlc-player bin_PROGRAMS = experiment-player experiment_player_SOURCES = main.c +experiment_player_LDADD = $(top_srcdir)/lib/gtk-vlc-player/libgtk-vlc-player.la |