[tracker] Add a libav based generic media extractor.



commit 816fef43ccf06366c9c5f427f8a52046e32872bb
Author: Andrew den Exter <andrew den exter jollamobile com>
Date:   Tue Sep 3 04:23:12 2013 +0000

    Add a libav based generic media extractor.

 configure.ac                                |   45 ++++-
 src/tracker-extract/Makefile.am             |   19 ++
 src/tracker-extract/tracker-extract-libav.c |  369 +++++++++++++++++++++++++++
 3 files changed, 432 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index d733ae1..65784e3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1687,7 +1687,7 @@ AM_CONDITIONAL(HAVE_GDKPIXBUF, test "x$have_gdkpixbuf" = "xyes")
 
 AC_ARG_ENABLE(generic-media-extractor,
               AS_HELP_STRING([--enable-generic-media-extractor=ARG],
-                             [enables one of the (gstreamer, xine, external, auto) generic media extractor 
backends [[default=auto]]]),,
+                             [enables one of the (gstreamer, xine, libav, external, auto) generic media 
extractor backends [[default=auto]]]),,
               [enable_generic_media_extractor=auto])
 
 PKG_CHECK_MODULES(GSTREAMER,
@@ -1707,6 +1707,30 @@ PKG_CHECK_MODULES(XINE,
 AC_SUBST(XINE_CFLAGS)
 AC_SUBST(XINE_LIBS)
 
+PKG_CHECK_MODULES(AVFORMAT,
+                  [libavformat >= 0.8.4],
+                  [have_libavformat=yes],
+                  [have_libavformat=no])
+
+AC_SUBST(AVFORMAT_CFLAGS)
+AC_SUBST(AVFORMAT_LIBS)
+
+PKG_CHECK_MODULES(AVCODEC,
+                  [libavcodec >= 0.8.4],
+                  [have_libavcodec=yes],
+                  [have_libavcodec=no])
+
+AC_SUBST(AVCODEC_CFLAGS)
+AC_SUBST(AVCODEC_LIBS)
+
+PKG_CHECK_MODULES(AVCODEC,
+                  [libavutil >= 0.8.4],
+                  [have_libavutil=yes],
+                  [have_libavutil=no])
+
+AC_SUBST(AVUTIL_CFLAGS)
+AC_SUBST(AVUTIL_LIBS)
+
 if test "x$enable_generic_media_extractor" = "xauto"; then
    if test "$have_libgstreamer" = "yes"; then
       have_generic_media_handler="yes"
@@ -1714,6 +1738,9 @@ if test "x$enable_generic_media_extractor" = "xauto"; then
    elif test "$have_libxine" = "yes"; then
       have_generic_media_handler_app="Xine"
       have_generic_media_handler="yes"
+   elif test "$have_libav" = "yes"; then
+      have_generic_media_handler_app="libav"
+      have_generic_media_handler="yes"
    else
       have_generic_media_handler="?"
       have_generic_media_handler_app="An external generic_media player will be called"
@@ -1732,6 +1759,13 @@ elif test "x$enable_generic_media_extractor" = "xxine"; then
    else
       AC_MSG_ERROR([Couldn't find libxine])
    fi
+elif test "x$enable_generic_media_extractor" = "xlibav"; then
+   if test "$have_libavformat" = "yes" && test "$have_libavcodec" = "yes" && test "$have_libavutil" = "yes"; 
then
+      have_generic_media_handler_app="libav"
+      have_generic_media_handler="yes"
+   else
+      AC_MSG_ERROR([Couldn't find libav])
+   fi
 else
    have_generic_media_handler="?"
    have_generic_media_handler_app="An external generic media player will be called"
@@ -1741,17 +1775,26 @@ if test "$have_generic_media_handler_app" = "GStreamer"; then
    AC_DEFINE(HAVE_GSTREAMER, [], [Define if we have GStreamer])
    AM_CONDITIONAL(HAVE_GSTREAMER, true)
    AM_CONDITIONAL(HAVE_LIBXINE, false)
+   AM_CONDITIONAL(HAVE_LIBAV, false)
    AM_CONDITIONAL(USING_EXTERNAL_GENERIC_MEDIA_PLAYER, false)
 elif test "$have_generic_media_handler_app" = "Xine"; then
    AC_DEFINE(HAVE_LIBXINE, [], [Define if we have Libxine])
    AM_CONDITIONAL(HAVE_LIBXINE, true)
    AM_CONDITIONAL(HAVE_GSTREAMER, false)
+   AM_CONDITIONAL(HAVE_LIBAV, false)
    AM_CONDITIONAL(USING_EXTERNAL_GENERIC_MEDIA_PLAYER, false)
+elif test "$have_generic_media_handler_app" = "libav"; then
+    AC_DEFINE(HAVE_GSTREAMER, [], [Define if we have libav])
+    AM_CONDITIONAL(HAVE_LIBAV, true)
+    AM_CONDITIONAL(HAVE_GSTREAMER, false)
+    AM_CONDITIONAL(HAVE_LIBXINE, false)
+    AM_CONDITIONAL(USING_EXTERNAL_GENERIC_MEDIA_PLAYER, false)
 else
    AC_DEFINE(USING_EXTERNAL_GENERIC_MEDIA_PLAYER, [], [Define that Tracker will try to use external generic 
media players])
    AM_CONDITIONAL(USING_EXTERNAL_GENERIC_MEDIA_PLAYER, true)
    AM_CONDITIONAL(HAVE_GSTREAMER, false)
    AM_CONDITIONAL(HAVE_LIBXINE, false)
+   AM_CONDITIONAL(HAVE_LIBAV, false)
 fi
 
 ###########################################################################
diff --git a/src/tracker-extract/Makefile.am b/src/tracker-extract/Makefile.am
index d8d175f..bb8296e 100644
--- a/src/tracker-extract/Makefile.am
+++ b/src/tracker-extract/Makefile.am
@@ -42,6 +42,7 @@ rules_files = \
        15-playlist.rule \
        90-gstreamer-generic.rule \
        90-text-generic.rule \
+        90-libav-generic.rule \
        91-gstreamer-generic-dlna.rule \
        92-xine-generic.rule \
        93-mplayer-generic.rule \
@@ -173,6 +174,11 @@ extractmodules_LTLIBRARIES += libextract-icon.la
 rules_DATA += 10-ico.rule
 endif
 
+if HAVE_LIBAV
+extractmodules_LTLIBRARIES += libextract-libav.la
+rules_DATA += 90-libav-generic.rule
+endif
+
 # ABW
 libextract_abw_la_SOURCES = tracker-extract-abw.c
 libextract_abw_la_CFLAGS = $(TRACKER_EXTRACT_MODULES_CFLAGS)
@@ -491,6 +497,19 @@ libextract_iso_la_LIBADD = \
        $(TRACKER_EXTRACT_MODULES_LIBS) \
        $(LIBOSINFO_LIBS)
 
+# libav
+libextract_libav_la_SOURCES = tracker-extract-libav.c
+libextract_libav_la_CFLAGS = $(TRACKER_EXTRACT_MODULES_CFLAGS)
+libextract_libav_la_LDFLAGS = $(module_flags)
+libextract_libav_la_LIBADD = \
+       $(top_builddir)/src/libtracker-extract/libtracker-extract- TRACKER_API_VERSION@.la \
+       $(top_builddir)/src/libtracker-common/libtracker-common.la \
+       $(BUILD_LIBS) \
+       $(TRACKER_EXTRACT_MODULES_LIBS) \
+        $(AVFORMAT_LIBS) \
+        $(AVUTIL_LIBS)
+
+
 #
 # Binaries
 #
diff --git a/src/tracker-extract/tracker-extract-libav.c b/src/tracker-extract/tracker-extract-libav.c
new file mode 100644
index 0000000..04ed3a0
--- /dev/null
+++ b/src/tracker-extract/tracker-extract-libav.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2013 Jolla Ltd.
+ * Contact: Andrew den Exter <andrew den exter jollamobile com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+
+#include <glib.h>
+
+#include <libtracker-common/tracker-ontologies.h>
+#include <libtracker-common/tracker-utils.h>
+
+#include <libtracker-extract/tracker-extract.h>
+
+#include <tracker-media-art.h>
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavutil/mathematics.h>
+
+static void
+open_insert (TrackerSparqlBuilder *preupdate, const char *graph, const gchar *iri, const gchar *type)
+{
+       tracker_sparql_builder_insert_open (preupdate, NULL);
+       if (graph) {
+               tracker_sparql_builder_graph_open(preupdate, graph);
+       }
+
+       tracker_sparql_builder_subject_iri (preupdate, iri);
+       tracker_sparql_builder_predicate (preupdate, "a");
+       tracker_sparql_builder_object (preupdate, type);
+}
+
+static void
+close_insert (TrackerSparqlBuilder *preupdate, const char *graph)
+{
+       if (graph) {
+               tracker_sparql_builder_graph_close (preupdate);
+       }
+       tracker_sparql_builder_insert_close (preupdate);
+}
+
+static void
+delete_value (TrackerSparqlBuilder *preupdate, const gchar *iri, const gchar *predicate,
+                         const char *value)
+{
+       tracker_sparql_builder_delete_open (preupdate, NULL);
+       tracker_sparql_builder_subject_iri (preupdate, iri);
+       tracker_sparql_builder_predicate (preupdate, predicate);
+       tracker_sparql_builder_object_variable (preupdate, value);
+       tracker_sparql_builder_delete_close (preupdate);
+
+       tracker_sparql_builder_where_open (preupdate);
+       tracker_sparql_builder_subject_iri (preupdate, iri);
+       tracker_sparql_builder_predicate (preupdate, predicate);
+       tracker_sparql_builder_object_variable (preupdate, value);
+       tracker_sparql_builder_where_close (preupdate);
+}
+
+static void
+set_value_iri (TrackerSparqlBuilder *metadata, const gchar *predicate, const gchar *iri)
+{
+       tracker_sparql_builder_predicate (metadata, predicate);
+       tracker_sparql_builder_object_iri (metadata, iri);
+}
+
+static void
+set_value_double (TrackerSparqlBuilder *metadata, const gchar *predicate, gdouble value)
+{
+       tracker_sparql_builder_predicate (metadata, predicate);
+       tracker_sparql_builder_object_double (metadata, value);
+}
+
+static void
+set_value_int64 (TrackerSparqlBuilder *metadata, const gchar *predicate, gint64 value)
+{
+       tracker_sparql_builder_predicate (metadata, predicate);
+       tracker_sparql_builder_object_int64 (metadata, value);
+}
+
+static void
+set_value_string (TrackerSparqlBuilder *metadata, const gchar *predicate, const gchar *value)
+{
+       tracker_sparql_builder_predicate (metadata, predicate);
+       tracker_sparql_builder_object_unvalidated (metadata, value);
+}
+
+static gchar *
+create_artist (TrackerSparqlBuilder *preupdate, const gchar *graph, const char *name)
+{
+       gchar *uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", name);
+
+       open_insert (preupdate, graph, uri, "nmm:Artist");
+       set_value_string (preupdate, "nmm:artistName", name);
+       close_insert (preupdate, graph);
+
+       return uri;
+}
+
+G_MODULE_EXPORT gboolean
+tracker_extract_get_metadata (TrackerExtractInfo *info)
+{
+       GFile *file;
+       TrackerSparqlBuilder *metadata;
+       TrackerSparqlBuilder *preupdate;
+       const gchar *graph;
+       gchar *absoluteFilePath;
+       gchar *uri;
+       AVFormatContext *format = NULL;
+       AVStream *audio_stream = NULL;
+       AVStream *video_stream = NULL;
+       int streamIndex;
+       AVDictionaryEntry *tag = NULL;
+       const char *title;
+
+       av_register_all();
+
+       file = tracker_extract_info_get_file (info);
+       metadata = tracker_extract_info_get_metadata_builder (info);
+       preupdate = tracker_extract_info_get_preupdate_builder (info);
+       graph = tracker_extract_info_get_graph (info);
+
+       uri = g_file_get_uri (file);
+
+       absoluteFilePath = g_file_get_path (file);
+       if (avformat_open_input(&format, absoluteFilePath, NULL, NULL)) {
+               g_free (absoluteFilePath);
+               return FALSE;
+       }
+       g_free (absoluteFilePath);
+
+       streamIndex = av_find_best_stream (format, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
+       if (streamIndex >= 0) {
+               audio_stream = format->streams[streamIndex];
+       }
+
+       streamIndex = av_find_best_stream (format, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
+       if (streamIndex >= 0) {
+               video_stream = format->streams[streamIndex];
+       }
+
+       if (!audio_stream && !video_stream) {
+               avformat_free_context(format);
+               return FALSE;
+       }
+
+       if (video_stream) {
+               tracker_sparql_builder_predicate (metadata, "a");
+               tracker_sparql_builder_object (metadata, "nmm:Video");
+
+               if (video_stream->codec->width > 0 && video_stream->codec->height > 0) {
+                       set_value_int64 (metadata, "nfo:width", video_stream->codec->width);
+                       set_value_int64 (metadata, "nfo:height", video_stream->codec->height);
+               }
+
+               if (video_stream->avg_frame_rate.num > 0) {
+                       gdouble frame_rate
+                                       = (gdouble) video_stream->avg_frame_rate.num
+                                       / video_stream->avg_frame_rate.den;
+                       set_value_double (metadata, "nfo:frameRate", frame_rate);
+               }
+
+               if (video_stream->duration > 0) {
+                       gint64 duration = av_rescale(video_stream->duration, video_stream->time_base.num,
+                                                    video_stream->time_base.den);
+                       set_value_int64 (metadata, "nfo:duration", duration);
+               }
+
+               if (video_stream->sample_aspect_ratio.num > 0) {
+                       gdouble aspect_ratio
+                                       = (gdouble) video_stream->sample_aspect_ratio.num
+                                       / video_stream->sample_aspect_ratio.den;
+                       set_value_double (metadata, "nfo:aspectRatio", aspect_ratio);
+               }
+
+               if (video_stream->nb_frames > 0) {
+                       set_value_int64 (metadata, "nfo:frameCount", video_stream->nb_frames);
+               }
+
+               if ((tag = av_dict_get (format->metadata, "synopsis", NULL, 0))) {
+                       set_value_string (metadata, "nmm:synopsis", tag->value);
+               }
+
+               if ((tag = av_dict_get (format->metadata, "episode_sort", NULL, 0))) {
+                       set_value_int64 (metadata, "nmm:episodeNumber", atoi(tag->value));
+               }
+
+               if ((tag = av_dict_get (format->metadata, "season_number", NULL, 0))) {
+                       set_value_int64 (metadata, "nmm:season", atoi(tag->value));
+               }
+
+       } else if (audio_stream) {
+               const char *album_title = NULL;
+               const char *album_artist = NULL;
+               gchar *album_artist_uri = NULL;
+               gchar *performer_uri = NULL;
+
+               tracker_sparql_builder_predicate (metadata, "a");
+               tracker_sparql_builder_object (metadata, "nmm:MusicPiece");
+               tracker_sparql_builder_object (metadata, "nfo:Audio");
+
+               if (audio_stream->duration > 0) {
+                       gint64 duration = av_rescale(audio_stream->duration, audio_stream->time_base.num,
+                                                    audio_stream->time_base.den);
+                       set_value_int64 (metadata, "nfo:duration", duration);
+               }
+
+               if ((tag = av_dict_get (format->metadata, "track", NULL, 0))) {
+                       int track = atoi(tag->value);
+                       if (track > 0) {
+                               set_value_int64 (metadata, "nmm:trackNumber", track);
+                       }
+               }
+
+               if ((tag = av_dict_get (format->metadata, "album", NULL, 0))) {
+                       album_title = tag->value;
+               }
+
+               if (album_title && (tag = av_dict_get (format->metadata, "album_artist", NULL, 0))) {
+                       album_artist_uri = create_artist (preupdate, graph, tag->value);
+                       album_artist = tag->value;
+               }
+
+               if ((tag = av_dict_get (format->metadata, "artist", tag, 0))) {
+                       performer_uri = create_artist (preupdate, graph, tag->value);
+                       if (!album_artist) {
+                               album_artist = tag->value;
+                       }
+               }
+
+               if (!performer_uri && (tag = av_dict_get (format->metadata, "performer", tag, 0))) {
+                       performer_uri = create_artist (preupdate, graph, tag->value);
+                       if (!album_artist) {
+                               album_artist = tag->value;
+                       }
+               }
+
+               if (performer_uri) {
+                       set_value_iri (metadata, "nmm:performer", performer_uri);
+
+                       if (album_title && album_artist_uri) {
+                               g_free(performer_uri);
+                       }
+               } else if (album_artist_uri) {
+                       set_value_iri (metadata, "nmm:performer", album_artist_uri);
+               }
+
+               if ((tag = av_dict_get (format->metadata, "composer", tag, 0))) {
+                       gchar *composer_uri = create_artist (preupdate, graph, tag->value);
+                       set_value_iri (metadata, "nmm:composer", composer_uri);
+                       g_free(composer_uri);
+               }
+
+
+               if (album_title) {
+                       int disc = 1;
+                       gchar *disc_uri;
+                       gchar *album_uri = tracker_sparql_escape_uri_printf ("urn:album:%s", album_title);
+
+                       open_insert (preupdate, graph, album_uri, "nmm:MusicAlbum");
+                       set_value_string (preupdate, "nmm:albumTitle", album_title);
+                       if (album_artist_uri) {
+                               set_value_iri (preupdate, "nmm:albumArtist", album_artist_uri);
+                       } else if (performer_uri) {
+                               set_value_iri (preupdate, "nmm:albumArtist", performer_uri);
+                       }
+                       close_insert (preupdate, graph);
+
+
+                       if ((tag = av_dict_get (format->metadata, "disc", NULL, 0))) {
+                               disc = atoi (tag->value);
+                       }
+
+                       disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:Disc%d",
+                                                                    album_title,
+                                                                    disc);
+
+                       delete_value (preupdate, disc_uri, "nmm:setNumber", "unknown");
+                       delete_value (preupdate, disc_uri, "nmm:albumDiscAlbum", "unknown");
+
+                       open_insert (preupdate, graph, disc_uri, "nmm:MusicAlbumDisc");
+                       set_value_int64 (preupdate, "nmm:setNumber", disc);
+                       set_value_iri (preupdate, "nmm:albumDiscAlbum", album_uri);
+                       close_insert (preupdate, graph);
+
+                       set_value_iri (metadata, "nmm:musicAlbumDisc", disc_uri);
+                       set_value_iri (metadata, "nmm:musicAlbum", album_uri);
+
+                       g_free (disc_uri);
+                       g_free (album_uri);
+               }
+
+               tracker_media_art_process (NULL,
+                                          0,
+                                          NULL,
+                                          TRACKER_MEDIA_ART_ALBUM,
+                                          album_artist,
+                                          album_title,
+                                          uri);
+       }
+
+       if (audio_stream) {
+               if (audio_stream->codec->sample_rate > 0) {
+                       set_value_int64 (metadata, "nfo:sampleRate", audio_stream->codec->sample_rate);
+               }
+               if (audio_stream->codec->channels > 0) {
+                       set_value_int64 (metadata, "nfo:channels", audio_stream->codec->channels);
+               }
+       }
+
+       if (format->bit_rate > 0) {
+               set_value_int64 (metadata, "nfo:averageBitrate", format->bit_rate);
+       }
+
+
+       if ((tag = av_dict_get (format->metadata, "comment", NULL, 0))) {
+               set_value_string (metadata, "nie:comment", tag->value);
+       }
+
+       if ((tag = av_dict_get (format->metadata, "copyright", NULL, 0))) {
+               set_value_string (metadata, "nie:copyright", tag->value);
+       }
+
+       if ((tag = av_dict_get (format->metadata, "creation_time", NULL, 0))) {
+               gchar *content_created = tracker_date_guess (tag->value);
+               if (content_created) {
+                       set_value_string (metadata, "nie:contentCreated", content_created);
+                       g_free (content_created);
+               }
+       }
+
+       if ((tag = av_dict_get (format->metadata, "description", NULL, 0))) {
+               set_value_string (metadata, "nie:description", tag->value);
+       }
+
+       if ((tag = av_dict_get (format->metadata, "genre", NULL, 0))) {
+               set_value_string (metadata, "nfo:genre", tag->value);
+       }
+
+       if ((tag = av_dict_get (format->metadata, "language", NULL, 0))) {
+               set_value_string (metadata, "nfo:language", tag->value);
+       }
+
+       if ((tag = av_dict_get (format->metadata, "title", NULL, 0))) {
+               title = tag->value;
+       }
+
+       tracker_guarantee_title_from_file (metadata, "nie:title", title, uri, NULL);
+
+       g_free (uri);
+
+       avformat_free_context (format);
+
+       return TRUE;
+}


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