-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

This extractor uses libavformat (apt-get install libavformat-dev) to
extract metadata from certain audio and video formats.

It's written by/for Jolla by Andrew Den Exter (in CC).

I left the patches as is, not squashing them together as we generally
prefer to retain the development-cycle of a feature in our git repository.

Small adaptations were needed to port this to master, in particular
the 90*.rule file and Makefile.am of tracker-extract had to be adapted.

Kind regards,

Philip
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.20 (MingW32)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQEcBAEBAgAGBQJSxXMvAAoJEEP2NSGEz4aD5gQIAJY22u430z4D7kmsAF/lfXqA
97dQbnqDr9kAbOlLcO0CAAxEJO2Gesjfr0V5mJMPUjrI93lt5vC8Ny6PND7ogYNa
llV+W5Y3ZjoE9PcnwxUjFPMmkdSESjNqe7+fyiVpleqPim0C9MTjTkWQp12MkN0R
1Xxfr0fISTZ+kHkBwQ8EuBOqW1XAvWa3kY4CBH0AMQ2egj4dFSYfe/LedtQmyObO
ugm4OYKjA0PP1Va5s8mnylPb0sWPl5MYgzPWyAYVjx11ls3Vy8kaOluaKj0y9Bx+
CdLJ897ElSYnaC3yLnY078EIoK1bopDTaIBVJBbVKCIYOB3odE8NyvpCd9mJU1E=
=+Qvs
-----END PGP SIGNATURE-----
>From e14fbe8bea83a5131520d8925792b899032fcc47 Mon Sep 17 00:00:00 2001
From: Andrew den Exter <andrew.den.ex...@jollamobile.com>
Date: Tue, 3 Sep 2013 04:23:12 +0000
Subject: [PATCH 1/4] 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 deletion(-)
 create mode 100644 src/tracker-extract/tracker-extract-libav.c

diff --git a/configure.ac b/configure.ac
index 090ebd2..91cb91a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1646,7 +1646,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,
@@ -1666,6 +1666,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"
@@ -1673,6 +1697,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"
@@ -1691,6 +1718,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"
@@ -1700,17 +1734,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.ex...@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;
+}
-- 
1.8.4.2

>From e62f008e777654a406b1491576ee71aa7af2fa2a Mon Sep 17 00:00:00 2001
From: Andrew den Exter <andrew.den.ex...@jollamobile.com>
Date: Fri, 13 Sep 2013 03:09:51 +0000
Subject: [PATCH 2/4] Fix uninitialized variable in libav extractor.

And warning about passing NULL to an argument that takes an int in
vorbis extractor.
---
 src/tracker-extract/tracker-extract-libav.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tracker-extract/tracker-extract-libav.c 
b/src/tracker-extract/tracker-extract-libav.c
index 04ed3a0..1414b5d 100644
--- a/src/tracker-extract/tracker-extract-libav.c
+++ b/src/tracker-extract/tracker-extract-libav.c
@@ -125,7 +125,7 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        AVStream *video_stream = NULL;
        int streamIndex;
        AVDictionaryEntry *tag = NULL;
-       const char *title;
+       const char *title = NULL;
 
        av_register_all();
 
-- 
1.8.4.2

>From 6572856a17c77738a52ce14d0cd65f32b2e1883d Mon Sep 17 00:00:00 2001
From: Andrew den Exter <andrew.den.ex...@jollamobile.com>
Date: Tue, 22 Oct 2013 03:28:08 +0000
Subject: [PATCH 3/4] Ensure video size is extracted by libav extractor.

It may be necessary to parse the MPEG bitstream to get width and height
from some videos so if the resolution isn't immediately available decode
enough data to determine it.
---
 src/tracker-extract/Makefile.am             |  5 +-
 src/tracker-extract/tracker-extract-libav.c | 96 ++++++++++++++++++++++++-----
 2 files changed, 83 insertions(+), 18 deletions(-)

diff --git a/src/tracker-extract/Makefile.am b/src/tracker-extract/Makefile.am
index bb8296e..5ec6b66 100644
--- a/src/tracker-extract/Makefile.am
+++ b/src/tracker-extract/Makefile.am
@@ -506,8 +506,9 @@ libextract_libav_la_LIBADD = \
        $(top_builddir)/src/libtracker-common/libtracker-common.la \
        $(BUILD_LIBS) \
        $(TRACKER_EXTRACT_MODULES_LIBS) \
-        $(AVFORMAT_LIBS) \
-        $(AVUTIL_LIBS)
+       $(AVFORMAT_LIBS) \
+       $(AVUTIL_LIBS) \
+       $(AVCODEC_LIBS)
 
 
 #
diff --git a/src/tracker-extract/tracker-extract-libav.c 
b/src/tracker-extract/tracker-extract-libav.c
index 1414b5d..3c71807 100644
--- a/src/tracker-extract/tracker-extract-libav.c
+++ b/src/tracker-extract/tracker-extract-libav.c
@@ -123,7 +123,10 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        AVFormatContext *format = NULL;
        AVStream *audio_stream = NULL;
        AVStream *video_stream = NULL;
-       int streamIndex;
+       AVCodec *audio_codec = NULL;
+       AVCodec *video_codec = NULL;
+       int audio_stream_index;
+       int video_stream_index;
        AVDictionaryEntry *tag = NULL;
        const char *title = NULL;
 
@@ -143,14 +146,14 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        }
        g_free (absoluteFilePath);
 
-       streamIndex = av_find_best_stream (format, AVMEDIA_TYPE_AUDIO, -1, -1, 
NULL, 0);
-       if (streamIndex >= 0) {
-               audio_stream = format->streams[streamIndex];
+       audio_stream_index = av_find_best_stream (format, AVMEDIA_TYPE_AUDIO, 
-1, -1, &audio_codec, 0);
+       if (audio_stream_index >= 0) {
+               audio_stream = format->streams[audio_stream_index];
        }
 
-       streamIndex = av_find_best_stream (format, AVMEDIA_TYPE_VIDEO, -1, -1, 
NULL, 0);
-       if (streamIndex >= 0) {
-               video_stream = format->streams[streamIndex];
+       video_stream_index = av_find_best_stream (format, AVMEDIA_TYPE_VIDEO, 
-1, -1, &video_codec, 0);
+       if (video_stream_index >= 0) {
+               video_stream = format->streams[video_stream_index];
        }
 
        if (!audio_stream && !video_stream) {
@@ -158,6 +161,45 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                return FALSE;
        }
 
+       if (audio_stream) {
+               if (audio_stream->codec->sample_rate > 0) {
+                       set_value_int64 (metadata, "nfo:sampleRate", 
audio_stream->codec->sample_rate);
+               } else if (avcodec_open2(audio_stream->codec, audio_codec, 0) 
>= 0) {
+                       AVFrame *frame;
+                       AVPacket packet;
+                       av_init_packet(&packet);
+
+                       frame = avcodec_alloc_frame();
+
+                       for (;;) {
+                               int decoded = 0;
+                               if (av_read_frame (format, &packet) < 0) {
+                                       break;
+                               } else if (packet.stream_index != 
audio_stream_index) {
+                               } else if (!avcodec_decode_audio4(
+                                       audio_stream->codec, frame, &decoded, 
&packet) < 0) {
+                                       av_free_packet(&packet);
+                                       break;
+                               } else if (audio_stream->codec->sample_rate > 
0) {
+                                       set_value_int64 (metadata, 
"nfo:sampleRate",
+                                                        
audio_stream->codec->sample_rate);
+                                       break;
+                               }
+                               av_free_packet(&packet);
+
+                               if (decoded) {
+                                       break;
+                               }
+                       }
+                       av_free(frame);
+
+                       avcodec_close(audio_stream->codec);
+               }
+               if (audio_stream->codec->channels > 0) {
+                       set_value_int64 (metadata, "nfo:channels", 
audio_stream->codec->channels);
+               }
+       }
+
        if (video_stream) {
                tracker_sparql_builder_predicate (metadata, "a");
                tracker_sparql_builder_object (metadata, "nmm:Video");
@@ -165,6 +207,37 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                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);
+               } else if (avcodec_open2(video_stream->codec, video_codec, 0) 
>= 0) {
+                       AVFrame *frame;
+                       AVPacket packet;
+                       av_init_packet(&packet);
+
+                       frame = avcodec_alloc_frame();
+
+                       av_seek_frame(format, video_stream_index, -1, 0);
+                       for (;;) {
+                               int decoded = 0;
+                               if (av_read_frame(format, &packet) < 0) {
+                                       break;
+                               } else if (packet.stream_index != 
video_stream_index) {
+                               } else if (!avcodec_decode_video2(
+                                       video_stream->codec, frame, &decoded, 
&packet) < 0) {
+                                       av_free_packet(&packet);
+                                       break;
+                               } else 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);
+                                       break;
+                               }
+                               av_free_packet(&packet);
+
+                               if (decoded) {
+                                       break;
+                               }
+                       }
+                       av_free(frame);
+
+                       avcodec_close(video_stream->codec);
                }
 
                if (video_stream->avg_frame_rate.num > 0) {
@@ -313,15 +386,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                                           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);
        }
-- 
1.8.4.2

>From 05775e9354e6c7502704e8989d40b74f40bffa65 Mon Sep 17 00:00:00 2001
From: Andrew den Exter <andrew.den.ex...@jollamobile.com>
Date: Fri, 22 Nov 2013 07:12:07 +0000
Subject: [PATCH 4/4] Improve detection of media stream properties.

Use the much more comprehensive avformat_stream_info to probe
data from packetized data rather than directly trying to partially
decode frames.
---
 src/tracker-extract/tracker-extract-libav.c | 69 ++---------------------------
 1 file changed, 4 insertions(+), 65 deletions(-)

diff --git a/src/tracker-extract/tracker-extract-libav.c 
b/src/tracker-extract/tracker-extract-libav.c
index 3c71807..ebcd1ba 100644
--- a/src/tracker-extract/tracker-extract-libav.c
+++ b/src/tracker-extract/tracker-extract-libav.c
@@ -123,8 +123,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        AVFormatContext *format = NULL;
        AVStream *audio_stream = NULL;
        AVStream *video_stream = NULL;
-       AVCodec *audio_codec = NULL;
-       AVCodec *video_codec = NULL;
        int audio_stream_index;
        int video_stream_index;
        AVDictionaryEntry *tag = NULL;
@@ -146,12 +144,14 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        }
        g_free (absoluteFilePath);
 
-       audio_stream_index = av_find_best_stream (format, AVMEDIA_TYPE_AUDIO, 
-1, -1, &audio_codec, 0);
+       avformat_find_stream_info (format, NULL);
+
+       audio_stream_index = av_find_best_stream (format, AVMEDIA_TYPE_AUDIO, 
-1, -1, NULL, 0);
        if (audio_stream_index >= 0) {
                audio_stream = format->streams[audio_stream_index];
        }
 
-       video_stream_index = av_find_best_stream (format, AVMEDIA_TYPE_VIDEO, 
-1, -1, &video_codec, 0);
+       video_stream_index = av_find_best_stream (format, AVMEDIA_TYPE_VIDEO, 
-1, -1, NULL, 0);
        if (video_stream_index >= 0) {
                video_stream = format->streams[video_stream_index];
        }
@@ -164,36 +164,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
        if (audio_stream) {
                if (audio_stream->codec->sample_rate > 0) {
                        set_value_int64 (metadata, "nfo:sampleRate", 
audio_stream->codec->sample_rate);
-               } else if (avcodec_open2(audio_stream->codec, audio_codec, 0) 
>= 0) {
-                       AVFrame *frame;
-                       AVPacket packet;
-                       av_init_packet(&packet);
-
-                       frame = avcodec_alloc_frame();
-
-                       for (;;) {
-                               int decoded = 0;
-                               if (av_read_frame (format, &packet) < 0) {
-                                       break;
-                               } else if (packet.stream_index != 
audio_stream_index) {
-                               } else if (!avcodec_decode_audio4(
-                                       audio_stream->codec, frame, &decoded, 
&packet) < 0) {
-                                       av_free_packet(&packet);
-                                       break;
-                               } else if (audio_stream->codec->sample_rate > 
0) {
-                                       set_value_int64 (metadata, 
"nfo:sampleRate",
-                                                        
audio_stream->codec->sample_rate);
-                                       break;
-                               }
-                               av_free_packet(&packet);
-
-                               if (decoded) {
-                                       break;
-                               }
-                       }
-                       av_free(frame);
-
-                       avcodec_close(audio_stream->codec);
                }
                if (audio_stream->codec->channels > 0) {
                        set_value_int64 (metadata, "nfo:channels", 
audio_stream->codec->channels);
@@ -207,37 +177,6 @@ tracker_extract_get_metadata (TrackerExtractInfo *info)
                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);
-               } else if (avcodec_open2(video_stream->codec, video_codec, 0) 
>= 0) {
-                       AVFrame *frame;
-                       AVPacket packet;
-                       av_init_packet(&packet);
-
-                       frame = avcodec_alloc_frame();
-
-                       av_seek_frame(format, video_stream_index, -1, 0);
-                       for (;;) {
-                               int decoded = 0;
-                               if (av_read_frame(format, &packet) < 0) {
-                                       break;
-                               } else if (packet.stream_index != 
video_stream_index) {
-                               } else if (!avcodec_decode_video2(
-                                       video_stream->codec, frame, &decoded, 
&packet) < 0) {
-                                       av_free_packet(&packet);
-                                       break;
-                               } else 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);
-                                       break;
-                               }
-                               av_free_packet(&packet);
-
-                               if (decoded) {
-                                       break;
-                               }
-                       }
-                       av_free(frame);
-
-                       avcodec_close(video_stream->codec);
                }
 
                if (video_stream->avg_frame_rate.num > 0) {
-- 
1.8.4.2

_______________________________________________
tracker-list mailing list
tracker-list@gnome.org
https://mail.gnome.org/mailman/listinfo/tracker-list

Reply via email to