[tracker] Add a libav based generic media extractor.
- From: Philip Van Hoof <pvanhoof src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker] Add a libav based generic media extractor.
- Date: Thu, 9 Jan 2014 13:22:13 +0000 (UTC)
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]