[tracker] Fixes: GB#608395, Flac extractor



commit 7cee56e7bfe1e81acff8078742d16b234a68f254
Author: Iain Holmes <iain openedhand com>
Date:   Tue Feb 2 14:13:37 2010 +0000

    Fixes: GB#608395, Flac extractor
    
    Add support for Flac files.

 configure.ac                               |   34 +++
 src/tracker-extract/Makefile.am            |   12 +
 src/tracker-extract/tracker-extract-flac.c |  336 ++++++++++++++++++++++++++++
 3 files changed, 382 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index fbb9d1c..39d6043 100644
--- a/configure.ac
+++ b/configure.ac
@@ -146,6 +146,7 @@ POPPLER_GLIB_REQUIRED=0.4.5
 CAIRO_REQUIRED=1.0
 GDK_REQUIRED=1.0
 LIBVORBIS_REQUIRED=0.22
+LIBFLAC_REQUIRED=1.2.1
 LIBEXIF_REQUIRED=0.6
 LIBGSF_REQUIRED=1.13
 EXEMPI_REQUIRED=2.1.0
@@ -1301,6 +1302,38 @@ fi
 AM_CONDITIONAL(HAVE_LIBVORBIS, test "x$have_libvorbis" = "xyes")
 
 ####################################################################
+# Check for flac
+####################################################################
+
+AC_ARG_ENABLE(libflac,
+	      AS_HELP_STRING([--enable-libflac],
+			     [enable extractor for flac data [[default=auto]]]),,
+	      [enable_libflac=auto])
+
+if test "x$enable_libflac" != "xno" ; then
+   PKG_CHECK_MODULES(LIBFLAC,
+		     [flac >= $LIBFLAC_REQUIRED],
+		     [have_libflac=yes],
+		     [have_libflac=no])
+   AC_SUBST(LIBFLAC_CFLAGS)
+   AC_SUBST(LIBFLAC_LIBS)
+
+   if test "x$have_libflac" = "xyes"; then
+      AC_DEFINE(HAVE_LIBFLAC, [], [Define if we have libflac])
+   fi
+else
+   have_libflac="no  (disabled)"
+fi
+
+if test "x$enable_libflac" = "xyes"; then
+   if test "x$have_libflac" != "xyes"; then
+      AC_MSG_ERROR([Couldn't find libflac >= $LIBFLAC_REQUIRED.])
+   fi
+fi
+
+AM_CONDITIONAL(HAVE_LIBFLAC, test "x$have_libflac" = "xyes")
+
+####################################################################
 # Check ioprio support
 ####################################################################
 
@@ -1720,6 +1753,7 @@ Metadata Extractors:
 	Support JPEG:				$have_libjpeg (xmp: $have_exempi, exif: $have_libexif, iptc: $have_libiptcdata)
 	Support TIFF:				$have_libtiff (xmp: $have_exempi, exif: yes, iptc: $have_libiptcdata)
 	Support Vorbis (ogg/etc):		$have_libvorbis
+	Support Flac:                           $have_libflac
 	Support MS & Open Office:	        $have_libgsf
 	Support XML / HTML:		        $have_libxml2
 	Support embedded / sidecar XMP:		$have_exempi
diff --git a/src/tracker-extract/Makefile.am b/src/tracker-extract/Makefile.am
index f3bc51d..240566f 100644
--- a/src/tracker-extract/Makefile.am
+++ b/src/tracker-extract/Makefile.am
@@ -45,6 +45,10 @@ if HAVE_LIBVORBIS
 modules_LTLIBRARIES += libextract-vorbis.la
 endif
 
+if HAVE_LIBFLAC
+modules_LTLIBRARIES += libextract-flac.la
+endif
+
 if HAVE_EXEMPI
 modules_LTLIBRARIES += libextract-xmp.la
 endif
@@ -124,6 +128,14 @@ libextract_vorbis_la_LIBADD = 						\
 	$(GLIB2_LIBS)							\
 	$(GCOV_LIBS)
 
+# Flac
+libextract_flac_la_SOURCES = tracker-extract-flac.c $(escape_sources)
+libextract_flac_la_LDFLAGS = $(module_flags)
+libextract_flac_la_LIBADD =						\
+	$(LIBFLAC_LIBS)							\
+	$(GLIB2_LIBS)							\
+	$(GCOV_LIBS)
+
 # MPlayer
 libextract_mplayer_la_SOURCES = tracker-extract-mplayer.c
 libextract_mplayer_la_LDFLAGS = $(module_flags)
diff --git a/src/tracker-extract/tracker-extract-flac.c b/src/tracker-extract/tracker-extract-flac.c
new file mode 100644
index 0000000..dbe7b63
--- /dev/null
+++ b/src/tracker-extract/tracker-extract-flac.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2010 Intel Corporation
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <glib.h>
+
+#include <FLAC/metadata.h>
+
+#include <libtracker-common/tracker-file-utils.h>
+#include <libtracker-common/tracker-ontology.h>
+#include <libtracker-common/tracker-utils.h>
+
+#include <libtracker-extract/tracker-extract.h>
+
+typedef struct {
+        gchar *title;
+        gchar *artist;
+        gchar *album;
+        gchar *albumartist;
+        gchar *trackcount;
+        gchar *tracknumber;
+        gchar *discno;
+        gchar *performer;
+        gchar *trackgain;
+        gchar *trackpeakgain;
+        gchar *albumgain;
+        gchar *albumpeakgain;
+        gchar *date;
+        gchar *comment;
+        gchar *genre;
+        gchar *mbalbumid;
+        gchar *mbartistid;
+        gchar *mbalbumartistid;
+        gchar *mbtrackid;
+        gchar *lyrics;
+        gchar *copyright;
+        gchar *license;
+        gchar *organisation;
+        gchar *location;
+        gchar *publisher;
+
+        guint samplerate;
+        guint channels;
+        guint bps;
+        guint64 total;
+} FlacData;
+
+static void extract_flac (const char           *uri,
+                          TrackerSparqlBuilder *metadata);
+
+static TrackerExtractData extract_data[] = {
+        { "audio/x-flac", extract_flac },
+        { NULL, NULL }
+};
+
+static void
+parse_vorbis_comments (FLAC__StreamMetadata_VorbisComment *comment,
+                       FlacData                           *fd)
+{
+        gint i;
+
+        /* FIXME: I hate the amount of duplicating this does, complete
+           memory fragmentation. We should be able to use some
+           GStringChunks */
+        for (i = 0; i < comment->num_comments; i++) {
+                FLAC__StreamMetadata_VorbisComment_Entry entry;
+
+                entry = comment->comments[i];
+
+                /* entry.entry is the format NAME=metadata */
+                if (g_ascii_strncasecmp (entry.entry, "title", 5) == 0) {
+                        fd->title = g_strdup (entry.entry + 6);
+                } else if (g_ascii_strncasecmp (entry.entry, "artist", 6) == 0) {
+                        /* FIXME: Handle multiple instances of artist */
+                        if (fd->artist == NULL) {
+                                fd->artist = g_strdup (entry.entry + 7);
+                        }
+                } else if (g_ascii_strncasecmp (entry.entry, "album", 5) == 0) {
+                        fd->album = g_strdup (entry.entry + 6);
+                } else if (g_ascii_strncasecmp (entry.entry, "albumartist", 11) == 0) {
+                        fd->albumartist = g_strdup (entry.entry + 12);
+                } else if (g_ascii_strncasecmp (entry.entry, "trackcount", 10) == 0) {
+                        fd->trackcount = g_strdup (entry.entry + 11);
+                } else if (g_ascii_strncasecmp (entry.entry, "tracknumber", 11) == 0) {
+                        fd->tracknumber = g_strdup (entry.entry + 12);
+                } else if (g_ascii_strncasecmp (entry.entry, "discno", 6) == 0) {
+                        fd->discno = g_strdup (entry.entry + 7);
+                } else if (g_ascii_strncasecmp (entry.entry, "performer", 9) == 0) {
+                        /* FIXME: Handle multiple instances of performer */
+                        if (fd->performer == NULL) {
+                                fd->performer = g_strdup (entry.entry + 10);
+                        }
+                } else if (g_ascii_strncasecmp (entry.entry, "trackgain", 9) == 0) {
+                        fd->trackgain = g_strdup (entry.entry + 10);
+                } else if (g_ascii_strncasecmp (entry.entry, "trackpeakgain", 13) == 0) {
+                        fd->trackpeakgain = g_strdup (entry.entry + 14);
+                } else if (g_ascii_strncasecmp (entry.entry, "albumgain", 9) == 0) {
+                        fd->albumgain = g_strdup (entry.entry + 10);
+                } else if (g_ascii_strncasecmp (entry.entry, "albumpeakgain", 13) == 0) {
+                        fd->albumpeakgain = g_strdup (entry.entry + 14);
+                } else if (g_ascii_strncasecmp (entry.entry, "date", 4) == 0) {
+                        fd->date = g_strdup (entry.entry + 5);
+                } else if (g_ascii_strncasecmp (entry.entry, "comment", 7) == 0) {
+                        fd->comment = g_strdup (entry.entry + 8);
+                } else if (g_ascii_strncasecmp (entry.entry, "genre", 5) == 0) {
+                        fd->genre = g_strdup (entry.entry + 6);
+                } else if (g_ascii_strncasecmp (entry.entry, "mbalbumid", 9) == 0) {
+                        fd->mbalbumid = g_strdup (entry.entry + 10);
+                } else if (g_ascii_strncasecmp (entry.entry, "mbartistid", 10) == 0) {
+                        fd->mbartistid = g_strdup (entry.entry + 11);
+                } else if (g_ascii_strncasecmp (entry.entry, "mbalbumartistid", 15) == 0) {
+                        fd->mbalbumartistid = g_strdup (entry.entry + 16);
+                } else if (g_ascii_strncasecmp (entry.entry, "mbtrackid", 9) == 0) {
+                        fd->mbtrackid = g_strdup (entry.entry + 10);
+                } else if (g_ascii_strncasecmp (entry.entry, "lyrics", 6) == 0) {
+                        fd->lyrics = g_strdup (entry.entry + 7);
+                } else if (g_ascii_strncasecmp (entry.entry, "copyright", 9) == 0) {
+                        fd->copyright = g_strdup (entry.entry + 10);
+                } else if (g_ascii_strncasecmp (entry.entry, "license", 8) == 0) {
+                        fd->license = g_strdup (entry.entry + 9);
+                } else if (g_ascii_strncasecmp (entry.entry, "organization", 12) == 0) {
+                        fd->organisation = g_strdup (entry.entry + 13);
+                } else if (g_ascii_strncasecmp (entry.entry, "location", 8) == 0) {
+                        fd->location = g_strdup (entry.entry + 9);
+                } else if (g_ascii_strncasecmp (entry.entry, "publisher", 9) == 0) {
+                        fd->publisher = g_strdup (entry.entry + 10);
+                }
+        }
+}
+
+static void
+add_tuple (TrackerSparqlBuilder *metadata,
+           const char           *predicate,
+           const char           *object)
+{
+        if (object) {
+                tracker_sparql_builder_predicate (metadata, predicate);
+                tracker_sparql_builder_object_unvalidated (metadata, object);
+        }
+}
+
+static void
+extract_flac (const gchar           *uri,
+              TrackerSparqlBuilder *metadata)
+{
+        FLAC__Metadata_SimpleIterator *iter;
+        FLAC__StreamMetadata *stream = NULL, *vorbis, *picture;
+        FLAC__bool success;
+        FlacData fd = { 0 };
+        gchar *filename, *creator, *artist_uri = NULL, *album_uri = NULL;
+	goffset size;
+
+        filename = g_filename_from_uri (uri, NULL, NULL);
+
+	size = tracker_file_get_size (filename);
+
+	if (size < 18) {
+		g_free (filename);
+		return;
+	}
+
+        iter = FLAC__metadata_simple_iterator_new ();
+        success = FLAC__metadata_simple_iterator_init (iter, filename, TRUE, FALSE);
+        g_free (filename);
+
+        if (!success) {
+                FLAC__metadata_simple_iterator_delete (iter);
+                return;
+        }
+
+        while (!FLAC__metadata_simple_iterator_is_last (iter)) {
+                switch (FLAC__metadata_simple_iterator_get_block_type (iter)) {
+                case FLAC__METADATA_TYPE_STREAMINFO:
+                        stream = FLAC__metadata_simple_iterator_get_block (iter);
+                        break;
+
+                case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                        vorbis = FLAC__metadata_simple_iterator_get_block (iter);
+                        parse_vorbis_comments (&(vorbis->data.vorbis_comment), &fd);
+                        FLAC__metadata_object_delete (vorbis);
+                        break;
+
+                case FLAC__METADATA_TYPE_PICTURE:
+                        picture = FLAC__metadata_simple_iterator_get_block (iter);
+                        /* Deal with picture */
+                        FLAC__metadata_object_delete (picture);
+                        break;
+
+                default:
+                        break;
+                }
+
+                FLAC__metadata_simple_iterator_next (iter);
+        }
+
+        /* This will find the first non-NULL and then free the rest */
+        creator = tracker_coalesce (3, fd.artist, fd.albumartist,
+                                    fd.performer);
+        if (creator) {
+                artist_uri = tracker_uri_printf_escaped ("urn:artist:%s",
+                                                         creator);
+                tracker_sparql_builder_subject_iri (metadata, artist_uri);
+                tracker_sparql_builder_predicate (metadata, "a");
+                tracker_sparql_builder_object (metadata, "nmm:Artist");
+                tracker_sparql_builder_predicate (metadata, "nmm:artistName");
+                tracker_sparql_builder_object_unvalidated (metadata, creator);
+                g_free (creator);
+        }
+
+        if (fd.album) {
+                album_uri = tracker_uri_printf_escaped ("urn:album:%s",
+                                                        fd.album);
+                tracker_sparql_builder_subject_iri (metadata, album_uri);
+                tracker_sparql_builder_predicate (metadata, "a");
+                tracker_sparql_builder_object (metadata, "nmm:MusicAlbum");
+                tracker_sparql_builder_predicate (metadata, "nmm:albumTitle");
+                tracker_sparql_builder_object_unvalidated (metadata,
+                                                           fd.album);
+
+                if (fd.trackcount) {
+                        tracker_sparql_builder_predicate (metadata, "nmm:albumTrackCount");
+                        tracker_sparql_builder_object_unvalidated (metadata,
+                                                                   fd.trackcount);
+                }
+        }
+
+        tracker_sparql_builder_subject_iri (metadata, uri);
+        tracker_sparql_builder_predicate (metadata, "a");
+        tracker_sparql_builder_object (metadata, "nmm:MusicPiece");
+        tracker_sparql_builder_object (metadata, "nfo:Audio");
+
+        add_tuple (metadata, "nmm:performer", artist_uri);
+        g_free (artist_uri);
+
+        add_tuple (metadata, "nmm:musicAlbum", album_uri);
+        g_free (album_uri);
+
+        add_tuple (metadata, "nie:title", fd.title);
+        add_tuple (metadata, "nmm:trackNumber", fd.tracknumber);
+
+        /* FIXME: This is commented out in vorbis extractor... */
+        add_tuple (metadata, "nmm:setNumber", fd.discno);
+
+        /* FIXME: Trackgain/Trackpeakgain: commented out in vorbis */
+
+        add_tuple (metadata, "nmm:albumGain", fd.albumgain);
+        add_tuple (metadata, "nmm:albumPeakGain", fd.albumpeakgain);
+        add_tuple (metadata, "nie:comment", fd.comment);
+        add_tuple (metadata, "nie:contentCreated", "2003-08-22T19:52:10Z");
+        add_tuple (metadata, "nfo:genre", fd.genre);
+        add_tuple (metadata, "nie:plainTextContent", fd.lyrics);
+        add_tuple (metadata, "nie:copyright", fd.copyright);
+        add_tuple (metadata, "nie:license", fd.license);
+
+        if (fd.publisher) {
+                tracker_sparql_builder_predicate (metadata, "dc:publisher");
+
+                tracker_sparql_builder_object_blank_open (metadata);
+                tracker_sparql_builder_predicate (metadata, "a");
+                tracker_sparql_builder_object (metadata, "nco:Contact");
+
+                tracker_sparql_builder_predicate (metadata, "nco:fullname");
+                tracker_sparql_builder_object_unvalidated (metadata,
+                                                           fd.publisher);
+                tracker_sparql_builder_object_blank_close (metadata);
+        }
+
+        if (stream) {
+                tracker_sparql_builder_predicate (metadata, "nfo:sampleRate");
+                tracker_sparql_builder_object_int64 (metadata, 
+                                                     stream->data.stream_info.sample_rate);
+
+                tracker_sparql_builder_predicate (metadata, "nfo:channels");
+                tracker_sparql_builder_object_int64 (metadata, 
+                                                     stream->data.stream_info.channels);
+
+                tracker_sparql_builder_predicate (metadata,
+                                                  "nfo:averageBitrate");
+                tracker_sparql_builder_object_int64 (metadata, 
+                                                     stream->data.stream_info.bits_per_sample);
+
+                tracker_sparql_builder_predicate (metadata, "nfo:duration");
+                tracker_sparql_builder_object_int64 (metadata, 
+                                                     stream->data.stream_info.total_samples / 
+                                                     stream->data.stream_info.sample_rate);
+        }
+
+        g_free (fd.title);
+        g_free (fd.trackcount);
+        g_free (fd.tracknumber);
+        g_free (fd.discno);
+        g_free (fd.trackgain);
+        g_free (fd.trackpeakgain);
+        g_free (fd.albumgain);
+        g_free (fd.albumpeakgain);
+        g_free (fd.date);
+        g_free (fd.comment);
+        g_free (fd.genre);
+        g_free (fd.mbalbumid);
+        g_free (fd.mbartistid);
+        g_free (fd.mbalbumartistid);
+        g_free (fd.mbtrackid);
+        g_free (fd.lyrics);
+        g_free (fd.copyright);
+        g_free (fd.license);
+        g_free (fd.organisation);
+        g_free (fd.location);
+        g_free (fd.publisher);
+}
+
+TrackerExtractData *
+tracker_extract_get_data (void)
+{
+        return extract_data;
+}



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