tracker r2539 - in trunk: . src/tracker-extract



Author: mottela
Date: Thu Nov 20 22:06:56 2008
New Revision: 2539
URL: http://svn.gnome.org/viewvc/tracker?rev=2539&view=rev

Log:
Added initial gstreamer helix bin extractor implementation

Added:
   trunk/src/tracker-extract/tracker-extract-gstreamer-helix.c
Modified:
   trunk/ChangeLog
   trunk/configure.ac
   trunk/src/tracker-extract/Makefile.am

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Thu Nov 20 22:06:56 2008
@@ -492,6 +492,43 @@
    AM_CONDITIONAL(HAVE_LIBXINE, false)
 fi
 
+##################################################################
+# Check for Helixbin for GStreamer
+##################################################################
+
+AC_ARG_ENABLE(gstreamer-helix, 
+	      AS_HELP_STRING([--enable-gstreamer-helix=@<:@no/yes/auto@:>@],
+			     [enable GStreamer helixbin extractor (Real Media) (yes/no/auto)]),,
+	      [enable_gst_helix=no])
+
+if test "x$enable_gst_helix" != "xno"; then
+   PKG_CHECK_MODULES(GST_HELIX,
+		     [gstreamer0.10-helixbin],
+		     [have_gst_helix=yes],
+		     [have_gst_helix=no])
+   AC_SUBST(GST_HELIX_LIBS)
+   AC_SUBST(GST_HELIX_CFLAGS)
+
+   if test "x$have_gst_helix" = "xyes"; then
+      if test "x$have_libgstreamer" = "xyes"; then 
+      	 AC_DEFINE(HAVE_GST_HELIX, [], [Define if we have GStreamer Helix Bin])
+      fi
+   fi
+else
+   have_gst_helix="no  (disabled)"
+fi
+
+if test "x$enable_gst_helix" = "xyes"; then
+   if test "x$have_gst_helix" != "xyes"; then
+      AC_MSG_ERROR([Couldn't find GStreamer Helix Bin])
+   fi
+   if test "x$have_libgstreamer" != "xyes"; then
+      AC_MSG_ERROR([GStreamer is not found/used but GStreamer Helix Bin requested])
+   fi
+fi
+
+AM_CONDITIONAL(HAVE_GST_HELIX, test "x$have_gst_helix" = "xyes")
+
 ####################################################################
 # Windows check
 ####################################################################

Modified: trunk/src/tracker-extract/Makefile.am
==============================================================================
--- trunk/src/tracker-extract/Makefile.am	(original)
+++ trunk/src/tracker-extract/Makefile.am	Thu Nov 20 22:06:56 2008
@@ -64,6 +64,10 @@
 modules_LTLIBRARIES += libextract-gstreamer.la
 endif
 
+if HAVE_GST_HELIX
+modules_LTLIBRARIES += libextract-gstreamer-helix.la
+endif 
+
 if HAVE_LIBXINE
 modules_LTLIBRARIES += libextract-xine.la
 endif
@@ -163,6 +167,11 @@
 libextract_gstreamer_la_LDFLAGS = $(module_flags) $(albumart_flags)
 libextract_gstreamer_la_LIBADD = $(albumart_libs) $(GSTREAMER_LIBS) $(GLIB2_LIBS)
 
+# GStreamer helix
+libextract_gstreamer_helix_la_SOURCES = tracker-extract-gstreamer-helix.c $(albumart_sources)
+libextract_gstreamer_helix_la_LDFLAGS = $(module_flags) $(albumart_flags)
+libextract_gstreamer_helix_la_LIBADD = $(albumart_libs) $(GSTREAMER_LIBS) $(GLIB2_LIBS)
+
 # Xine
 libextract_xine_la_SOURCES = tracker-extract-libxine.c
 libextract_xine_la_LDFLAGS = $(module_flags)

Added: trunk/src/tracker-extract/tracker-extract-gstreamer-helix.c
==============================================================================
--- (empty file)
+++ trunk/src/tracker-extract/tracker-extract-gstreamer-helix.c	Thu Nov 20 22:06:56 2008
@@ -0,0 +1,883 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006, Laurent Aguerreche (laurent aguerreche free fr)
+ * Copyright (C) 2007, Mr Jamie McCracken (jamiemcc gnome org)
+ * Copyright (C) 2008, Nokia
+ *
+ * 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.
+ */
+
+/* This is an extractor for Real Media and Audio content using the
+ * helixbin element if available.
+ * FIXME Share with other gstreamer based extractors
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib.h>
+#include <gst/gst.h>
+#include <gst/tag/tag.h>
+
+#include "tracker-extract.h"
+#include "tracker-albumart.h"
+
+typedef enum {
+	EXTRACT_MIME_UNDEFINED=0,
+	EXTRACT_MIME_AUDIO,
+	EXTRACT_MIME_VIDEO,
+} ExtractMime;
+
+typedef struct {
+	GstElement	*playbin;
+
+	GstTagList	*tagcache;
+	GstTagList	*audiotags;
+	GstTagList	*videotags;
+
+	GstMessageType	ignore_messages_mask;
+
+	gboolean	has_audio;
+	gboolean	has_video;
+
+	ExtractMime	mime;
+
+	gint		video_height;
+	gint		video_width;
+	gint		video_fps_n;
+	gint		video_fps_d;
+	gint		audio_channels;
+	gint		audio_samplerate;
+
+	unsigned char  *album_art_data;
+	guint           album_art_size;
+
+} MetadataExtractor;
+
+static void extract_gstreamer_helix_audio (const gchar *uri, GHashTable *metadata);
+static void extract_gstreamer_helix_video (const gchar *uri, GHashTable *metadata);
+
+static TrackerExtractorData data[] = {
+	{ "audio/helix", extract_gstreamer_helix_audio },
+	{ NULL, NULL }
+};
+
+static void
+caps_set (GObject	    *object,
+	  MetadataExtractor *extractor,
+	  const gchar	    *type)
+{
+	GstPad	     *pad;
+	GstStructure *s;
+	GstCaps	     *caps;
+
+	pad = GST_PAD (object);
+
+	if (!(caps = gst_pad_get_negotiated_caps (pad))) {
+		return;
+	}
+
+	s = gst_caps_get_structure (caps, 0);
+
+	if (s) {
+		if (!strcmp (type, "audio")) {
+			if ((extractor->audio_channels != -1 &&
+			     extractor->audio_samplerate != -1) ||
+			    !(gst_structure_get_int (s, "channels", &extractor->audio_channels) &&
+			      gst_structure_get_int (s, "rate", &extractor->audio_samplerate))) {
+				return;
+			}
+		} else if (!strcmp (type, "video")) {
+			if ((extractor->video_fps_n != -1 &&
+			     extractor->video_fps_d != -1 &&
+			     extractor->video_width != -1 &&
+			     extractor->video_height != -1) ||
+			    !(gst_structure_get_fraction (s, "framerate", &extractor->video_fps_n, &extractor->video_fps_d) &&
+			      gst_structure_get_int (s, "width", &extractor->video_width) &&
+			      gst_structure_get_int (s, "height", &extractor->video_height))) {
+				return;
+			}
+		} else {
+			g_assert_not_reached ();
+		}
+	}
+
+	gst_caps_unref (caps);
+}
+
+static void
+caps_set_audio (GObject		  *object,
+		MetadataExtractor *extractor)
+{
+	g_return_if_fail (object);
+	g_return_if_fail (extractor);
+
+	caps_set (object, extractor, "audio");
+}
+
+static void
+caps_set_video (GObject		  *object,
+		MetadataExtractor *extractor)
+{
+	g_return_if_fail (object);
+	g_return_if_fail (extractor);
+
+	caps_set (object, extractor, "video");
+}
+
+static void
+update_stream_info (MetadataExtractor *extractor)
+{
+	GList  *streaminfo;
+	GstPad *audiopad, *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 ( ; streaminfo; streaminfo = streaminfo->next) {
+		GObject	   *info;
+		gint	    type;
+		GParamSpec *pspec;
+		GEnumValue *val;
+
+		info = streaminfo->data;
+
+		if (!info) {
+			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")) {
+			extractor->has_audio = TRUE;
+			if (!audiopad) {
+				g_object_get (info, "object", &audiopad, NULL);
+			}
+		} else if (!strcmp (val->value_nick, "video")) {
+			extractor->has_video = TRUE;
+			if (!videopad) {
+				g_object_get (info, "object", &videopad, NULL);
+			}
+		}
+	}
+
+	if (audiopad) {
+		GstCaps *caps;
+
+		if ((caps = gst_pad_get_negotiated_caps (audiopad))) {
+			caps_set_audio (G_OBJECT (audiopad), extractor);
+			gst_caps_unref (caps);
+		}
+	}
+
+	if (videopad) {
+		GstCaps *caps;
+
+		if ((caps = gst_pad_get_negotiated_caps (videopad))) {
+			caps_set_video (G_OBJECT (videopad), extractor);
+			gst_caps_unref (caps);
+		}
+	}
+
+	g_list_foreach (streaminfo, (GFunc) g_object_unref, NULL);
+	g_list_free (streaminfo);
+}
+
+static void
+gst_bus_cb (GstBus	      *bus,
+	    GstMessage	      *message,
+	    MetadataExtractor *extractor)
+{
+	GstMessageType msg_type;
+
+	g_return_if_fail (bus);
+	g_return_if_fail (message);
+	g_return_if_fail (extractor);
+
+	msg_type = GST_MESSAGE_TYPE (message);
+
+	/* Somebody else is handling the message, probably in
+	 * poll_for_state_change.
+	 */
+	if (extractor->ignore_messages_mask & msg_type) {
+		gchar *src_name;
+
+		src_name = gst_object_get_name (message->src);
+		GST_LOG ("Ignoring %s message from element %s as requested",
+			 gst_message_type_get_name (msg_type), src_name);
+		g_free (src_name);
+
+		return;
+	}
+
+	switch (msg_type) {
+	case GST_MESSAGE_ERROR: {
+		GstMessage *message  = NULL;
+		GError	   *gsterror = NULL;
+		gchar	   *debug    = NULL;
+
+		gst_message_parse_error (message, &gsterror, &debug);
+		g_warning ("Error: %s (%s)", gsterror->message, debug);
+
+		gst_message_unref (message);
+		g_error_free (gsterror);
+		g_free (debug);
+	}
+		break;
+
+	case GST_MESSAGE_STATE_CHANGED: {
+		GstState old_state, 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) {
+			/* Clean metadata cache */
+			if (extractor->tagcache) {
+				gst_tag_list_free (extractor->tagcache);
+				extractor->tagcache = NULL;
+			}
+
+			if (extractor->audiotags) {
+				gst_tag_list_free (extractor->audiotags);
+				extractor->audiotags = NULL;
+			}
+
+			if (extractor->videotags) {
+				gst_tag_list_free (extractor->videotags);
+				extractor->videotags = NULL;
+			}
+
+			extractor->has_audio = extractor->has_video = FALSE;
+
+			extractor->video_fps_n = extractor->video_fps_d = -1;
+			extractor->video_height = extractor->video_width = -1;
+			extractor->audio_channels = -1;
+			extractor->audio_samplerate = -1;
+		}
+
+		break;
+	}
+
+	case GST_MESSAGE_TAG: {
+		GstTagList	  *tag_list, *result;
+		GstElementFactory *f;
+
+		tag_list = NULL;
+
+		gst_message_parse_tag (message, &tag_list);
+
+		GST_DEBUG ("Tags: %" GST_PTR_FORMAT, tag_list);
+
+		/* All tags */
+		result = gst_tag_list_merge (extractor->tagcache,
+					     tag_list,
+					     GST_TAG_MERGE_KEEP);
+
+		if (extractor->tagcache) {
+			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)))) {
+			GstTagList  **cache;
+			const gchar  *klass;
+
+			cache = NULL;
+			klass = gst_element_factory_get_klass (f);
+
+			if (g_strrstr (klass, "Audio")) {
+				cache = &extractor->audiotags;
+			} else if (g_strrstr (klass, "Video")) {
+				cache = &extractor->videotags;
+			}
+
+			if (cache) {
+				result = gst_tag_list_merge (*cache,
+							     tag_list,
+							     GST_TAG_MERGE_KEEP);
+				if (*cache) {
+					gst_tag_list_free (*cache);
+				}
+
+				*cache = result;
+			}
+		}
+
+		gst_tag_list_free (tag_list);
+
+		break;
+	}
+
+	default:
+		break;
+	}
+}
+
+static void
+add_int64_info (GHashTable *metadata,
+		gchar	   *key,
+		gint64	    info)
+{
+	gchar *str_info;
+
+	str_info = g_strdup_printf ("%" G_GINT64_FORMAT, info);
+	g_hash_table_insert (metadata, key, str_info);
+}
+
+static void
+add_uint_info (GHashTable *metadata,
+	       gchar	  *key,
+	       guint	   info)
+{
+	gchar *str_info;
+
+	str_info = g_strdup_printf ("%d", info);
+	g_hash_table_insert (metadata, key, str_info);
+}
+
+static void
+add_string_gst_tag (GHashTable	*metadata,
+		    const gchar *key,
+		    GstTagList	*tag_list,
+		    const gchar *tag)
+{
+	gchar	 *s;
+	gboolean  ret;
+
+	s = NULL;
+	ret = gst_tag_list_get_string (tag_list, tag, &s);
+
+	if (s) {
+		if (ret && s[0] != '\0') {
+			g_hash_table_insert (metadata,
+					     g_strdup (key),
+					     s);
+		} else {
+			g_free (s);
+		}
+	}
+}
+
+static void
+add_uint_gst_tag (GHashTable  *metadata,
+		  const gchar *key,
+		  GstTagList  *tag_list,
+		  const gchar *tag)
+{
+	gboolean ret;
+	guint	 n;
+
+	ret = gst_tag_list_get_uint (tag_list, tag, &n);
+
+	if (ret) {
+		g_hash_table_insert (metadata,
+				     g_strdup (key),
+				     g_strdup_printf ("%d", n));
+	}
+}
+
+static void
+add_double_gst_tag (GHashTable	*metadata,
+		    const gchar *key,
+		    GstTagList	*tag_list,
+		    const gchar *tag)
+{
+	gboolean ret;
+	gdouble	 n;
+
+	ret = gst_tag_list_get_double (tag_list, tag, &n);
+
+	if (ret) {
+		g_hash_table_insert (metadata,
+				     g_strdup (key),
+				     g_strdup_printf ("%f", n));
+	}
+}
+
+static void
+add_year_of_gdate_gst_tag (GHashTable  *metadata,
+			   const gchar *key,
+			   GstTagList  *tag_list,
+			   const gchar *tag)
+{
+	GDate	 *date;
+	gboolean  ret;
+
+	date = NULL;
+	ret = gst_tag_list_get_date (tag_list, tag, &date);
+
+	if (ret) {
+		gchar buf[10];
+
+		if (g_date_strftime (buf, 10, "%Y", date)) {
+			g_hash_table_insert (metadata,
+					     g_strdup (key),
+					     g_strdup (buf));
+		}
+	}
+
+	if (date) {
+		g_date_free (date);
+	}
+}
+
+static gint64
+get_media_duration (MetadataExtractor *extractor)
+{
+	gint64	  duration;
+	GstFormat fmt;
+
+	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
+get_embedded_album_art(MetadataExtractor *extractor)
+{
+	const GValue *value;
+	guint         index;
+
+	index = 0;
+
+	do {
+		value = gst_tag_list_get_value_index (extractor->tagcache, GST_TAG_IMAGE, index);
+
+		if (value) {
+			GstBuffer    *buffer;
+			GstCaps      *caps;
+			GstStructure *caps_struct;
+			gint          type;
+
+			buffer = gst_value_get_buffer (value);
+			caps   = gst_buffer_get_caps (buffer);
+			caps_struct = gst_caps_get_structure (buffer->caps, 0);
+
+			gst_structure_get_enum (caps_struct,
+						"image-type",
+						GST_TYPE_TAG_IMAGE_TYPE,
+						&type);
+			
+			if ((type == GST_TAG_IMAGE_TYPE_FRONT_COVER)||
+			    ((type == GST_TAG_IMAGE_TYPE_UNDEFINED)&&(extractor->album_art_size == 0))) {
+				extractor->album_art_data = buffer->data;
+				extractor->album_art_size = buffer->size;
+
+				return;
+			}
+
+			gst_object_unref (caps);
+
+			index++;
+		}
+	} while (value);
+}
+
+static void
+extract_metadata (MetadataExtractor *extractor,
+		  GHashTable  *metadata)
+{
+	g_return_if_fail (extractor);
+	g_return_if_fail (metadata);
+
+	if (extractor->audio_channels >= 0) {
+		add_uint_info (metadata,
+			       g_strdup ("Audio:Channels"),
+			       extractor->audio_channels);
+	}
+
+	if (extractor->audio_samplerate >= 0) {
+		add_uint_info (metadata,
+			       g_strdup ("Audio:Samplerate"),
+			       extractor->audio_samplerate);
+	}
+
+	if (extractor->video_height >= 0) {
+		add_uint_info (metadata,
+			       g_strdup ("Video:Height"),
+			       extractor->video_height);
+	}
+
+	if (extractor->video_width >= 0) {
+		add_uint_info (metadata,
+			       g_strdup ("Video:Width"),
+			       extractor->video_height);
+	}
+
+	if (extractor->video_fps_n >= 0 && extractor->video_fps_d >= 0) {
+		add_uint_info (metadata,
+			       g_strdup ("Video:FrameRate"),
+			       ((extractor->video_fps_n + extractor->video_fps_d / 2) / extractor->video_fps_d));
+	}
+
+	if (extractor->tagcache) {
+		gint64 duration;
+
+		/* Audio */
+		add_string_gst_tag (metadata, "Audio:Album", extractor->tagcache, GST_TAG_ALBUM);
+		add_uint_gst_tag (metadata, "Audio:AlbumTrackCount", extractor->tagcache, GST_TAG_TRACK_COUNT);
+		add_uint_gst_tag (metadata, "Audio:TrackNo", extractor->tagcache, GST_TAG_TRACK_NUMBER);
+		add_uint_gst_tag (metadata, "Audio:DiscNo", extractor->tagcache, GST_TAG_ALBUM_VOLUME_NUMBER);
+		add_string_gst_tag (metadata, "Audio:Performer", extractor->tagcache, GST_TAG_PERFORMER);
+		add_double_gst_tag (metadata, "Audio:TrackGain", extractor->tagcache, GST_TAG_TRACK_GAIN);
+		add_double_gst_tag (metadata, "Audio:PeakTrackGain", extractor->tagcache, GST_TAG_TRACK_PEAK);
+		add_double_gst_tag (metadata, "Audio:AlbumGain", extractor->tagcache, GST_TAG_ALBUM_GAIN);
+		add_double_gst_tag (metadata, "Audio:AlbumPeakGain", extractor->tagcache, GST_TAG_ALBUM_PEAK);
+		add_year_of_gdate_gst_tag (metadata, "Audio:ReleaseDate", extractor->tagcache, GST_TAG_DATE);
+		add_string_gst_tag (metadata, "Audio:Genre", extractor->tagcache, GST_TAG_GENRE);
+		add_string_gst_tag (metadata, "Audio:Codec", extractor->tagcache, GST_TAG_AUDIO_CODEC);
+
+		/* Video */
+		add_string_gst_tag (metadata, "Video:Codec", extractor->tagcache, GST_TAG_VIDEO_CODEC);
+
+		/* General */
+		add_string_gst_tag (metadata, "File:Copyright", extractor->tagcache, GST_TAG_COPYRIGHT);
+		add_string_gst_tag (metadata, "File:License", extractor->tagcache, GST_TAG_LICENSE);
+		add_string_gst_tag (metadata, "DC:Coverage", extractor->tagcache, GST_TAG_LOCATION);
+
+		duration = get_media_duration (extractor);
+
+		/* FIXME Use the has_video and has_audio rather than mime type once dsp problems are solved */
+/* 		if (extractor->has_video) { */
+		if (extractor->mime == EXTRACT_MIME_VIDEO) {
+			add_string_gst_tag (metadata, "Video:Title", extractor->tagcache, GST_TAG_TITLE);
+			add_string_gst_tag (metadata, "Video:Comments", extractor->tagcache, GST_TAG_COMMENT);
+
+			/* FIXME: is it a good idea to use GST_TAG_ARTIST as author?! */
+			add_string_gst_tag (metadata, "Video:Author", extractor->tagcache, GST_TAG_ARTIST);
+			add_string_gst_tag (metadata, "File:Copyright", extractor->tagcache, GST_TAG_COPYRIGHT);
+
+			if (duration >= 0) {
+				add_int64_info (metadata, g_strdup ("Video:Duration"), duration);
+			}
+/* 		} else if (extractor->has_audio) { */
+		} else if (extractor->mime == EXTRACT_MIME_AUDIO) {
+			/* No video? So we assume we are treating a song */
+			add_string_gst_tag (metadata, "Audio:Title", extractor->tagcache, GST_TAG_TITLE);
+			add_string_gst_tag (metadata, "Audio:Artist", extractor->tagcache, GST_TAG_ARTIST);
+			add_string_gst_tag (metadata, "Audio:Comment", extractor->tagcache, GST_TAG_COMMENT);
+
+			if (duration >= 0) {
+				add_int64_info (metadata, g_strdup ("Audio:Duration"), duration);
+			}
+
+			get_embedded_album_art (extractor);
+		}
+	}
+
+	if (extractor->audiotags) {
+		add_uint_gst_tag (metadata, "Audio:Bitrate", extractor->tagcache, GST_TAG_BITRATE);
+	}
+
+	if (extractor->videotags) {
+		add_uint_gst_tag (metadata, "Video:Bitrate", extractor->tagcache, GST_TAG_BITRATE);
+	}
+}
+
+static gboolean
+poll_for_state_change (MetadataExtractor *extractor,
+		       GstState		  state)
+{
+	GstBus	       *bus;
+	GstMessageType	events, saved_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_STATE_CHANGED |
+		GST_MESSAGE_ERROR |
+		GST_MESSAGE_EOS;
+
+	saved_events = extractor->ignore_messages_mask;
+
+	if (extractor->playbin) {
+		/* we do want the main handler to process state changed messages for
+		 * playbin as well, otherwise it won't hook up the timeout etc. */
+		extractor->ignore_messages_mask |= (events ^ GST_MESSAGE_STATE_CHANGED);
+	} else {
+		extractor->ignore_messages_mask |= events;
+	}
+
+	for (;;) {
+		GstMessage *message;
+		GstElement *src;
+
+		message = gst_bus_poll (bus, events, GST_SECOND * 5);
+
+		if (!message) {
+			goto timed_out;
+		}
+
+		src = (GstElement *) GST_MESSAGE_SRC (message);
+
+		switch (GST_MESSAGE_TYPE (message)) {
+		case GST_MESSAGE_STATE_CHANGED: {
+			GstState old, new, pending;
+
+			old = new = pending = GST_STATE_NULL;
+
+			if (src == extractor->playbin) {
+				gst_message_parse_state_changed (message, &old, &new, &pending);
+
+				if (new == state) {
+					gst_message_unref (message);
+					goto success;
+				}
+			}
+
+			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));
+	extractor->ignore_messages_mask = saved_events;
+	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));
+	extractor->ignore_messages_mask = saved_events;
+	return TRUE;
+
+ error:
+	/* Already set *error */
+	GST_DEBUG ("error while waiting for state change to %s",
+		   gst_element_state_get_name (state));
+	extractor->ignore_messages_mask = saved_events;
+	return FALSE;
+}
+
+static void
+tracker_extract_gstreamer_helix (const gchar *uri,
+				 GHashTable  *metadata,
+				 ExtractMime	type)
+{
+	MetadataExtractor *extractor;
+	gchar		  *mrl;
+	GstElement	  *fakesink_video;
+	GstBus		  *bus;
+
+	g_return_if_fail (uri);
+	g_return_if_fail (metadata);
+
+	g_type_init ();
+
+	gst_init (NULL, NULL);
+
+	/* set up */
+	extractor = g_slice_new0 (MetadataExtractor);
+
+	extractor->tagcache = NULL;
+	extractor->audiotags = extractor->videotags = NULL;
+
+	extractor->has_audio = extractor->has_video = FALSE;
+
+	extractor->video_fps_n = extractor->video_fps_d = -1;
+	extractor->video_height = extractor->video_width = -1;
+	extractor->audio_channels = -1;
+	extractor->audio_samplerate = -1;
+
+	extractor->ignore_messages_mask = 0;
+
+	extractor->mime = type;
+
+	extractor->album_art_data = NULL;
+	extractor->album_art_size = 0;
+
+	extractor->playbin = gst_element_factory_make ("helixbin", "playbin");
+
+	/* Add bus callback */
+	bus = gst_element_get_bus (GST_ELEMENT (extractor->playbin));
+	gst_bus_add_signal_watch (bus);
+	g_signal_connect (bus, "message", G_CALLBACK (gst_bus_cb), extractor);
+	gst_object_unref (bus);
+
+	mrl = g_strconcat ("file://", uri, NULL);
+
+	/* Set playbin object */
+	g_object_set (G_OBJECT (extractor->playbin), "uri", mrl, NULL);
+	g_free (mrl);
+
+	fakesink_video = gst_element_factory_make ("fakesink", "fakesink-video");
+	g_object_set (G_OBJECT (extractor->playbin), "video-sink", fakesink_video, NULL);
+
+	/* start to parse infos and extract them */
+	gst_element_set_state (extractor->playbin, GST_STATE_PAUSED);
+
+	poll_for_state_change (extractor, GST_STATE_PAUSED);
+
+	extract_metadata (extractor, metadata);
+
+	/* Save embedded art */
+	if (extractor->album_art_data && extractor->album_art_size) {
+#ifdef HAVE_GDKPIXBUF
+		tracker_process_albumart (extractor->album_art_data, extractor->album_art_size,
+				       g_hash_table_lookup (metadata, "Audio:Artist") ,
+				       g_hash_table_lookup (metadata, "Audio:Album"),
+				       g_hash_table_lookup (metadata, "Audio:AlbumTrackCount"),
+				       uri);
+#else
+		tracker_process_albumart (NULL, 0,
+				       g_hash_table_lookup (metadata, "Audio:Artist") ,
+				       g_hash_table_lookup (metadata, "Audio:Album"),
+				       g_hash_table_lookup (metadata, "Audio:AlbumTrackCount"),
+				       uri);
+
+#endif /* HAVE_GDKPIXBUF */
+	}
+
+	/* Check that we have the minimum data. FIXME We should not need to do this */
+
+	if (type==EXTRACT_MIME_AUDIO) {
+		if (!g_hash_table_lookup (metadata, "Audio:Title")) {
+			g_hash_table_insert (metadata, g_strdup ("Audio:Title"), g_strdup (METADATA_UNKNONN));
+		}
+		
+		if (!g_hash_table_lookup (metadata, "Audio:Album")) {
+			g_hash_table_insert (metadata, g_strdup ("Audio:Album"), g_strdup (METADATA_UNKNONN));
+		}
+		
+		if (!g_hash_table_lookup (metadata, "Audio:Artist")) {
+			g_hash_table_insert (metadata, g_strdup ("Audio:Artist"), g_strdup (METADATA_UNKNONN));
+		}
+		
+		if (!g_hash_table_lookup (metadata, "Audio:Genre")) {
+			g_hash_table_insert (metadata, g_strdup ("Audio:Genre"), g_strdup (METADATA_UNKNONN));
+		}
+
+		if (!g_hash_table_lookup (metadata, "Audio:PlayCount")) {
+			g_hash_table_insert (metadata, g_strdup ("Audio:PlayCount"), g_strdup ("0"));
+		}
+	} else if (type==EXTRACT_MIME_VIDEO) {
+		if (!g_hash_table_lookup (metadata, "Video:Title")) {
+			g_hash_table_insert (metadata, g_strdup ("Video:Title"), g_strdup (METADATA_UNKNONN));
+		}
+		
+		if (!g_hash_table_lookup (metadata, "Video:Author")) {
+			g_hash_table_insert (metadata, g_strdup ("Video:Author"), g_strdup (METADATA_UNKNONN));
+		}
+
+		if (!g_hash_table_lookup (metadata, "Video:PlayCount")) {
+			g_hash_table_insert (metadata, g_strdup ("Video:PlayCount"), g_strdup ("0"));
+		}
+	}
+
+	/* Also clean up */
+	gst_element_set_state (extractor->playbin, GST_STATE_NULL);
+
+	gst_object_unref (GST_OBJECT (extractor->playbin));
+
+	g_slice_free (MetadataExtractor, extractor);
+}
+
+static void
+extract_gstreamer_helix_audio (const gchar *uri, GHashTable *metadata)
+{
+	tracker_extract_gstreamer_helix (uri, metadata, EXTRACT_MIME_AUDIO);
+}
+
+static void
+extract_gstreamer_helix_video (const gchar *uri, GHashTable *metadata)
+{
+	tracker_extract_gstreamer_helix (uri, metadata, EXTRACT_MIME_VIDEO);
+}
+
+TrackerExtractorData *
+tracker_get_extractor_data (void)
+{
+	return data;
+}



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