Re: Gstreamer filter



On Tue, 2004-11-09 at 15:54 -0500, Christopher James Lahey wrote: 
> Le dimanche 07 novembre 2004 à 19:30 +0000, Adam Lofts a écrit :
> > Hi,
> > 
> > I've written a Gstreamer filter which currently extracts tags
> > from .mp3, .ogg, .wmv, .asf and .flac. You need module gst-sharp installed 
> > (from mono cvs) and the relevant decoder plugin (e.g. gstreamer0.8-flac 
> > for flac tags).
> > 
> > In theory, simply adding a mime type to the filter should enable video
> > tag extraction of any video format nautilus will give you tag information
> > about - but I can't test this since i have no tagged video
> > files. Gstreamer should also be able to extract tags from images but I
> > haven't got this to work yet.
> 
> So, this looks mostly okay.  I've noticed that gst-sharp requires
> gstreamer 0.8.7.  Is this a hard requirement?

I think that the tagging interface changed between gstreamer 0.6-0.8, so
even if gst-sharp did build with < 0.8.7 the filter wouldn't work.

> 
> The main issue that I see is the mime type handling.  It looks like
> you're attempting to create filters and then letting them be garbage
> collected to detect mime types.  However, this happens every time the
> filter gets created, which means every time a file is going to be
> filtered.
> 

Fair enough - here's a new version.

> Instead of this, you should create a cache of mime types and fill this
> cache in your Init function.  Then, in your constructor, add the mime
> types based on this cache.  The cache should probably be an ArrayList
> storing strings?  (Someone with more mono knowledge should correct me on
> this if I'm wrong.)

> I haven't reviewed the code to do the actual reading of the tags, as I
> don't know the gstreamer stuff very well.  I assume this is correct
> since you've tested it and it presumably works.  My only concern in this
> code would be the possibility that it reads to the end of the file, even
> if the tags are at the beginning (and doesn't skip to the end if the
> tags are always at the end.)  Is this the case?  And if so, is it
> possible to avoid this?
> 

The code will read data from the file, until the first chunk of data is
decoded or an error in the pipeline is thrown. i.e. Under no situation
will an entire media file be decoded - hopefully all the individual
decoder elements will skip in the file stream rather than read it all if
tags are at the end.

Rhythmbox extracts tags in this way - i hope it's fairly efficient.


> Other than those two issues, the code looks fine.  If you fix the cache
> thing and test it, I'd be willing to commit this.

Great.

You will probably have noticed the long list of possible tags at the end
of the file. Which tags should be indexed by the filter? Does beagle
care about the bitrate of a stream?

Finally, (i forgot about this in my first post) the gstreamer name for
the title of a song is "title" and so is indexed as "fixme:title",
FilterMusic.cs calls the title "fixme:song". Title seems to make more
sense to me, can we not standardise on the gstreamer tag names? [ title
does seem more accurate than song ]

> 
> Thanks,
>     Chris
> 
> 
//
// FilterGst.cs
//
// Copyright (C) 2004 Adam Lofts
//

//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

using System;
using System.IO;
using System.Collections;
using Gst;
using Beagle.Util;

namespace Beagle.Filters {

	public class FilterGst : Beagle.Daemon.Filter {

		static bool has_inited = false;
		static ArrayList mime_cache;

		private static void InitGst() {
			Gst.Application.Init("Beagle");

			mime_cache = new ArrayList();
			
			Element decoder;
			
			decoder = ElementFactory.Make("mad",null);
			if (decoder != null)
				mime_cache.Add("audio/x-mp3");

			decoder = ElementFactory.Make("vorbisdec",null);
			if (decoder != null)
				mime_cache.Add("application/ogg");

			decoder = ElementFactory.Make("flacdec",null);
			if (decoder != null)
				mime_cache.Add("application/x-flac");
			
			decoder = ElementFactory.Make("asfdemux",null);
			if (decoder != null)
				mime_cache.Add("video/x-ms-asf");
		}

		public FilterGst ()
		{
			if (!has_inited) {
				InitGst();
				has_inited = true;
			}

			foreach(string mime_type in mime_cache) {
				AddSupportedMimeType (mime_type);
			}
		}

		bool keep_looking;

		protected override void DoPullProperties ()
		{
			//Util.Logger.Log.Debug("FilterGst begin: {0}", FileInfo.FullName);

			Pipeline pipe = new Pipeline(null);

			FileSrc src = ElementFactory.Make ("filesrc", null) as FileSrc;
			Spider spider = ElementFactory.Make ("spider", null) as Spider;
			FakeSink sink = ElementFactory.Make ("fakesink", null) as FakeSink;

			pipe.Add(src);
			pipe.Add(spider);
			pipe.Add(sink);
	
			src.Link(spider);
		
			Caps caps = Caps.FromString("audio/x-raw-int");
			spider.LinkFiltered(sink, caps);

			src.Location = FileInfo.FullName;
			sink.SignalHandoffs = true;
		
			spider.FoundTag += FoundTagHandler;
			pipe.Error += ErrorHandler;
			sink.Handoff += HandoffHandler;

			pipe.SetState(ElementState.Playing);
			keep_looking = true;
			while (pipe.Iterate() && keep_looking) { /* wait here! */ }
			pipe.SetState(ElementState.Null);

			Finished ();
			//Util.Logger.Log.Debug("FilterGst end: {0}", FileInfo.FullName);
		}

		void HandoffHandler (object o, HandoffArgs args) {
			keep_looking = false; 
		}
		void ErrorHandler (object o, ErrorArgs args) {
			Logger.Log.Warn("FilterGst error: {0}", args.Debug);
			keep_looking = false; 
		}
		void FoundTagHandler (object o, FoundTagArgs args) {
			TagList list = args.TagList;
			list.Foreach(new TagForeachFunc(TagForeachFunc));
			//Util.Logger.Log.Debug("FilterGst Got tags");
		}
		void TagForeachFunc (TagList list, string tag) {
			string val_str;
			
			switch (tag) {
				//Strings
				case "comment":
				case "title":
				case "genre":
				case "artist":
				case "album":
				list.GetString(tag, out val_str);
				AddProperty (Beagle.Property.New ("fixme:" + tag, val_str));
				break;
			}
		}
	}
}

/* Stolen from Gstreamer gsttag.h - All possible tags?

#define GST_TAG_TITLE			"title"
#define GST_TAG_ARTIST			"artist"
#define GST_TAG_ALBUM			"album"
#define GST_TAG_DATE			"date"
#define GST_TAG_GENRE			"genre"
#define GST_TAG_COMMENT			"comment"
#define GST_TAG_TRACK_NUMBER		"track-number"
#define GST_TAG_TRACK_COUNT		"track-count"
#define GST_TAG_ALBUM_VOLUME_NUMBER	"album-disc-number"
#define GST_TAG_ALBUM_VOLUME_COUNT	"album-disc-count"
#define GST_TAG_LOCATION		"location"
#define GST_TAG_DESCRIPTION		"description"
#define GST_TAG_VERSION			"version"
#define GST_TAG_ISRC			"isrc"
#define GST_TAG_ORGANIZATION		"organization"
#define GST_TAG_COPYRIGHT		"copyright"
#define GST_TAG_CONTACT			"contact"
#define GST_TAG_LICENSE			"license"
#define GST_TAG_PERFORMER		"performer"
#define GST_TAG_DURATION		"duration"
#define GST_TAG_CODEC			"codec"
#define GST_TAG_VIDEO_CODEC		"video-codec"
#define GST_TAG_AUDIO_CODEC		"audio-codec"
#define GST_TAG_BITRATE			"bitrate"
#define GST_TAG_NOMINAL_BITRATE		"nominal-bitrate"
#define GST_TAG_MINIMUM_BITRATE		"minimum-bitrate"
#define GST_TAG_MAXIMUM_BITRATE		"maximum-bitrate"
#define GST_TAG_SERIAL			"serial"
#define GST_TAG_ENCODER			"encoder"
#define GST_TAG_ENCODER_VERSION		"encoder-version"
#define GST_TAG_TRACK_GAIN		"replaygain-track-gain"
#define GST_TAG_TRACK_PEAK		"replaygain-track-peak"
#define GST_TAG_ALBUM_GAIN  		"replaygain-album-gain"
#define GST_TAG_ALBUM_PEAK		"replaygain-album-peak"
*/
? beagle/Filters/FilterGst.cs
Index: beagle/configure.in
===================================================================
RCS file: /cvs/gnome/beagle/configure.in,v
retrieving revision 1.53
diff -u -r1.53 configure.in
--- beagle/configure.in	4 Nov 2004 21:46:59 -0000	1.53
+++ beagle/configure.in	7 Nov 2004 19:28:44 -0000
@@ -207,6 +207,9 @@
 PKG_CHECK_MODULES(GSF_SHARP, gsf-sharp, enable_gsf_sharp=yes, enable_gsf_sharp=no)
 AM_CONDITIONAL(ENABLE_GSF_SHARP, test "x$enable_gsf_sharp" = "xyes")
 
+PKG_CHECK_MODULES(GST_SHARP, gst-sharp, enable_gst_sharp=yes, enable_gst_sharp=no)
+AM_CONDITIONAL(ENABLE_GST_SHARP, test "x$enable_gst_sharp" = "xyes")
+
 PKG_CHECK_MODULES(BEAGLED, gtk-sharp dbus-sharp gconf-sharp)
 BEAGLED_LIBS="$BEAGLED_LIBS $EVO_SHARP_LIBS $GSF_SHARP_LIBS"
 AC_SUBST(BEAGLED_LIBS)
@@ -320,6 +323,7 @@
 	Prefix:			${prefix}
 	Evolution-Sharp?	${enable_evo_sharp}
 	gsf-sharp?		${enable_gsf_sharp}
+	gst-sharp?		${enable_gst_sharp}
 	Epiphany Extension?	${enable_epiphany_extension}
 	Mozilla Extension?	yes
 
Index: beagle/Filters/Makefile.am
===================================================================
RCS file: /cvs/gnome/beagle/Filters/Makefile.am,v
retrieving revision 1.23
diff -u -r1.23 Makefile.am
--- beagle/Filters/Makefile.am	4 Nov 2004 16:34:12 -0000	1.23
+++ beagle/Filters/Makefile.am	7 Nov 2004 19:28:45 -0000
@@ -25,7 +25,6 @@
 	$(srcdir)/FilterFlac.cs		\
 	$(srcdir)/FilterJpeg.cs		\
 	$(srcdir)/FilterMan.cs		\
-	$(srcdir)/FilterMusic.cs	\
 	$(srcdir)/FilterOpenOffice.cs	\
 	$(srcdir)/FilterPdf.cs		\
 	$(srcdir)/FilterPng.cs		\
@@ -40,6 +39,14 @@
 	$(srcdir)/FilterPPT.cs
 endif
 
+if ENABLE_GST_SHARP
+CSFILES +=				\
+	$(srcdir)/FilterGst.cs
+else
+CSFILES +=				\
+	$(srcdir)/FilterMusic.cs
+endif
+
 LOCAL_ASSEMBLIES =				\
 	../Util/Util.dll			\
 	../BeagleClient/Beagle.dll		\
@@ -49,6 +56,11 @@
 	$(BEAGLED_LIBS)			\
 	-r:ICSharpCode.SharpZipLib.dll	\
 	$(LOCAL_ASSEMBLIES:%=-r:%)
+
+if ENABLE_GST_SHARP
+ASSEMBLIES +=				\
+	$(GST_SHARP_LIBS)
+endif
 
 RESOURCES =
 


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