[evince] libview: Add EvMediaPlayer and EvMediaControls classes to show videos using GStreamer



commit a7a2b1ae6fad56e252deee2354a11da833738133
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Wed May 27 12:58:10 2015 +0200

    libview: Add EvMediaPlayer and EvMediaControls classes to show videos using GStreamer
    
    GStreamer is now an optional dependency.

 configure.ac                |   32 +++-
 libview/Makefile.am         |    8 +
 libview/ev-media-controls.c |  179 ++++++++++++++++
 libview/ev-media-controls.h |   45 ++++
 libview/ev-media-player.c   |  495 +++++++++++++++++++++++++++++++++++++++++++
 libview/ev-media-player.h   |   60 ++++++
 6 files changed, 817 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 21b6af3..1a1b2c1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -324,6 +324,33 @@ if test "$enable_gnome_desktop" != "no"; then
    fi
 fi
 
+# **********************
+# GStreamer (Multimedia)
+# **********************
+
+AC_ARG_ENABLE([multimedia],
+        [AS_HELP_STRING([--disable-multimedia], [Disable Multimedia support])],
+        [enable_multimedia=$enableval],
+        [enable_multimedia=auto])
+
+if test "$enable_multimedia" != "no"; then
+   if test "$enable_multimedia" = "auto"; then
+      PKG_CHECK_MODULES([GSTREAMER], [gstreamer-1.0 gstreamer-base-1.0 gstreamer-video-1.0], 
has_gstreamer=yes, has_gstreamer=no)
+   else
+      PKG_CHECK_MODULES([GSTREAMER], [gstreamer-1.0 gstreamer-base-1.0 gstreamer-video-1.0])
+      has_gstreamer=yes
+   fi
+
+   if test x$has_gstreamer = xyes; then
+      AC_DEFINE([ENABLE_MULTIMEDIA], [1], [Whether multimedia support is enabled])
+      enable_multimedia=yes
+   else
+      enable_multimedia=no
+   fi
+fi
+
+AM_CONDITIONAL([ENABLE_MULTIMEDIA], [test "$enable_multimedia" = "yes"])
+
 dnl ========= Check for Desktop Schemas
 PKG_CHECK_MODULES([DESKTOP_SCHEMAS], [gsettings-desktop-schemas],
                   has_desktop_schemas=yes, has_desktop_schemas=no)
@@ -348,8 +375,8 @@ LIBDOCUMENT_LIBS="$LIBDOCUMENT_LIBS"
 AC_SUBST(LIBDOCUMENT_CFLAGS)
 AC_SUBST(LIBDOCUMENT_LIBS)
 
-LIBVIEW_CFLAGS="$LIBVIEW_CFLAGS $GTKUNIXPRINT_CFLAGS $DEBUG_FLAGS"
-LIBVIEW_LIBS="$LIBVIEW_LIBS $GTKUNIXPRINT_LIBS -lm"
+LIBVIEW_CFLAGS="$LIBVIEW_CFLAGS $GTKUNIXPRINT_CFLAGS $GSTREAMER_CFLAGS $DEBUG_FLAGS"
+LIBVIEW_LIBS="$LIBVIEW_LIBS $GTKUNIXPRINT_LIBS $GSTREAMER_LIBS -lm"
 AC_SUBST(LIBVIEW_CFLAGS)
 AC_SUBST(LIBVIEW_LIBS)
 
@@ -952,5 +979,6 @@ DBUS communication .......:  $enable_dbus
 Keyring integration ......:  $with_keyring
 GTK+ Unix Print ..........:  $with_gtk_unix_print
 Thumbnail cache ..........:  $enable_gnome_desktop
+Multimedia ...............:  $enable_multimedia
 
 ])
diff --git a/libview/Makefile.am b/libview/Makefile.am
index c45f09c..3ffabeb 100644
--- a/libview/Makefile.am
+++ b/libview/Makefile.am
@@ -55,6 +55,14 @@ libevview3_la_SOURCES =                      \
        $(NOINST_H_SRC_FILES)           \
        $(INST_H_SRC_FILES)
 
+if ENABLE_MULTIMEDIA
+libevview3_la_SOURCES +=       \
+       ev-media-controls.h     \
+       ev-media-controls.c     \
+       ev-media-player.h       \
+       ev-media-player.c
+endif
+
 nodist_libevview3_la_SOURCES = \
        ev-view-marshal.c \
        ev-view-type-builtins.c \
diff --git a/libview/ev-media-controls.c b/libview/ev-media-controls.c
new file mode 100644
index 0000000..2b0cb4c
--- /dev/null
+++ b/libview/ev-media-controls.c
@@ -0,0 +1,179 @@
+/* ev-media-controls.h
+ *  this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2015 Igalia S.L.
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "ev-media-controls.h"
+
+struct _EvMediaControls {
+        GtkBox         parent;
+
+        GtkWidget     *button;
+        GtkWidget     *slider;
+
+        EvMediaPlayer *player;
+};
+
+struct _EvMediaControlsClass {
+        GtkBoxClass parent_class;
+};
+
+G_DEFINE_TYPE (EvMediaControls, ev_media_controls, GTK_TYPE_BOX)
+
+static void
+ev_media_controls_toggle_state (EvMediaControls *controls)
+{
+        ev_media_player_toggle_state (controls->player);
+}
+
+static void
+ev_media_controls_seek (EvMediaControls *controls,
+                        GtkScrollType    scroll,
+                        gdouble          value)
+{
+        ev_media_player_seek (controls->player, value);
+}
+
+static void
+media_player_state_changed (EvMediaPlayer   *player,
+                            guint            state,
+                            EvMediaControls *controls)
+{
+        const gchar *icon_name = NULL;
+        GtkWidget   *image;
+
+        image = gtk_button_get_image (GTK_BUTTON (controls->button));
+
+        switch (state) {
+        case EV_MEDIA_PLAYER_STATE_PLAY:
+                icon_name = "media-playback-pause-symbolic";
+                break;
+        case EV_MEDIA_PLAYER_STATE_PAUSE:
+                icon_name = "media-playback-start-symbolic";
+                break;
+        default:
+                g_assert_not_reached ();
+        }
+
+        gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name, GTK_ICON_SIZE_MENU);
+}
+
+static void
+media_player_duration_changed (EvMediaPlayer   *player,
+                               GParamSpec      *spec,
+                               EvMediaControls *controls)
+{
+        gtk_range_set_range (GTK_RANGE (controls->slider), 0,
+                             ev_media_player_get_duration (player));
+}
+
+static void
+media_player_position_changed (EvMediaPlayer   *player,
+                               GParamSpec      *spec,
+                               EvMediaControls *controls)
+{
+        gtk_range_set_value (GTK_RANGE (controls->slider),
+                             ev_media_player_get_position (player));
+}
+
+static void
+ev_media_controls_dispose (GObject *object)
+{
+        EvMediaControls *controls = EV_MEDIA_CONTROLS (object);
+
+        g_clear_object (&controls->player);
+
+        G_OBJECT_CLASS (ev_media_controls_parent_class)->dispose (object);
+}
+
+static void
+ev_media_controls_init (EvMediaControls *controls)
+{
+        GtkAdjustment  *adjustment;
+        GtkCssProvider *provider;
+
+        gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (controls)),
+                                     GTK_STYLE_CLASS_OSD);
+
+        gtk_orientable_set_orientation (GTK_ORIENTABLE (controls), GTK_ORIENTATION_HORIZONTAL);
+
+        controls->button = gtk_button_new ();
+        g_signal_connect_swapped (controls->button, "clicked",
+                                  G_CALLBACK (ev_media_controls_toggle_state),
+                                  controls);
+        gtk_widget_set_name (controls->button, "ev-media-controls-play-button");
+        gtk_widget_set_valign (controls->button, GTK_ALIGN_CENTER);
+        gtk_button_set_relief (GTK_BUTTON (controls->button), GTK_RELIEF_NONE);
+        gtk_button_set_image (GTK_BUTTON (controls->button),
+                              gtk_image_new_from_icon_name ("media-playback-start-symbolic",
+                                                            GTK_ICON_SIZE_MENU));
+        gtk_button_set_label(GTK_BUTTON (controls->button), NULL);
+        gtk_button_set_focus_on_click (GTK_BUTTON (controls->button), FALSE);
+
+        provider = gtk_css_provider_new ();
+        gtk_css_provider_load_from_data (provider, "#ev-media-controls-play-button { padding: 0px 8px 0px 
8px; }", -1, NULL);
+        gtk_style_context_add_provider (gtk_widget_get_style_context (controls->button),
+                                        GTK_STYLE_PROVIDER (provider),
+                                        GTK_STYLE_PROVIDER_PRIORITY_USER);
+        g_object_unref (provider);
+
+        gtk_box_pack_start (GTK_BOX (controls), controls->button, FALSE, TRUE, 0);
+        gtk_widget_show (controls->button);
+
+        adjustment = gtk_adjustment_new (0, 0, 1, 0.1, 0.10, 0);
+        controls->slider = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adjustment);
+        g_signal_connect_swapped (controls->slider, "change-value",
+                                  G_CALLBACK (ev_media_controls_seek),
+                                  controls);
+        gtk_widget_set_hexpand (controls->slider, TRUE);
+        gtk_scale_set_draw_value (GTK_SCALE (controls->slider), FALSE);
+        gtk_box_pack_start (GTK_BOX (controls), controls->slider, FALSE, TRUE, 0);
+        gtk_widget_show (controls->slider);
+}
+
+static void
+ev_media_controls_class_init (EvMediaControlsClass *klass)
+{
+        GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
+
+        g_object_class->dispose = ev_media_controls_dispose;
+}
+
+GtkWidget *
+ev_media_controls_new (EvMediaPlayer *player)
+{
+        EvMediaControls *controls;
+
+        g_return_val_if_fail (EV_IS_MEDIA_PLAYER (player), NULL);
+
+        controls = EV_MEDIA_CONTROLS (g_object_new (EV_TYPE_MEDIA_CONTROLS, NULL));
+        controls->player = g_object_ref (player);
+        g_signal_connect_object (controls->player, "state-changed",
+                                 G_CALLBACK (media_player_state_changed),
+                                 controls, 0);
+        g_signal_connect_object (controls->player, "notify::duration",
+                                 G_CALLBACK (media_player_duration_changed),
+                                 controls, 0);
+        g_signal_connect_object (controls->player, "notify::position",
+                                 G_CALLBACK (media_player_position_changed),
+                                 controls, 0);
+
+        return GTK_WIDGET (controls);
+}
diff --git a/libview/ev-media-controls.h b/libview/ev-media-controls.h
new file mode 100644
index 0000000..a280e51
--- /dev/null
+++ b/libview/ev-media-controls.h
@@ -0,0 +1,45 @@
+/* ev-media-controls.h
+ *  this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2015 Igalia S.L.
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EV_MEDIA_CONTROLS_H
+#define EV_MEDIA_CONTROLS_H
+
+#include <gtk/gtk.h>
+#include "ev-media-player.h"
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_MEDIA_CONTROLS              (ev_media_controls_get_type())
+#define EV_MEDIA_CONTROLS(object)           (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_MEDIA_CONTROLS, 
EvMediaControls))
+#define EV_IS_MEDIA_CONTROLS(object)        (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_MEDIA_CONTROLS))
+#define EV_MEDIA_CONTROLS_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_MEDIA_CONTROLS, 
EvMediaControlsClass))
+#define EV_IS_MEDIA_CONTROLS_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_MEDIA_CONTROLS))
+#define EV_MEDIA_CONTROLS_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_MEDIA_CONTROLS, 
EvMediaControlsClass))
+
+typedef struct _EvMediaControls      EvMediaControls;
+typedef struct _EvMediaControlsClass EvMediaControlsClass;
+
+GType      ev_media_controls_get_type (void) G_GNUC_CONST;
+
+GtkWidget *ev_media_controls_new      (EvMediaPlayer *player);
+
+G_END_DECLS
+
+#endif /* EV_MEDIA_CONTROLS_H */
diff --git a/libview/ev-media-player.c b/libview/ev-media-player.c
new file mode 100644
index 0000000..acde3d7
--- /dev/null
+++ b/libview/ev-media-player.c
@@ -0,0 +1,495 @@
+/* ev-media-player.h
+ *  this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2015 Igalia S.L.
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "ev-media-player.h"
+
+#include <gst/video/videooverlay.h>
+
+enum {
+        PROP_0,
+        PROP_MEDIA,
+        PROP_WINDOW_ID,
+        PROP_RENDER_AREA,
+        PROP_DURATION,
+        PROP_POSITION
+};
+
+enum {
+        STATE_CHANGED,
+        N_SIGNALS
+};
+
+struct _EvMediaPlayer {
+        GObject          parent;
+
+        EvMedia         *media;
+        guint64          window_id;
+        GdkRectangle     render_area;
+
+        GstElement      *pipeline;
+        GstBus          *bus;
+        GstVideoOverlay *overlay;
+        gboolean         is_playing;
+        gboolean         is_seeking;
+        gdouble          duration;
+        gdouble          position;
+
+        guint            position_timeout_id;
+};
+
+struct _EvMediaPlayerClass {
+        GObjectClass parent_class;
+};
+
+static guint signals[N_SIGNALS];
+
+G_DEFINE_TYPE (EvMediaPlayer, ev_media_player, G_TYPE_OBJECT)
+
+static gboolean
+update_position_cb (EvMediaPlayer *player)
+{
+        gint64 position;
+
+        gst_element_query_position (player->pipeline, GST_FORMAT_TIME, &position);
+        player->position = (gdouble)position / GST_SECOND;
+        g_object_notify (G_OBJECT (player), "position");
+
+        return G_SOURCE_CONTINUE;
+}
+
+static void
+ev_media_player_update_position_start (EvMediaPlayer *player)
+{
+        if (player->position_timeout_id > 0)
+                return;
+
+        player->position_timeout_id = g_timeout_add (1000 / 15,
+                                                     (GSourceFunc)update_position_cb,
+                                                     player);
+}
+
+static void
+ev_media_player_update_position_stop (EvMediaPlayer *player)
+{
+        if (player->position_timeout_id > 0) {
+                g_source_remove (player->position_timeout_id);
+                player->position_timeout_id = 0;
+        }
+}
+
+static void
+ev_media_player_update_position (EvMediaPlayer *player)
+{
+        if (player->duration <= 0)
+                return;
+
+        if (player->is_playing)
+                ev_media_player_update_position_start (player);
+        else
+                ev_media_player_update_position_stop (player);
+        update_position_cb (player);
+}
+
+static void
+ev_media_player_update_state (EvMediaPlayer *player,
+                              GstState      *new_state)
+{
+        GstState state, pending;
+        gboolean is_playing;
+
+        gst_element_get_state (player->pipeline, &state, &pending, 250 * GST_NSECOND);
+
+        is_playing = state == GST_STATE_PLAYING;
+        if (is_playing != player->is_playing) {
+                player->is_playing = is_playing;
+                g_signal_emit (player, signals[STATE_CHANGED], 0, player->is_playing ? 
EV_MEDIA_PLAYER_STATE_PLAY : EV_MEDIA_PLAYER_STATE_PAUSE);
+                ev_media_player_update_position (player);
+        }
+
+        if (new_state)
+                *new_state = state;
+}
+
+static void
+ev_media_player_notify_eos (EvMediaPlayer *player)
+{
+        g_signal_emit (player, signals[STATE_CHANGED], 0, EV_MEDIA_PLAYER_STATE_PAUSE);
+        ev_media_player_update_position_stop (player);
+        player->position = 0;
+        g_object_notify (G_OBJECT (player), "position");
+        gst_element_set_state (player->pipeline, GST_STATE_READY);
+}
+
+static GstBusSyncReply
+bus_sync_handle (GstBus        *bus,
+                 GstMessage    *message,
+                 EvMediaPlayer *player)
+{
+        GstVideoOverlay *overlay;
+
+        if (!gst_is_video_overlay_prepare_window_handle_message (message))
+                return GST_BUS_PASS;
+
+        overlay = GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (message));
+        gst_video_overlay_set_window_handle (overlay, (guintptr)player->window_id);
+        gst_video_overlay_set_render_rectangle (overlay,
+                                                player->render_area.x,
+                                                player->render_area.y,
+                                                player->render_area.width,
+                                                player->render_area.height);
+        gst_video_overlay_expose (overlay);
+
+        player->overlay = overlay;
+
+        gst_message_unref (message);
+
+        return GST_BUS_DROP;
+}
+
+static void
+bus_message_handle (GstBus        *bus,
+                    GstMessage    *message,
+                    EvMediaPlayer *player)
+{
+        switch (GST_MESSAGE_TYPE (message)) {
+        case GST_MESSAGE_ERROR: {
+                GError *error = NULL;
+                gchar  *dbg;
+
+                gst_message_parse_error (message, &error, &dbg);
+                g_warning ("Error: %s (%s)\n", error->message, dbg);
+                g_error_free (error);
+                g_free (dbg);
+        }
+                break;
+        case GST_MESSAGE_STATE_CHANGED:
+                if (GST_MESSAGE_SRC (message) != (GstObject *)player->pipeline)
+                        return;
+
+                if (!player->is_seeking)
+                        ev_media_player_update_state (player, NULL);
+
+                break;
+        case GST_MESSAGE_ASYNC_DONE: {
+                GstState state;
+
+                if (GST_MESSAGE_SRC (message) != (GstObject *)player->pipeline)
+                        return;
+
+                if (player->is_seeking) {
+                        player->is_seeking = FALSE;
+                        if (player->is_playing)
+                                ev_media_player_update_position_start (player);
+                } else {
+                        ev_media_player_update_state (player, &state);
+
+                        if (player->duration == 0 && (state == GST_STATE_PAUSED || state == 
GST_STATE_PLAYING)) {
+                                gint64 duration;
+
+                                gst_element_query_duration (player->pipeline, GST_FORMAT_TIME, &duration);
+                                player->duration = (gdouble)duration / GST_SECOND;
+                                g_object_notify (G_OBJECT (player), "duration");
+                        }
+                }
+
+        }
+                break;
+        case GST_MESSAGE_EOS:
+                player->is_playing = FALSE;
+                ev_media_player_notify_eos (player);
+
+                break;
+        default:
+                break;
+        }
+}
+
+static void
+ev_media_player_dispose (GObject *object)
+{
+        EvMediaPlayer *player = EV_MEDIA_PLAYER (object);
+
+        ev_media_player_update_position_stop (player);
+
+        if (player->bus) {
+                gst_bus_remove_signal_watch (player->bus);
+                gst_object_unref (player->bus);
+                player->bus = NULL;
+        }
+
+        if (player->pipeline) {
+                gst_element_set_state (player->pipeline, GST_STATE_NULL);
+                gst_object_unref (player->pipeline);
+                player->pipeline = NULL;
+        }
+
+        g_clear_object (&player->media);
+
+        G_OBJECT_CLASS (ev_media_player_parent_class)->dispose (object);
+}
+
+static void
+ev_media_player_get_property (GObject    *object,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+        EvMediaPlayer *player = EV_MEDIA_PLAYER (object);
+
+        switch (prop_id) {
+        case PROP_DURATION:
+                g_value_set_double (value, player->duration);
+                break;
+        case PROP_POSITION:
+                g_value_set_double (value, player->position);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        }
+}
+
+static void
+ev_media_player_set_property (GObject      *object,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+        EvMediaPlayer *player = EV_MEDIA_PLAYER (object);
+
+        switch (prop_id) {
+        case PROP_MEDIA:
+                player->media = EV_MEDIA (g_value_dup_object (value));
+                break;
+        case PROP_WINDOW_ID:
+                player->window_id = g_value_get_uint64 (value);
+                break;
+        case PROP_RENDER_AREA:
+                ev_media_player_set_render_area (player, (GdkRectangle *)g_value_get_boxed (value));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        }
+}
+
+static void
+ev_media_player_init (EvMediaPlayer *player)
+{
+        player->pipeline = gst_element_factory_make ("playbin", NULL);
+        if (!player->pipeline) {
+                g_warning ("Failed to create playbin\n");
+                return;
+        }
+
+        player->bus = gst_pipeline_get_bus (GST_PIPELINE (player->pipeline));
+        gst_bus_set_sync_handler (player->bus, (GstBusSyncHandler)bus_sync_handle, player, NULL);
+        gst_bus_add_signal_watch (player->bus);
+        g_signal_connect_object (player->bus, "message",
+                                 G_CALLBACK (bus_message_handle),
+                                 player, 0);
+}
+
+static void
+ev_media_player_constructed (GObject *object)
+{
+        EvMediaPlayer *player = EV_MEDIA_PLAYER (object);
+
+        G_OBJECT_CLASS (ev_media_player_parent_class)->constructed (object);
+
+        if (!player->pipeline)
+                return;
+
+        g_object_set (player->pipeline, "uri", ev_media_get_uri (player->media), NULL);
+        gst_element_set_state (player->pipeline, GST_STATE_PLAYING);
+}
+
+static void
+ev_media_player_class_init (EvMediaPlayerClass *klass)
+{
+        GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
+
+        if (!gst_is_initialized ()) {
+                GError  *error = NULL;
+
+                if (!gst_init_check (NULL, NULL, &error)) {
+                        g_warning ("Failed to initialize GStreamer: %s\n", error->message);
+                        g_error_free (error);
+                }
+        }
+
+        g_object_class->constructed = ev_media_player_constructed;
+        g_object_class->dispose = ev_media_player_dispose;
+        g_object_class->get_property = ev_media_player_get_property;
+        g_object_class->set_property = ev_media_player_set_property;
+
+        g_object_class_install_property (g_object_class,
+                                         PROP_MEDIA,
+                                         g_param_spec_object ("media",
+                                                              "Media",
+                                                              "The media played by the player",
+                                                              EV_TYPE_MEDIA,
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_CONSTRUCT_ONLY |
+                                                              G_PARAM_STATIC_STRINGS));
+        g_object_class_install_property (g_object_class,
+                                         PROP_WINDOW_ID,
+                                         g_param_spec_uint64 ("window-id",
+                                                              "Window ID",
+                                                              "The identifier of the window where the media 
will be rendered",
+                                                              0, G_MAXUINT64, 0,
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_CONSTRUCT_ONLY |
+                                                              G_PARAM_STATIC_STRINGS));
+        g_object_class_install_property (g_object_class,
+                                         PROP_RENDER_AREA,
+                                         g_param_spec_boxed ("render-area",
+                                                             "Render area",
+                                                             "The area of the window where the media will be 
rendered",
+                                                             GDK_TYPE_RECTANGLE,
+                                                             G_PARAM_WRITABLE |
+                                                             G_PARAM_CONSTRUCT |
+                                                             G_PARAM_STATIC_STRINGS));
+        g_object_class_install_property (g_object_class,
+                                         PROP_DURATION,
+                                         g_param_spec_double ("duration",
+                                                              "Duration",
+                                                              "Duration of the media",
+                                                              0, G_MAXDOUBLE, 0,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_STATIC_STRINGS));
+        g_object_class_install_property (g_object_class,
+                                         PROP_POSITION,
+                                         g_param_spec_double ("position",
+                                                              "Position",
+                                                              "Current position of the media",
+                                                              0, G_MAXDOUBLE, 0,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_STATIC_STRINGS));
+
+        signals[STATE_CHANGED] =
+                g_signal_new ("state-changed",
+                              G_TYPE_FROM_CLASS (g_object_class),
+                              G_SIGNAL_RUN_LAST,
+                              0, NULL, NULL,
+                              g_cclosure_marshal_VOID__UINT,
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
+}
+
+EvMediaPlayer *
+ev_media_player_new (EvMedia      *media,
+                     guint64       window_id,
+                     GdkRectangle *area)
+{
+        g_return_val_if_fail (EV_IS_MEDIA (media), NULL);
+        g_return_val_if_fail (window_id > 0, NULL);
+        g_return_val_if_fail (area != NULL, NULL);
+
+        return EV_MEDIA_PLAYER (g_object_new (EV_TYPE_MEDIA_PLAYER,
+                                              "media", media,
+                                              "window-id", window_id,
+                                              "render-area", area,
+                                              NULL));
+}
+
+void
+ev_media_player_set_render_area (EvMediaPlayer *player,
+                                 GdkRectangle  *area)
+{
+        g_return_if_fail (EV_IS_MEDIA_PLAYER (player));
+        g_return_if_fail (area != NULL);
+
+        if (player->render_area.x == area->x &&
+            player->render_area.y == area->y &&
+            player->render_area.width == area->width &&
+            player->render_area.height == area->height)
+                return;
+
+        player->render_area = *area;
+        if (!player->overlay)
+                return;
+
+        gst_video_overlay_set_render_rectangle (player->overlay, area->x, area->y, area->width, 
area->height);
+        gst_video_overlay_expose (player->overlay);
+}
+
+void
+ev_media_player_expose (EvMediaPlayer *player)
+{
+        g_return_if_fail (EV_IS_MEDIA_PLAYER (player));
+
+        if (!player->overlay)
+                return;
+
+        gst_video_overlay_expose (player->overlay);
+}
+
+gdouble
+ev_media_player_get_duration (EvMediaPlayer *player)
+{
+        g_return_val_if_fail (EV_IS_MEDIA_PLAYER (player), 0);
+
+        return player->duration;
+}
+
+gdouble
+ev_media_player_get_position (EvMediaPlayer *player)
+{
+        g_return_val_if_fail (EV_IS_MEDIA_PLAYER (player), 0);
+
+        return player->position;
+}
+
+void
+ev_media_player_toggle_state (EvMediaPlayer *player)
+{
+        GstState current, pending, new_state;
+
+        g_return_if_fail (EV_IS_MEDIA_PLAYER (player));
+
+        if (!player->pipeline)
+                return;
+
+        gst_element_get_state (player->pipeline, &current, &pending, 0);
+        new_state = current == GST_STATE_PLAYING ? GST_STATE_PAUSED : GST_STATE_PLAYING;
+        if (pending != new_state)
+                gst_element_set_state (player->pipeline, new_state);
+}
+
+void
+ev_media_player_seek (EvMediaPlayer *player,
+                      gdouble        position)
+{
+        g_return_if_fail (EV_IS_MEDIA_PLAYER (player));
+
+        if (!player->pipeline)
+                return;
+
+        position = CLAMP (position, 0, player->duration);
+        if (gst_element_seek_simple (player->pipeline,
+                                     GST_FORMAT_TIME,
+                                     GST_SEEK_FLAG_FLUSH,
+                                     (gint64)(position * GST_SECOND))) {
+                player->is_seeking = TRUE;
+                ev_media_player_update_position_stop (player);
+                player->position = position;
+                g_object_notify (G_OBJECT (player), "position");
+        }
+}
diff --git a/libview/ev-media-player.h b/libview/ev-media-player.h
new file mode 100644
index 0000000..083df1e
--- /dev/null
+++ b/libview/ev-media-player.h
@@ -0,0 +1,60 @@
+/* ev-media-player.h
+ *  this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2015 Igalia S.L.
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EV_MEDIA_PLAYER_H
+#define EV_MEDIA_PLAYER_H
+
+#include <glib-object.h>
+#include <gdk/gdk.h>
+#include "ev-media.h"
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_MEDIA_PLAYER              (ev_media_player_get_type())
+#define EV_MEDIA_PLAYER(object)           (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_MEDIA_PLAYER, 
EvMediaPlayer))
+#define EV_IS_MEDIA_PLAYER(object)        (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_MEDIA_PLAYER))
+#define EV_MEDIA_PLAYER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_MEDIA_PLAYER, 
EvMediaPlayerClass))
+#define EV_IS_MEDIA_PLAYER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_MEDIA_PLAYER))
+#define EV_MEDIA_PLAYER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_MEDIA_PLAYER, 
EvMediaPlayerClass))
+
+typedef enum {
+        EV_MEDIA_PLAYER_STATE_PAUSE,
+        EV_MEDIA_PLAYER_STATE_PLAY
+} EvMediaPlayerState;
+
+typedef struct _EvMediaPlayer      EvMediaPlayer;
+typedef struct _EvMediaPlayerClass EvMediaPlayerClass;
+
+GType          ev_media_player_get_type        (void) G_GNUC_CONST;
+EvMediaPlayer *ev_media_player_new             (EvMedia       *media,
+                                                guint64        window_id,
+                                                GdkRectangle  *area);
+void           ev_media_player_set_render_area (EvMediaPlayer *player,
+                                                GdkRectangle  *area);
+void           ev_media_player_expose          (EvMediaPlayer *player);
+gdouble        ev_media_player_get_duration    (EvMediaPlayer *player);
+gdouble        ev_media_player_get_position    (EvMediaPlayer *player);
+void           ev_media_player_toggle_state    (EvMediaPlayer *player);
+void           ev_media_player_seek            (EvMediaPlayer *player,
+                                                gdouble        position);
+
+G_END_DECLS
+
+#endif /* EV_MEDIA_PLAYER_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]