diff options
Diffstat (limited to 'src/tracker-extract/tracker-extract-gstreamer.c')
-rw-r--r-- | src/tracker-extract/tracker-extract-gstreamer.c | 1324 |
1 files changed, 0 insertions, 1324 deletions
diff --git a/src/tracker-extract/tracker-extract-gstreamer.c b/src/tracker-extract/tracker-extract-gstreamer.c deleted file mode 100644 index c389a1151..000000000 --- a/src/tracker-extract/tracker-extract-gstreamer.c +++ /dev/null @@ -1,1324 +0,0 @@ -/* - * Copyright (C) 2006, Laurent Aguerreche <laurent.aguerreche@free.fr> - * Copyright (C) 2007, Jamie McCracken <jamiemcc@gnome.org> - * Copyright (C) 2008, Nokia <ivan.frade@nokia.com> - * Copyright (C) 2016, Sam Thursfield <sam@afuera.me.uk> - * - * 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 "config.h" - -/* Ensure we have a valid backend enabled */ -#if !defined(GSTREAMER_BACKEND_DISCOVERER) && \ - !defined(GSTREAMER_BACKEND_GUPNP_DLNA) -#error Not a valid GStreamer backend defined -#endif - -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <math.h> - -#include <glib.h> -#include <glib/gstdio.h> - -#if defined(GSTREAMER_BACKEND_DISCOVERER) || \ - defined(GSTREAMER_BACKEND_GUPNP_DLNA) -#define GST_USE_UNSTABLE_API -#include <gst/pbutils/pbutils.h> -#endif - -#if defined(GSTREAMER_BACKEND_GUPNP_DLNA) -#include <libgupnp-dlna/gupnp-dlna.h> -#include <libgupnp-dlna/gupnp-dlna-gst-utils.h> -#endif - -#include <gst/gst.h> -#include <gst/tag/tag.h> - -#include <libtracker-common/tracker-common.h> -#include <libtracker-extract/tracker-extract.h> - -#include "tracker-cue-sheet.h" - -/* We wait this long (seconds) for NULL state before freeing */ -#define TRACKER_EXTRACT_GUARD_TIMEOUT 3 - -/* An additional tag in gstreamer for the content source. Remove when in upstream */ -#ifndef GST_TAG_CLASSIFICATION -#define GST_TAG_CLASSIFICATION "classification" -#endif - -/* Some additional tagreadbin tags (FIXME until they are defined upstream)*/ -#ifndef GST_TAG_CHANNEL -#define GST_TAG_CHANNEL "channels" -#endif - -#ifndef GST_TAG_RATE -#define GST_TAG_RATE "rate" -#endif - -#ifndef GST_TAG_WIDTH -#define GST_TAG_WIDTH "width" -#endif - -#ifndef GST_TAG_HEIGHT -#define GST_TAG_HEIGHT "height" -#endif - -#ifndef GST_TAG_PIXEL_RATIO -#define GST_TAG_PIXEL_RATIO "pixel-aspect-ratio" -#endif - -#ifndef GST_TAG_FRAMERATE -#define GST_TAG_FRAMERATE "framerate" -#endif - -typedef enum { - EXTRACT_MIME_AUDIO, - EXTRACT_MIME_VIDEO, - EXTRACT_MIME_IMAGE, - EXTRACT_MIME_GUESS -} ExtractMime; - -typedef struct { - ExtractMime mime; - GstTagList *tagcache; - GstToc *gst_toc; - TrackerToc *toc; - gboolean is_content_encrypted; - - GSList *artist_list; - - GstSample *sample; - GstMapInfo info; - -#if defined(GSTREAMER_BACKEND_DISCOVERER) || \ - defined(GSTREAMER_BACKEND_GUPNP_DLNA) - gboolean has_image; - gboolean has_audio; - gboolean has_video; - GList *streams; -#endif - -#if defined(GSTREAMER_BACKEND_DISCOVERER) || \ - defined(GSTREAMER_BACKEND_GUPNP_DLNA) - GstDiscoverer *discoverer; -#endif - -#if defined(GSTREAMER_BACKEND_GUPNP_DLNA) - const gchar *dlna_profile; - const gchar *dlna_mime; -#endif - -#if defined(GSTREAMER_BACKEND_DISCOVERER) || \ - defined(GSTREAMER_BACKEND_GUPNP_DLNA) - gint64 duration; - gint audio_channels; - gint audio_samplerate; - gint height; - gint width; - gfloat aspect_ratio; - gfloat video_fps; -#endif -} MetadataExtractor; - -static void common_extract_stream_metadata (MetadataExtractor *extractor, - const gchar *uri, - TrackerResource *resource); - -static TrackerResource * -intern_artist (MetadataExtractor *extractor, - const gchar *artist_name) -{ - GSList *node; - TrackerResource *artist; - gchar *artist_uri; - - if (artist_name == NULL) - return NULL; - - artist_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", artist_name); - - node = g_slist_find_custom (extractor->artist_list, artist_uri, - (GCompareFunc) tracker_resource_identifier_compare_func); - if (node) { - g_free (artist_uri); - return node->data; - } - - artist = tracker_extract_new_artist (artist_name); - g_free (artist_uri); - - extractor->artist_list = g_slist_prepend (extractor->artist_list, artist); - - return artist; -} - -static void -set_property_from_gst_tag (TrackerResource *resource, - const gchar *property_uri, - GstTagList *tag_list, - const gchar *tag) -{ - GValue value = G_VALUE_INIT; - - if (gst_tag_list_copy_value (&value, tag_list, tag)) { - tracker_resource_set_gvalue (resource, property_uri, &value); - g_value_unset (&value); - } -} - -static inline gboolean -get_gst_date_time_to_buf (GstDateTime *date_time, - gchar *buf, - size_t size) -{ - const gchar *offset_str; - gint year, month, day, hour, minute, second; - gfloat offset; - gboolean complete; - - offset_str = "+"; - year = hour = minute = second = 0; - month = day = 1; - offset = 0.0; - complete = TRUE; - - if (gst_date_time_has_year (date_time)) { - year = gst_date_time_get_year (date_time); - } else { - complete = FALSE; - } - - if (gst_date_time_has_month (date_time)) { - month = gst_date_time_get_month (date_time); - } else { - complete = FALSE; - } - - if (gst_date_time_has_day (date_time)) { - day = gst_date_time_get_day (date_time); - } else { - complete = FALSE; - } - - /* Hour and Minute data is retrieved by first checking the - * _has_time() API. - */ - - if (gst_date_time_has_second (date_time)) { - second = gst_date_time_get_second (date_time); - } else { - complete = FALSE; - } - - if (gst_date_time_has_time (date_time)) { - hour = gst_date_time_get_hour (date_time); - minute = gst_date_time_get_minute (date_time); - offset_str = gst_date_time_get_time_zone_offset (date_time) >= 0 ? "+" : ""; - offset = gst_date_time_get_time_zone_offset (date_time); - } else { - offset_str = "+"; - complete = FALSE; - } - - snprintf (buf, size, "%04d-%02d-%02dT%02d:%02d:%02d%s%02d:00", - year, - month, - day, - hour, - minute, - second, - offset_str, - (gint) offset); - - return complete; -} - -static void -add_date_time_gst_tag_with_mtime_fallback (TrackerResource *resource, - const gchar *uri, - const gchar *key, - GstTagList *tag_list, - const gchar *tag_date_time, - const gchar *tag_date) -{ - GstDateTime *date_time; - GDate *date; - gchar buf[26]; - - date_time = NULL; - date = NULL; - buf[0] = '\0'; - - if (gst_tag_list_get_date_time (tag_list, tag_date_time, &date_time)) { - gboolean complete; - - complete = get_gst_date_time_to_buf (date_time, buf, sizeof (buf)); - gst_date_time_unref (date_time); - - if (!complete) { - g_debug ("GstDateTime was not complete, parts of the date/time were missing (e.g. hours, minutes, seconds)"); - } - } else if (gst_tag_list_get_date (tag_list, tag_date, &date)) { - gboolean ret = FALSE; - - if (date && g_date_valid (date)) { - if (date->julian) - ret = g_date_valid_julian (date->julian_days); - if (date->dmy) - ret = g_date_valid_dmy (date->day, date->month, date->year); - } - - if (ret) { - /* GDate does not carry time zone information, assume UTC */ - g_date_strftime (buf, sizeof (buf), "%Y-%m-%dT%H:%M:%SZ", date); - } - } - - if (date) { - g_date_free (date); - } - - tracker_guarantee_resource_date_from_file_mtime (resource, key, buf, uri); -} - -static void -set_keywords_from_gst_tag (TrackerResource *resource, - GstTagList *tag_list) -{ - gboolean ret; - gchar *str; - - ret = gst_tag_list_get_string (tag_list, GST_TAG_KEYWORDS, &str); - - if (ret) { - GStrv keywords; - gint i = 0; - - keywords = g_strsplit_set (str, " ,", -1); - - while (keywords[i]) { - tracker_resource_add_string (resource, "nie:keyword", g_strstrip (keywords[i])); - i++; - } - - g_strfreev (keywords); - g_free (str); - } -} - -static gchar * -get_embedded_cue_sheet_data (GstTagList *tag_list) -{ - gint i, count; - gchar *buffer = NULL; - - count = gst_tag_list_get_tag_size (tag_list, GST_TAG_EXTENDED_COMMENT); - for (i = 0; i < count; i++) { - gst_tag_list_get_string_index (tag_list, GST_TAG_EXTENDED_COMMENT, i, &buffer); - - if (g_ascii_strncasecmp (buffer, "cuesheet=", 9) == 0) { - /* Use same functionality as g_strchug() here - * for cuesheet, to avoid allocating new - * memory but also to return the string and - * not have to jump past cuesheet= on the - * returned value. - */ - g_memmove (buffer, buffer + 9, strlen ((gchar *) buffer + 9) + 1); - - return buffer; - } - - g_free (buffer); - } - - return NULL; -} - -static TrackerToc * -translate_discoverer_toc (GstToc *gst_toc) -{ - const GList *entries, *l; - TrackerToc *toc; - gint i = 0; - - entries = gst_toc_get_entries (gst_toc); - if (!entries) - return NULL; - - toc = tracker_toc_new (); - - for (l = entries; l; l = l->next) { - GstTocEntry *entry = l->data; - GstTagList *tags, *copy = NULL; - gint64 start, stop; - - tags = gst_toc_entry_get_tags (entry); - - if (tags) { - copy = gst_tag_list_copy (tags); - - if (gst_tag_list_get_tag_size (copy, GST_TAG_TRACK_NUMBER) == 0) { - gst_tag_list_add (copy, GST_TAG_MERGE_REPLACE, - GST_TAG_TRACK_NUMBER, i + 1, - NULL); - } - } - - gst_toc_entry_get_start_stop_times (entry, &start, &stop); - tracker_toc_add_entry (toc, copy, (gdouble) start / GST_SECOND, - (gdouble) (stop - start) / GST_SECOND); - gst_tag_list_unref (copy); - i++; - } - - return toc; -} - -static TrackerResource * -extractor_get_geolocation (MetadataExtractor *extractor, - GstTagList *tag_list) -{ - TrackerResource *location = NULL; - gdouble lat, lon, alt; - gboolean has_coords; - - g_debug ("Retrieving geolocation metadata..."); - - has_coords = (gst_tag_list_get_double (tag_list, GST_TAG_GEO_LOCATION_LATITUDE, &lat) && - gst_tag_list_get_double (tag_list, GST_TAG_GEO_LOCATION_LONGITUDE, &lon) && - gst_tag_list_get_double (tag_list, GST_TAG_GEO_LOCATION_ELEVATION, &alt)); - - if (has_coords) { - location = tracker_resource_new (NULL); - tracker_resource_set_uri (location, "rdf:type", "slo:GeoLocation"); - - tracker_resource_set_double (location, "slo:latitude", lat); - tracker_resource_set_double (location, "slo:longitude", lon); - tracker_resource_set_double (location, "slo:altitude", alt); - } - - return location; -} - -static TrackerResource * -extractor_get_address (MetadataExtractor *extractor, - GstTagList *tag_list) -{ - TrackerResource *address = NULL; - gchar *country = NULL, *city = NULL, *sublocation = NULL; - - g_debug ("Retrieving address metadata..."); - - gst_tag_list_get_string (tag_list, GST_TAG_GEO_LOCATION_CITY, &city); - gst_tag_list_get_string (tag_list, GST_TAG_GEO_LOCATION_COUNTRY, &country); - gst_tag_list_get_string (tag_list, GST_TAG_GEO_LOCATION_SUBLOCATION, &sublocation); - - if (city || country || sublocation) { - gchar *address_uri = NULL; - - address_uri = tracker_sparql_get_uuid_urn (); - address = tracker_resource_new (address_uri); - - tracker_resource_set_string (address, "rdf:type", "nco:PostalAddress"); - - if (sublocation) { - tracker_resource_set_string (address, "nco:region", sublocation); - } - - if (city) { - tracker_resource_set_string (address, "nco:locality", city); - } - - if (country) { - tracker_resource_set_string (address, "nco:country", country); - } - } - - return address; -} - -static void -extractor_guess_content_type (MetadataExtractor *extractor) -{ - if (extractor->has_video) { - extractor->mime = EXTRACT_MIME_VIDEO; - } else if (extractor->has_audio) { - extractor->mime = EXTRACT_MIME_AUDIO; - } else if (extractor->has_image) { - extractor->mime = EXTRACT_MIME_IMAGE; - } else { - /* default to video */ - extractor->mime = EXTRACT_MIME_VIDEO; - } -} - -static void -extractor_apply_general_metadata (MetadataExtractor *extractor, - GstTagList *tag_list, - const gchar *file_url, - TrackerResource *resource, - TrackerResource **p_performer, - TrackerResource **p_composer) -{ - const gchar *performer_name = NULL; - gchar *performer_temp = NULL; - gchar *artist_temp = NULL; - gchar *composer_name = NULL; - gchar *genre = NULL; - gchar *title = NULL; - gchar *title_guaranteed = NULL; - - *p_composer = NULL; - *p_performer = NULL; - - gst_tag_list_get_string (tag_list, GST_TAG_PERFORMER, &performer_temp); - gst_tag_list_get_string (tag_list, GST_TAG_ARTIST, &artist_temp); - gst_tag_list_get_string (tag_list, GST_TAG_COMPOSER, &composer_name); - - performer_name = tracker_coalesce_strip (2, performer_temp, artist_temp); - - if (performer_name != NULL) { - *p_performer = intern_artist (extractor, performer_name); - } - - if (composer_name != NULL) { - *p_composer = intern_artist (extractor, composer_name); - } - - gst_tag_list_get_string (tag_list, GST_TAG_GENRE, &genre); - gst_tag_list_get_string (tag_list, GST_TAG_TITLE, &title); - - if (genre && g_strcmp0 (genre, "Unknown") != 0) { - tracker_resource_add_string (resource, "nfo:genre", genre); - } - - tracker_guarantee_resource_title_from_file (resource, - "nie:title", - title, - file_url, - &title_guaranteed); - - add_date_time_gst_tag_with_mtime_fallback (resource, - file_url, - "nie:contentCreated", - tag_list, - GST_TAG_DATE_TIME, - GST_TAG_DATE); - - set_property_from_gst_tag (resource, "nie:copyright", tag_list, GST_TAG_COPYRIGHT); - set_property_from_gst_tag (resource, "nie:license", tag_list, GST_TAG_LICENSE); - set_property_from_gst_tag (resource, "dc:coverage", tag_list, GST_TAG_LOCATION); - set_property_from_gst_tag (resource, "nie:comment", tag_list, GST_TAG_COMMENT); - - g_free (title_guaranteed); - g_free (performer_temp); - g_free (artist_temp); - g_free (composer_name); - g_free (genre); - g_free (title); -} - -static TrackerResource * -extractor_maybe_get_album_disc (MetadataExtractor *extractor, - GstTagList *tag_list) -{ - GstDateTime *datetime_temp = NULL; - TrackerResource *album = NULL, *album_artist = NULL, *album_disc = NULL; - gchar *album_artist_name = NULL; - gchar *album_datetime = NULL; - gchar *album_title = NULL; - gchar *track_artist_temp = NULL; - gboolean has_it; - guint volume_number; - - gst_tag_list_get_string (tag_list, GST_TAG_ALBUM, &album_title); - - if (!album_title) - return NULL; - - gst_tag_list_get_string (tag_list, GST_TAG_ALBUM_ARTIST, &album_artist_name); - gst_tag_list_get_string (tag_list, GST_TAG_ARTIST, &track_artist_temp); - gst_tag_list_get_date_time (tag_list, GST_TAG_DATE_TIME, &datetime_temp); - - if (datetime_temp) - album_datetime = gst_date_time_to_iso8601_string (datetime_temp); - album_artist = intern_artist (extractor, album_artist_name); - has_it = gst_tag_list_get_uint (tag_list, GST_TAG_ALBUM_VOLUME_NUMBER, &volume_number); - - album_disc = tracker_extract_new_music_album_disc (album_title, - album_artist, - has_it ? volume_number : 1, - album_datetime); - - album = tracker_resource_get_first_relation (album_disc, "nmm:albumDiscAlbum"); - set_property_from_gst_tag (album, "nmm:albumTrackCount", tag_list, GST_TAG_TRACK_COUNT); - set_property_from_gst_tag (album, "nmm:albumGain", extractor->tagcache, GST_TAG_ALBUM_GAIN); - set_property_from_gst_tag (album, "nmm:albumPeakGain", extractor->tagcache, GST_TAG_ALBUM_PEAK); - - g_clear_pointer (&datetime_temp, (GDestroyNotify) gst_date_time_unref); - g_free (album_artist_name); - g_free (album_datetime); - g_free (track_artist_temp); - - return album_disc; -} - -static TrackerResource * -extractor_get_equipment (MetadataExtractor *extractor, - GstTagList *tag_list) -{ - TrackerResource *equipment; - gchar *model = NULL, *manuf = NULL; - - gst_tag_list_get_string (tag_list, GST_TAG_DEVICE_MODEL, &model); - gst_tag_list_get_string (tag_list, GST_TAG_DEVICE_MANUFACTURER, &manuf); - - if (model == NULL && manuf == NULL) - return NULL; - - equipment = tracker_extract_new_equipment (manuf, model); - - g_free (model); - g_free (manuf); - - return equipment; -} - -static void -extractor_apply_audio_metadata (MetadataExtractor *extractor, - GstTagList *tag_list, - TrackerResource *audio, - TrackerResource *performer, - TrackerResource *composer, - TrackerResource *album_disc) -{ - set_property_from_gst_tag (audio, "nmm:trackNumber", tag_list, GST_TAG_TRACK_NUMBER); - set_property_from_gst_tag (audio, "nfo:codec", tag_list, GST_TAG_AUDIO_CODEC); - set_property_from_gst_tag (audio, "nfo:gain", tag_list, GST_TAG_TRACK_GAIN); - set_property_from_gst_tag (audio, "nfo:peakGain", tag_list, GST_TAG_TRACK_PEAK); - - if (performer) { - tracker_resource_set_relation (audio, "nmm:performer", performer); - } - - if (composer) { - tracker_resource_set_relation (audio, "nmm:composer", composer); - } - - if (album_disc) { - TrackerResource *album; - album = tracker_resource_get_first_relation (album_disc, "nmm:albumDiscAlbum"); - - tracker_resource_set_relation (audio, "nmm:musicAlbumDisc", album_disc); - tracker_resource_set_relation (audio, "nmm:musicAlbum", album); - } -} - -static void -extractor_apply_video_metadata (MetadataExtractor *extractor, - GstTagList *tag_list, - TrackerResource *video, - TrackerResource *performer, - TrackerResource *composer) -{ - set_property_from_gst_tag (video, "dc:source", tag_list, GST_TAG_CLASSIFICATION); - - if (performer) { - tracker_resource_set_relation (video, "nmm:leadActor", performer); - } - - if (composer) { - tracker_resource_set_relation (video, "nmm:director", composer); - } - - set_keywords_from_gst_tag (video, tag_list); -} - -static TrackerResource * -extract_track (MetadataExtractor *extractor, - TrackerTocEntry *toc_entry, - const gchar *file_url, - TrackerResource *album_disc) -{ - TrackerResource *track; - TrackerResource *track_performer = NULL, *track_composer = NULL; - gchar *track_uri; - - track_uri = tracker_sparql_get_uuid_urn (); - track = tracker_resource_new (track_uri); - - tracker_resource_add_uri (track, "rdf:type", "nmm:MusicPiece"); - tracker_resource_add_uri (track, "rdf:type", "nfo:Audio"); - - extractor_apply_general_metadata (extractor, - toc_entry->tag_list, - file_url, - track, - &track_performer, - &track_composer); - - extractor_apply_audio_metadata (extractor, - toc_entry->tag_list, - track, - track_performer, - track_composer, - album_disc); - - if (toc_entry->duration > 0) { - tracker_resource_set_int64 (track, "nfo:duration", (gint64)toc_entry->duration); - } else if (extractor->toc->entry_list && - toc_entry == g_list_last (extractor->toc->entry_list)->data) { - /* The last element may not have a duration, because it depends - * on the duration of the media file rather than info from the - * cue sheet. In this case figure the data out from the total - * duration. - */ - tracker_resource_set_int64 (track, "nfo:duration", (gint64)extractor->duration - toc_entry->start); - } - - tracker_resource_set_double (track, "nfo:audioOffset", toc_entry->start); - - g_free (track_uri); - - return track; -} - -#define CHUNK_N_BYTES (2 << 15) - -static guint64 -extract_gibest_hash (GFile *file) -{ - guint64 buffer[2][CHUNK_N_BYTES/8]; - GInputStream *stream = NULL; - gssize n_bytes, file_size; - GError *error = NULL; - guint64 hash = 0; - gint i; - - stream = G_INPUT_STREAM (g_file_read (file, NULL, &error)); - if (stream == NULL) - goto fail; - - /* Extract start/end chunks of the file */ - n_bytes = g_input_stream_read (stream, buffer[0], CHUNK_N_BYTES, NULL, &error); - if (n_bytes == -1) - goto fail; - - if (!g_seekable_seek (G_SEEKABLE (stream), -CHUNK_N_BYTES, G_SEEK_END, NULL, &error)) - goto fail; - - n_bytes = g_input_stream_read (stream, buffer[1], CHUNK_N_BYTES, NULL, &error); - if (n_bytes == -1) - goto fail; - - for (i = 0; i < G_N_ELEMENTS (buffer[0]); i++) - hash += buffer[0][i] + buffer[1][i]; - - file_size = g_seekable_tell (G_SEEKABLE (stream)); - - if (file_size < CHUNK_N_BYTES) - goto end; - - /* Include file size */ - hash += file_size; - g_object_unref (stream); - - return hash; - -fail: - g_warning ("Could not get file hash: %s\n", error ? error->message : "Unknown error"); - g_clear_error (&error); - -end: - g_clear_object (&stream); - return 0; -} - -static TrackerResource * -extract_metadata (MetadataExtractor *extractor, - const gchar *file_url) -{ - TrackerResource *resource; - - g_return_val_if_fail (extractor != NULL, NULL); - - resource = tracker_resource_new (NULL); - - if (extractor->toc) { - gst_tag_list_insert (extractor->tagcache, - extractor->toc->tag_list, - GST_TAG_MERGE_KEEP); - - if (g_list_length (extractor->toc->entry_list) == 1) { - /* If we only got one track, stick all the info together and - * forget about the table of contents - */ - TrackerTocEntry *toc_entry; - - toc_entry = extractor->toc->entry_list->data; - gst_tag_list_insert (extractor->tagcache, - toc_entry->tag_list, - GST_TAG_MERGE_KEEP); - - tracker_toc_free (extractor->toc); - extractor->toc = NULL; - } - } - - if (extractor->mime == EXTRACT_MIME_GUESS && !gst_tag_list_is_empty (extractor->tagcache)) { - extractor_guess_content_type (extractor); - } else { - /* Rely on the information from the discoverer rather than the - * mimetype, this is a safety net for those formats that fool - * mimetype sniffing (eg. .ogg suffixed OGG videos being detected - * as audio/ogg. - */ - if (extractor->mime == EXTRACT_MIME_AUDIO && extractor->has_video) { - g_debug ("mimetype says its audio, but has video frames. Falling back to video extraction."); - extractor->mime = EXTRACT_MIME_VIDEO; - } else if (extractor->mime == EXTRACT_MIME_VIDEO && - !extractor->has_video && extractor->has_audio) { - g_debug ("mimetype says its video, but has only audio. Falling back to audio extraction."); - extractor->mime = EXTRACT_MIME_AUDIO; - } - } - - if (extractor->mime == EXTRACT_MIME_GUESS) { - g_warning ("Cannot guess real stream type if no tags were read! " - "Defaulting to Video."); - tracker_resource_add_uri (resource, "rdf:type", "nmm:Video"); - } else { - if (extractor->mime == EXTRACT_MIME_AUDIO) { - /* Audio: don't make an nmm:MusicPiece for the file resource if it's - * actually a container for an entire album - we will make a - * nmm:MusicPiece for each of the tracks inside instead. - */ - tracker_resource_add_uri (resource, "rdf:type", "nfo:Audio"); - - if (extractor->toc == NULL || extractor->toc->entry_list == NULL) - tracker_resource_add_uri (resource, "rdf:type", "nmm:MusicPiece"); - } else if (extractor->mime == EXTRACT_MIME_VIDEO) { - tracker_resource_add_uri (resource, "rdf:type", "nmm:Video"); - } else { - tracker_resource_add_uri (resource, "rdf:type", "nfo:Image"); - tracker_resource_add_uri (resource, "rdf:type", "nmm:Photo"); - } - } - - if (!gst_tag_list_is_empty (extractor->tagcache)) { - GList *node; - TrackerResource *equipment; - TrackerResource *geolocation, *address; - TrackerResource *performer = NULL, *composer = NULL; - TrackerResource *album_disc; - - extractor_apply_general_metadata (extractor, - extractor->tagcache, - file_url, - resource, - &performer, - &composer); - - equipment = extractor_get_equipment (extractor, extractor->tagcache); - if (equipment) { - tracker_resource_set_relation (resource, "nfo:equipment", equipment); - g_object_unref (equipment); - } - - geolocation = extractor_get_geolocation (extractor, extractor->tagcache); - if (geolocation) { - tracker_resource_set_relation (resource, "slo:location", geolocation); - g_object_unref (geolocation); - } - - address = extractor_get_address (extractor, extractor->tagcache); - if (address) { - tracker_resource_set_relation (resource, "slo:postalAddress", address); - g_object_unref (address); - } - - if (extractor->mime == EXTRACT_MIME_VIDEO) { - extractor_apply_video_metadata (extractor, - extractor->tagcache, - resource, - performer, - composer); - } - - if (extractor->mime == EXTRACT_MIME_AUDIO) { - album_disc = extractor_maybe_get_album_disc (extractor, extractor->tagcache); - - extractor_apply_audio_metadata (extractor, - extractor->tagcache, - resource, - performer, - composer, - album_disc); - - /* If the audio file contains multiple tracks, we create the tracks - * as abstract information element types and relate them to the - * concrete nfo:FileDataObject using nie:isStoredAs. - */ - if (extractor->toc && g_list_length (extractor->toc->entry_list) > 1) { - for (node = extractor->toc->entry_list; node; node = node->next) { - TrackerResource *track; - - track = extract_track (extractor, node->data, file_url, album_disc); - tracker_resource_set_relation (track, "nie:isStoredAs", resource); - g_object_unref (track); - } - - tracker_resource_set_string (resource, "nie:url", file_url); - } - - if (album_disc) - g_object_unref (album_disc); - } - } - - /* OpenSubtitles compatible hash */ - if (extractor->mime == EXTRACT_MIME_VIDEO) { - guint64 hash; - GFile *file; - - file = g_file_new_for_uri (file_url); - hash = extract_gibest_hash (file); - g_object_unref (file); - - if (hash) { - TrackerResource *hash_resource; - char *hash_str; - - hash_resource = tracker_resource_new (NULL); - tracker_resource_set_uri (hash_resource, "rdf:type", "nfo:FileHash"); - - hash_str = g_strdup_printf ("%" G_GINT64_MODIFIER "x", hash); - tracker_resource_set_string (hash_resource, "nfo:hashValue", hash_str); - g_free (hash_str); - - tracker_resource_set_string (hash_resource, "nfo:hashAlgorithm", "gibest"); - - tracker_resource_set_relation (resource, "nfo:hasHash", hash_resource); - - g_object_unref (hash_resource); - } - } - - /* If content was encrypted, set it. */ -/* #warning TODO: handle encrypted content with the Discoverer/GUPnP-DLNA backends */ - - common_extract_stream_metadata (extractor, file_url, resource); - - return resource; -} - -#if defined(GSTREAMER_BACKEND_DISCOVERER) || \ - defined(GSTREAMER_BACKEND_GUPNP_DLNA) -static void -common_extract_stream_metadata (MetadataExtractor *extractor, - const gchar *uri, - TrackerResource *resource) -{ - if (extractor->mime == EXTRACT_MIME_AUDIO || - extractor->mime == EXTRACT_MIME_VIDEO) { - if (extractor->audio_channels >= 0) { - tracker_resource_set_int64 (resource, "nfo:channels", extractor->audio_channels); - } - - if (extractor->audio_samplerate >= 0) { - tracker_resource_set_int64 (resource, "nfo:sampleRate", extractor->audio_samplerate); - } - - if (extractor->duration >= 0) { - tracker_resource_set_int64 (resource, "nfo:duration", extractor->duration); - } - } - - if (extractor->mime == EXTRACT_MIME_VIDEO) { - if (extractor->video_fps >= 0) { - tracker_resource_set_double (resource, "nfo:frameRate", (gdouble)extractor->video_fps); - } - } - - if (extractor->mime == EXTRACT_MIME_IMAGE || - extractor->mime == EXTRACT_MIME_VIDEO) { - - if (extractor->width >= 0) { - tracker_resource_set_int64 (resource, "nfo:width", extractor->width); - } - - if (extractor->height >= 0) { - tracker_resource_set_int64 (resource, "nfo:height", extractor->height); - } - - if (extractor->aspect_ratio >= 0) { - tracker_resource_set_double (resource, "nfo:aspectRatio", (gdouble)extractor->aspect_ratio); - } - } - -#if defined(GSTREAMER_BACKEND_GUPNP_DLNA) - if (extractor->dlna_profile) { - tracker_resource_set_string (resource, "nmm:dlnaProfile", extractor->dlna_profile); - } else { - g_debug ("No DLNA profile found"); - } - - if (extractor->dlna_mime) { - tracker_resource_set_string (resource, "nmm:dlnaMime", extractor->dlna_mime); - } else { - g_debug ("No DLNA mime found"); - } -#endif /* GSTREAMER_BACKEND_GUPNP_DLNA */ -} - -#endif - -/* ----------------------- Discoverer/GUPnP-DLNA specific implementation --------------- */ - -#if defined(GSTREAMER_BACKEND_DISCOVERER) || \ - defined(GSTREAMER_BACKEND_GUPNP_DLNA) - -static void -discoverer_shutdown (MetadataExtractor *extractor) -{ - if (extractor->streams) - gst_discoverer_stream_info_list_free (extractor->streams); - if (extractor->discoverer) - g_object_unref (extractor->discoverer); -} - -static gchar * -get_discoverer_required_plugins_message (GstDiscovererInfo *info) -{ - GString *str; - gchar **plugins; - gchar *plugins_str; - - plugins = (gchar **) - gst_discoverer_info_get_missing_elements_installer_details (info); - - if (g_strv_length((gchar **)plugins) == 0) { - str = g_string_new ("No information available on which plugin is required."); - } else { - str = g_string_new("Required plugins: "); - plugins_str = g_strjoinv (", ", (gchar **)plugins); - g_string_append (str, plugins_str); - g_free (plugins_str); - } - - return g_string_free (str, FALSE); -} - -static gboolean -discoverer_init_and_run (MetadataExtractor *extractor, - const gchar *uri) -{ - GstDiscovererInfo *info; - const GstTagList *discoverer_tags; - const GstToc *gst_toc; - GError *error = NULL; - GList *l; - gchar *required_plugins_message; - - extractor->duration = -1; - extractor->audio_channels = -1; - extractor->audio_samplerate = -1; - extractor->height = -1; - extractor->width = -1; - extractor->video_fps = -1.0; - extractor->aspect_ratio = -1.0; - - extractor->has_image = FALSE; - extractor->has_video = FALSE; - extractor->has_audio = FALSE; - - extractor->discoverer = gst_discoverer_new (5 * GST_SECOND, &error); - if (!extractor->discoverer) { - g_warning ("Couldn't create discoverer: %s", - error ? error->message : "unknown error"); - g_clear_error (&error); - return FALSE; - } - -#if defined(GST_TYPE_DISCOVERER_FLAGS) - /* Tell the discoverer to use *only* Tagreadbin backend. - * See https://bugzilla.gnome.org/show_bug.cgi?id=656345 - */ - g_debug ("Using Tagreadbin backend in the GStreamer discoverer..."); - g_object_set (extractor->discoverer, - "flags", GST_DISCOVERER_FLAGS_EXTRACT_LIGHTWEIGHT, - NULL); -#endif - - info = gst_discoverer_discover_uri (extractor->discoverer, - uri, - &error); - - if (!info) { - g_warning ("Nothing discovered, bailing out"); - return TRUE; - } - - if (error) { - if (gst_discoverer_info_get_result(info) == GST_DISCOVERER_MISSING_PLUGINS) { - required_plugins_message = get_discoverer_required_plugins_message (info); - g_message ("Missing a GStreamer plugin for %s. %s", uri, - required_plugins_message); - g_free (required_plugins_message); - } else if (error->domain != GST_STREAM_ERROR || - (error->code != GST_STREAM_ERROR_TYPE_NOT_FOUND && - error->code != GST_STREAM_ERROR_WRONG_TYPE && - error->code != GST_STREAM_ERROR_DECODE)) { - g_warning ("Call to gst_discoverer_discover_uri(%s) failed: %s", - uri, error->message); - } - gst_discoverer_info_unref (info); - g_error_free (error); - return FALSE; - } - -#if defined(GSTREAMER_BACKEND_GUPNP_DLNA) - { - GUPnPDLNAProfile *profile; - GUPnPDLNAInformation *dlna_info; - GUPnPDLNAProfileGuesser *guesser; - - dlna_info = gupnp_dlna_gst_utils_information_from_discoverer_info (info); - guesser = gupnp_dlna_profile_guesser_new (TRUE, FALSE); - profile = gupnp_dlna_profile_guesser_guess_profile_from_info (guesser, dlna_info); - - if (profile) { - extractor->dlna_profile = gupnp_dlna_profile_get_name (profile); - extractor->dlna_mime = gupnp_dlna_profile_get_mime (profile); - } - - g_object_unref (guesser); - g_object_unref (dlna_info); - } -#endif - - gst_toc = gst_discoverer_info_get_toc (info); - if (gst_toc) - extractor->gst_toc = gst_toc_copy (gst_toc); - - extractor->duration = gst_discoverer_info_get_duration (info) / GST_SECOND; - - /* Retrieve global tags */ - discoverer_tags = gst_discoverer_info_get_tags (info); - - if (discoverer_tags) { - gst_tag_list_insert (extractor->tagcache, - discoverer_tags, - GST_TAG_MERGE_APPEND); - } - - /* Get list of Streams to iterate */ - extractor->streams = gst_discoverer_info_get_stream_list (info); - for (l = extractor->streams; l; l = g_list_next (l)) { - GstDiscovererStreamInfo *stream = l->data; - const GstTagList *stream_tags; - - if (G_TYPE_CHECK_INSTANCE_TYPE (stream, GST_TYPE_DISCOVERER_AUDIO_INFO)) { - GstDiscovererAudioInfo *audio = (GstDiscovererAudioInfo*)stream; - - extractor->has_audio = TRUE; - extractor->audio_samplerate = gst_discoverer_audio_info_get_sample_rate (audio); - extractor->audio_channels = gst_discoverer_audio_info_get_channels (audio); - } else if (G_TYPE_CHECK_INSTANCE_TYPE (stream, GST_TYPE_DISCOVERER_VIDEO_INFO)) { - GstDiscovererVideoInfo *video = (GstDiscovererVideoInfo*)stream; - - if (gst_discoverer_video_info_is_image (video)) { - extractor->has_image = TRUE; - } else { - extractor->has_video = TRUE; - if (gst_discoverer_video_info_get_framerate_denom (video) > 0) { - extractor->video_fps = (gfloat)(gst_discoverer_video_info_get_framerate_num (video) / - gst_discoverer_video_info_get_framerate_denom (video)); - } - extractor->width = gst_discoverer_video_info_get_width (video); - extractor->height = gst_discoverer_video_info_get_height (video); - if (gst_discoverer_video_info_get_par_denom (video) > 0) { - extractor->aspect_ratio = (gfloat)(gst_discoverer_video_info_get_par_num (video) / - gst_discoverer_video_info_get_par_denom (video)); - } - } - } else { - /* Unknown type - do nothing */ - } - - stream_tags = gst_discoverer_stream_info_get_tags (stream); - - if (stream_tags) { - gst_tag_list_insert (extractor->tagcache, - stream_tags, - GST_TAG_MERGE_APPEND); - } - } - - gst_discoverer_info_unref (info); - - return TRUE; -} - -#endif /* defined(GSTREAMER_BACKEND_DISCOVERER) || \ - defined(GSTREAMER_BACKEND_GUPNP_DLNA) */ - -static TrackerResource * -tracker_extract_gstreamer (const gchar *uri, - TrackerExtractInfo *info, - ExtractMime type) -{ - TrackerResource *main_resource = NULL; - MetadataExtractor *extractor; - GstBuffer *buffer; - gchar *cue_sheet; - gboolean success; - - g_return_val_if_fail (uri, NULL); - - extractor = g_slice_new0 (MetadataExtractor); - extractor->mime = type; - extractor->tagcache = gst_tag_list_new_empty (); - - g_debug ("GStreamer backend in use:"); - g_debug (" Discoverer/GUPnP-DLNA"); - success = discoverer_init_and_run (extractor, uri); - - if (success) { - cue_sheet = get_embedded_cue_sheet_data (extractor->tagcache); - - if (cue_sheet) { - g_debug ("Using embedded CUE sheet."); - extractor->toc = tracker_cue_sheet_parse (cue_sheet); - g_free (cue_sheet); - } - - if (extractor->toc == NULL) { - extractor->toc = tracker_cue_sheet_parse_uri (uri); - } - - if (extractor->toc == NULL && - extractor->gst_toc != NULL) { - extractor->toc = translate_discoverer_toc (extractor->gst_toc); - } - - main_resource = extract_metadata (extractor, uri); - } - - /* Clean up */ - if (extractor->sample) { - buffer = gst_sample_get_buffer (extractor->sample); - gst_buffer_unmap (buffer, &extractor->info); - gst_sample_unref (extractor->sample); - } - - gst_tag_list_free (extractor->tagcache); - - tracker_toc_free (extractor->toc); - - if (extractor->gst_toc) - gst_toc_unref (extractor->gst_toc); - - g_slist_foreach (extractor->artist_list, (GFunc)g_object_unref, NULL); - g_slist_free (extractor->artist_list); - - discoverer_shutdown (extractor); - - g_slice_free (MetadataExtractor, extractor); - - return main_resource; -} - -G_MODULE_EXPORT gboolean -tracker_extract_get_metadata (TrackerExtractInfo *info) -{ - GFile *file; - gchar *uri; - const gchar *mimetype; - TrackerResource *main_resource; - - file = tracker_extract_info_get_file (info); - uri = g_file_get_uri (file); - mimetype = tracker_extract_info_get_mimetype (info); - -#if defined(GSTREAMER_BACKEND_GUPNP_DLNA) - if (g_str_has_prefix (mimetype, "dlna/")) { - main_resource = tracker_extract_gstreamer (uri, info, EXTRACT_MIME_GUESS); - } else -#endif /* GSTREAMER_BACKEND_GUPNP_DLNA */ - - if (strcmp (mimetype, "video/3gpp") == 0 || - strcmp (mimetype, "video/mp4") == 0 || - strcmp (mimetype, "video/x-ms-asf") == 0 || - strcmp (mimetype, "application/vnd.ms-asf") == 0 || - strcmp (mimetype, "application/vnd.rn-realmedia") == 0) { - main_resource = tracker_extract_gstreamer (uri, info, EXTRACT_MIME_GUESS); - } else if (g_str_has_prefix (mimetype, "audio/")) { - main_resource = tracker_extract_gstreamer (uri, info, EXTRACT_MIME_AUDIO); - } else if (g_str_has_prefix (mimetype, "video/")) { - main_resource = tracker_extract_gstreamer (uri, info, EXTRACT_MIME_VIDEO); - } else if (g_str_has_prefix (mimetype, "image/")) { - main_resource = tracker_extract_gstreamer (uri, info, EXTRACT_MIME_IMAGE); - } else { - g_free (uri); - return FALSE; - } - - if (main_resource) { - tracker_extract_info_set_resource (info, main_resource); - g_object_unref (main_resource); - } - - g_free (uri); - return TRUE; -} - -G_MODULE_EXPORT gboolean -tracker_extract_module_init (GError **error) -{ - /* Lifted from totem-video-thumbnailer */ - const gchar *blacklisted[] = { - "vaapidecodebin", - "vaapidecode", - "vaapimpeg2dec", - "vaapih264dec", - "vaapivc1dec", - "vaapivp8dec", - "vaapivp9dec", - "vaapih265dec", - "bcmdec", - }; - GstRegistry *registry; - guint i; - - gst_init (NULL, NULL); - registry = gst_registry_get (); - - for (i = 0; i < G_N_ELEMENTS (blacklisted); i++) { - GstPluginFeature *feature = - gst_registry_find_feature (registry, - blacklisted[i], - GST_TYPE_ELEMENT_FACTORY); - if (feature) - gst_registry_remove_feature (registry, feature); - } - - return TRUE; -} |