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 = "+";
(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 }