[Xfce4-commits] <tumbler:master> Add GStreamer-based thumbnailer for video thumbnails
Jannis Pohlmann
noreply at xfce.org
Fri May 20 01:20:01 CEST 2011
Updating branch refs/heads/master
to 88a5e9692fcc2f2b64c152f25a98721d631b2ad7 (commit)
from 57a3b9f3042d7d1e8f781dca5eb333d50cb1bb53 (commit)
commit 88a5e9692fcc2f2b64c152f25a98721d631b2ad7
Author: Ross Burton <ross at linux.intel.com>
Date: Mon Jan 31 15:48:34 2011 +0000
Add GStreamer-based thumbnailer for video thumbnails
Signed-off-by: Jannis Pohlmann <jannis at xfce.org>
acinclude.m4 | 24 ++
configure.ac | 7 +
plugins/Makefile.am | 1 +
.../Makefile.am | 30 +-
plugins/gst-thumbnailer/gst-helper.c | 192 ++++++++++
plugins/gst-thumbnailer/gst-helper.h | 35 ++
.../gst-thumbnailer-plugin.c} | 20 +-
plugins/gst-thumbnailer/gst-thumbnailer-provider.c | 151 ++++++++
plugins/gst-thumbnailer/gst-thumbnailer-provider.h | 45 +++
plugins/gst-thumbnailer/gst-thumbnailer.c | 389 ++++++++++++++++++++
plugins/gst-thumbnailer/gst-thumbnailer.h | 45 +++
11 files changed, 917 insertions(+), 22 deletions(-)
diff --git a/acinclude.m4 b/acinclude.m4
index e2d374b..2271773 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -145,6 +145,30 @@ AC_MSG_RESULT([$ac_tumbler_ffmpeg_thumbnailer])
+dnl TUMBLER_GSTREAMER_THUMBNAILER()
+dnl
+dnl Check whether to build and install the gstreamer video thumbnailer plugin.
+dnl
+AC_DEFUN([TUMBLER_GSTREAMER_THUMBNAILER],
+[
+AC_ARG_ENABLE([gstreamer-thumbnailer], [AC_HELP_STRING([--disable-gstreamer-thumbnailer], [Don't build the GStreamer video thumbnailer plugin])],
+ [ac_tumbler_gstreamer_thumbnailer=$enableval], [ac_tumbler_gstreamer_thumbnailer=yes])
+if test x"$ac_tumbler_gstreamer_thumbnailer" = x"yes"; then
+ dnl Check for gdk-pixbuf
+ PKG_CHECK_MODULES([GDK_PIXBUF], [gdk-pixbuf-2.0 >= 2.14],
+ [
+ dnl Check for libgstreamerthumbnailer
+ PKG_CHECK_MODULES([GSTREAMER], [gstreamer-0.10], [], [ac_tumbler_gstreamer_thumbnailer=no])
+ ], [ac_tumbler_gstreamer_thumbnailer=no])
+fi
+
+AC_MSG_CHECKING([whether to build the gstreamer video thumbnailer plugin])
+AM_CONDITIONAL([TUMBLER_GSTREAMER_THUMBNAILER], [test x"$ac_tumbler_gstreamer_thumbnailer" = x"yes"])
+AC_MSG_RESULT([$ac_tumbler_gstreamer_thumbnailer])
+])
+
+
+
dnl TUMBLER_POPPLER_THUMBNAILER()
dnl
dnl Check whether to build and install the poppler PDF/PS thumbnailer plugin.
diff --git a/configure.ac b/configure.ac
index 0c9fac7..6e7b8a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -154,6 +154,7 @@ TUMBLER_FONT_THUMBNAILER()
TUMBLER_JPEG_THUMBNAILER()
TUMBLER_PIXBUF_THUMBNAILER()
TUMBLER_FFMPEG_THUMBNAILER()
+TUMBLER_GSTREAMER_THUMBNAILER()
TUMBLER_POPPLER_THUMBNAILER()
TUMBLER_XDG_CACHE()
@@ -181,6 +182,7 @@ docs/reference/tumbler/Makefile
docs/reference/tumbler/version.xml
plugins/Makefile
plugins/font-thumbnailer/Makefile
+plugins/gst-thumbnailer/Makefile
plugins/jpeg-thumbnailer/Makefile
plugins/pixbuf-thumbnailer/Makefile
plugins/ffmpeg-thumbnailer/Makefile
@@ -223,6 +225,11 @@ echo " * Video thumbnailer plugin using ffmpegthumbnailer: yes"
else
echo " * Video thumbnailer plugin using ffmpegthumbnailer: no"
fi
+if test x"$ac_tumbler_gstreamer_thumbnailer" = x"yes"; then
+echo " * Video thumbnailer plugin using GStreamer: yes"
+else
+echo " * Video thumbnailer plugin using GStreamer : no"
+fi
if test x"$ac_tumbler_poppler_thumbnailer" = x"yes"; then
echo " * PDF/PS thumbnailer plugin using poppler: yes"
else
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 7894a05..7e810d4 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -19,6 +19,7 @@
SUBDIRS = \
font-thumbnailer \
+ gst-thumbnailer \
jpeg-thumbnailer \
pixbuf-thumbnailer \
ffmpeg-thumbnailer \
diff --git a/plugins/pixbuf-thumbnailer/Makefile.am b/plugins/gst-thumbnailer/Makefile.am
similarity index 72%
copy from plugins/pixbuf-thumbnailer/Makefile.am
copy to plugins/gst-thumbnailer/Makefile.am
index 691f3d1..24ed555 100644
--- a/plugins/pixbuf-thumbnailer/Makefile.am
+++ b/plugins/gst-thumbnailer/Makefile.am
@@ -17,44 +17,48 @@
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
-if TUMBLER_PIXBUF_THUMBNAILER
+if TUMBLER_GSTREAMER_THUMBNAILER
tumbler_plugindir = $(libdir)/tumbler-$(TUMBLER_VERSION_API)/plugins
tumbler_plugin_LTLIBRARIES = \
- tumbler-pixbuf-thumbnailer.la
+ tumbler-gst-thumbnailer.la
-tumbler_pixbuf_thumbnailer_la_SOURCES = \
- pixbuf-thumbnailer-plugin.c \
- pixbuf-thumbnailer-provider.c \
- pixbuf-thumbnailer-provider.h \
- pixbuf-thumbnailer.c \
- pixbuf-thumbnailer.h
+tumbler_gst_thumbnailer_la_SOURCES = \
+ gst-thumbnailer-plugin.c \
+ gst-thumbnailer-provider.c \
+ gst-thumbnailer-provider.h \
+ gst-thumbnailer.c \
+ gst-thumbnailer.h \
+ gst-helper.c \
+ gst-helper.h
-tumbler_pixbuf_thumbnailer_la_CFLAGS = \
+tumbler_gst_thumbnailer_la_CFLAGS = \
-I$(top_builddir) \
-I$(top_builddir)/plugins \
-I$(top_srcdir) \
-I$(top_srcdir)/plugins \
- -DG_LOG_DOMAIN=\"tumbler-pixbuf-thumbnailer\" \
+ -DG_LOG_DOMAIN=\"tumbler-gst-thumbnailer\" \
-DPACKAGE_LOCALE_DIR=\"$(localedir)\" \
$(GDK_PIXBUF_CFLAGS) \
+ $(GSTREAMER_CFLAGS) \
$(GIO_CFLAGS) \
$(GLIB_CFLAGS) \
$(PLATFORM_CPPFLAGS)
-tumbler_pixbuf_thumbnailer_la_LDFLAGS = \
+tumbler_gst_thumbnailer_la_LDFLAGS = \
-avoid-version \
-export-dynamic \
-module \
$(PLATFORM_LDFLAGS)
-tumbler_pixbuf_thumbnailer_la_LIBADD = \
+tumbler_gst_thumbnailer_la_LIBADD = \
$(top_builddir)/tumbler/libtumbler-$(TUMBLER_VERSION_API).la \
$(GDK_PIXBUF_LIBS) \
+ $(GSTREAMER_LIBS) \
$(GIO_LIBS) \
$(GLIB_LIBS)
-tumbler_pixbuf_thumbnailer_la_DEPENDENCIES = \
+tumbler_gst_thumbnailer_la_DEPENDENCIES = \
$(top_builddir)/tumbler/libtumbler-$(TUMBLER_VERSION_API).la
endif
diff --git a/plugins/gst-thumbnailer/gst-helper.c b/plugins/gst-thumbnailer/gst-helper.c
new file mode 100644
index 0000000..c5a571c
--- /dev/null
+++ b/plugins/gst-thumbnailer/gst-helper.c
@@ -0,0 +1,192 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*
+ * Originally from Bickley - a meta data management framework.
+ * Copyright © 2008, 2011 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gst/gst.h>
+#include <tumbler/tumbler.h>
+#include "gst-helper.h"
+
+static void
+push_buffer (GstElement *element,
+ GstBuffer *out_buffer,
+ GstPad *pad,
+ GstBuffer *in_buffer)
+{
+ gst_buffer_set_caps (out_buffer, GST_BUFFER_CAPS (in_buffer));
+ GST_BUFFER_SIZE (out_buffer) = GST_BUFFER_SIZE (in_buffer);
+ memcpy (GST_BUFFER_DATA (out_buffer), GST_BUFFER_DATA (in_buffer),
+ GST_BUFFER_SIZE (in_buffer));
+}
+
+static void
+pull_buffer (GstElement *element,
+ GstBuffer *in_buffer,
+ GstPad *pad,
+ GstBuffer **out_buffer)
+{
+ *out_buffer = gst_buffer_ref (in_buffer);
+}
+
+GdkPixbuf *
+gst_helper_convert_buffer_to_pixbuf (GstBuffer *buffer,
+ GCancellable *cancellable,
+ TumblerThumbnailFlavor *flavour)
+{
+ GstCaps *pb_caps;
+ GstElement *pipeline;
+ GstBuffer *out_buffer = NULL;
+ GstElement *src, *sink, *colorspace, *scale, *filter;
+ GstBus *bus;
+ GstMessage *msg;
+ GstStateChangeReturn state;
+ gboolean ret;
+ int thumb_size = 0, width, height, dw, dh, i;
+ GstStructure *s;
+
+ /* TODO: get the width and height, and handle them being different when
+ scaling */
+ tumbler_thumbnail_flavor_get_size (flavour, &thumb_size, NULL);
+
+ s = gst_caps_get_structure (GST_BUFFER_CAPS (buffer), 0);
+ gst_structure_get_int (s, "width", &width);
+ gst_structure_get_int (s, "height", &height);
+
+ if (width > height)
+ {
+ double ratio;
+
+ ratio = (double) thumb_size / (double) width;
+ dw = thumb_size;
+ dh = height * ratio;
+ }
+ else
+ {
+ double ratio;
+
+ ratio = (double) thumb_size / (double) height;
+ dh = thumb_size;
+ dw = width * ratio;
+ }
+
+ pb_caps = gst_caps_new_simple ("video/x-raw-rgb",
+ "bpp", G_TYPE_INT, 24,
+ "depth", G_TYPE_INT, 24,
+ "width", G_TYPE_INT, dw,
+ "height", G_TYPE_INT, dh,
+ "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
+ NULL);
+
+ pipeline = gst_pipeline_new ("pipeline");
+
+ src = gst_element_factory_make ("fakesrc", "src");
+ colorspace = gst_element_factory_make ("ffmpegcolorspace", "colorspace");
+ scale = gst_element_factory_make ("videoscale", "scale");
+ filter = gst_element_factory_make ("capsfilter", "filter");
+ sink = gst_element_factory_make ("fakesink", "sink");
+
+ gst_bin_add_many (GST_BIN (pipeline), src, colorspace, scale,
+ filter, sink, NULL);
+
+ g_object_set (filter,
+ "caps", pb_caps,
+ NULL);
+ g_object_set (src,
+ "num-buffers", 1,
+ "sizetype", 2,
+ "sizemax", GST_BUFFER_SIZE (buffer),
+ "signal-handoffs", TRUE,
+ NULL);
+ g_signal_connect (src, "handoff",
+ G_CALLBACK (push_buffer), buffer);
+
+ g_object_set (sink,
+ "signal-handoffs", TRUE,
+ "preroll-queue-len", 1,
+ NULL);
+ g_signal_connect (sink, "handoff",
+ G_CALLBACK (pull_buffer), &out_buffer);
+
+ ret = gst_element_link (src, colorspace);
+ if (ret == FALSE)
+ {
+ g_warning ("Failed to link src->colorspace");
+ return NULL;
+ }
+
+ ret = gst_element_link (colorspace, scale);
+ if (ret == FALSE)
+ {
+ g_warning ("Failed to link colorspace->scale");
+ return NULL;
+ }
+
+ ret = gst_element_link (scale, filter);
+ if (ret == FALSE)
+ {
+ g_warning ("Failed to link scale->filter");
+ return NULL;
+ }
+
+ ret = gst_element_link (filter, sink);
+ if (ret == FALSE)
+ {
+ g_warning ("Failed to link filter->sink");
+ return NULL;
+ }
+
+ bus = gst_element_get_bus (GST_ELEMENT (pipeline));
+ state = gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
+
+ i = 0;
+ msg = NULL;
+ while (msg == NULL && i < 5)
+ {
+ msg = gst_bus_timed_pop_filtered (bus, GST_SECOND,
+ GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
+ i++;
+ }
+
+ /* FIXME: Notify about error? */
+ gst_message_unref (msg);
+
+ gst_caps_unref (pb_caps);
+
+ if (out_buffer)
+ {
+ GdkPixbuf *pixbuf;
+ char *data;
+
+ data = g_memdup (GST_BUFFER_DATA (out_buffer),
+ GST_BUFFER_SIZE (out_buffer));
+ pixbuf = gdk_pixbuf_new_from_data ((guchar *) data,
+ GDK_COLORSPACE_RGB, FALSE,
+ 8, dw, dh, GST_ROUND_UP_4 (dw * 3),
+ (GdkPixbufDestroyNotify) g_free,
+ NULL);
+
+ gst_buffer_unref (buffer);
+ return pixbuf;
+ }
+
+ /* FIXME: Check what buffers need freed */
+ return NULL;
+}
diff --git a/plugins/gst-thumbnailer/gst-helper.h b/plugins/gst-thumbnailer/gst-helper.h
new file mode 100644
index 0000000..594e13c
--- /dev/null
+++ b/plugins/gst-thumbnailer/gst-helper.h
@@ -0,0 +1,35 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*
+ * Originally from Bickley - a meta data management framework.
+ * Copyright © 2008, 2011 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GST_HELPER_H__
+#define __GST_HELPER_H__
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gst/gst.h>
+#include <tumbler/tumbler.h>
+
+G_BEGIN_DECLS
+
+GdkPixbuf *gst_helper_convert_buffer_to_pixbuf (GstBuffer *buffer,
+ GCancellable *cancellable,
+ TumblerThumbnailFlavor *flavour);
+
+G_END_DECLS
+
+#endif
diff --git a/plugins/poppler-thumbnailer/poppler-thumbnailer-plugin.c b/plugins/gst-thumbnailer/gst-thumbnailer-plugin.c
similarity index 81%
copy from plugins/poppler-thumbnailer/poppler-thumbnailer-plugin.c
copy to plugins/gst-thumbnailer/gst-thumbnailer-plugin.c
index 6567de1..5b302bb 100644
--- a/plugins/poppler-thumbnailer/poppler-thumbnailer-plugin.c
+++ b/plugins/gst-thumbnailer/gst-thumbnailer-plugin.c
@@ -1,6 +1,8 @@
/* vi:set et ai sw=2 sts=2 ts=2: */
-/*-
- * Copyright (c) 2010 Jannis Pohlmann <jannis at xfce.org>
+/*
+ * Copyright (c) 2011 Intel Corporation
+ *
+ * Author: Ross Burton <ross at linux.intel.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -28,8 +30,8 @@
#include <tumbler/tumbler.h>
-#include <poppler-thumbnailer/poppler-thumbnailer-provider.h>
-#include <poppler-thumbnailer/poppler-thumbnailer.h>
+#include <gst-thumbnailer/gst-thumbnailer-provider.h>
+#include <gst-thumbnailer/gst-thumbnailer.h>
@@ -59,15 +61,15 @@ tumbler_plugin_initialize (TumblerProviderPlugin *plugin)
}
#ifdef DEBUG
- g_message (_("Initializing the Tumbler Poppler PDF/PS Thumbnailer plugin"));
+ g_message (_("Initializing the Tumbler GStreamer Thumbnailer plugin"));
#endif
/* register the types provided by this plugin */
- poppler_thumbnailer_register (plugin);
- poppler_thumbnailer_provider_register (plugin);
+ gst_thumbnailer_register (plugin);
+ gst_thumbnailer_provider_register (plugin);
/* set up the plugin provider type list */
- type_list[0] = TYPE_POPPLER_THUMBNAILER_PROVIDER;
+ type_list[0] = TYPE_GST_THUMBNAILER_PROVIDER;
}
@@ -76,7 +78,7 @@ void
tumbler_plugin_shutdown (void)
{
#ifdef DEBUG
- g_message (_("Shutting down the Tumbler Pixbuf Thumbnailer plugin"));
+ g_message (_("Shutting down the Tumbler GStreamer Thumbnailer plugin"));
#endif
}
diff --git a/plugins/gst-thumbnailer/gst-thumbnailer-provider.c b/plugins/gst-thumbnailer/gst-thumbnailer-provider.c
new file mode 100644
index 0000000..44285f8
--- /dev/null
+++ b/plugins/gst-thumbnailer/gst-thumbnailer-provider.c
@@ -0,0 +1,151 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*
+ * Copyright (c) 2011 Intel Corporation
+ *
+ * Author: Ross Burton <ross at linux.intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gst/gst.h>
+
+#include <tumbler/tumbler.h>
+
+#include <gst-thumbnailer/gst-thumbnailer-provider.h>
+#include <gst-thumbnailer/gst-thumbnailer.h>
+
+
+static void gst_thumbnailer_provider_thumbnailer_provider_init (TumblerThumbnailerProviderIface *iface);
+static GList *gst_thumbnailer_provider_get_thumbnailers (TumblerThumbnailerProvider *provider);
+
+
+struct _GstThumbnailerProviderClass
+{
+ GObjectClass __parent__;
+};
+
+struct _GstThumbnailerProvider
+{
+ GObject __parent__;
+};
+
+
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (GstThumbnailerProvider,
+ gst_thumbnailer_provider,
+ G_TYPE_OBJECT,
+ 0,
+ TUMBLER_ADD_INTERFACE (TUMBLER_TYPE_THUMBNAILER_PROVIDER,
+ gst_thumbnailer_provider_thumbnailer_provider_init));
+
+
+
+void
+gst_thumbnailer_provider_register (TumblerProviderPlugin *plugin)
+{
+ gst_thumbnailer_provider_register_type (G_TYPE_MODULE (plugin));
+}
+
+
+
+static void
+gst_thumbnailer_provider_class_init (GstThumbnailerProviderClass *klass)
+{
+}
+
+
+
+static void
+gst_thumbnailer_provider_class_finalize (GstThumbnailerProviderClass *klass)
+{
+}
+
+
+
+static void
+gst_thumbnailer_provider_thumbnailer_provider_init (TumblerThumbnailerProviderIface *iface)
+{
+ iface->get_thumbnailers = gst_thumbnailer_provider_get_thumbnailers;
+}
+
+
+
+static void
+gst_thumbnailer_provider_init (GstThumbnailerProvider *provider)
+{
+}
+
+static GList *
+gst_thumbnailer_provider_get_thumbnailers (TumblerThumbnailerProvider *provider)
+{
+ static const char *mime_types[] = {
+ /* This list is mainly from Totem. Generating a list from GStreamer isn't
+ realistic, so we have to hardcode it. */
+ "application/asx",
+ "application/ogg",
+ "application/x-flash-video",
+ "application/x-ms-wmp",
+ "application/x-ms-wms",
+ "application/x-ogg",
+ "video/3gpp",
+ "video/divx",
+ "video/flv",
+ "video/jpeg",
+ "video/mp4",
+ "video/mpeg",
+ "video/ogg",
+ "video/quicktime",
+ "video/x-flv",
+ "video/x-m4v",
+ "video/x-matroska",
+ "video/x-ms-asf",
+ "video/x-ms-wm",
+ "video/x-ms-wmp",
+ "video/x-ms-wmv",
+ "video/x-ms-wvx",
+ "video/x-msvideo",
+ "video/x-ogg",
+ "video/x-wmv",
+ NULL
+ };
+
+ GstThumbnailer *thumbnailer;
+ GStrv uri_schemes;
+ GError *error = NULL;
+
+ if (!gst_init_check (0, NULL, &error))
+ {
+ g_warning ("Cannot initialize GStreamer, thumbnailer not loaded: %s", error->message);
+ return NULL;
+ }
+
+ uri_schemes = tumbler_util_get_supported_uri_schemes ();
+
+ thumbnailer = g_object_new (TYPE_GST_THUMBNAILER,
+ "uri-schemes", uri_schemes,
+ "mime-types", mime_types,
+ NULL);
+
+ g_strfreev (uri_schemes);
+
+ return g_list_append (NULL, thumbnailer);
+}
diff --git a/plugins/gst-thumbnailer/gst-thumbnailer-provider.h b/plugins/gst-thumbnailer/gst-thumbnailer-provider.h
new file mode 100644
index 0000000..44ce46e
--- /dev/null
+++ b/plugins/gst-thumbnailer/gst-thumbnailer-provider.h
@@ -0,0 +1,45 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*
+ * Copyright (c) 2011 Intel Corporation
+ *
+ * Author: Ross Burton <ross at linux.intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_THUMBNAILER_PROVIDER_H__
+#define __GST_THUMBNAILER_PROVIDER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS;
+
+#define TYPE_GST_THUMBNAILER_PROVIDER (gst_thumbnailer_provider_get_type ())
+#define GST_THUMBNAILER_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_GST_THUMBNAILER_PROVIDER, GstThumbnailerProvider))
+#define GST_THUMBNAILER_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_GST_THUMBNAILER_PROVIDER, GstThumbnailerProviderClass))
+#define IS_GST_THUMBNAILER_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_GST_THUMBNAILER_PROVIDER))
+#define IS_GST_THUMBNAILER_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_GST_THUMBNAILER_PROVIDER)
+#define GST_THUMBNAILER_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_GST_THUMBNAILER_PROVIDER, GstThumbnailerProviderClass))
+
+typedef struct _GstThumbnailerProviderClass GstThumbnailerProviderClass;
+typedef struct _GstThumbnailerProvider GstThumbnailerProvider;
+
+GType gst_thumbnailer_provider_get_type (void) G_GNUC_CONST;
+void gst_thumbnailer_provider_register (TumblerProviderPlugin *plugin);
+
+G_END_DECLS;
+
+#endif /* !__GST_THUMBNAILER_PROVIDER_H__ */
diff --git a/plugins/gst-thumbnailer/gst-thumbnailer.c b/plugins/gst-thumbnailer/gst-thumbnailer.c
new file mode 100644
index 0000000..4f95694
--- /dev/null
+++ b/plugins/gst-thumbnailer/gst-thumbnailer.c
@@ -0,0 +1,389 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*
+ * Copyright (c) 2011 Intel Corporation
+ *
+ * Author: Ross Burton <ross at linux.intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <tumbler/tumbler.h>
+#include <gst/gst.h>
+
+#include "gst-thumbnailer.h"
+#include "gst-helper.h"
+
+#ifdef DEBUG
+#define LOG(...) g_message (__VA_ARGS__)
+#else
+#define LOG(...)
+#endif
+
+static void gst_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
+ GCancellable *cancellable,
+ TumblerFileInfo *info);
+
+struct _GstThumbnailerClass
+{
+ TumblerAbstractThumbnailerClass __parent__;
+};
+
+struct _GstThumbnailer
+{
+ TumblerAbstractThumbnailer __parent__;
+};
+
+
+G_DEFINE_DYNAMIC_TYPE (GstThumbnailer,
+ gst_thumbnailer,
+ TUMBLER_TYPE_ABSTRACT_THUMBNAILER);
+
+
+void
+gst_thumbnailer_register (TumblerProviderPlugin *plugin)
+{
+ gst_thumbnailer_register_type (G_TYPE_MODULE (plugin));
+}
+
+static void
+gst_thumbnailer_class_init (GstThumbnailerClass *klass)
+{
+ TumblerAbstractThumbnailerClass *abstractthumbnailer_class;
+
+ abstractthumbnailer_class = TUMBLER_ABSTRACT_THUMBNAILER_CLASS (klass);
+ abstractthumbnailer_class->create = gst_thumbnailer_create;
+}
+
+static void
+gst_thumbnailer_class_finalize (GstThumbnailerClass *klass)
+{
+}
+
+static void
+gst_thumbnailer_init (GstThumbnailer *thumbnailer)
+{
+}
+
+
+/*
+ * Determine if the image is "interesting" or not. This implementation reduces
+ * the RGB from 24 to 12 bits and examines the distribution of colours.
+ *
+ * This function is taken from Bickley, Copyright (c) Intel Corporation 2008.
+ */
+static gboolean
+is_interesting (GdkPixbuf *pixbuf)
+{
+ int width, height, y, rowstride;
+ gboolean has_alpha;
+ guint32 histogram[4][4][4] = {{{0,},},};
+ guchar *pixels;
+ guint pxl_count = 0, count, i;
+
+ g_assert (GDK_IS_PIXBUF (pixbuf));
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
+
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ for (y = 0; y < height; y++)
+ {
+ guchar *row = pixels + (y * rowstride);
+ int c;
+
+ for (c = 0; c < width; c++)
+ {
+ guchar r, g, b;
+
+ r = row[0];
+ g = row[1];
+ b = row[2];
+
+ histogram[r / 64][g / 64][b / 64]++;
+
+ if (has_alpha)
+ {
+ row += 4;
+ }
+ else
+ {
+ row += 3;
+ }
+
+ pxl_count++;
+ }
+ }
+
+ count = 0;
+ for (i = 0; i < 4; i++)
+ {
+ int j;
+ for (j = 0; j < 4; j++)
+ {
+ int k;
+
+ for (k = 0; k < 4; k++)
+ {
+ /* Count how many bins have more than
+ 1% of the pixels in the histogram */
+ if (histogram[i][j][k] > pxl_count / 100)
+ count++;
+ }
+ }
+ }
+
+ /* Image is boring if there is only 1 bin with > 1% of pixels */
+ return count > 1;
+}
+
+/*
+ * Construct a pipline for a given @info, cancelling during initialisation on
+ * @cancellable. This function will either return a #GstElement that has been
+ * prerolled and is in the paused state, or %NULL if the initialisation is
+ * cancelled or an error occurs.
+ */
+static GstElement *
+make_pipeline (TumblerFileInfo *info, GCancellable *cancellable)
+{
+ GstElement *playbin, *audio_sink, *video_sink;
+ int count = 0, n_video = 0;
+ GstStateChangeReturn state;
+
+ g_assert (info);
+
+ playbin = gst_element_factory_make ("playbin2", "playbin");
+ g_assert (playbin);
+ audio_sink = gst_element_factory_make ("fakesink", "audiosink");
+ g_assert (audio_sink);
+ video_sink = gst_element_factory_make ("fakesink", "videosink");
+ g_assert (video_sink);
+
+ g_object_set (playbin,
+ "uri", tumbler_file_info_get_uri (info),
+ "audio-sink", audio_sink,
+ "video-sink", video_sink,
+ NULL);
+
+ g_object_set (video_sink,
+ "sync", TRUE,
+ NULL);
+
+ /* Change to paused state so we're ready to seek */
+ state = gst_element_set_state (playbin, GST_STATE_PAUSED);
+ while (state == GST_STATE_CHANGE_ASYNC
+ && count < 5
+ && !g_cancellable_is_cancelled (cancellable))
+ {
+ state = gst_element_get_state (playbin, NULL, 0, 1 * GST_SECOND);
+ count++;
+
+ /* Spin mainloop so we can pick up the cancels */
+ while (g_main_context_pending (NULL))
+ g_main_context_iteration (NULL, FALSE);
+ }
+
+ if (state == GST_STATE_CHANGE_FAILURE || state == GST_STATE_CHANGE_ASYNC)
+ {
+ LOG ("failed to or still changing state, aborting (state change %d)", state);
+ g_object_unref (playbin);
+ return NULL;
+ }
+
+ g_object_get (playbin, "n-video", &n_video, NULL);
+ if (n_video == 0)
+ {
+ LOG ("no video stream, aborting");
+ g_object_unref (playbin);
+ return NULL;
+ }
+
+ return playbin;
+}
+
+/*
+ * Get the total duration in nanoseconds of the stream.
+ */
+static gint64
+get_duration (GstElement *playbin)
+{
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 duration = 0;
+
+ g_assert (playbin);
+
+ gst_element_query_duration (playbin, &format, &duration);
+
+ return duration;
+}
+
+/*
+ * Generate a thumbnail for @info.
+ */
+static void
+gst_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
+ GCancellable *cancellable,
+ TumblerFileInfo *info)
+{
+ /* These positions are taken from Totem */
+ const double positions[] = {
+ 1.0 / 3.0,
+ 2.0 / 3.0,
+ 0.1,
+ 0.9,
+ 0.5
+ };
+ GstElement *playbin;
+ gint64 duration;
+ unsigned int i;
+ GstBuffer *frame;
+ GdkPixbuf *shot;
+ TumblerThumbnail *thumbnail;
+ TumblerThumbnailFlavor *flavour;
+ TumblerImageData data;
+ GError *error = NULL;
+
+ g_return_if_fail (IS_GST_THUMBNAILER (thumbnailer));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ g_return_if_fail (TUMBLER_IS_FILE_INFO (info));
+
+ /* Check for early cancellation */
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
+
+ playbin = make_pipeline (info, cancellable);
+ if (playbin == NULL)
+ {
+ /* TODO: emit an error, but the specification won't let me. */
+ return;
+ }
+
+ duration = get_duration (playbin);
+
+ /* Now we have a pipeline that we know has video and is paused, ready for
+ seeking. Try to find an interesting frame at each of the positions in
+ order. */
+ for (i = 0; i < G_N_ELEMENTS (positions); i++)
+ {
+ /* Check if we've been cancelled */
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ gst_element_set_state (playbin, GST_STATE_NULL);
+ g_object_unref (playbin);
+ return;
+ }
+
+ LOG ("trying position %f", positions[i]);
+
+ gst_element_seek_simple (playbin,
+ GST_FORMAT_TIME,
+ GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,
+ (gint64)(positions[i] * duration));
+
+ if (gst_element_get_state (playbin, NULL, NULL, 1 * GST_SECOND)
+ == GST_STATE_CHANGE_FAILURE)
+ {
+ LOG ("Could not seek");
+ gst_element_set_state (playbin, GST_STATE_NULL);
+ g_object_unref (playbin);
+ return;
+ }
+
+ g_object_get (playbin, "frame", &frame, NULL);
+
+ if (frame == NULL)
+ {
+ LOG ("No frame found!");
+ gst_element_set_state (playbin, GST_STATE_NULL);
+ g_object_unref (playbin);
+ continue;
+ }
+
+ thumbnail = tumbler_file_info_get_thumbnail (info);
+ flavour = tumbler_thumbnail_get_flavor (thumbnail);
+ /* This frees the buffer for us */
+ shot = gst_helper_convert_buffer_to_pixbuf (frame, cancellable, flavour);
+ g_object_unref (flavour);
+
+ /* If it's not interesting, throw it away and try again*/
+ if (is_interesting (shot))
+ {
+ /* Got an interesting image, break out */
+ LOG ("Found an interesting image");
+ break;
+ }
+
+ /*
+ * If we've still got positions to try, free the current uninteresting
+ * shot. Otherwise we'll make do with what we have.
+ */
+ if (i + 1 < G_N_ELEMENTS (positions) && shot)
+ {
+ g_object_unref (shot);
+ shot = NULL;
+ }
+
+ /* Spin mainloop so we can pick up the cancels */
+ while (g_main_context_pending (NULL))
+ {
+ g_main_context_iteration (NULL, FALSE);
+ }
+ }
+
+ gst_element_set_state (playbin, GST_STATE_NULL);
+ g_object_unref (playbin);
+
+ if (shot)
+ {
+ data.data = gdk_pixbuf_get_pixels (shot);
+ data.has_alpha = gdk_pixbuf_get_has_alpha (shot);
+ data.bits_per_sample = gdk_pixbuf_get_bits_per_sample (shot);
+ data.width = gdk_pixbuf_get_width (shot);
+ data.height = gdk_pixbuf_get_height (shot);
+ data.rowstride = gdk_pixbuf_get_rowstride (shot);
+ data.colorspace = (TumblerColorspace) gdk_pixbuf_get_colorspace (shot);
+
+ tumbler_thumbnail_save_image_data (thumbnail, &data,
+ tumbler_file_info_get_mtime (info),
+ NULL, &error);
+
+ g_object_unref (shot);
+
+ if (error != NULL)
+ {
+ g_signal_emit_by_name (thumbnailer, "error",
+ tumbler_file_info_get_uri (info),
+ error->code, error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ g_signal_emit_by_name (thumbnailer, "ready",
+ tumbler_file_info_get_uri (info));
+ }
+ }
+}
diff --git a/plugins/gst-thumbnailer/gst-thumbnailer.h b/plugins/gst-thumbnailer/gst-thumbnailer.h
new file mode 100644
index 0000000..c587f63
--- /dev/null
+++ b/plugins/gst-thumbnailer/gst-thumbnailer.h
@@ -0,0 +1,45 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*
+ * Copyright (c) 2011 Intel Corporation
+ *
+ * Author: Ross Burton <ross at linux.intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_THUMBNAILER_H__
+#define __GST_THUMBNAILER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS;
+
+#define TYPE_GST_THUMBNAILER (gst_thumbnailer_get_type ())
+#define GST_THUMBNAILER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_GST_THUMBNAILER, GstThumbnailer))
+#define GST_THUMBNAILER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_GST_THUMBNAILER, GstThumbnailerClass))
+#define IS_GST_THUMBNAILER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_GST_THUMBNAILER))
+#define IS_GST_THUMBNAILER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_GST_THUMBNAILER)
+#define GST_THUMBNAILER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_GST_THUMBNAILER, GstThumbnailerClass))
+
+typedef struct _GstThumbnailerClass GstThumbnailerClass;
+typedef struct _GstThumbnailer GstThumbnailer;
+
+GType gst_thumbnailer_get_type (void) G_GNUC_CONST;
+void gst_thumbnailer_register (TumblerProviderPlugin *plugin);
+
+G_END_DECLS;
+
+#endif /* !__GST_THUMBNAILER_H__ */
More information about the Xfce4-commits
mailing list