[gthumb/ext: 1/18] read audio/video metadata with gstreamer



commit 4724dc5fe9e355f25f688ac2fd6e1a2d4168085c
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sun Nov 1 21:09:42 2009 +0100

    read audio/video metadata with gstreamer

 configure.ac                                       |   19 +
 extensions/Makefile.am                             |    1 +
 extensions/gstreamer/Makefile.am                   |   34 +
 extensions/gstreamer/gstreamer-utils.c             |  690 ++++++++++++++++++++
 extensions/gstreamer/gstreamer-utils.h             |   38 ++
 extensions/gstreamer/gstreamer.extension.in.in     |   10 +
 .../gstreamer/gth-metadata-provider-gstreamer.c    |  135 ++++
 .../gstreamer/gth-metadata-provider-gstreamer.h    |   54 ++
 extensions/gstreamer/main.c                        |   88 +++
 extensions/image_viewer/main.c                     |    2 +-
 gthumb/Makefile.am                                 |    1 +
 11 files changed, 1071 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 1b1eaf1..4339a65 100644
--- a/configure.ac
+++ b/configure.ac
@@ -31,6 +31,7 @@ GCONF_REQUIRED=2.6.0
 EXIV2_REQUIRED=0.18
 CLUTTER_REQUIRED=1.0.0
 CLUTTER_GTK_REQUIRED=0.10.0
+GSTREAMER_REQUIRED=0.10
 
 dnl ===========================================================================
 
@@ -133,6 +134,22 @@ AM_CONDITIONAL(ENABLE_CLUTTER, test "x$enable_clutter" = xyes)
 
 dnl ===========================================================================
 
+AC_ARG_ENABLE([gstreamer],
+	      [AS_HELP_STRING([--disable-gstreamer],[do not compile code that uses the gstreamer library])],,
+	      [enable_gstreamer=yes])
+
+if test x$enable_gstreamer = xyes ; then
+	PKG_CHECK_MODULES(GSTREAMER,
+			  [gstreamer-0.10 >= $GSTREAMER_REQUIRED],
+			  [enable_gstreamer=yes],
+			  [enable_gstreamer=no])
+fi
+AC_SUBST(GSTREAMER_LIBS)
+AC_SUBST(GSTREAMER_CFLAGS)
+AM_CONDITIONAL(ENABLE_GSTREAMER, test "x$enable_gstreamer" = xyes)
+
+dnl ===========================================================================
+
 IT_PROG_INTLTOOL([0.35.0])
 GETTEXT_PACKAGE=gthumb
 AC_SUBST([GETTEXT_PACKAGE])
@@ -295,6 +312,7 @@ extensions/file_tools/Makefile
 extensions/file_tools/data/Makefile
 extensions/file_tools/data/ui/Makefile
 extensions/file_viewer/Makefile
+extensions/gstreamer/Makefile
 extensions/image_rotation/Makefile
 extensions/image_viewer/Makefile
 extensions/image_viewer/data/Makefile
@@ -346,4 +364,5 @@ Configuration:
 	JPEG tools           : ${enable_jpeg}
 	TIFF tools           : ${enable_tiff}
 	Clutter support      : ${enable_clutter}
+	GStreamer support    : ${enable_gstreamer}
 "
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index 6a326f0..91bad31 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -7,6 +7,7 @@ SUBDIRS = 			\
 	file_manager		\
 	file_tools		\
 	file_viewer		\
+	gstreamer		\
 	image_rotation		\
 	image_viewer		\
 	jpeg_utils		\
diff --git a/extensions/gstreamer/Makefile.am b/extensions/gstreamer/Makefile.am
new file mode 100644
index 0000000..a1b1774
--- /dev/null
+++ b/extensions/gstreamer/Makefile.am
@@ -0,0 +1,34 @@
+if ENABLE_GSTREAMER
+
+extensiondir = $(libdir)/gthumb-2.0/extensions
+extension_LTLIBRARIES = libgstreamer.la
+
+libgstreamer_la_SOURCES = 			\
+	gstreamer-utils.c			\
+	gstreamer-utils.h			\
+	gth-metadata-provider-gstreamer.c	\
+	gth-metadata-provider-gstreamer.h	\
+	main.c
+
+libgstreamer_la_CPPFLAGS = $(GTHUMB_CFLAGS) $(GSTREAMER_CFLAGS) $(DISABLE_DEPRECATED) $(WARNINGS) -I$(top_srcdir) -I$(top_builddir)/gthumb 
+libgstreamer_la_LDFLAGS = $(EXTENSION_LIBTOOL_FLAGS)
+libgstreamer_la_LIBADD = $(GTHUMB_LIBS) 
+libgstreamer_la_DEPENDENCIES = $(top_builddir)/gthumb/gthumb$(EXEEXT)
+
+extensioninidir = $(extensiondir)
+extensionini_in_files = gstreamer.extension.in.in
+extensionini_DATA = $(extensionini_in_files:.extension.in.in=.extension)
+
+%.extension.in: %.extension.in.in $(extension_LTLIBRARIES)
+	sed -e "s|%LIBRARY%|`. ./$(extension_LTLIBRARIES) && echo $$dlname`|" \
+	$< > $@
+
+%.extension: %.extension.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+
+EXTRA_DIST = $(extensionini_in_files) 
+
+DISTCLEANFILES = $(extensionini_DATA)
+
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/extensions/gstreamer/gstreamer-utils.c b/extensions/gstreamer/gstreamer-utils.c
new file mode 100644
index 0000000..66c9ca5
--- /dev/null
+++ b/extensions/gstreamer/gstreamer-utils.c
@@ -0,0 +1,690 @@
+/* -*- Mode: CPP; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2008-2009 Free Software Foundation, Inc.
+ *
+ *  This program 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.
+ *
+ *  This program 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+/* This was based on a file from Tracker */
+/*
+ * Tracker - audio/video metadata extraction based on GStreamer
+ * Copyright (C) 2006, Laurent Aguerreche (laurent aguerreche free fr)
+ *
+ * This program 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.
+ *
+ * This program 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 <gst/gst.h>
+#include <gthumb.h>
+#include "gstreamer-utils.h"
+
+
+static gboolean gstreamer_initialized = FALSE;
+
+
+typedef struct {
+	GstElement	*playbin;
+
+	GstTagList	*tagcache;
+	GstTagList	*audiotags;
+	GstTagList	*videotags;
+	GstTagList	*demuxertags;
+
+	gboolean	has_audio;
+	gboolean	has_video;
+
+	gint		video_height;
+	gint		video_width;
+	gint		video_fps_n;
+	gint		video_fps_d;
+	gint		video_bitrate;
+	char           *video_codec;
+	gint		audio_channels;
+	gint		audio_samplerate;
+	gint		audio_bitrate;
+	char           *audio_codec;
+} MetadataExtractor;
+
+
+static void
+reset_extractor_data (MetadataExtractor *extractor)
+{
+	if (extractor->tagcache != NULL) {
+		gst_tag_list_free (extractor->tagcache);
+		extractor->tagcache = NULL;
+	}
+
+	if (extractor->audiotags != NULL) {
+		gst_tag_list_free (extractor->audiotags);
+		extractor->audiotags = NULL;
+	}
+
+	if (extractor->videotags != NULL) {
+		gst_tag_list_free (extractor->videotags);
+		extractor->videotags = NULL;
+	}
+
+	if (extractor->demuxertags != NULL) {
+		gst_tag_list_free (extractor->demuxertags);
+		extractor->demuxertags = NULL;
+	}
+
+	g_free (extractor->audio_codec);
+	extractor->audio_codec = NULL;
+
+	g_free (extractor->video_codec);
+	extractor->video_codec = NULL;
+
+	extractor->has_audio = FALSE;
+	extractor->has_video = FALSE;
+	extractor->video_fps_n = -1;
+	extractor->video_fps_d = -1;
+	extractor->video_height = -1;
+	extractor->video_width = -1;
+	extractor->video_bitrate = -1;
+	extractor->audio_channels = -1;
+	extractor->audio_samplerate = -1;
+	extractor->audio_bitrate = -1;
+}
+
+
+static void
+metadata_extractor_free (MetadataExtractor *extractor)
+{
+	reset_extractor_data (extractor);
+	gst_element_set_state (extractor->playbin, GST_STATE_NULL);
+	gst_object_unref (GST_OBJECT (extractor->playbin));
+	g_slice_free (MetadataExtractor, extractor);
+}
+
+
+static gboolean
+gstreamer_init (void)
+{
+	if (! gstreamer_initialized) {
+		if (! gst_init_check (NULL, NULL, NULL))
+			return FALSE;
+		gstreamer_initialized = TRUE;
+	}
+
+	return TRUE;
+}
+
+
+static void
+add_metadata (GFileInfo  *info,
+              const char *key,
+              char       *raw,
+              char       *formatted)
+{
+	GthMetadata *metadata;
+
+	if (raw == NULL)
+		return;
+
+	metadata = gth_metadata_new ();
+	g_object_set (metadata,
+		      "id", key,
+		      "formatted", formatted != NULL ? formatted : raw,
+		      "raw", raw,
+		      NULL);
+	g_file_info_set_attribute_object (info, key, G_OBJECT (metadata));
+
+	g_object_unref (metadata);
+	g_free (raw);
+	g_free (formatted);
+}
+
+
+static void
+add_metadata_from_tag (GFileInfo         *info,
+		       const GstTagList  *list,
+		       const char        *tag,
+		       const char        *tag_key)
+{
+	GType tag_type;
+
+	tag_type = gst_tag_get_type (tag);
+
+	if (tag_type == G_TYPE_BOOLEAN) {
+		gboolean ret;
+		if (gst_tag_list_get_boolean (list, tag, &ret)) {
+			if (ret)
+				add_metadata (info, tag_key, g_strdup ("TRUE"), NULL);
+			else
+				add_metadata (info, tag_key, g_strdup ("FALSE"), NULL);
+		}
+	}
+
+	if (tag_type == G_TYPE_STRING) {
+		char *ret = NULL;
+		if (gst_tag_list_get_string (list, tag, &ret))
+			add_metadata (info, tag_key, ret, NULL);
+	}
+
+        if (tag_type == G_TYPE_UCHAR) {
+                guchar ret = 0;
+                if (gst_tag_list_get_uchar (list, tag, &ret))
+                        add_metadata (info, tag_key, g_strdup_printf ("%u", ret), NULL);
+        }
+
+        if (tag_type == G_TYPE_CHAR) {
+                gchar ret = 0;
+                if (gst_tag_list_get_char (list, tag, &ret))
+                        add_metadata (info, tag_key, g_strdup_printf ("%d", ret), NULL);
+        }
+
+        if (tag_type == G_TYPE_UINT) {
+                guint ret = 0;
+                if (gst_tag_list_get_uint (list, tag, &ret))
+                        add_metadata (info, tag_key, g_strdup_printf ("%u", ret), NULL);
+        }
+
+        if (tag_type == G_TYPE_INT) {
+                gint ret = 0;
+                if (gst_tag_list_get_int (list, tag, &ret))
+                        add_metadata (info, tag_key, g_strdup_printf ("%d", ret), NULL);
+        }
+
+        if (tag_type == G_TYPE_ULONG) {
+                gulong ret = 0;
+                if (gst_tag_list_get_ulong (list, tag, &ret))
+                        add_metadata (info, tag_key, g_strdup_printf ("%lu", ret), NULL);
+        }
+
+        if (tag_type == G_TYPE_LONG) {
+                glong ret = 0;
+                if (gst_tag_list_get_long (list, tag, &ret))
+                        add_metadata (info, tag_key, g_strdup_printf ("%ld", ret), NULL);
+        }
+
+        if (tag_type == G_TYPE_INT64) {
+                gint64 ret = 0;
+                if (gst_tag_list_get_int64 (list, tag, &ret))
+                        add_metadata (info, tag_key, g_strdup_printf ("%" G_GINT64_FORMAT, ret), NULL);
+        }
+
+        if (tag_type == G_TYPE_UINT64) {
+                guint64 ret = 0;
+                if (gst_tag_list_get_uint64 (list, tag, &ret))
+                        add_metadata (info, tag_key, g_strdup_printf ("%" G_GUINT64_FORMAT, ret), NULL);
+        }
+
+        if (tag_type == G_TYPE_DOUBLE) {
+                gdouble ret = 0;
+                if (gst_tag_list_get_double (list, tag, &ret))
+                        add_metadata (info, tag_key, g_strdup_printf ("%f", ret), NULL);
+        }
+
+        if (tag_type == G_TYPE_FLOAT) {
+                gfloat ret = 0;
+                if (gst_tag_list_get_float (list, tag, &ret))
+                        add_metadata (info, tag_key, g_strdup_printf ("%f", ret), NULL);
+        }
+
+        if (tag_type == G_TYPE_DATE) {
+                GDate *ret = NULL;
+                if (gst_tag_list_get_date (list, tag, &ret)) {
+			if (ret != NULL) {
+				char  buf[128];
+				char *raw;
+				char *formatted;
+
+				g_date_strftime (buf, 10, "%F %T", ret);
+				raw = g_strdup (buf);
+
+				g_date_strftime (buf, 10, "%x %X", ret);
+				formatted = g_strdup (buf);
+				add_metadata (info, tag_key, raw, formatted);
+			}
+			g_free (ret);
+		}
+        }
+}
+
+
+static void
+tag_iterate (const GstTagList *list,
+	     const char       *tag,
+	     GFileInfo        *info)
+{
+	const char *tag_key;
+	char       *attribute = NULL;
+
+	tag_key = NULL;
+
+	if (strcmp (tag, "container-format") == 0) {
+		tag_key = "audio-video::general::container-format";
+	}
+	else if (strcmp (tag, "encoder") == 0) {
+		tag_key = "audio-video::general::encoder";
+	}
+	else if (strcmp (tag, "title") == 0) {
+		tag_key = "audio-video::general::title";
+	}
+	else if (strcmp (tag, "artist") == 0) {
+		tag_key = "audio-video::general::artist";
+	}
+	else if (strcmp (tag, "album") == 0) {
+		tag_key = "audio-video::general::album";
+	}
+	else if (strcmp (tag, "audio-codec") == 0) {
+		tag_key = "audio-video::audio::codec";
+	}
+	else if (strcmp (tag, "video-codec") == 0) {
+		tag_key = "audio-video::video::codec";
+	}
+
+	if (tag_key == NULL) {
+		GthMetadataInfo *metadata_info;
+
+		attribute = g_strconcat ("audio-video::other::", tag, NULL);
+		metadata_info = gth_main_get_metadata_info (attribute);
+		if (metadata_info == NULL) {
+			GthMetadataInfo info;
+
+			info.id = attribute;
+			info.display_name = gst_tag_get_nick (tag);
+			info.category = "audio-video::other";
+			info.sort_order = 500;
+			info.flags = GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW;
+			metadata_info = gth_main_register_metadata_info (&info);
+		}
+
+		tag_key = attribute;
+	}
+
+	add_metadata_from_tag (info, list, tag, tag_key);
+
+	g_free (attribute);
+}
+
+
+static gint64
+get_media_duration (MetadataExtractor *extractor)
+{
+	GstFormat fmt;
+	gint64	  duration;
+
+	g_return_val_if_fail (extractor, -1);
+	g_return_val_if_fail (extractor->playbin, -1);
+
+	fmt = GST_FORMAT_TIME;
+	duration = -1;
+	if (gst_element_query_duration (extractor->playbin, &fmt, &duration) && (duration >= 0))
+		return duration / GST_SECOND;
+	else
+		return -1;
+}
+
+
+static void
+extract_metadata (MetadataExtractor *extractor,
+		  GFileInfo         *info)
+{
+	gint64 duration;
+
+	if (extractor->audio_channels >= 0)
+		add_metadata (info,
+			      "audio-video::audio::channels",
+			      g_strdup_printf ("%d", (guint) extractor->audio_channels),
+			      g_strdup (extractor->audio_channels == 2 ? _("Stereo") : _("Mono")));
+
+        if (extractor->audio_samplerate >= 0)
+                add_metadata (info,
+                              "audio-video::audio::samplerate",
+                              g_strdup_printf ("%d", (guint) extractor->audio_samplerate),
+                              g_strdup_printf ("%d Hz", (guint) extractor->audio_samplerate));
+
+        if (extractor->audio_bitrate >= 0)
+                add_metadata (info,
+                              "audio-video::audio::bitrate",
+                              g_strdup_printf ("%d", (guint) extractor->audio_bitrate),
+                              g_strdup_printf ("%d bps", (guint) extractor->audio_bitrate));
+
+        if (extractor->video_height >= 0)
+                add_metadata (info,
+                	      "audio-video::video::height",
+                	      g_strdup_printf ("%d", (guint) extractor->video_height),
+                	      NULL);
+
+        if (extractor->video_width >= 0)
+                add_metadata (info,
+                	      "audio-video::video::width",
+                	      g_strdup_printf ("%d", (guint) extractor->video_width),
+                	      NULL);
+
+        if ((extractor->video_height >= 0) && (extractor->video_width >= 0))
+                add_metadata (info,
+                	      "audio-video::video::size",
+                	      g_strdup_printf ("%d x %d", (guint) extractor->video_width, (guint) extractor->video_height),
+                	      NULL);
+
+        if ((extractor->video_fps_n >= 0) && (extractor->video_fps_d >= 0))
+                add_metadata (info,
+                              "audio-video::video::framerate",
+                              g_strdup_printf ("%.7g", (gdouble) extractor->video_fps_n / (gdouble) extractor->video_fps_d),
+                              g_strdup_printf ("%.7g fps", (gdouble) extractor->video_fps_n / (gdouble) extractor->video_fps_d));
+
+        if (extractor->video_bitrate >= 0)
+                add_metadata (info,
+                              "audio-video::video::bitrate",
+                              g_strdup_printf ("%d", (guint) extractor->video_bitrate),
+                              g_strdup_printf ("%d bps", (guint) extractor->video_bitrate));
+
+	duration = get_media_duration (extractor);
+	if (duration >= 0)
+		add_metadata (info,
+			      "audio-video::general::duration",
+			      g_strdup_printf ("%" G_GINT64_FORMAT, duration),
+			      g_strdup_printf ("%" G_GINT64_FORMAT " sec", duration));
+
+	if (extractor->tagcache != NULL)
+		gst_tag_list_foreach (extractor->tagcache, (GstTagForeachFunc) tag_iterate, info);
+}
+
+
+static void
+caps_set (GstPad           *pad,
+	  MetadataExtractor *extractor,
+	  const char        *type)
+{
+	GstCaps	     *caps;
+	GstStructure *structure;
+
+	if ((caps = gst_pad_get_negotiated_caps (pad)) == NULL)
+		return;
+
+	structure = gst_caps_get_structure (caps, 0);
+	if (structure == NULL) {
+		gst_caps_unref (caps);
+		return;
+	}
+
+	if (strcmp (type, "audio") == 0) {
+		gst_structure_get_int (structure, "channels", &extractor->audio_channels);
+		gst_structure_get_int (structure, "rate", &extractor->audio_samplerate);
+		gst_structure_get_int (structure, "bitrate", &extractor->audio_bitrate);
+	}
+	else if (strcmp (type, "video") == 0) {
+		gst_structure_get_fraction (structure, "framerate", &extractor->video_fps_n, &extractor->video_fps_d);
+		gst_structure_get_int (structure, "bitrate", &extractor->video_bitrate);
+		gst_structure_get_int (structure, "width", &extractor->video_width);
+		gst_structure_get_int (structure, "height", &extractor->video_height);
+	}
+
+	gst_caps_unref (caps);
+}
+
+
+static void
+update_stream_info (MetadataExtractor *extractor)
+{
+	GList  *streaminfo;
+	GstPad *audiopad;
+	GstPad *videopad;
+
+	g_return_if_fail (extractor);
+
+	streaminfo = NULL;
+	audiopad = videopad = NULL;
+
+	g_object_get (extractor->playbin, "stream-info", &streaminfo, NULL);
+	streaminfo = g_list_copy (streaminfo);
+	g_list_foreach (streaminfo, (GFunc) g_object_ref, NULL);
+
+	for (/* void */ ; streaminfo; streaminfo = streaminfo->next) {
+		GObject    *info;
+		int         type;
+		GParamSpec *pspec;
+		GEnumValue *val;
+
+		info = streaminfo->data;
+		if (info == NULL)
+			continue;
+
+                type = -1;
+
+		g_object_get (info, "type", &type, NULL);
+		pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (info), "type");
+		val = g_enum_get_value (G_PARAM_SPEC_ENUM (pspec)->enum_class, type);
+
+		if (strcmp (val->value_nick, "audio") == 0) {
+			extractor->has_audio = TRUE;
+			if (audiopad == NULL)
+				g_object_get (info, "object", &audiopad, NULL);
+		}
+		else if (strcmp (val->value_nick, "video") == 0) {
+			extractor->has_video = TRUE;
+			if (videopad == NULL)
+				g_object_get (info, "object", &videopad, NULL);
+		}
+	}
+
+	if (audiopad != NULL) {
+		GstCaps *caps;
+
+		if ((caps = gst_pad_get_negotiated_caps (audiopad)) != NULL) {
+			caps_set (audiopad, extractor, "audio");
+			gst_caps_unref (caps);
+		}
+	}
+
+	if (videopad != NULL) {
+		GstCaps *caps;
+
+		if ((caps = gst_pad_get_negotiated_caps (videopad)) != NULL) {
+			caps_set (videopad, extractor, "video");
+			gst_caps_unref (caps);
+		}
+	}
+
+	g_list_foreach (streaminfo, (GFunc) g_object_unref, NULL);
+	g_list_free (streaminfo);
+}
+
+
+static gboolean
+message_loop_to_state_change (MetadataExtractor *extractor,
+			      GstState           state)
+{
+	GstBus         *bus;
+	GstMessageType  events;
+
+	g_return_val_if_fail (extractor, FALSE);
+	g_return_val_if_fail (extractor->playbin, FALSE);
+
+	bus = gst_element_get_bus (extractor->playbin);
+
+	events = (GST_MESSAGE_TAG | GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
+
+	for (;;) {
+		GstMessage *message;
+
+		message = gst_bus_timed_pop_filtered (bus, GST_SECOND * 5, events);
+		if (message == NULL)
+			goto timed_out;
+
+		switch (GST_MESSAGE_TYPE (message)) {
+		case GST_MESSAGE_STATE_CHANGED: {
+			GstState old_state;
+			GstState new_state;
+
+			old_state = new_state = GST_STATE_NULL;
+
+			gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
+			if (old_state == new_state)
+				break;
+
+			/* we only care about playbin (pipeline) state changes */
+			if (GST_MESSAGE_SRC (message) != GST_OBJECT (extractor->playbin))
+				break;
+
+			if ((old_state == GST_STATE_READY) && (new_state == GST_STATE_PAUSED))
+				update_stream_info (extractor);
+			else if ((old_state == GST_STATE_PAUSED) && (new_state == GST_STATE_READY))
+				reset_extractor_data (extractor);
+
+			if (new_state == state) {
+				gst_message_unref (message);
+				goto success;
+			}
+
+			break;
+		}
+
+		case GST_MESSAGE_TAG: {
+			GstTagList	  *tag_list;
+			GstTagList        *result;
+			GstElementFactory *f;
+
+			tag_list = NULL;
+			gst_message_parse_tag (message, &tag_list);
+
+			/* all tags */
+
+			result = gst_tag_list_merge (extractor->tagcache, tag_list, GST_TAG_MERGE_KEEP);
+			if (extractor->tagcache != NULL)
+				gst_tag_list_free (extractor->tagcache);
+			extractor->tagcache = result;
+
+			/* media-type-specific tags */
+
+			if (GST_IS_ELEMENT (message->src) && (f = gst_element_get_factory (GST_ELEMENT (message->src)))) {
+				const char  *klass;
+				GstTagList **cache;
+
+				klass = gst_element_factory_get_klass (f);
+
+				cache = NULL;
+				if (g_strrstr (klass, "Audio"))
+					cache = &extractor->audiotags;
+				else if (g_strrstr (klass, "Video"))
+					cache = &extractor->videotags;
+				else if (g_strrstr (klass, "Demuxer"))
+					cache = &extractor->demuxertags;
+
+				if (cache != NULL) {
+					result = gst_tag_list_merge (*cache, tag_list, GST_TAG_MERGE_KEEP);
+					if (*cache != NULL)
+						gst_tag_list_free (*cache);
+					*cache = result;
+				}
+			}
+
+			/* clean up */
+			gst_tag_list_free (tag_list);
+
+			break;
+		}
+
+		case GST_MESSAGE_ERROR: {
+			gchar  *debug    = NULL;
+			GError *gsterror = NULL;
+
+			gst_message_parse_error (message, &gsterror, &debug);
+
+			g_warning ("Error: %s (%s)", gsterror->message, debug);
+
+			g_error_free (gsterror);
+			gst_message_unref (message);
+			g_free (debug);
+			goto error;
+		}
+			break;
+
+		case GST_MESSAGE_EOS: {
+			g_warning ("Media file could not be played.");
+			gst_message_unref (message);
+			goto error;
+		}
+			break;
+
+		default:
+			g_assert_not_reached ();
+			break;
+		}
+
+		gst_message_unref (message);
+	}
+
+	g_assert_not_reached ();
+
+ success:
+	/* state change succeeded */
+	GST_DEBUG ("state change to %s succeeded", gst_element_state_get_name (state));
+	return TRUE;
+
+ timed_out:
+	/* it's taking a long time to open  */
+	GST_DEBUG ("state change to %s timed out, returning success", gst_element_state_get_name (state));
+	return TRUE;
+
+ error:
+	GST_DEBUG ("error while waiting for state change to %s", gst_element_state_get_name (state));
+	/* already set *error */
+	return FALSE;
+}
+
+
+gboolean
+gstreamer_read_metadata_from_file (GFile       *file,
+				   GFileInfo   *info,
+				   GError     **error)
+{
+	char              *uri;
+	MetadataExtractor *extractor;
+
+	if (! gstreamer_init ())
+		return FALSE;
+
+	uri = g_file_get_uri (file);
+	g_return_val_if_fail (uri != NULL, FALSE);
+
+	extractor = g_slice_new0 (MetadataExtractor);
+	reset_extractor_data (extractor);
+
+	extractor->playbin = gst_element_factory_make ("playbin", "playbin");
+	g_object_set (G_OBJECT (extractor->playbin),
+		      "uri", uri,
+		      "audio-sink", gst_element_factory_make ("fakesink", "fakesink-audio"),
+		      "video-sink", gst_element_factory_make ("fakesink", "fakesink-video"),
+		      NULL);
+
+	gst_element_set_state (extractor->playbin, GST_STATE_PAUSED);
+	message_loop_to_state_change (extractor, GST_STATE_PAUSED);
+	extract_metadata (extractor, info);
+
+	metadata_extractor_free (extractor);
+	g_free (uri);
+
+	return TRUE;
+}
diff --git a/extensions/gstreamer/gstreamer-utils.h b/extensions/gstreamer/gstreamer-utils.h
new file mode 100644
index 0000000..d5d98b0
--- /dev/null
+++ b/extensions/gstreamer/gstreamer-utils.h
@@ -0,0 +1,38 @@
+/* -*- Mode: CPP; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ *  This program 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.
+ *
+ *  This program 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GSTREAMER_UTILS_H
+#define GSTREAMER_UTILS_H
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+gboolean  gstreamer_read_metadata_from_file (GFile       *file,
+					     GFileInfo   *info,
+					     GError     **error);
+
+G_END_DECLS
+
+#endif /* GSTREAMER_UTILS_H */
diff --git a/extensions/gstreamer/gstreamer.extension.in.in b/extensions/gstreamer/gstreamer.extension.in.in
new file mode 100644
index 0000000..79c375b
--- /dev/null
+++ b/extensions/gstreamer/gstreamer.extension.in.in
@@ -0,0 +1,10 @@
+[Extension]
+_Name=Audio/Video support
+_Description=Play audio and video files.
+_Authors=gthumb development team
+Copyright=Copyright © 2009 The Free Software Foundation, Inc.
+Version=1.0
+
+[Loader]
+Type=module
+File=%LIBRARY%
diff --git a/extensions/gstreamer/gth-metadata-provider-gstreamer.c b/extensions/gstreamer/gth-metadata-provider-gstreamer.c
new file mode 100644
index 0000000..f5e003d
--- /dev/null
+++ b/extensions/gstreamer/gth-metadata-provider-gstreamer.c
@@ -0,0 +1,135 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ *  This program 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.
+ *
+ *  This program 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n.h>
+#include <glib.h>
+#include <gthumb.h>
+#include "gstreamer-utils.h"
+#include "gth-metadata-provider-gstreamer.h"
+
+
+#define GTH_METADATA_PROVIDER_GSTREAMER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTH_TYPE_METADATA_PROVIDER_GSTREAMER, GthMetadataProviderGstreamerPrivate))
+
+
+struct _GthMetadataProviderGstreamerPrivate {
+	int dummy;
+};
+
+
+static GthMetadataProviderClass *parent_class = NULL;
+
+
+static void
+gth_metadata_provider_gstreamer_read (GthMetadataProvider *self,
+				      GthFileData         *file_data,
+				      const char          *attributes)
+{
+	if (! g_content_type_is_a (gth_file_data_get_mime_type (file_data), "audio/*")
+	    && ! g_content_type_is_a (gth_file_data_get_mime_type (file_data), "video/*"))
+	{
+		return;
+	}
+
+	/* this function is executed in a secondary thread, so calling
+	 * slow sync functions is not a problem. */
+
+	gstreamer_read_metadata_from_file (file_data->file, file_data->info, NULL);
+}
+
+
+static void
+gth_metadata_provider_gstreamer_finalize (GObject *object)
+{
+	/*GthMetadataProviderGstreamer *comment = GTH_METADATA_PROVIDER_GSTREAMER (object);*/
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static GObject *
+gth_metadata_provider_constructor (GType                  type,
+				   guint                  n_construct_properties,
+				   GObjectConstructParam *construct_properties)
+{
+	GthMetadataProviderClass *klass;
+	GObjectClass             *parent_class;
+	GObject                  *obj;
+	GthMetadataProvider      *self;
+
+	klass = GTH_METADATA_PROVIDER_CLASS (g_type_class_peek (GTH_TYPE_METADATA_PROVIDER));
+	parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
+	obj = parent_class->constructor (type, n_construct_properties, construct_properties);
+	self = GTH_METADATA_PROVIDER (obj);
+
+	g_object_set (self, "readable-attributes", "audio-video::*", NULL);
+
+	return obj;
+}
+
+
+static void
+gth_metadata_provider_gstreamer_class_init (GthMetadataProviderGstreamerClass *klass)
+{
+	parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GthMetadataProviderGstreamerPrivate));
+
+	G_OBJECT_CLASS (klass)->finalize = gth_metadata_provider_gstreamer_finalize;
+	G_OBJECT_CLASS (klass)->constructor = gth_metadata_provider_constructor;
+
+	GTH_METADATA_PROVIDER_CLASS (klass)->read = gth_metadata_provider_gstreamer_read;
+}
+
+
+static void
+gth_metadata_provider_gstreamer_init (GthMetadataProviderGstreamer *catalogs)
+{
+}
+
+
+GType
+gth_metadata_provider_gstreamer_get_type (void)
+{
+	static GType type = 0;
+
+	if (! type) {
+		GTypeInfo type_info = {
+			sizeof (GthMetadataProviderGstreamerClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) gth_metadata_provider_gstreamer_class_init,
+			NULL,
+			NULL,
+			sizeof (GthMetadataProviderGstreamer),
+			0,
+			(GInstanceInitFunc) gth_metadata_provider_gstreamer_init
+		};
+
+		type = g_type_register_static (GTH_TYPE_METADATA_PROVIDER,
+					       "GthMetadataProviderGstreamer",
+					       &type_info,
+					       0);
+	}
+
+	return type;
+}
diff --git a/extensions/gstreamer/gth-metadata-provider-gstreamer.h b/extensions/gstreamer/gth-metadata-provider-gstreamer.h
new file mode 100644
index 0000000..58c3337
--- /dev/null
+++ b/extensions/gstreamer/gth-metadata-provider-gstreamer.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ *  This program 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.
+ *
+ *  This program 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTH_METADATA_PROVIDER_GSTREAMER_H
+#define GTH_METADATA_PROVIDER_GSTREAMER_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gthumb.h>
+
+#define GTH_TYPE_METADATA_PROVIDER_GSTREAMER         (gth_metadata_provider_gstreamer_get_type ())
+#define GTH_METADATA_PROVIDER_GSTREAMER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTH_TYPE_METADATA_PROVIDER_GSTREAMER, GthMetadataProviderGstreamer))
+#define GTH_METADATA_PROVIDER_GSTREAMER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTH_TYPE_METADATA_PROVIDER_GSTREAMER, GthMetadataProviderGstreamerClass))
+#define GTH_IS_METADATA_PROVIDER_GSTREAMER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTH_TYPE_METADATA_PROVIDER_GSTREAMER))
+#define GTH_IS_METADATA_PROVIDER_GSTREAMER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GTH_TYPE_METADATA_PROVIDER_GSTREAMER))
+#define GTH_METADATA_PROVIDER_GSTREAMER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GTH_TYPE_METADATA_PROVIDER_GSTREAMER, GthMetadataProviderGstreamerClass))
+
+typedef struct _GthMetadataProviderGstreamer         GthMetadataProviderGstreamer;
+typedef struct _GthMetadataProviderGstreamerPrivate  GthMetadataProviderGstreamerPrivate;
+typedef struct _GthMetadataProviderGstreamerClass    GthMetadataProviderGstreamerClass;
+
+struct _GthMetadataProviderGstreamer
+{
+	GthMetadataProvider __parent;
+	GthMetadataProviderGstreamerPrivate *priv;
+};
+
+struct _GthMetadataProviderGstreamerClass
+{
+	GthMetadataProviderClass __parent_class;	
+};
+
+GType gth_metadata_provider_gstreamer_get_type (void) G_GNUC_CONST;
+
+#endif /* GTH_METADATA_PROVIDER_GSTREAMER_H */
diff --git a/extensions/gstreamer/main.c b/extensions/gstreamer/main.c
new file mode 100644
index 0000000..0465225
--- /dev/null
+++ b/extensions/gstreamer/main.c
@@ -0,0 +1,88 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ *  This program 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.
+ *
+ *  This program 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include <gthumb.h>
+#include "gth-metadata-provider-gstreamer.h"
+
+
+GthMetadataCategory gstreamer_metadata_category[] = {
+	{ "audio-video::general", N_("General"), 30 },
+	{ "audio-video::video", N_("Video"), 40 },
+	{ "audio-video::audio", N_("Audio"), 50 },
+	{ "audio-video::other", N_("Other"), 60 },
+	{ NULL, NULL, 0 }
+};
+
+
+GthMetadataInfo gstreamer_metadata_info[] = {
+	{ "audio-video::general::title", N_("Title"), "audio-video::general", 1, GTH_METADATA_ALLOW_EVERYWHERE },
+	{ "audio-video::general::artist", N_("Artist"), "audio-video::general", 2, GTH_METADATA_ALLOW_EVERYWHERE },
+	{ "audio-video::general::album", N_("Album"), "audio-video::general", 3, GTH_METADATA_ALLOW_EVERYWHERE },
+	{ "audio-video::general::duration", N_("Duration"), "audio-video::general", 4, GTH_METADATA_ALLOW_EVERYWHERE },
+	{ "audio-video::general::container-format", N_("Container Format"), "audio-video::general", 5, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW },
+	{ "audio-video::general::encoder", N_("Encoder"), "audio-video::general", 6, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW },
+
+	{ "audio-video::video::size", N_("Dimensions"), "audio-video::video", 1, GTH_METADATA_ALLOW_EVERYWHERE },
+	{ "audio-video::video::codec", N_("Codec"), "audio-video::video", 2, GTH_METADATA_ALLOW_EVERYWHERE },
+	{ "audio-video::video::framerate", N_("Framerate"), "audio-video::video", 3, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW },
+	{ "audio-video::video::bitrate", N_("Bitrate"), "audio-video::video", 4, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW },
+	{ "audio-video::video::width", N_("Width"), "audio-video::video", 0, GTH_METADATA_ALLOW_NOWHERE },
+	{ "audio-video::video::height", N_("Height"), "audio-video::video", 0, GTH_METADATA_ALLOW_NOWHERE },
+
+	{ "audio-video::audio::codec", N_("Codec"), "audio-video::audio", 1, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW },
+	{ "audio-video::audio::channels", N_("Channels"), "audio-video::audio", 2, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW },
+	{ "audio-video::audio::samplerate", N_("Sample rate"), "audio-video::audio", 3, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW },
+	{ "audio-video::audio::bitrate", N_("Bitrate"), "audio-video::audio", 4, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW },
+
+	{ NULL, NULL, NULL, 0, 0 }
+};
+
+
+G_MODULE_EXPORT void
+gthumb_extension_activate (void)
+{
+	gth_main_register_metadata_category (gstreamer_metadata_category);
+	gth_main_register_metadata_info_v (gstreamer_metadata_info);
+	gth_main_register_metadata_provider (GTH_TYPE_METADATA_PROVIDER_GSTREAMER);
+}
+
+
+G_MODULE_EXPORT void
+gthumb_extension_deactivate (void)
+{
+}
+
+
+G_MODULE_EXPORT gboolean
+gthumb_extension_is_configurable (void)
+{
+	return FALSE;
+}
+
+
+G_MODULE_EXPORT void
+gthumb_extension_configure (GtkWindow *parent)
+{
+}
diff --git a/extensions/image_viewer/main.c b/extensions/image_viewer/main.c
index 5bd8a24..2536443 100644
--- a/extensions/image_viewer/main.c
+++ b/extensions/image_viewer/main.c
@@ -36,7 +36,7 @@ GthMetadataCategory image_metadata_category[] = {
 
 
 GthMetadataInfo image_metadata_info[] = {
-	{ "image::size", N_("Image Size"), "image", 1, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW | GTH_METADATA_ALLOW_IN_FILE_LIST },
+	{ "image::size", N_("Dimensions"), "image", 1, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW | GTH_METADATA_ALLOW_IN_FILE_LIST },
 	{ "image::format", N_("Format"), "image", 2, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW },
 	{ NULL, NULL, NULL, 0, 0 }
 };
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index 2b7e80a..388a701 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -239,6 +239,7 @@ gthumb_LDADD =						\
 	$(JPEG_LIBS)					\
 	$(TIFF_LIBS)					\
 	$(CLUTTER_LIBS)					\
+	$(GSTREAMER_LIBS)				\
 	$(NULL)	
 
 if RUN_IN_PLACE



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