tracker-0.16.2/src/tracker-extract/tracker-extract-gstreamer.c

Location Tool Test ID Function Issue
tracker-extract-gstreamer.c:272:2 clang-analyzer Value stored to 'offset_str' is never read
   1 /*
   2  * Copyright (C) 2006, Laurent Aguerreche <laurent.aguerreche@free.fr>
   3  * Copyright (C) 2007, Jamie McCracken <jamiemcc@gnome.org>
   4  * Copyright (C) 2008, Nokia <ivan.frade@nokia.com>
   5  *
   6  * This library is free software; you can redistribute it and/or
   7  * modify it under the terms of the GNU Lesser General Public
   8  * License as published by the Free Software Foundation; either
   9  * version 2.1 of the License, or (at your option) any later version.
  10  *
  11  * This library is distributed in the hope that it will be useful,
  12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14  * Lesser General Public License for more details.
  15  *
  16  * You should have received a copy of the GNU Lesser General Public
  17  * License along with this library; if not, write to the
  18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  19  * Boston, MA  02110-1301, USA.
  20  */
  21 
  22 #include "config.h"
  23 
  24 /* Ensure we have a valid backend enabled */
  25 #if !defined(GSTREAMER_BACKEND_TAGREADBIN) && \
  26     !defined(GSTREAMER_BACKEND_DECODEBIN2) && \
  27     !defined(GSTREAMER_BACKEND_DISCOVERER) && \
  28     !defined(GSTREAMER_BACKEND_GUPNP_DLNA)
  29 #error Not a valid GStreamer backend defined
  30 #endif
  31 
  32 #include <string.h>
  33 #include <stdio.h>
  34 #include <stdlib.h>
  35 #include <math.h>
  36 
  37 #include <glib.h>
  38 #include <glib/gstdio.h>
  39 
  40 #if defined(GSTREAMER_BACKEND_DISCOVERER) || \
  41     defined(GSTREAMER_BACKEND_GUPNP_DLNA)
  42 #define GST_USE_UNSTABLE_API
  43 #include <gst/pbutils/pbutils.h>
  44 #endif
  45 
  46 #if defined(GSTREAMER_BACKEND_GUPNP_DLNA)
  47 #include <libgupnp-dlna/gupnp-dlna.h>
  48 #include <libgupnp-dlna/gupnp-dlna-gst-utils.h>
  49 #endif
  50 
  51 #include <gst/gst.h>
  52 #include <gst/tag/tag.h>
  53 
  54 #include <libtracker-common/tracker-common.h>
  55 #include <libtracker-extract/tracker-extract.h>
  56 
  57 #include "tracker-media-art.h"
  58 #include "tracker-cue-sheet.h"
  59 
  60 /* We wait this long (seconds) for NULL state before freeing */
  61 #define TRACKER_EXTRACT_GUARD_TIMEOUT 3
  62 
  63 /* An additional tag in gstreamer for the content source. Remove when in upstream */
  64 #ifndef GST_TAG_CLASSIFICATION
  65 #define GST_TAG_CLASSIFICATION "classification"
  66 #endif
  67 
  68 /* Some additional tagreadbin tags (FIXME until they are defined upstream)*/
  69 #ifndef GST_TAG_CHANNEL
  70 #define GST_TAG_CHANNEL "channels"
  71 #endif
  72 
  73 #ifndef GST_TAG_RATE
  74 #define GST_TAG_RATE "rate"
  75 #endif
  76 
  77 #ifndef GST_TAG_WIDTH
  78 #define GST_TAG_WIDTH "width"
  79 #endif
  80 
  81 #ifndef GST_TAG_HEIGHT
  82 #define GST_TAG_HEIGHT "height"
  83 #endif
  84 
  85 #ifndef GST_TAG_PIXEL_RATIO
  86 #define GST_TAG_PIXEL_RATIO "pixel-aspect-ratio"
  87 #endif
  88 
  89 #ifndef GST_TAG_FRAMERATE
  90 #define GST_TAG_FRAMERATE "framerate"
  91 #endif
  92 
  93 typedef enum {
  94 	EXTRACT_MIME_AUDIO,
  95 	EXTRACT_MIME_VIDEO,
  96 	EXTRACT_MIME_IMAGE,
  97 	EXTRACT_MIME_GUESS,
  98 	EXTRACT_MIME_SVG,
  99 } ExtractMime;
 100 
 101 typedef struct {
 102 	ExtractMime     mime;
 103 	GstTagList     *tagcache;
 104 	TrackerToc     *toc;
 105 	gboolean        is_content_encrypted;
 106 
 107 	GSList         *artist_list;
 108 
 109 	TrackerMediaArtType  media_art_type;
 110 	gchar               *media_art_artist;
 111 	gchar               *media_art_title;
 112 
 113 	unsigned char       *media_art_buffer;
 114 	guint                media_art_buffer_size;
 115 	const gchar         *media_art_buffer_mime;
 116 
 117 	GstSample      *sample;
 118 	GstMapInfo      info;
 119 
 120 #if defined(GSTREAMER_BACKEND_TAGREADBIN) || \
 121     defined(GSTREAMER_BACKEND_DECODEBIN2)
 122 	GstElement     *pipeline;
 123 	GstBus         *bus;
 124 #endif
 125 
 126 #if defined(GSTREAMER_BACKEND_DECODEBIN2)
 127 	GstElement     *bin;
 128 	GList          *fsinks;
 129 #endif
 130 
 131 #if defined(GSTREAMER_BACKEND_DISCOVERER) || \
 132     defined(GSTREAMER_BACKEND_GUPNP_DLNA)
 133 	gboolean        has_image;
 134 	gboolean        has_audio;
 135 	gboolean        has_video;
 136 	GList          *streams;
 137 #endif
 138 
 139 #if defined(GSTREAMER_BACKEND_DISCOVERER) || \
 140     defined(GSTREAMER_BACKEND_GUPNP_DLNA)
 141 	GstDiscoverer  *discoverer;
 142 #endif
 143 
 144 #if defined(GSTREAMER_BACKEND_GUPNP_DLNA)
 145 	const gchar          *dlna_profile;
 146 	const gchar          *dlna_mime;
 147 #endif
 148 
 149 #if defined(GSTREAMER_BACKEND_DISCOVERER) || \
 150     defined(GSTREAMER_BACKEND_DECODEBIN2) || \
 151     defined(GSTREAMER_BACKEND_GUPNP_DLNA)
 152 	gint64          duration;
 153 	gint            audio_channels;
 154 	gint            audio_samplerate;
 155 	gint            height;
 156 	gint            width;
 157 	gfloat          aspect_ratio;
 158 	gfloat          video_fps;
 159 #endif
 160 } MetadataExtractor;
 161 
 162 #if defined(GSTREAMER_BACKEND_TAGREADBIN)
 163 static void tagreadbin_extract_stream_metadata (MetadataExtractor    *extractor,
 164                                                 const gchar          *uri,
 165                                                 TrackerSparqlBuilder *metadata);
 166 #else  /* DECODEBIN2/DISCOVERER/GUPnP-DLNA */
 167 static void common_extract_stream_metadata (MetadataExtractor    *extractor,
 168                                             const gchar          *uri,
 169                                             TrackerSparqlBuilder *metadata);
 170 #endif /* DECODEBIN2/DISCOVERER/GUPnP-DLNA */
 171 
 172 static void
 173 add_artist (MetadataExtractor     *extractor,
 174             TrackerSparqlBuilder  *preupdate,
 175             const gchar           *graph,
 176             const gchar           *artist_name,
 177             gchar                **p_artist_uri)
 178 {
 179 	g_return_if_fail (artist_name != NULL);
 180 
 181 	*p_artist_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", artist_name);
 182 
 183 	/* Check if already added to the preupdate, to avoid sending 9 identical INSERTs */
 184 	if (g_slist_find_custom (extractor->artist_list, artist_name, (GCompareFunc) strcmp))
 185 		return;
 186 
 187 	tracker_sparql_builder_insert_open (preupdate, NULL);
 188 	if (graph) {
 189 		tracker_sparql_builder_graph_open (preupdate, graph);
 190 	}
 191 
 192 	tracker_sparql_builder_subject_iri (preupdate, *p_artist_uri);
 193 	tracker_sparql_builder_predicate (preupdate, "a");
 194 	tracker_sparql_builder_object (preupdate, "nmm:Artist");
 195 	tracker_sparql_builder_predicate (preupdate, "nmm:artistName");
 196 	tracker_sparql_builder_object_unvalidated (preupdate, artist_name);
 197 
 198 	if (graph) {
 199 		tracker_sparql_builder_graph_close (preupdate);
 200 	}
 201 	tracker_sparql_builder_insert_close (preupdate);
 202 
 203 	extractor->artist_list = g_slist_prepend (extractor->artist_list, g_strdup (artist_name));
 204 }
 205 
 206 static void
 207 add_string_gst_tag (TrackerSparqlBuilder *metadata,
 208                     const gchar          *key,
 209                     GstTagList           *tag_list,
 210                     const gchar          *tag)
 211 {
 212 	gchar *s;
 213 	gboolean ret;
 214 
 215 	s = NULL;
 216 	ret = gst_tag_list_get_string (tag_list, tag, &s);
 217 
 218 	if (s) {
 219 		if (ret && s[0] != '\0') {
 220 			tracker_sparql_builder_predicate (metadata, key);
 221 			tracker_sparql_builder_object_unvalidated (metadata, s);
 222 		}
 223 
 224 		g_free (s);
 225 	}
 226 }
 227 
 228 static void
 229 add_uint_gst_tag (TrackerSparqlBuilder  *metadata,
 230                   const gchar           *key,
 231                   GstTagList            *tag_list,
 232                   const gchar           *tag)
 233 {
 234 	gboolean ret;
 235 	guint n;
 236 
 237 	ret = gst_tag_list_get_uint (tag_list, tag, &n);
 238 
 239 	if (ret) {
 240 		tracker_sparql_builder_predicate (metadata, key);
 241 		tracker_sparql_builder_object_int64 (metadata, n);
 242 	}
 243 }
 244 
 245 static void
 246 add_double_gst_tag (TrackerSparqlBuilder  *metadata,
 247                     const gchar           *key,
 248                     GstTagList            *tag_list,
 249                     const gchar           *tag)
 250 {
 251 	gboolean ret;
 252 	gdouble n;
 253 
 254 	ret = gst_tag_list_get_double (tag_list, tag, &n);
 255 
 256 	if (ret) {
 257 		tracker_sparql_builder_predicate (metadata, key);
 258 		tracker_sparql_builder_object_int64 (metadata, (gint64) n);
 259 	}
 260 }
 261 
 262 static inline gboolean
 263 get_gst_date_time_to_buf (GstDateTime *date_time,
 264                           gchar       *buf,
 265                           size_t       size)
 266 {
 267 	const gchar *offset_str;
 268 	gint year, month, day, hour, minute, second;
 269 	gfloat offset;
 270 	gboolean complete;
 271 
 272 	offset_str = "+";
Value stored to 'offset_str' is never read
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

273 year = month = day = hour = minute = second = 0; 274 offset = 0.0; 275 complete = TRUE; 276 277 if (gst_date_time_has_year (date_time)) { 278 year = gst_date_time_get_year (date_time); 279 } else { 280 complete = FALSE; 281 } 282 283 if (gst_date_time_has_month (date_time)) { 284 month = gst_date_time_get_month (date_time); 285 } else { 286 complete = FALSE; 287 } 288 289 if (gst_date_time_has_day (date_time)) { 290 day = gst_date_time_get_day (date_time); 291 } else { 292 complete = FALSE; 293 } 294 295 /* Hour and Minute data is retrieved by first checking the 296 * _has_time() API. 297 */ 298 299 if (gst_date_time_has_second (date_time)) { 300 second = gst_date_time_get_second (date_time); 301 } else { 302 complete = FALSE; 303 } 304 305 if (gst_date_time_has_time (date_time)) { 306 hour = gst_date_time_get_hour (date_time); 307 minute = gst_date_time_get_minute (date_time); 308 offset_str = gst_date_time_get_time_zone_offset (date_time) >= 0 ? "+" : ""; 309 offset = gst_date_time_get_time_zone_offset (date_time); 310 } else { 311 offset_str = "+"; 312 complete = FALSE; 313 } 314 315 snprintf (buf, size, "%04d-%02d-%02dT%02d:%02d:%02d%s%02d00", 316 year, 317 month, 318 day, 319 hour, 320 minute, 321 second, 322 offset_str, 323 (gint) offset); 324 325 return complete; 326 } 327 328 static void 329 add_date_time_gst_tag_with_mtime_fallback (TrackerSparqlBuilder *metadata, 330 const gchar *uri, 331 const gchar *key, 332 GstTagList *tag_list, 333 const gchar *tag_date_time, 334 const gchar *tag_date) 335 { 336 GstDateTime *date_time; 337 GDate *date; 338 gchar buf[25]; 339 340 date_time = NULL; 341 date = NULL; 342 buf[0] = '\0'; 343 344 if (gst_tag_list_get_date_time (tag_list, tag_date_time, &date_time)) { 345 gboolean complete; 346 347 complete = get_gst_date_time_to_buf (date_time, buf, sizeof (buf)); 348 gst_date_time_unref (date_time); 349 350 if (!complete) { 351 g_message ("GstDateTime was not complete, parts of the date/time were missing (e.g. hours, minutes, seconds)"); 352 } 353 } else if (gst_tag_list_get_date (tag_list, tag_date, &date)) { 354 gboolean ret = FALSE; 355 356 if (date && g_date_valid (date)) { 357 if (date->julian) 358 ret = g_date_valid_julian (date->julian_days); 359 if (date->dmy) 360 ret = g_date_valid_dmy (date->day, date->month, date->year); 361 } 362 363 if (ret) { 364 /* GDate does not carry time zone information, assume UTC */ 365 g_date_strftime (buf, sizeof (buf), "%Y-%m-%dT%H:%M:%SZ", date); 366 } 367 } 368 369 if (date) { 370 g_date_free (date); 371 } 372 373 tracker_guarantee_date_from_file_mtime (metadata, key, buf, uri); 374 } 375 376 static void 377 add_keywords_gst_tag (TrackerSparqlBuilder *metadata, 378 GstTagList *tag_list) 379 { 380 gboolean ret; 381 gchar *str; 382 383 ret = gst_tag_list_get_string (tag_list, GST_TAG_KEYWORDS, &str); 384 385 if (ret) { 386 GStrv keywords; 387 gint i = 0; 388 389 keywords = g_strsplit_set (str, " ,", -1); 390 391 while (keywords[i]) { 392 tracker_sparql_builder_predicate (metadata, "nie:keyword"); 393 tracker_sparql_builder_object_unvalidated (metadata, g_strstrip (keywords[i])); 394 i++; 395 } 396 397 g_strfreev (keywords); 398 g_free (str); 399 } 400 } 401 402 static void 403 replace_double_gst_tag (TrackerSparqlBuilder *preupdate, 404 const gchar *uri, 405 const gchar *key, 406 GstTagList *tag_list, 407 const gchar *tag, 408 const gchar *graph) 409 { 410 gdouble value; 411 gboolean has_it; 412 413 has_it = gst_tag_list_get_double (tag_list, tag, &value); 414 415 if (! has_it) 416 return; 417 418 tracker_sparql_builder_delete_open (preupdate, NULL); 419 tracker_sparql_builder_subject_iri (preupdate, uri); 420 tracker_sparql_builder_predicate (preupdate, key); 421 tracker_sparql_builder_object_variable (preupdate, "unknown"); 422 tracker_sparql_builder_delete_close (preupdate); 423 424 tracker_sparql_builder_where_open (preupdate); 425 tracker_sparql_builder_subject_iri (preupdate, uri); 426 tracker_sparql_builder_predicate (preupdate, key); 427 tracker_sparql_builder_object_variable (preupdate, "unknown"); 428 tracker_sparql_builder_where_close (preupdate); 429 430 tracker_sparql_builder_insert_open (preupdate, NULL); 431 if (graph) { 432 tracker_sparql_builder_graph_open (preupdate, graph); 433 } 434 435 tracker_sparql_builder_subject_iri (preupdate, uri); 436 tracker_sparql_builder_predicate (preupdate, key); 437 tracker_sparql_builder_object_double (preupdate, value); 438 439 if (graph) { 440 tracker_sparql_builder_graph_close (preupdate); 441 } 442 tracker_sparql_builder_insert_close (preupdate); 443 } 444 445 static gchar * 446 get_embedded_cue_sheet_data (GstTagList *tag_list) 447 { 448 gint i, count; 449 gchar *buffer = NULL; 450 451 count = gst_tag_list_get_tag_size (tag_list, GST_TAG_EXTENDED_COMMENT); 452 for (i = 0; i < count; i++) { 453 gst_tag_list_get_string_index (tag_list, GST_TAG_EXTENDED_COMMENT, i, &buffer); 454 455 if (g_ascii_strncasecmp (buffer, "cuesheet=", 9) == 0) { 456 /* Use same functionality as g_strchug() here 457 * for cuesheet, to avoid allocating new 458 * memory but also to return the string and 459 * not have to jump past cuesheet= on the 460 * returned value. 461 */ 462 g_memmove (buffer, buffer + 9, strlen ((gchar *) buffer + 9) + 1); 463 464 return buffer; 465 } 466 467 g_free (buffer); 468 } 469 470 return NULL; 471 } 472 473 static gboolean 474 get_embedded_media_art (MetadataExtractor *extractor) 475 { 476 gboolean have_sample; 477 guint lindex; 478 479 lindex = 0; 480 481 do { 482 have_sample = gst_tag_list_get_sample_index (extractor->tagcache, GST_TAG_IMAGE, lindex, &extractor->sample); 483 484 if (have_sample) { 485 GstBuffer *buffer; 486 const GstStructure *info_struct; 487 gint type; 488 489 buffer = gst_sample_get_buffer (extractor->sample); 490 info_struct = gst_sample_get_info (extractor->sample); 491 if (gst_structure_get_enum (info_struct, 492 "image-type", 493 GST_TYPE_TAG_IMAGE_TYPE, 494 &type)) { 495 if (type == GST_TAG_IMAGE_TYPE_FRONT_COVER || 496 (type == GST_TAG_IMAGE_TYPE_UNDEFINED && 497 extractor->media_art_buffer_size == 0)) { 498 GstCaps *caps; 499 GstStructure *caps_struct; 500 501 if (!gst_buffer_map (buffer, &extractor->info, GST_MAP_READ)) 502 return FALSE; 503 504 caps = gst_sample_get_caps (extractor->sample); 505 caps_struct = gst_caps_get_structure (caps, 0); 506 507 extractor->media_art_buffer = extractor->info.data; 508 extractor->media_art_buffer_size = extractor->info.size; 509 extractor->media_art_buffer_mime = gst_structure_get_name (caps_struct); 510 511 return TRUE; 512 } 513 } 514 515 lindex++; 516 } 517 518 } while (have_sample); 519 520 have_sample = gst_tag_list_get_sample_index (extractor->tagcache, GST_TAG_IMAGE, lindex, &extractor->sample); 521 522 if (have_sample) { 523 GstBuffer *buffer; 524 GstCaps *caps; 525 GstStructure *caps_struct; 526 527 buffer = gst_sample_get_buffer (extractor->sample); 528 caps = gst_sample_get_caps (extractor->sample); 529 caps_struct = gst_caps_get_structure (caps, 0); 530 531 if (!gst_buffer_map (buffer, &extractor->info, GST_MAP_READ)) 532 return FALSE; 533 534 extractor->media_art_buffer = extractor->info.data; 535 extractor->media_art_buffer_size = extractor->info.size; 536 extractor->media_art_buffer_mime = gst_structure_get_name (caps_struct); 537 538 return TRUE; 539 } 540 541 return FALSE; 542 } 543 544 static void 545 extractor_apply_geolocation_metadata (MetadataExtractor *extractor, 546 GstTagList *tag_list, 547 TrackerSparqlBuilder *preupdate, 548 TrackerSparqlBuilder *metadata, 549 const gchar *graph) 550 { 551 gchar *country = NULL, *city = NULL, *sublocation = NULL; 552 gdouble lat, lon, alt; 553 gboolean has_coords; 554 555 g_debug ("Retrieving geolocation metadata..."); 556 557 country = city = sublocation = NULL; 558 has_coords = (gst_tag_list_get_double (tag_list, GST_TAG_GEO_LOCATION_LATITUDE, &lat) && 559 gst_tag_list_get_double (tag_list, GST_TAG_GEO_LOCATION_LONGITUDE, &lon) && 560 gst_tag_list_get_double (tag_list, GST_TAG_GEO_LOCATION_ELEVATION, &alt)); 561 562 gst_tag_list_get_string (tag_list, GST_TAG_GEO_LOCATION_CITY, &city); 563 gst_tag_list_get_string (tag_list, GST_TAG_GEO_LOCATION_COUNTRY, &country); 564 gst_tag_list_get_string (tag_list, GST_TAG_GEO_LOCATION_SUBLOCATION, &sublocation); 565 566 if (city || country || sublocation || has_coords) { 567 gchar *address_uri = NULL; 568 569 /* Create postal address */ 570 if (city || country || sublocation) { 571 address_uri = tracker_sparql_get_uuid_urn (); 572 573 tracker_sparql_builder_insert_open (preupdate, NULL); 574 if (graph) { 575 tracker_sparql_builder_graph_open (preupdate, graph); 576 } 577 578 tracker_sparql_builder_subject_iri (preupdate, address_uri); 579 tracker_sparql_builder_predicate (preupdate, "a"); 580 tracker_sparql_builder_object (preupdate, "nco:PostalAddress"); 581 582 if (sublocation) { 583 tracker_sparql_builder_predicate (preupdate, "nco:region"); 584 tracker_sparql_builder_object_unvalidated (preupdate, sublocation); 585 } 586 587 if (city) { 588 tracker_sparql_builder_predicate (preupdate, "nco:locality"); 589 tracker_sparql_builder_object_unvalidated (preupdate, city); 590 } 591 592 if (country) { 593 tracker_sparql_builder_predicate (preupdate, "nco:country"); 594 tracker_sparql_builder_object_unvalidated (preupdate, country); 595 } 596 597 if (graph) { 598 tracker_sparql_builder_graph_close (preupdate); 599 } 600 tracker_sparql_builder_insert_close (preupdate); 601 } 602 603 /* Create geolocation */ 604 tracker_sparql_builder_predicate (metadata, "slo:location"); 605 606 tracker_sparql_builder_object_blank_open (metadata); 607 tracker_sparql_builder_predicate (metadata, "a"); 608 tracker_sparql_builder_object (metadata, "slo:GeoLocation"); 609 610 if (address_uri) { 611 tracker_sparql_builder_predicate (metadata, "slo:postalAddress"); 612 tracker_sparql_builder_object_iri (metadata, address_uri); 613 } 614 615 if (has_coords) { 616 tracker_sparql_builder_predicate (metadata, "slo:latitude"); 617 tracker_sparql_builder_object_double (metadata, lat); 618 619 tracker_sparql_builder_predicate (metadata, "slo:longitude"); 620 tracker_sparql_builder_object_double (metadata, lon); 621 622 tracker_sparql_builder_predicate (metadata, "slo:altitude"); 623 tracker_sparql_builder_object_double (metadata, alt); 624 } 625 626 tracker_sparql_builder_object_blank_close (metadata); 627 g_free (address_uri); 628 } 629 630 g_free (city); 631 g_free (country); 632 g_free (sublocation); 633 } 634 635 static void 636 extractor_guess_content_type (MetadataExtractor *extractor) 637 { 638 #if defined(GSTREAMER_BACKEND_TAGREADBIN) || \ 639 defined(GSTREAMER_BACKEND_DECODEBIN2) 640 char *video_codec = NULL, *audio_codec = NULL; 641 642 gst_tag_list_get_string (extractor->tagcache, GST_TAG_VIDEO_CODEC, &video_codec); 643 gst_tag_list_get_string (extractor->tagcache, GST_TAG_AUDIO_CODEC, &audio_codec); 644 645 g_debug ("Reading codecs from the stream... audio: '%s', video: '%s'", 646 audio_codec ? audio_codec : "none", 647 video_codec ? video_codec : "none"); 648 649 if (audio_codec && !video_codec) { 650 extractor->mime = EXTRACT_MIME_AUDIO; 651 } else { 652 /* default to video */ 653 extractor->mime = EXTRACT_MIME_VIDEO; 654 } 655 656 g_free (video_codec); 657 g_free (audio_codec); 658 #else /* DISCOVERER/GUPNP-DLNA... */ 659 if (extractor->has_video) { 660 extractor->mime = EXTRACT_MIME_VIDEO; 661 } else if (extractor->has_audio) { 662 extractor->mime = EXTRACT_MIME_AUDIO; 663 } else if (extractor->has_image) { 664 extractor->mime = EXTRACT_MIME_IMAGE; 665 } else { 666 /* default to video */ 667 extractor->mime = EXTRACT_MIME_VIDEO; 668 } 669 #endif /* DISCOVERER/GUPNP-DLNA... */ 670 } 671 672 static void 673 extractor_apply_general_metadata (MetadataExtractor *extractor, 674 GstTagList *tag_list, 675 const gchar *file_url, 676 TrackerSparqlBuilder *preupdate, 677 TrackerSparqlBuilder *metadata, 678 const gchar *graph, 679 gchar **p_performer_uri, 680 gchar **p_composer_uri) 681 { 682 const gchar *performer = NULL; 683 gchar *performer_temp = NULL; 684 gchar *artist_temp = NULL; 685 gchar *composer = NULL; 686 gchar *genre = NULL; 687 gchar *title = NULL; 688 gchar *title_guaranteed = NULL; 689 690 gst_tag_list_get_string (tag_list, GST_TAG_PERFORMER, &performer_temp); 691 gst_tag_list_get_string (tag_list, GST_TAG_ARTIST, &artist_temp); 692 gst_tag_list_get_string (tag_list, GST_TAG_COMPOSER, &composer); 693 694 performer = tracker_coalesce_strip (2, performer_temp, artist_temp); 695 696 if (performer != NULL) { 697 add_artist (extractor, preupdate, graph, performer, p_performer_uri); 698 } 699 700 if (composer != NULL) { 701 add_artist (extractor, preupdate, graph, composer, p_composer_uri); 702 } 703 704 gst_tag_list_get_string (tag_list, GST_TAG_GENRE, &genre); 705 gst_tag_list_get_string (tag_list, GST_TAG_TITLE, &title); 706 707 if (genre && g_strcmp0 (genre, "Unknown") != 0) { 708 tracker_sparql_builder_predicate (metadata, "nfo:genre"); 709 tracker_sparql_builder_object_unvalidated (metadata, genre); 710 } 711 712 tracker_guarantee_title_from_file (metadata, 713 "nie:title", 714 title, 715 file_url, 716 &title_guaranteed); 717 718 add_date_time_gst_tag_with_mtime_fallback (metadata, 719 file_url, 720 "nie:contentCreated", 721 tag_list, 722 GST_TAG_DATE_TIME, 723 GST_TAG_DATE); 724 725 add_string_gst_tag (metadata, "nie:copyright", tag_list, GST_TAG_COPYRIGHT); 726 add_string_gst_tag (metadata, "nie:license", tag_list, GST_TAG_LICENSE); 727 add_string_gst_tag (metadata, "dc:coverage", tag_list, GST_TAG_LOCATION); 728 add_string_gst_tag (metadata, "nie:comment", tag_list, GST_TAG_COMMENT); 729 730 if (extractor->media_art_type == TRACKER_MEDIA_ART_VIDEO) { 731 extractor->media_art_title = title_guaranteed; 732 } else { 733 g_free (title_guaranteed); 734 } 735 736 g_free (performer_temp); 737 g_free (artist_temp); 738 g_free (composer); 739 g_free (genre); 740 g_free (title); 741 } 742 743 static void 744 extractor_apply_album_metadata (MetadataExtractor *extractor, 745 GstTagList *tag_list, 746 TrackerSparqlBuilder *preupdate, 747 const gchar *graph, 748 gchar **p_album_artist_uri, 749 gchar **p_album_uri, 750 gchar **p_album_disc_uri) 751 { 752 gchar *album_artist; 753 gchar *album_title = NULL; 754 gchar *album_artist_temp = NULL; 755 gchar *track_artist_temp = NULL; 756 gboolean has_it; 757 guint count; 758 759 gst_tag_list_get_string (tag_list, GST_TAG_ALBUM, &album_title); 760 761 if (!album_title) 762 return; 763 764 gst_tag_list_get_string (tag_list, GST_TAG_ALBUM_ARTIST, &album_artist_temp); 765 gst_tag_list_get_string (tag_list, GST_TAG_ARTIST, &track_artist_temp); 766 767 album_artist = g_strdup (tracker_coalesce_strip (2, album_artist_temp, track_artist_temp)); 768 769 if (album_artist != NULL) 770 add_artist (extractor, preupdate, graph, album_artist, p_album_artist_uri); 771 772 *p_album_uri = tracker_sparql_escape_uri_printf ("urn:album:%s", album_title); 773 774 tracker_sparql_builder_insert_open (preupdate, NULL); 775 if (graph) { 776 tracker_sparql_builder_graph_open (preupdate, graph); 777 } 778 779 tracker_sparql_builder_subject_iri (preupdate, *p_album_uri); 780 tracker_sparql_builder_predicate (preupdate, "a"); 781 tracker_sparql_builder_object (preupdate, "nmm:MusicAlbum"); 782 /* FIXME: nmm:albumTitle is now deprecated 783 * tracker_sparql_builder_predicate (preupdate, "nie:title"); 784 */ 785 tracker_sparql_builder_predicate (preupdate, "nmm:albumTitle"); 786 tracker_sparql_builder_object_unvalidated (preupdate, album_title); 787 788 if (*p_album_artist_uri) { 789 tracker_sparql_builder_predicate (preupdate, "nmm:albumArtist"); 790 tracker_sparql_builder_object_iri (preupdate, *p_album_artist_uri); 791 } 792 793 if (graph) { 794 tracker_sparql_builder_graph_close (preupdate); 795 } 796 tracker_sparql_builder_insert_close (preupdate); 797 798 has_it = gst_tag_list_get_uint (tag_list, GST_TAG_TRACK_COUNT, &count); 799 800 if (has_it) { 801 tracker_sparql_builder_delete_open (preupdate, NULL); 802 tracker_sparql_builder_subject_iri (preupdate, *p_album_uri); 803 tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount"); 804 tracker_sparql_builder_object_variable (preupdate, "unknown"); 805 tracker_sparql_builder_delete_close (preupdate); 806 tracker_sparql_builder_where_open (preupdate); 807 tracker_sparql_builder_subject_iri (preupdate, *p_album_uri); 808 tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount"); 809 tracker_sparql_builder_object_variable (preupdate, "unknown"); 810 tracker_sparql_builder_where_close (preupdate); 811 812 tracker_sparql_builder_insert_open (preupdate, NULL); 813 if (graph) { 814 tracker_sparql_builder_graph_open (preupdate, graph); 815 } 816 817 tracker_sparql_builder_subject_iri (preupdate, *p_album_uri); 818 tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount"); 819 tracker_sparql_builder_object_int64 (preupdate, count); 820 821 if (graph) { 822 tracker_sparql_builder_graph_close (preupdate); 823 } 824 tracker_sparql_builder_insert_close (preupdate); 825 } 826 827 has_it = gst_tag_list_get_uint (tag_list, GST_TAG_ALBUM_VOLUME_NUMBER, &count); 828 829 *p_album_disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:Disc%d", 830 album_title, 831 has_it ? count : 1); 832 833 tracker_sparql_builder_delete_open (preupdate, NULL); 834 tracker_sparql_builder_subject_iri (preupdate, *p_album_disc_uri); 835 tracker_sparql_builder_predicate (preupdate, "nmm:setNumber"); 836 tracker_sparql_builder_object_variable (preupdate, "unknown"); 837 tracker_sparql_builder_delete_close (preupdate); 838 tracker_sparql_builder_where_open (preupdate); 839 tracker_sparql_builder_subject_iri (preupdate, *p_album_disc_uri); 840 tracker_sparql_builder_predicate (preupdate, "nmm:setNumber"); 841 tracker_sparql_builder_object_variable (preupdate, "unknown"); 842 tracker_sparql_builder_where_close (preupdate); 843 844 tracker_sparql_builder_delete_open (preupdate, NULL); 845 tracker_sparql_builder_subject_iri (preupdate, *p_album_disc_uri); 846 tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum"); 847 tracker_sparql_builder_object_variable (preupdate, "unknown"); 848 tracker_sparql_builder_delete_close (preupdate); 849 tracker_sparql_builder_where_open (preupdate); 850 tracker_sparql_builder_subject_iri (preupdate, *p_album_disc_uri); 851 tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum"); 852 tracker_sparql_builder_object_variable (preupdate, "unknown"); 853 tracker_sparql_builder_where_close (preupdate); 854 855 tracker_sparql_builder_insert_open (preupdate, NULL); 856 if (graph) { 857 tracker_sparql_builder_graph_open (preupdate, graph); 858 } 859 860 tracker_sparql_builder_subject_iri (preupdate, *p_album_disc_uri); 861 tracker_sparql_builder_predicate (preupdate, "a"); 862 tracker_sparql_builder_object (preupdate, "nmm:MusicAlbumDisc"); 863 tracker_sparql_builder_predicate (preupdate, "nmm:setNumber"); 864 tracker_sparql_builder_object_int64 (preupdate, has_it ? count : 1); 865 tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum"); 866 tracker_sparql_builder_object_iri (preupdate, *p_album_uri); 867 868 if (graph) { 869 tracker_sparql_builder_graph_close (preupdate); 870 } 871 tracker_sparql_builder_insert_close (preupdate); 872 873 replace_double_gst_tag (preupdate, *p_album_uri, "nmm:albumGain", extractor->tagcache, GST_TAG_ALBUM_GAIN, graph); 874 replace_double_gst_tag (preupdate, *p_album_uri, "nmm:albumPeakGain", extractor->tagcache, GST_TAG_ALBUM_PEAK, graph); 875 876 extractor->media_art_artist = album_artist; 877 extractor->media_art_title = album_title; 878 879 g_free (album_artist_temp); 880 g_free (track_artist_temp); 881 } 882 883 static void 884 extractor_apply_device_metadata (MetadataExtractor *extractor, 885 GstTagList *tag_list, 886 TrackerSparqlBuilder *preupdate, 887 TrackerSparqlBuilder *metadata, 888 const gchar *graph) 889 { 890 gchar *equip_uri; 891 gchar *model = NULL, *manuf = NULL; 892 893 gst_tag_list_get_string (tag_list, GST_TAG_DEVICE_MODEL, &model); 894 gst_tag_list_get_string (tag_list, GST_TAG_DEVICE_MANUFACTURER, &manuf); 895 896 if (model == NULL && manuf == NULL) 897 return; 898 899 equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:", 900 manuf ? manuf : "", 901 model ? model : ""); 902 903 tracker_sparql_builder_insert_open (preupdate, NULL); 904 if (graph) { 905 tracker_sparql_builder_graph_open (preupdate, graph); 906 } 907 908 tracker_sparql_builder_subject_iri (preupdate, equip_uri); 909 tracker_sparql_builder_predicate (preupdate, "a"); 910 tracker_sparql_builder_object (preupdate, "nfo:Equipment"); 911 912 if (manuf) { 913 tracker_sparql_builder_predicate (preupdate, "nfo:manufacturer"); 914 tracker_sparql_builder_object_unvalidated (preupdate, manuf); 915 } 916 if (model) { 917 tracker_sparql_builder_predicate (preupdate, "nfo:model"); 918 tracker_sparql_builder_object_unvalidated (preupdate, model); 919 } 920 921 if (graph) { 922 tracker_sparql_builder_graph_close (preupdate); 923 } 924 tracker_sparql_builder_insert_close (preupdate); 925 926 tracker_sparql_builder_predicate (metadata, "nfo:equipment"); 927 tracker_sparql_builder_object_iri (metadata, equip_uri); 928 929 g_free (equip_uri); 930 g_free (model); 931 g_free (manuf); 932 } 933 934 static void 935 extractor_apply_audio_metadata (MetadataExtractor *extractor, 936 GstTagList *tag_list, 937 TrackerSparqlBuilder *metadata, 938 const gchar *performer_uri, 939 const gchar *composer_uri, 940 const gchar *album_uri, 941 const gchar *album_disc_uri) 942 { 943 add_uint_gst_tag (metadata, "nmm:trackNumber", tag_list, GST_TAG_TRACK_NUMBER); 944 add_string_gst_tag (metadata, "nfo:codec", tag_list, GST_TAG_AUDIO_CODEC); 945 add_double_gst_tag (metadata, "nfo:gain", tag_list, GST_TAG_TRACK_GAIN); 946 add_double_gst_tag (metadata, "nfo:peakGain", tag_list, GST_TAG_TRACK_PEAK); 947 948 if (performer_uri) { 949 tracker_sparql_builder_predicate (metadata, "nmm:performer"); 950 tracker_sparql_builder_object_iri (metadata, performer_uri); 951 } 952 953 if (composer_uri) { 954 tracker_sparql_builder_predicate (metadata, "nmm:composer"); 955 tracker_sparql_builder_object_iri (metadata, composer_uri); 956 } 957 958 if (album_uri) { 959 tracker_sparql_builder_predicate (metadata, "nmm:musicAlbum"); 960 tracker_sparql_builder_object_iri (metadata, album_uri); 961 } 962 963 if (album_disc_uri) { 964 tracker_sparql_builder_predicate (metadata, "nmm:musicAlbumDisc"); 965 tracker_sparql_builder_object_iri (metadata, album_disc_uri); 966 } 967 } 968 969 static void 970 extractor_apply_video_metadata (MetadataExtractor *extractor, 971 GstTagList *tag_list, 972 TrackerSparqlBuilder *metadata, 973 const gchar *performer_uri, 974 const gchar *composer_uri) 975 { 976 add_string_gst_tag (metadata, "dc:source", tag_list, GST_TAG_CLASSIFICATION); 977 978 if (performer_uri) { 979 tracker_sparql_builder_predicate (metadata, "nmm:leadActor"); 980 tracker_sparql_builder_object_iri (metadata, performer_uri); 981 } 982 983 if (composer_uri) { 984 tracker_sparql_builder_predicate (metadata, "nmm:director"); 985 tracker_sparql_builder_object_iri (metadata, composer_uri); 986 } 987 988 add_keywords_gst_tag (metadata, tag_list); 989 } 990 991 static void 992 extract_track_metadata (MetadataExtractor *extractor, 993 TrackerTocEntry *toc_entry, 994 const gchar *file_url, 995 TrackerSparqlBuilder *preupdate, 996 TrackerSparqlBuilder *postupdate, 997 const gchar *graph, 998 const gchar *album_uri, 999 const gchar *album_disc_uri) 1000 { 1001 gchar *track_performer_uri = NULL; 1002 gchar *track_composer_uri = NULL; 1003 gchar *track_uri; 1004 1005 track_uri = tracker_sparql_get_uuid_urn (); 1006 1007 tracker_sparql_builder_subject_iri (postupdate, track_uri); 1008 1009 tracker_sparql_builder_predicate (postupdate, "a"); 1010 tracker_sparql_builder_object (postupdate, "nmm:MusicPiece"); 1011 tracker_sparql_builder_object (postupdate, "nfo:Audio"); 1012 1013 extractor_apply_general_metadata (extractor, 1014 toc_entry->tag_list, 1015 file_url, 1016 preupdate, 1017 postupdate, 1018 graph, 1019 &track_performer_uri, 1020 &track_composer_uri); 1021 1022 extractor_apply_audio_metadata (extractor, 1023 toc_entry->tag_list, 1024 postupdate, 1025 track_performer_uri, 1026 track_composer_uri, 1027 album_uri, 1028 album_disc_uri); 1029 1030 if (toc_entry->duration > 0) { 1031 tracker_sparql_builder_predicate (postupdate, "nfo:duration"); 1032 tracker_sparql_builder_object_int64 (postupdate, (gint64)toc_entry->duration); 1033 } 1034 1035 tracker_sparql_builder_predicate (postupdate, "nfo:audioOffset"); 1036 tracker_sparql_builder_object_double (postupdate, toc_entry->start); 1037 1038 /* Link the track to its container file. Since the file might not have been 1039 * inserted yet, we use a WHERE clause based on its nie:url to refer to it. 1040 */ 1041 tracker_sparql_builder_predicate (postupdate, "nie:isStoredAs"); 1042 tracker_sparql_builder_object_variable (postupdate, "file"); 1043 1044 g_free (track_performer_uri); 1045 g_free (track_composer_uri); 1046 1047 g_free (track_uri); 1048 } 1049 1050 static void 1051 delete_existing_tracks (TrackerSparqlBuilder *postupdate, 1052 const gchar *graph, 1053 const gchar *file_url) 1054 { 1055 gchar *sparql; 1056 1057 /* Delete existing tracks */ 1058 1059 tracker_sparql_builder_delete_open (postupdate, NULL); 1060 if (graph) { 1061 tracker_sparql_builder_graph_open (postupdate, graph); 1062 } 1063 1064 tracker_sparql_builder_subject_variable (postupdate, "track"); 1065 tracker_sparql_builder_predicate (postupdate, "a"); 1066 tracker_sparql_builder_object (postupdate, "rdfs:Resource"); 1067 1068 if (graph) { 1069 tracker_sparql_builder_graph_close (postupdate); 1070 } 1071 tracker_sparql_builder_delete_close (postupdate); 1072 1073 sparql = g_strdup_printf ("WHERE { " 1074 " ?track a nmm:MusicPiece . " 1075 " ?file a nfo:FileDataObject ; " 1076 " nie:url \"%s\" . " 1077 " ?track nie:isStoredAs ?file " 1078 "} \n", 1079 file_url); 1080 tracker_sparql_builder_append (postupdate, sparql); 1081 g_free (sparql); 1082 } 1083 1084 static void 1085 extract_metadata (MetadataExtractor *extractor, 1086 const gchar *file_url, 1087 TrackerSparqlBuilder *preupdate, 1088 TrackerSparqlBuilder *postupdate, 1089 TrackerSparqlBuilder *metadata, 1090 const gchar *graph) 1091 { 1092 g_return_if_fail (extractor != NULL); 1093 g_return_if_fail (preupdate != NULL); 1094 g_return_if_fail (postupdate != NULL); 1095 g_return_if_fail (metadata != NULL); 1096 1097 extractor->media_art_type = TRACKER_MEDIA_ART_NONE; 1098 1099 if (extractor->toc) { 1100 gst_tag_list_insert (extractor->tagcache, 1101 extractor->toc->tag_list, 1102 GST_TAG_MERGE_REPLACE); 1103 1104 if (g_list_length (extractor->toc->entry_list) == 1) { 1105 /* If we only got one track, stick all the info together and 1106 * forget about the table of contents 1107 */ 1108 TrackerTocEntry *toc_entry; 1109 1110 toc_entry = extractor->toc->entry_list->data; 1111 gst_tag_list_insert (extractor->tagcache, 1112 toc_entry->tag_list, 1113 GST_TAG_MERGE_REPLACE); 1114 1115 tracker_toc_free (extractor->toc); 1116 extractor->toc = NULL; 1117 } 1118 } 1119 1120 if (extractor->mime == EXTRACT_MIME_GUESS && !gst_tag_list_is_empty (extractor->tagcache)) { 1121 extractor_guess_content_type (extractor); 1122 } 1123 1124 if (extractor->mime == EXTRACT_MIME_GUESS) { 1125 g_warning ("Cannot guess real stream type if no tags were read! " 1126 "Defaulting to Video."); 1127 tracker_sparql_builder_predicate (metadata, "a"); 1128 tracker_sparql_builder_object (metadata, "nmm:Video"); 1129 } else { 1130 tracker_sparql_builder_predicate (metadata, "a"); 1131 1132 if (extractor->mime == EXTRACT_MIME_AUDIO) { 1133 /* Audio: don't make an nmm:MusicPiece for the file resource if it's 1134 * actually a container for an entire album - we will make a 1135 * nmm:MusicPiece for each of the tracks inside instead. 1136 */ 1137 tracker_sparql_builder_object (metadata, "nfo:Audio"); 1138 1139 if (extractor->toc == NULL || extractor->toc->entry_list == NULL) 1140 tracker_sparql_builder_object (metadata, "nmm:MusicPiece"); 1141 1142 extractor->media_art_type = TRACKER_MEDIA_ART_ALBUM; 1143 } else if (extractor->mime == EXTRACT_MIME_VIDEO) { 1144 tracker_sparql_builder_object (metadata, "nmm:Video"); 1145 1146 extractor->media_art_type = TRACKER_MEDIA_ART_VIDEO; 1147 } else { 1148 tracker_sparql_builder_object (metadata, "nfo:Image"); 1149 1150 if (extractor->mime != EXTRACT_MIME_SVG) { 1151 tracker_sparql_builder_object (metadata, "nmm:Photo"); 1152 } else { 1153 tracker_sparql_builder_object (metadata, "nfo:VectorImage"); 1154 } 1155 } 1156 } 1157 1158 if (!gst_tag_list_is_empty (extractor->tagcache)) { 1159 GList *node; 1160 gchar *performer_uri = NULL; 1161 gchar *composer_uri = NULL; 1162 gchar *album_artist_uri = NULL; 1163 gchar *album_uri = NULL; 1164 gchar *album_disc_uri = NULL; 1165 1166 extractor_apply_general_metadata (extractor, 1167 extractor->tagcache, 1168 file_url, 1169 preupdate, 1170 metadata, 1171 graph, 1172 &performer_uri, 1173 &composer_uri); 1174 1175 extractor_apply_device_metadata (extractor, 1176 extractor->tagcache, 1177 preupdate, 1178 metadata, 1179 graph); 1180 1181 extractor_apply_geolocation_metadata (extractor, 1182 extractor->tagcache, 1183 preupdate, 1184 metadata, 1185 graph); 1186 1187 if (extractor->mime == EXTRACT_MIME_VIDEO) { 1188 extractor_apply_video_metadata (extractor, 1189 extractor->tagcache, 1190 metadata, 1191 performer_uri, 1192 composer_uri); 1193 } 1194 1195 if (extractor->mime == EXTRACT_MIME_AUDIO) { 1196 extractor_apply_album_metadata (extractor, 1197 extractor->tagcache, 1198 preupdate, 1199 graph, 1200 &album_artist_uri, 1201 &album_uri, 1202 &album_disc_uri); 1203 1204 extractor_apply_audio_metadata (extractor, 1205 extractor->tagcache, 1206 metadata, 1207 performer_uri, 1208 composer_uri, 1209 album_uri, 1210 album_disc_uri); 1211 1212 /* If the audio file contains multiple tracks, we create the tracks 1213 * as abstract information element types and relate them to the 1214 * concrete nfo:FileDataObject using nie:isStoredAs. 1215 */ 1216 if (extractor->toc && g_list_length (extractor->toc->entry_list) > 1) { 1217 delete_existing_tracks (postupdate, graph, file_url); 1218 1219 tracker_sparql_builder_insert_open (postupdate, NULL); 1220 if (graph) { 1221 tracker_sparql_builder_graph_open (postupdate, graph); 1222 } 1223 1224 for (node = extractor->toc->entry_list; node; node = node->next) 1225 extract_track_metadata (extractor, 1226 node->data, 1227 file_url, 1228 preupdate, 1229 postupdate, 1230 graph, 1231 album_uri, 1232 album_disc_uri); 1233 1234 if (graph) { 1235 tracker_sparql_builder_graph_close (postupdate); 1236 } 1237 tracker_sparql_builder_insert_close (postupdate); 1238 1239 tracker_sparql_builder_where_open (postupdate); 1240 tracker_sparql_builder_subject_variable (postupdate, "file"); 1241 tracker_sparql_builder_predicate (postupdate, "nie:url"); 1242 tracker_sparql_builder_object_string (postupdate, file_url); 1243 tracker_sparql_builder_where_close (postupdate); 1244 } 1245 } 1246 1247 g_free (performer_uri); 1248 g_free (composer_uri); 1249 g_free (album_uri); 1250 g_free (album_disc_uri); 1251 g_free (album_artist_uri); 1252 } 1253 1254 /* If content was encrypted, set it. */ 1255 #if defined(GSTREAMER_BACKEND_TAGREADBIN) || \ 1256 defined(GSTREAMER_BACKEND_DECODEBIN2) 1257 if (extractor->is_content_encrypted) { 1258 tracker_sparql_builder_predicate (metadata, "nfo:isContentEncrypted"); 1259 tracker_sparql_builder_object_boolean (metadata, TRUE); 1260 } 1261 #else 1262 /* #warning TODO: handle encrypted content with the Discoverer/GUPnP-DLNA backends */ 1263 #endif 1264 1265 #if defined(GSTREAMER_BACKEND_TAGREADBIN) 1266 tagreadbin_extract_stream_metadata (extractor, file_url, metadata); 1267 #else /* DECODEBIN2/DISCOVERER/GUPnP-DLNA */ 1268 common_extract_stream_metadata (extractor, file_url, metadata); 1269 #endif /* DECODEBIN2/DISCOVERER/GUPnP-DLNA */ 1270 1271 if (extractor->mime == EXTRACT_MIME_AUDIO) { 1272 get_embedded_media_art (extractor); 1273 } 1274 } 1275 1276 #if defined(GSTREAMER_BACKEND_DISCOVERER) || \ 1277 defined(GSTREAMER_BACKEND_DECODEBIN2) || \ 1278 defined(GSTREAMER_BACKEND_GUPNP_DLNA) 1279 static void 1280 common_extract_stream_metadata (MetadataExtractor *extractor, 1281 const gchar *uri, 1282 TrackerSparqlBuilder *metadata) 1283 { 1284 if (extractor->mime == EXTRACT_MIME_AUDIO || 1285 extractor->mime == EXTRACT_MIME_VIDEO) { 1286 if (extractor->audio_channels >= 0) { 1287 tracker_sparql_builder_predicate (metadata, "nfo:channels"); 1288 tracker_sparql_builder_object_int64 (metadata, extractor->audio_channels); 1289 } 1290 1291 if (extractor->audio_samplerate >= 0) { 1292 tracker_sparql_builder_predicate (metadata, "nfo:sampleRate"); 1293 tracker_sparql_builder_object_int64 (metadata, extractor->audio_samplerate); 1294 } 1295 1296 if (extractor->duration >= 0) { 1297 tracker_sparql_builder_predicate (metadata, "nfo:duration"); 1298 tracker_sparql_builder_object_int64 (metadata, extractor->duration); 1299 } 1300 } 1301 1302 if (extractor->mime == EXTRACT_MIME_VIDEO) { 1303 if (extractor->video_fps >= 0) { 1304 tracker_sparql_builder_predicate (metadata, "nfo:frameRate"); 1305 tracker_sparql_builder_object_double (metadata, (gdouble)extractor->video_fps); 1306 } 1307 } 1308 1309 if (extractor->mime == EXTRACT_MIME_IMAGE || 1310 extractor->mime == EXTRACT_MIME_SVG || 1311 extractor->mime == EXTRACT_MIME_VIDEO) { 1312 1313 if (extractor->width) { 1314 tracker_sparql_builder_predicate (metadata, "nfo:width"); 1315 tracker_sparql_builder_object_int64 (metadata, extractor->width); 1316 } 1317 1318 if (extractor->height >= 0) { 1319 tracker_sparql_builder_predicate (metadata, "nfo:height"); 1320 tracker_sparql_builder_object_int64 (metadata, extractor->height); 1321 } 1322 1323 if (extractor->aspect_ratio >= 0) { 1324 tracker_sparql_builder_predicate (metadata, "nfo:aspectRatio"); 1325 tracker_sparql_builder_object_double (metadata, (gdouble)extractor->aspect_ratio); 1326 } 1327 } 1328 1329 #if defined(GSTREAMER_BACKEND_GUPNP_DLNA) 1330 if (extractor->dlna_profile) { 1331 tracker_sparql_builder_predicate (metadata, "nmm:dlnaProfile"); 1332 tracker_sparql_builder_object_string (metadata, extractor->dlna_profile); 1333 } else { 1334 g_debug ("No DLNA profile found"); 1335 } 1336 1337 if (extractor->dlna_mime) { 1338 tracker_sparql_builder_predicate (metadata, "nmm:dlnaMime"); 1339 tracker_sparql_builder_object_string (metadata, extractor->dlna_mime); 1340 } else { 1341 g_debug ("No DLNA mime found"); 1342 } 1343 #endif /* GSTREAMER_BACKEND_GUPNP_DLNA */ 1344 } 1345 1346 #endif 1347 1348 /* ----------------------- Discoverer/GUPnP-DLNA specific implementation --------------- */ 1349 1350 #if defined(GSTREAMER_BACKEND_DISCOVERER) || \ 1351 defined(GSTREAMER_BACKEND_GUPNP_DLNA) 1352 1353 static void 1354 discoverer_shutdown (MetadataExtractor *extractor) 1355 { 1356 if (extractor->streams) 1357 gst_discoverer_stream_info_list_free (extractor->streams); 1358 if (extractor->discoverer) 1359 g_object_unref (extractor->discoverer); 1360 } 1361 1362 static gboolean 1363 discoverer_init_and_run (MetadataExtractor *extractor, 1364 const gchar *uri) 1365 { 1366 GstDiscovererInfo *info; 1367 const GstTagList *discoverer_tags; 1368 GError *error = NULL; 1369 GList *l; 1370 1371 extractor->duration = -1; 1372 extractor->audio_channels = -1; 1373 extractor->audio_samplerate = -1; 1374 extractor->height = -1; 1375 extractor->width = -1; 1376 extractor->video_fps = -1.0; 1377 extractor->aspect_ratio = -1.0; 1378 1379 extractor->has_image = FALSE; 1380 extractor->has_video = FALSE; 1381 extractor->has_audio = FALSE; 1382 1383 extractor->discoverer = gst_discoverer_new (5 * GST_SECOND, &error); 1384 if (!extractor->discoverer) { 1385 g_warning ("Couldn't create discoverer: %s", 1386 error ? error->message : "unknown error"); 1387 g_clear_error (&error); 1388 return FALSE; 1389 } 1390 1391 #if defined(GST_TYPE_DISCOVERER_FLAGS) 1392 /* Tell the discoverer to use *only* Tagreadbin backend. 1393 * See https://bugzilla.gnome.org/show_bug.cgi?id=656345 1394 */ 1395 g_debug ("Using Tagreadbin backend in the GStreamer discoverer..."); 1396 g_object_set (extractor->discoverer, 1397 "flags", GST_DISCOVERER_FLAGS_EXTRACT_LIGHTWEIGHT, 1398 NULL); 1399 #endif 1400 1401 info = gst_discoverer_discover_uri (extractor->discoverer, 1402 uri, 1403 &error); 1404 if (error) { 1405 g_warning ("Call to gst_discoverer_discover_uri() failed: %s", 1406 error->message); 1407 g_error_free (error); 1408 return FALSE; 1409 } 1410 1411 if (!info) { 1412 g_warning ("Nothing discovered, bailing out"); 1413 return TRUE; 1414 } 1415 1416 #if defined(GSTREAMER_BACKEND_GUPNP_DLNA) 1417 { 1418 GUPnPDLNAProfile *profile; 1419 GUPnPDLNAInformation *dlna_info; 1420 GUPnPDLNAProfileGuesser *guesser; 1421 1422 dlna_info = gupnp_dlna_gst_utils_information_from_discoverer_info (info); 1423 guesser = gupnp_dlna_profile_guesser_new (TRUE, FALSE); 1424 profile = gupnp_dlna_profile_guesser_guess_profile_from_info (guesser, dlna_info); 1425 1426 if (profile) { 1427 extractor->dlna_profile = gupnp_dlna_profile_get_name (profile); 1428 extractor->dlna_mime = gupnp_dlna_profile_get_mime (profile); 1429 } 1430 1431 g_object_unref (guesser); 1432 g_object_unref (dlna_info); 1433 } 1434 #endif 1435 1436 extractor->duration = gst_discoverer_info_get_duration (info) / GST_SECOND; 1437 1438 /* Retrieve global tags */ 1439 discoverer_tags = gst_discoverer_info_get_tags (info); 1440 1441 if (discoverer_tags) { 1442 gst_tag_list_insert (extractor->tagcache, 1443 discoverer_tags, 1444 GST_TAG_MERGE_APPEND); 1445 } 1446 1447 /* Get list of Streams to iterate */ 1448 extractor->streams = gst_discoverer_info_get_stream_list (info); 1449 for (l = extractor->streams; l; l = g_list_next (l)) { 1450 GstDiscovererStreamInfo *stream = l->data; 1451 const GstTagList *stream_tags; 1452 1453 if (G_TYPE_CHECK_INSTANCE_TYPE (stream, GST_TYPE_DISCOVERER_AUDIO_INFO)) { 1454 GstDiscovererAudioInfo *audio = (GstDiscovererAudioInfo*)stream; 1455 1456 extractor->has_audio = TRUE; 1457 extractor->audio_samplerate = gst_discoverer_audio_info_get_sample_rate (audio); 1458 extractor->audio_channels = gst_discoverer_audio_info_get_channels (audio); 1459 } else if (G_TYPE_CHECK_INSTANCE_TYPE (stream, GST_TYPE_DISCOVERER_VIDEO_INFO)) { 1460 GstDiscovererVideoInfo *video = (GstDiscovererVideoInfo*)stream; 1461 1462 if (gst_discoverer_video_info_is_image (video)) { 1463 extractor->has_image = TRUE; 1464 } else { 1465 extractor->has_video = TRUE; 1466 if (gst_discoverer_video_info_get_framerate_denom (video) > 0) { 1467 extractor->video_fps = (gfloat)(gst_discoverer_video_info_get_framerate_num (video) / 1468 gst_discoverer_video_info_get_framerate_denom (video)); 1469 } 1470 extractor->width = gst_discoverer_video_info_get_width (video); 1471 extractor->height = gst_discoverer_video_info_get_height (video); 1472 if (gst_discoverer_video_info_get_par_denom (video) > 0) { 1473 extractor->aspect_ratio = (gfloat)(gst_discoverer_video_info_get_par_num (video) / 1474 gst_discoverer_video_info_get_par_denom (video)); 1475 } 1476 } 1477 } else { 1478 /* Unknown type - do nothing */ 1479 } 1480 1481 stream_tags = gst_discoverer_stream_info_get_tags (stream); 1482 1483 if (stream_tags) { 1484 gst_tag_list_insert (extractor->tagcache, 1485 stream_tags, 1486 GST_TAG_MERGE_APPEND); 1487 } 1488 } 1489 1490 return TRUE; 1491 } 1492 1493 #endif /* defined(GSTREAMER_BACKEND_DISCOVERER) || \ 1494 defined(GSTREAMER_BACKEND_GUPNP_DLNA) */ 1495 1496 /* --------------- Common Tagreadbin and Decodebin2 implementation ---------- */ 1497 1498 #if defined(GSTREAMER_BACKEND_TAGREADBIN) || \ 1499 defined(GSTREAMER_BACKEND_DECODEBIN2) 1500 1501 static void 1502 pipeline_shutdown (MetadataExtractor *extractor) 1503 { 1504 gst_element_set_state (extractor->pipeline, GST_STATE_NULL); 1505 gst_element_get_state (extractor->pipeline, NULL, NULL, TRACKER_EXTRACT_GUARD_TIMEOUT* GST_SECOND); 1506 gst_object_unref (extractor->bus); 1507 gst_object_unref (GST_OBJECT (extractor->pipeline)); 1508 } 1509 1510 static gboolean 1511 pipeline_poll_for_ready (MetadataExtractor *extractor, 1512 GstState state, 1513 gboolean ready_with_state, 1514 gboolean ready_with_eos) 1515 { 1516 gint64 timeout = 5 * GST_SECOND; 1517 GstBus *bus = extractor->bus; 1518 GstTagList *new_tags; 1519 1520 gst_element_set_state (extractor->pipeline, state); 1521 1522 while (TRUE) { 1523 GstMessage *message; 1524 GstElement *src; 1525 1526 message = gst_bus_timed_pop (bus, timeout); 1527 1528 if (!message) { 1529 g_warning ("Pipeline timed out"); 1530 return FALSE; 1531 } 1532 1533 src = (GstElement*)GST_MESSAGE_SRC (message); 1534 1535 switch (GST_MESSAGE_TYPE (message)) { 1536 case GST_MESSAGE_STATE_CHANGED: { 1537 if (ready_with_state) { 1538 GstState old, new, pending; 1539 1540 if (src == extractor->pipeline) { 1541 gst_message_parse_state_changed (message, &old, &new, &pending); 1542 if (new == state) { 1543 gst_message_unref (message); 1544 return TRUE; 1545 } 1546 } 1547 } 1548 break; 1549 } 1550 case GST_MESSAGE_ERROR: { 1551 GError *lerror = NULL; 1552 gchar *error_debug_message; 1553 1554 gst_message_parse_error (message, &lerror, &error_debug_message); 1555 1556 if (lerror->domain == GST_STREAM_ERROR) { 1557 if (lerror->code == GST_STREAM_ERROR_DECRYPT || 1558 lerror->code == GST_STREAM_ERROR_DECRYPT_NOKEY) { 1559 /* Set content as being encrypted */ 1560 extractor->is_content_encrypted = TRUE; 1561 1562 g_message ("Encrypted stream found: '%s' (%s)", 1563 lerror ? lerror->message : "Unknown error", 1564 error_debug_message); 1565 1566 g_free (error_debug_message); 1567 g_error_free (lerror); 1568 1569 /* We really need to keep on reading as tags may come 1570 * afterwards, like codec tags in DRM-ed files. */ 1571 break; 1572 } 1573 } 1574 1575 g_warning ("Error in GStreamer: '%s' (%s)", 1576 lerror ? lerror->message : "Unknown error", 1577 error_debug_message); 1578 1579 gst_message_unref (message); 1580 g_free (error_debug_message); 1581 g_error_free (lerror); 1582 1583 return FALSE; 1584 break; 1585 } 1586 case GST_MESSAGE_EOS: { 1587 gst_message_unref (message); 1588 1589 if (ready_with_eos) { 1590 return TRUE; 1591 } else { 1592 g_warning ("Reached end-of-file without proper content"); 1593 return FALSE; 1594 } 1595 break; 1596 } 1597 case GST_MESSAGE_TAG: { 1598 gst_message_parse_tag (message, &new_tags); 1599 gst_tag_list_insert (extractor->tagcache, new_tags, GST_TAG_MERGE_KEEP); 1600 gst_tag_list_free (new_tags); 1601 break; 1602 } 1603 default: 1604 /* Nothing to do here */ 1605 break; 1606 } 1607 1608 gst_message_unref (message); 1609 } 1610 1611 g_assert_not_reached (); 1612 1613 return FALSE; 1614 } 1615 1616 #endif /* defined(GSTREAMER_BACKEND_TAGREADBIN) || \ 1617 defined(GSTREAMER_BACKEND_DECODEBIN2) */ 1618 1619 /* ----------------------- Decodebin2 specific implementation --------------- */ 1620 1621 #if defined(GSTREAMER_BACKEND_DECODEBIN2) 1622 1623 static void 1624 decodebin2_unlink_fsink (void *obj, 1625 void *data) 1626 { 1627 MetadataExtractor *extractor = (MetadataExtractor *) data; 1628 GstElement *fsink = (GstElement *) obj; 1629 1630 gst_element_unlink (extractor->bin, fsink); 1631 gst_bin_remove (GST_BIN (extractor->pipeline), fsink); 1632 gst_element_set_state (fsink, GST_STATE_NULL); 1633 } 1634 1635 static void 1636 decodebin2_dpad_cb (GstElement *e, 1637 GstPad *pad, 1638 gboolean cont, 1639 gpointer data) 1640 { 1641 MetadataExtractor *extractor = (MetadataExtractor *)data; 1642 GstElement *fsink; 1643 GstPad *fsinkpad; 1644 GValue val = { 0, }; 1645 1646 fsink = gst_element_factory_make ("fakesink", NULL); 1647 1648 /* We increase the preroll buffer so we get duration (one frame not enough)*/ 1649 g_value_init (&val, G_TYPE_INT); 1650 g_value_set_int (&val, 51); 1651 g_object_set_property (G_OBJECT (fsink), "preroll-queue-len", &val); 1652 g_value_unset (&val); 1653 1654 extractor->fsinks = g_list_append (extractor->fsinks, fsink); 1655 gst_element_set_state (fsink, GST_STATE_PAUSED); 1656 1657 gst_bin_add (GST_BIN (extractor->pipeline), fsink); 1658 fsinkpad = gst_element_get_static_pad (fsink, "sink"); 1659 gst_pad_link (pad, fsinkpad); 1660 gst_object_unref (fsinkpad); 1661 } 1662 1663 static guint64 1664 decodebin2_get_media_duration (MetadataExtractor *extractor) 1665 { 1666 gint64 duration; 1667 GstFormat fmt; 1668 1669 g_return_val_if_fail (extractor, -1); 1670 g_return_val_if_fail (extractor->pipeline, -1); 1671 1672 fmt = GST_FORMAT_TIME; 1673 1674 duration = -1; 1675 1676 if (gst_element_query_duration (extractor->pipeline, 1677 &fmt, 1678 &duration) && 1679 duration >= 0) { 1680 return duration / GST_SECOND; 1681 } else { 1682 return -1; 1683 } 1684 } 1685 1686 static void 1687 decodebin2_add_stream_tag (void *obj, void *data) 1688 { 1689 MetadataExtractor *extractor = (MetadataExtractor *) data; 1690 GstElement *fsink = (GstElement *) obj; 1691 1692 GstStructure *s = NULL; 1693 GstCaps *caps = NULL; 1694 1695 if ((caps = GST_PAD_CAPS (fsink))) { 1696 s = gst_caps_get_structure (caps, 0); 1697 1698 if (s) { 1699 if (g_strrstr (gst_structure_get_name (s), "audio")) { 1700 if ((extractor->audio_channels != -1) && 1701 (extractor->audio_samplerate != -1)) 1702 return; 1703 1704 if (extractor->audio_channels == -1) 1705 gst_structure_get_int (s, "channels", &extractor->audio_channels); 1706 1707 if (extractor->audio_samplerate == -1) 1708 gst_structure_get_int (s, "rate", &extractor->audio_samplerate); 1709 return; 1710 } 1711 1712 if (g_strrstr (gst_structure_get_name (s), "video")) { 1713 if ((extractor->video_fps != -1) && 1714 (extractor->width != -1) && 1715 (extractor->height != -1) && 1716 (extractor->aspect_ratio != -1)){ 1717 return; 1718 } 1719 1720 if (extractor->video_fps == -1) { 1721 gint video_fps_n; 1722 gint video_fps_d; 1723 1724 if (gst_structure_get_fraction (s, 1725 "framerate", 1726 &video_fps_n, 1727 &video_fps_d)) { 1728 extractor->video_fps = (video_fps_n + video_fps_d / 2) / video_fps_d; 1729 } 1730 } 1731 1732 if (extractor->width == -1) 1733 gst_structure_get_int (s, "width", &extractor->width); 1734 1735 if (extractor->height == -1) 1736 gst_structure_get_int (s, "height", &extractor->height); 1737 1738 if (extractor->aspect_ratio == -1) { 1739 gint aspect_ratio; 1740 1741 gst_structure_get_int (s, "pixel-aspect-ratio", &aspect_ratio); 1742 extractor->aspect_ratio = aspect_ratio; 1743 } 1744 1745 return; 1746 } 1747 1748 /* TODO: Add aspect-ratio, width and height in case of images */ 1749 } 1750 } 1751 } 1752 1753 static void 1754 decodebin2_add_stream_tags (MetadataExtractor *extractor) 1755 { 1756 extractor->duration = decodebin2_get_media_duration (extractor); 1757 g_list_foreach (extractor->fsinks, decodebin2_add_stream_tag, extractor); 1758 } 1759 1760 static GstElement * 1761 decodebin2_create_pipeline (MetadataExtractor *extractor, 1762 const gchar *uri) 1763 { 1764 GstElement *pipeline = NULL; 1765 GstElement *filesrc = NULL; 1766 GstElement *bin = NULL; 1767 1768 pipeline = gst_element_factory_make ("pipeline", NULL); 1769 if (!pipeline) { 1770 g_warning ("Failed to create GStreamer pipeline"); 1771 return NULL; 1772 } 1773 1774 filesrc = gst_element_factory_make ("giosrc", NULL); 1775 if (!filesrc) { 1776 g_warning ("Failed to create GStreamer giosrc"); 1777 gst_object_unref (GST_OBJECT (pipeline)); 1778 return NULL; 1779 } 1780 1781 bin = gst_element_factory_make ("decodebin2", "decodebin2"); 1782 if (!bin) { 1783 g_warning ("Failed to create GStreamer decodebin"); 1784 gst_object_unref (GST_OBJECT (pipeline)); 1785 gst_object_unref (GST_OBJECT (filesrc)); 1786 return NULL; 1787 } 1788 1789 g_signal_connect (G_OBJECT (bin), 1790 "new-decoded-pad", 1791 G_CALLBACK (decodebin2_dpad_cb), 1792 extractor); 1793 1794 gst_bin_add (GST_BIN (pipeline), filesrc); 1795 gst_bin_add (GST_BIN (pipeline), bin); 1796 1797 if (!gst_element_link_many (filesrc, bin, NULL)) { 1798 g_warning ("Could not link GStreamer elements"); 1799 gst_object_unref (GST_OBJECT (pipeline)); 1800 return NULL; 1801 } 1802 1803 g_object_set (G_OBJECT (filesrc), "location", uri, NULL); 1804 1805 extractor->bin = bin; 1806 1807 return pipeline; 1808 } 1809 1810 static void 1811 decodebin2_shutdown (MetadataExtractor *extractor) 1812 { 1813 pipeline_shutdown (extractor); 1814 } 1815 1816 static gboolean 1817 decodebin2_init_and_run (MetadataExtractor *extractor, 1818 const gchar *uri) 1819 { 1820 extractor->bus = NULL; 1821 extractor->bin = NULL; 1822 extractor->fsinks = NULL; 1823 extractor->duration = -1; 1824 extractor->audio_channels = -1; 1825 extractor->audio_samplerate = -1; 1826 extractor->height = -1; 1827 extractor->width = -1; 1828 extractor->video_fps = -1; 1829 extractor->aspect_ratio = -1; 1830 1831 extractor->pipeline = decodebin2_create_pipeline (extractor, uri); 1832 if (!extractor->pipeline) { 1833 g_warning ("No valid pipeline for uri %s", uri); 1834 g_list_free (extractor->fsinks); 1835 return FALSE; 1836 } 1837 1838 /* Get bus */ 1839 extractor->bus = gst_pipeline_get_bus (GST_PIPELINE (extractor->pipeline)); 1840 1841 /* Run! */ 1842 if (!pipeline_poll_for_ready (extractor, GST_STATE_PAUSED, TRUE, FALSE)) { 1843 g_warning ("Error running decodebin"); 1844 gst_element_set_state (extractor->pipeline, GST_STATE_NULL); 1845 gst_object_unref (GST_OBJECT (extractor->pipeline)); 1846 gst_object_unref (extractor->bus); 1847 return FALSE; 1848 } 1849 1850 decodebin2_add_stream_tags (extractor); 1851 1852 gst_element_set_state (extractor->pipeline, GST_STATE_READY); 1853 gst_element_get_state (extractor->pipeline, NULL, NULL, 5 * GST_SECOND); 1854 g_list_foreach (extractor->fsinks, decodebin2_unlink_fsink, extractor); 1855 g_list_free (extractor->fsinks); 1856 extractor->fsinks = NULL; 1857 1858 return TRUE; 1859 } 1860 1861 #endif /* GSTREAMER_BACKEND_DECODEBIN2 */ 1862 1863 /* ----------------------- Tagreadbin specific implementation --------------- */ 1864 1865 #if defined(GSTREAMER_BACKEND_TAGREADBIN) 1866 1867 static void 1868 add_int_gst_tag (TrackerSparqlBuilder *metadata, 1869 const gchar *uri, 1870 const gchar *key, 1871 GstTagList *tag_list, 1872 const gchar *tag) 1873 { 1874 gboolean ret; 1875 gint n; 1876 1877 ret = gst_tag_list_get_int (tag_list, tag, &n); 1878 1879 if (ret) { 1880 tracker_sparql_builder_predicate (metadata, key); 1881 tracker_sparql_builder_object_int64 (metadata, n); 1882 } 1883 } 1884 1885 static void 1886 add_fraction_gst_tag (TrackerSparqlBuilder *metadata, 1887 const gchar *uri, 1888 const gchar *key, 1889 GstTagList *tag_list, 1890 const gchar *tag) 1891 { 1892 gboolean ret; 1893 GValue n = {0,}; 1894 gfloat f; 1895 1896 ret = gst_tag_list_copy_value (&n, tag_list, tag); 1897 1898 if (ret) { 1899 f = (gfloat)gst_value_get_fraction_numerator (&n)/ 1900 gst_value_get_fraction_denominator (&n); 1901 1902 tracker_sparql_builder_predicate (metadata, key); 1903 tracker_sparql_builder_object_double (metadata, (gdouble) f); 1904 1905 g_value_unset (&n); 1906 } 1907 } 1908 1909 static void 1910 add_time_gst_tag (TrackerSparqlBuilder *metadata, 1911 const gchar *uri, 1912 const gchar *key, 1913 GstTagList *tag_list, 1914 const gchar *tag) 1915 { 1916 gboolean ret; 1917 guint64 n; 1918 1919 ret = gst_tag_list_get_uint64 (tag_list, tag, &n); 1920 1921 if (ret) { 1922 gint64 duration; 1923 1924 duration = (n + (GST_SECOND / 2)) / GST_SECOND; 1925 1926 tracker_sparql_builder_predicate (metadata, key); 1927 tracker_sparql_builder_object_int64 (metadata, duration); 1928 } 1929 } 1930 1931 static void 1932 tagreadbin_extract_stream_metadata (MetadataExtractor *extractor, 1933 TrackerSparqlBuilder *metadata) 1934 { 1935 if (extractor->mime != EXTRACT_MIME_IMAGE && 1936 extractor->mime != EXTRACT_MIME_SVG) { 1937 add_int_gst_tag (metadata, "nfo:channels", extractor->tagcache, GST_TAG_CHANNEL); 1938 add_int_gst_tag (metadata, "nfo:sampleRate", extractor->tagcache, GST_TAG_RATE); 1939 add_time_gst_tag (metadata, "nfo:duration", extractor->tagcache, GST_TAG_DURATION); 1940 } 1941 1942 if (extractor->mime == EXTRACT_MIME_IMAGE || 1943 extractor->mime == EXTRACT_MIME_SVG || 1944 extractor->mime == EXTRACT_MIME_VIDEO) { 1945 add_fraction_gst_tag (metadata, "nfo:aspectRatio", extractor->tagcache, GST_TAG_PIXEL_RATIO); 1946 } 1947 1948 add_int_gst_tag (metadata, "nfo:height", extractor->tagcache, GST_TAG_HEIGHT); 1949 add_int_gst_tag (metadata, "nfo:width", extractor->tagcache, GST_TAG_WIDTH); 1950 1951 if (extractor->mime == EXTRACT_MIME_VIDEO) { 1952 add_fraction_gst_tag (metadata, "nfo:frameRate", extractor->tagcache, GST_TAG_FRAMERATE); 1953 } 1954 } 1955 1956 static GstElement * 1957 tagreadbin_create_pipeline (MetadataExtractor *extractor, 1958 const gchar *uri) 1959 { 1960 GstElement *pipeline = NULL; 1961 1962 pipeline = gst_element_factory_make ("tagreadbin", "tagreadbin"); 1963 if (!pipeline) { 1964 g_warning ("Failed to create GStreamer tagreadbin"); 1965 return NULL; 1966 } 1967 1968 g_object_set (G_OBJECT (pipeline), "uri", uri, NULL); 1969 return pipeline; 1970 } 1971 1972 static void 1973 tagreadbin_shutdown (MetadataExtractor *extractor) 1974 { 1975 pipeline_shutdown (extractor); 1976 } 1977 1978 static gboolean 1979 tagreadbin_init_and_run (MetadataExtractor *extractor, 1980 const gchar *uri) 1981 { 1982 extractor->bus = NULL; 1983 1984 /* Create pipeline */ 1985 extractor->pipeline = tagreadbin_create_pipeline (extractor, uri); 1986 if (!extractor->pipeline) { 1987 g_warning ("No valid pipeline for uri %s", uri); 1988 return FALSE; 1989 } 1990 1991 /* Get bus */ 1992 extractor->bus = gst_pipeline_get_bus (GST_PIPELINE (extractor->pipeline)); 1993 1994 /* Run */ 1995 if (!pipeline_poll_for_ready (extractor, GST_STATE_PLAYING, FALSE, TRUE)) { 1996 g_warning ("Error running tagreadbin"); 1997 gst_element_set_state (extractor->pipeline, GST_STATE_NULL); 1998 gst_object_unref (GST_OBJECT (extractor->pipeline)); 1999 gst_object_unref (extractor->bus); 2000 return FALSE; 2001 } 2002 2003 return TRUE; 2004 } 2005 2006 #endif /* GSTREAMER_BACKEND_TAGREADBIN */ 2007 2008 static void 2009 tracker_extract_gstreamer (const gchar *uri, 2010 TrackerSparqlBuilder *preupdate, 2011 TrackerSparqlBuilder *postupdate, 2012 TrackerSparqlBuilder *metadata, 2013 ExtractMime type, 2014 const gchar *graph) 2015 { 2016 MetadataExtractor *extractor; 2017 GstBuffer *buffer; 2018 gchar *cue_sheet; 2019 gboolean success; 2020 2021 g_return_if_fail (uri); 2022 g_return_if_fail (metadata); 2023 2024 gst_init (NULL, NULL); 2025 2026 extractor = g_slice_new0 (MetadataExtractor); 2027 extractor->mime = type; 2028 extractor->tagcache = gst_tag_list_new_empty (); 2029 extractor->media_art_type = TRACKER_MEDIA_ART_NONE; 2030 2031 g_debug ("GStreamer backend in use:"); 2032 2033 #if defined(GSTREAMER_BACKEND_TAGREADBIN) 2034 g_debug (" Tagreadbin"); 2035 success = tagreadbin_init_and_run (extractor, uri); 2036 #elif defined(GSTREAMER_BACKEND_DECODEBIN2) 2037 g_debug (" Decodebin2"); 2038 success = decodebin2_init_and_run (extractor, uri); 2039 #else /* DISCOVERER/GUPnP-DLNA */ 2040 g_debug (" Discoverer/GUPnP-DLNA"); 2041 success = discoverer_init_and_run (extractor, uri); 2042 #endif 2043 2044 if (success) { 2045 cue_sheet = get_embedded_cue_sheet_data (extractor->tagcache); 2046 2047 if (cue_sheet) { 2048 g_debug ("Using embedded CUE sheet."); 2049 extractor->toc = tracker_cue_sheet_parse (cue_sheet); 2050 g_free (cue_sheet); 2051 } 2052 2053 if (extractor->toc == NULL) { 2054 extractor->toc = tracker_cue_sheet_parse_uri (uri); 2055 } 2056 2057 extract_metadata (extractor, 2058 uri, 2059 preupdate, 2060 postupdate, 2061 metadata, 2062 graph); 2063 2064 if (extractor->media_art_type != TRACKER_MEDIA_ART_NONE) { 2065 tracker_media_art_process (extractor->media_art_buffer, 2066 extractor->media_art_buffer_size, 2067 extractor->media_art_buffer_mime, 2068 extractor->media_art_type, 2069 extractor->media_art_artist, 2070 extractor->media_art_title, 2071 uri); 2072 } 2073 } 2074 2075 /* Clean up */ 2076 g_free (extractor->media_art_artist); 2077 g_free (extractor->media_art_title); 2078 if (extractor->sample) { 2079 buffer = gst_sample_get_buffer (extractor->sample); 2080 gst_buffer_unmap (buffer, &extractor->info); 2081 gst_sample_unref (extractor->sample); 2082 } 2083 2084 gst_tag_list_free (extractor->tagcache); 2085 2086 tracker_toc_free (extractor->toc); 2087 2088 g_slist_foreach (extractor->artist_list, (GFunc)g_free, NULL); 2089 g_slist_free (extractor->artist_list); 2090 2091 #if defined(GSTREAMER_BACKEND_TAGREADBIN) 2092 tagreadbin_shutdown (extractor); 2093 #elif defined(GSTREAMER_BACKEND_DECODEBIN2) 2094 decodebin2_shutdown (extractor); 2095 #else /* DISCOVERER/GUPnP-DLNA */ 2096 discoverer_shutdown (extractor); 2097 #endif 2098 2099 g_slice_free (MetadataExtractor, extractor); 2100 } 2101 2102 G_MODULE_EXPORT gboolean 2103 tracker_extract_get_metadata (TrackerExtractInfo *info) 2104 { 2105 TrackerSparqlBuilder *metadata, *preupdate, *postupdate; 2106 const gchar *mimetype; 2107 GFile *file; 2108 gchar *uri; 2109 const gchar *graph; 2110 2111 graph = tracker_extract_info_get_graph (info); 2112 metadata = tracker_extract_info_get_metadata_builder (info); 2113 preupdate = tracker_extract_info_get_preupdate_builder (info); 2114 postupdate = tracker_extract_info_get_postupdate_builder (info); 2115 mimetype = tracker_extract_info_get_mimetype (info); 2116 2117 file = tracker_extract_info_get_file (info); 2118 uri = g_file_get_uri (file); 2119 2120 #if defined(GSTREAMER_BACKEND_GUPNP_DLNA) 2121 if (g_str_has_prefix (mimetype, "dlna/")) { 2122 tracker_extract_gstreamer (uri, preupdate, postupdate, metadata, EXTRACT_MIME_GUESS, graph); 2123 } else 2124 #endif /* GSTREAMER_BACKEND_GUPNP_DLNA */ 2125 2126 if (strcmp (mimetype, "image/svg+xml") == 0) { 2127 tracker_extract_gstreamer (uri, preupdate, postupdate, metadata, EXTRACT_MIME_SVG, graph); 2128 } else if (strcmp (mimetype, "video/3gpp") == 0 || 2129 strcmp (mimetype, "video/mp4") == 0 || 2130 strcmp (mimetype, "video/x-ms-asf") == 0 || 2131 strcmp (mimetype, "application/vnd.rn-realmedia") == 0) { 2132 tracker_extract_gstreamer (uri, preupdate, postupdate, metadata, EXTRACT_MIME_GUESS, graph); 2133 } else if (g_str_has_prefix (mimetype, "audio/")) { 2134 tracker_extract_gstreamer (uri, preupdate, postupdate, metadata, EXTRACT_MIME_AUDIO, graph); 2135 } else if (g_str_has_prefix (mimetype, "video/")) { 2136 tracker_extract_gstreamer (uri, preupdate, postupdate, metadata, EXTRACT_MIME_VIDEO, graph); 2137 } else if (g_str_has_prefix (mimetype, "image/")) { 2138 tracker_extract_gstreamer (uri, preupdate, postupdate, metadata, EXTRACT_MIME_IMAGE, graph); 2139 } else { 2140 g_free (uri); 2141 return FALSE; 2142 } 2143 2144 g_free (uri); 2145 return TRUE; 2146 }