libextractor  1.11
About: GNU libextractor is a library used to extract meta-data from files of arbitrary type.
  Fossies Dox: libextractor-1.11.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

gstreamer_extractor.c
Go to the documentation of this file.
1 /*
2  This file is part of libextractor.
3  Copyright (C) 2002, 2003, 2004, 2009, 2012 Vidyut Samanta and Christian Grothoff
4 
5  libextractor is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published
7  by the Free Software Foundation; either version 3, or (at your
8  option) any later version.
9 
10  libextractor is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with libextractor; see the file COPYING. If not, write to the
17  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19  */
20 /**
21  * @file plugins/gstreamer_extractor.c
22  * @brief extracts metadata from files using GStreamer
23  * @author LRN
24  */
25 #include "platform.h"
26 #include "extractor.h"
27 #include <glib.h>
28 #include <glib-object.h>
29 #include <gst/pbutils/pbutils.h>
30 #include <gst/tag/tag.h>
31 #include <gst/app/gstappsrc.h>
32 #include <pthread.h>
33 
34 GST_DEBUG_CATEGORY_STATIC (gstreamer_extractor);
35 #define GST_CAT_DEFAULT gstreamer_extractor
36 
37 /**
38  * Once discoverer has gone for that long without asking for data or
39  * asking to seek, or giving us discovered info, assume it hanged up
40  * and kill it.
41  * In milliseconds.
42  */
43 #define DATA_TIMEOUT 750 /* 750ms */
44 
45 pthread_mutex_t pipe_mutex;
46 
47 /**
48  * Struct mapping GSTREAMER tags to LE tags.
49  */
50 struct KnownTag
51 {
52  /**
53  * GStreamer tag.
54  */
55  const char *gst_tag_id;
56 
57  /**
58  * Corresponding LE tag.
59  */
61 };
62 
63 
64 /**
65  * Struct mapping known tags (that do occur in GST API) to LE tags.
66  */
67 static struct KnownTag __known_tags[] = {
68  /**
69  * GST_TAG_TITLE:
70  *
71  * commonly used title (string)
72  *
73  * The title as it should be displayed, e.g. 'The Doll House'
74  */
75  {GST_TAG_TITLE, EXTRACTOR_METATYPE_TITLE},
76 
77  /**
78  * GST_TAG_TITLE_SORTNAME:
79  *
80  * commonly used title, as used for sorting (string)
81  *
82  * The title as it should be sorted, e.g. 'Doll House, The'
83  */
84  {GST_TAG_TITLE_SORTNAME, EXTRACTOR_METATYPE_TITLE},
85 
86  /**
87  * GST_TAG_ARTIST:
88  *
89  * person(s) responsible for the recording (string)
90  *
91  * The artist name as it should be displayed, e.g. 'Jimi Hendrix' or
92  * 'The Guitar Heroes'
93  */
94  {GST_TAG_ARTIST, EXTRACTOR_METATYPE_ARTIST},
95 
96  /**
97  * GST_TAG_ARTIST_SORTNAME:
98  *
99  * person(s) responsible for the recording, as used for sorting (string)
100  *
101  * The artist name as it should be sorted, e.g. 'Hendrix, Jimi' or
102  * 'Guitar Heroes, The'
103  */
104  {GST_TAG_ARTIST_SORTNAME, EXTRACTOR_METATYPE_ARTIST},
105 
106  /**
107  * GST_TAG_ALBUM:
108  *
109  * album containing this data (string)
110  *
111  * The album name as it should be displayed, e.g. 'The Jazz Guitar'
112  */
113  {GST_TAG_ALBUM, EXTRACTOR_METATYPE_ALBUM},
114 
115  /**
116  * GST_TAG_ALBUM_SORTNAME:
117  *
118  * album containing this data, as used for sorting (string)
119  *
120  * The album name as it should be sorted, e.g. 'Jazz Guitar, The'
121  */
122  {GST_TAG_ALBUM_SORTNAME, EXTRACTOR_METATYPE_ALBUM},
123 
124  /**
125  * GST_TAG_ALBUM_ARTIST:
126  *
127  * The artist of the entire album, as it should be displayed.
128  */
129  {GST_TAG_ALBUM_ARTIST, EXTRACTOR_METATYPE_ARTIST},
130 
131  /**
132  * GST_TAG_ALBUM_ARTIST_SORTNAME:
133  *
134  * The artist of the entire album, as it should be sorted.
135  */
136  {GST_TAG_ALBUM_ARTIST_SORTNAME, EXTRACTOR_METATYPE_ARTIST},
137 
138  /**
139  * GST_TAG_COMPOSER:
140  *
141  * person(s) who composed the recording (string)
142  */
143  {GST_TAG_COMPOSER, EXTRACTOR_METATYPE_COMPOSER},
144 
145  /**
146  * GST_TAG_DATE:
147  *
148  * date the data was created (#GDate structure)
149  */
150  {GST_TAG_DATE, EXTRACTOR_METATYPE_CREATION_TIME},
151 
152  /**
153  * GST_TAG_DATE_TIME:
154  *
155  * date and time the data was created (#GstDateTime structure)
156  */
157  {GST_TAG_DATE_TIME, EXTRACTOR_METATYPE_CREATION_TIME},
158 
159  /**
160  * GST_TAG_GENRE:
161  *
162  * genre this data belongs to (string)
163  */
164  {GST_TAG_GENRE, EXTRACTOR_METATYPE_GENRE},
165 
166  /**
167  * GST_TAG_COMMENT:
168  *
169  * free text commenting the data (string)
170  */
171  {GST_TAG_COMMENT, EXTRACTOR_METATYPE_COMMENT},
172 
173  /**
174  * GST_TAG_EXTENDED_COMMENT:
175  *
176  * key/value text commenting the data (string)
177  *
178  * Must be in the form of 'key=comment' or
179  * 'key[lc]=comment' where 'lc' is an ISO-639
180  * language code.
181  *
182  * This tag is used for unknown Vorbis comment tags,
183  * unknown APE tags and certain ID3v2 comment fields.
184  */
185  {GST_TAG_EXTENDED_COMMENT, EXTRACTOR_METATYPE_COMMENT},
186 
187  /**
188  * GST_TAG_TRACK_NUMBER:
189  *
190  * track number inside a collection (unsigned integer)
191  */
192  {GST_TAG_TRACK_NUMBER, EXTRACTOR_METATYPE_TRACK_NUMBER},
193 
194  /**
195  * GST_TAG_TRACK_COUNT:
196  *
197  * count of tracks inside collection this track belongs to (unsigned integer)
198  */
199  {GST_TAG_TRACK_COUNT, EXTRACTOR_METATYPE_SONG_COUNT},
200 
201  /**
202  * GST_TAG_ALBUM_VOLUME_NUMBER:
203  *
204  * disc number inside a collection (unsigned integer)
205  */
206  {GST_TAG_ALBUM_VOLUME_NUMBER, EXTRACTOR_METATYPE_DISC_NUMBER},
207 
208  /**
209  * GST_TAG_ALBUM_VOLUME_COUNT:
210  *
211  * count of discs inside collection this disc belongs to (unsigned integer)
212  */
213  {GST_TAG_ALBUM_VOLUME_NUMBER, EXTRACTOR_METATYPE_DISC_COUNT},
214 
215  /**
216  * GST_TAG_LOCATION:
217  *
218  * Origin of media as a URI (location, where the original of the file or stream
219  * is hosted) (string)
220  */
221  {GST_TAG_LOCATION, EXTRACTOR_METATYPE_URL},
222 
223  /**
224  * GST_TAG_HOMEPAGE:
225  *
226  * Homepage for this media (i.e. artist or movie homepage) (string)
227  */
228  {GST_TAG_HOMEPAGE, EXTRACTOR_METATYPE_URL},
229 
230  /**
231  * GST_TAG_DESCRIPTION:
232  *
233  * short text describing the content of the data (string)
234  */
235  {GST_TAG_DESCRIPTION, EXTRACTOR_METATYPE_DESCRIPTION},
236 
237  /**
238  * GST_TAG_VERSION:
239  *
240  * version of this data (string)
241  */
242  {GST_TAG_VERSION, EXTRACTOR_METATYPE_PRODUCT_VERSION},
243 
244  /**
245  * GST_TAG_ISRC:
246  *
247  * International Standard Recording Code - see http://www.ifpi.org/isrc/ (string)
248  */
249  {GST_TAG_ISRC, EXTRACTOR_METATYPE_ISRC},
250 
251  /**
252  * GST_TAG_ORGANIZATION:
253  *
254  * organization (string)
255  */
256  {GST_TAG_ORGANIZATION, EXTRACTOR_METATYPE_COMPANY},
257 
258  /**
259  * GST_TAG_COPYRIGHT:
260  *
261  * copyright notice of the data (string)
262  */
263  {GST_TAG_COPYRIGHT, EXTRACTOR_METATYPE_COPYRIGHT},
264 
265  /**
266  * GST_TAG_COPYRIGHT_URI:
267  *
268  * URI to location where copyright details can be found (string)
269  */
270  {GST_TAG_COPYRIGHT_URI, EXTRACTOR_METATYPE_COPYRIGHT},
271 
272  /**
273  * GST_TAG_ENCODED_BY:
274  *
275  * name of the person or organisation that encoded the file. May contain a
276  * copyright message if the person or organisation also holds the copyright
277  * (string)
278  *
279  * Note: do not use this field to describe the encoding application. Use
280  * #GST_TAG_APPLICATION_NAME or #GST_TAG_COMMENT for that.
281  */
282  {GST_TAG_ENCODED_BY, EXTRACTOR_METATYPE_ENCODED_BY},
283 
284  /**
285  * GST_TAG_CONTACT:
286  *
287  * contact information (string)
288  */
289  {GST_TAG_CONTACT, EXTRACTOR_METATYPE_CONTACT_INFORMATION},
290 
291  /**
292  * GST_TAG_LICENSE:
293  *
294  * license of data (string)
295  */
296  {GST_TAG_LICENSE, EXTRACTOR_METATYPE_LICENSE},
297 
298  /**
299  * GST_TAG_LICENSE_URI:
300  *
301  * URI to location where license details can be found (string)
302  */
303  {GST_TAG_LICENSE_URI, EXTRACTOR_METATYPE_LICENSE},
304 
305  /**
306  * GST_TAG_PERFORMER:
307  *
308  * person(s) performing (string)
309  */
310  {GST_TAG_PERFORMER, EXTRACTOR_METATYPE_PERFORMER},
311 
312  /**
313  * GST_TAG_DURATION:
314  *
315  * length in GStreamer time units (nanoseconds) (unsigned 64-bit integer)
316  */
317  {GST_TAG_DURATION, EXTRACTOR_METATYPE_DURATION},
318 
319  /**
320  * GST_TAG_CODEC:
321  *
322  * codec the data is stored in (string)
323  */
324  {GST_TAG_CODEC, EXTRACTOR_METATYPE_CODEC},
325 
326  /**
327  * GST_TAG_VIDEO_CODEC:
328  *
329  * codec the video data is stored in (string)
330  */
331  {GST_TAG_VIDEO_CODEC, EXTRACTOR_METATYPE_VIDEO_CODEC},
332 
333  /**
334  * GST_TAG_AUDIO_CODEC:
335  *
336  * codec the audio data is stored in (string)
337  */
338  {GST_TAG_AUDIO_CODEC, EXTRACTOR_METATYPE_AUDIO_CODEC},
339 
340  /**
341  * GST_TAG_SUBTITLE_CODEC:
342  *
343  * codec/format the subtitle data is stored in (string)
344  */
345  {GST_TAG_SUBTITLE_CODEC, EXTRACTOR_METATYPE_SUBTITLE_CODEC},
346 
347  /**
348  * GST_TAG_CONTAINER_FORMAT:
349  *
350  * container format the data is stored in (string)
351  */
352  {GST_TAG_CONTAINER_FORMAT, EXTRACTOR_METATYPE_CONTAINER_FORMAT},
353 
354  /**
355  * GST_TAG_BITRATE:
356  *
357  * exact or average bitrate in bits/s (unsigned integer)
358  */
359  {GST_TAG_BITRATE, EXTRACTOR_METATYPE_BITRATE},
360 
361  /**
362  * GST_TAG_NOMINAL_BITRATE:
363  *
364  * nominal bitrate in bits/s (unsigned integer). The actual bitrate might be
365  * different from this target bitrate.
366  */
367  {GST_TAG_NOMINAL_BITRATE, EXTRACTOR_METATYPE_NOMINAL_BITRATE},
368 
369  /**
370  * GST_TAG_MINIMUM_BITRATE:
371  *
372  * minimum bitrate in bits/s (unsigned integer)
373  */
374  {GST_TAG_MINIMUM_BITRATE, EXTRACTOR_METATYPE_MINIMUM_BITRATE},
375 
376  /**
377  * GST_TAG_MAXIMUM_BITRATE:
378  *
379  * maximum bitrate in bits/s (unsigned integer)
380  */
381  {GST_TAG_MAXIMUM_BITRATE, EXTRACTOR_METATYPE_MAXIMUM_BITRATE},
382 
383  /**
384  * GST_TAG_SERIAL:
385  *
386  * serial number of track (unsigned integer)
387  */
388  {GST_TAG_SERIAL, EXTRACTOR_METATYPE_SERIAL},
389 
390  /**
391  * GST_TAG_ENCODER:
392  *
393  * encoder used to encode this stream (string)
394  */
395  {GST_TAG_ENCODER, EXTRACTOR_METATYPE_ENCODER}, /* New */
396 
397  /**
398  * GST_TAG_ENCODER_VERSION:
399  *
400  * version of the encoder used to encode this stream (unsigned integer)
401  */
402  {GST_TAG_ENCODER_VERSION, EXTRACTOR_METATYPE_ENCODER_VERSION},
403 
404  /**
405  * GST_TAG_TRACK_GAIN:
406  *
407  * track gain in db (double)
408  */
409  {GST_TAG_TRACK_GAIN, EXTRACTOR_METATYPE_TRACK_GAIN},
410 
411  /**
412  * GST_TAG_TRACK_PEAK:
413  *
414  * peak of the track (double)
415  */
416  {GST_TAG_TRACK_PEAK, EXTRACTOR_METATYPE_TRACK_PEAK},
417 
418  /**
419  * GST_TAG_ALBUM_GAIN:
420  *
421  * album gain in db (double)
422  */
423  {GST_TAG_ALBUM_GAIN, EXTRACTOR_METATYPE_ALBUM_GAIN},
424 
425  /**
426  * GST_TAG_ALBUM_PEAK:
427  *
428  * peak of the album (double)
429  */
430  {GST_TAG_ALBUM_PEAK, EXTRACTOR_METATYPE_ALBUM_PEAK},
431 
432  /**
433  * GST_TAG_REFERENCE_LEVEL:
434  *
435  * reference level of track and album gain values (double)
436  */
437  {GST_TAG_REFERENCE_LEVEL, EXTRACTOR_METATYPE_REFERENCE_LEVEL},
438 
439  /**
440  * GST_TAG_LANGUAGE_CODE:
441  *
442  * ISO-639-2 or ISO-639-1 code for the language the content is in (string)
443  *
444  * There is utility API in libgsttag in gst-plugins-base to obtain a translated
445  * language name from the language code: gst_tag_get_language_name()
446  */
447  {GST_TAG_LANGUAGE_CODE, EXTRACTOR_METATYPE_LANGUAGE},
448 
449  /**
450  * GST_TAG_LANGUAGE_NAME:
451  *
452  * Name of the language the content is in (string)
453  *
454  * Free-form name of the language the content is in, if a language code
455  * is not available. This tag should not be set in addition to a language
456  * code. It is undefined what language or locale the language name is in.
457  */
458  {GST_TAG_LANGUAGE_NAME, EXTRACTOR_METATYPE_LANGUAGE},
459 
460  /**
461  * GST_TAG_IMAGE:
462  *
463  * image (sample) (sample taglist should specify the content type and preferably
464  * also set "image-type" field as #GstTagImageType)
465  */
466  {GST_TAG_IMAGE, EXTRACTOR_METATYPE_PICTURE},
467 
468  /**
469  * GST_TAG_PREVIEW_IMAGE:
470  *
471  * image that is meant for preview purposes, e.g. small icon-sized version
472  * (sample) (sample taglist should specify the content type)
473  */
474  {GST_TAG_IMAGE, EXTRACTOR_METATYPE_THUMBNAIL},
475 
476  /**
477  * GST_TAG_ATTACHMENT:
478  *
479  * generic file attachment (sample) (sample taglist should specify the content
480  * type and if possible set "filename" to the file name of the
481  * attachment)
482  */
483  /* No equivalent, and none needed? */
484 
485  /**
486  * GST_TAG_BEATS_PER_MINUTE:
487  *
488  * number of beats per minute in audio (double)
489  */
490  {GST_TAG_BEATS_PER_MINUTE, EXTRACTOR_METATYPE_BEATS_PER_MINUTE},
491 
492  /**
493  * GST_TAG_KEYWORDS:
494  *
495  * comma separated keywords describing the content (string).
496  */
497  {GST_TAG_KEYWORDS, EXTRACTOR_METATYPE_KEYWORDS},
498 
499  /**
500  * GST_TAG_GEO_LOCATION_NAME:
501  *
502  * human readable descriptive location of where the media has been recorded or
503  * produced. (string).
504  */
505  {GST_TAG_GEO_LOCATION_NAME, EXTRACTOR_METATYPE_LOCATION_NAME},
506 
507  /**
508  * GST_TAG_GEO_LOCATION_LATITUDE:
509  *
510  * geo latitude location of where the media has been recorded or produced in
511  * degrees according to WGS84 (zero at the equator, negative values for southern
512  * latitudes) (double).
513  */
514  {GST_TAG_GEO_LOCATION_LATITUDE, EXTRACTOR_METATYPE_GPS_LATITUDE},
515 
516  /**
517  * GST_TAG_GEO_LOCATION_LONGITUDE:
518  *
519  * geo longitude location of where the media has been recorded or produced in
520  * degrees according to WGS84 (zero at the prime meridian in Greenwich/UK,
521  * negative values for western longitudes). (double).
522  */
523  {GST_TAG_GEO_LOCATION_LONGITUDE, EXTRACTOR_METATYPE_GPS_LONGITUDE},
524 
525  /**
526  * GST_TAG_GEO_LOCATION_ELEVATION:
527  *
528  * geo elevation of where the media has been recorded or produced in meters
529  * according to WGS84 (zero is average sea level) (double).
530  */
531  {GST_TAG_GEO_LOCATION_ELEVATION, EXTRACTOR_METATYPE_LOCATION_ELEVATION},
532 
533  /**
534  * GST_TAG_GEO_LOCATION_COUNTRY:
535  *
536  * The country (english name) where the media has been produced (string).
537  */
538  {GST_TAG_GEO_LOCATION_COUNTRY, EXTRACTOR_METATYPE_LOCATION_COUNTRY},
539 
540  /**
541  * GST_TAG_GEO_LOCATION_CITY:
542  *
543  * The city (english name) where the media has been produced (string).
544  */
545  {GST_TAG_GEO_LOCATION_CITY, EXTRACTOR_METATYPE_LOCATION_CITY},
546 
547  /**
548  * GST_TAG_GEO_LOCATION_SUBLOCATION:
549  *
550  * A location 'smaller' than GST_TAG_GEO_LOCATION_CITY that specifies better
551  * where the media has been produced. (e.g. the neighborhood) (string).
552  *
553  * This tag has been added as this is how it is handled/named in XMP's
554  * Iptc4xmpcore schema.
555  */
556  {GST_TAG_GEO_LOCATION_SUBLOCATION, EXTRACTOR_METATYPE_LOCATION_SUBLOCATION},
557 
558  /**
559  * GST_TAG_GEO_LOCATION_HORIZONTAL_ERROR:
560  *
561  * Represents the expected error on the horizontal positioning in
562  * meters (double).
563  */
564  {GST_TAG_GEO_LOCATION_HORIZONTAL_ERROR,
566 
567  /**
568  * GST_TAG_GEO_LOCATION_MOVEMENT_SPEED:
569  *
570  * Speed of the capturing device when performing the capture.
571  * Represented in m/s. (double)
572  *
573  * See also #GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION
574  */
575  {GST_TAG_GEO_LOCATION_MOVEMENT_SPEED,
577 
578  /**
579  * GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION:
580  *
581  * Indicates the movement direction of the device performing the capture
582  * of a media. It is represented as degrees in floating point representation,
583  * 0 means the geographic north, and increases clockwise (double from 0 to 360)
584  *
585  * See also #GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION
586  */
587  {GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION,
589 
590  /**
591  * GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION:
592  *
593  * Indicates the direction the device is pointing to when capturing
594  * a media. It is represented as degrees in floating point representation,
595  * 0 means the geographic north, and increases clockwise (double from 0 to 360)
596  *
597  * See also #GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION
598  */
599  {GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION,
601 
602  /**
603  * GST_TAG_SHOW_NAME:
604  *
605  * Name of the show, used for displaying (string)
606  */
607  {GST_TAG_SHOW_NAME, EXTRACTOR_METATYPE_SHOW_NAME},
608 
609  /**
610  * GST_TAG_SHOW_SORTNAME:
611  *
612  * Name of the show, used for sorting (string)
613  */
614  {GST_TAG_SHOW_SORTNAME, EXTRACTOR_METATYPE_SHOW_NAME},
615 
616  /**
617  * GST_TAG_SHOW_EPISODE_NUMBER:
618  *
619  * Number of the episode within a season/show (unsigned integer)
620  */
621  {GST_TAG_SHOW_EPISODE_NUMBER, EXTRACTOR_METATYPE_SHOW_EPISODE_NUMBER},
622 
623  /**
624  * GST_TAG_SHOW_SEASON_NUMBER:
625  *
626  * Number of the season of a show/series (unsigned integer)
627  */
628  {GST_TAG_SHOW_SEASON_NUMBER, EXTRACTOR_METATYPE_SHOW_SEASON_NUMBER},
629 
630  /**
631  * GST_TAG_LYRICS:
632  *
633  * The lyrics of the media (string)
634  */
635  {GST_TAG_LYRICS, EXTRACTOR_METATYPE_LYRICS},
636 
637  /**
638  * GST_TAG_COMPOSER_SORTNAME:
639  *
640  * The composer's name, used for sorting (string)
641  */
642  {GST_TAG_COMPOSER_SORTNAME, EXTRACTOR_METATYPE_COMPOSER},
643 
644  /**
645  * GST_TAG_GROUPING:
646  *
647  * Groups together media that are related and spans multiple tracks. An
648  * example are multiple pieces of a concerto. (string)
649  */
650  {GST_TAG_GROUPING, EXTRACTOR_METATYPE_GROUPING},
651 
652  /**
653  * GST_TAG_USER_RATING:
654  *
655  * Rating attributed by a person (likely the application user).
656  * The higher the value, the more the user likes this media
657  * (unsigned int from 0 to 100)
658  */
659  {GST_TAG_USER_RATING, EXTRACTOR_METATYPE_POPULARITY_METER},
660 
661  /**
662  * GST_TAG_DEVICE_MANUFACTURER:
663  *
664  * Manufacturer of the device used to create the media (string)
665  */
666  {GST_TAG_DEVICE_MANUFACTURER, EXTRACTOR_METATYPE_DEVICE_MANUFACTURER},
667 
668  /**
669  * GST_TAG_DEVICE_MODEL:
670  *
671  * Model of the device used to create the media (string)
672  */
673  {GST_TAG_DEVICE_MODEL, EXTRACTOR_METATYPE_DEVICE_MODEL},
674 
675  /**
676  * GST_TAG_APPLICATION_NAME:
677  *
678  * Name of the application used to create the media (string)
679  */
680  {GST_TAG_APPLICATION_NAME, EXTRACTOR_METATYPE_CREATED_BY_SOFTWARE},
681 
682  /**
683  * GST_TAG_APPLICATION_DATA:
684  *
685  * Arbitrary application data (sample)
686  *
687  * Some formats allow applications to add their own arbitrary data
688  * into files. This data is application dependent.
689  */
690  /* No equivalent, and none needed (not really metadata)? */
691 
692  /**
693  * GST_TAG_IMAGE_ORIENTATION:
694  *
695  * Represents the 'Orientation' tag from EXIF. Defines how the image
696  * should be rotated and mirrored for display. (string)
697  *
698  * This tag has a predefined set of allowed values:
699  * "rotate-0"
700  * "rotate-90"
701  * "rotate-180"
702  * "rotate-270"
703  * "flip-rotate-0"
704  * "flip-rotate-90"
705  * "flip-rotate-180"
706  * "flip-rotate-270"
707  *
708  * The naming is adopted according to a possible transformation to perform
709  * on the image to fix its orientation, obviously equivalent operations will
710  * yield the same result.
711  *
712  * Rotations indicated by the values are in clockwise direction and
713  * 'flip' means an horizontal mirroring.
714  */
715  {GST_TAG_IMAGE_ORIENTATION, EXTRACTOR_METATYPE_ORIENTATION}
716 
717 };
718 
719 
720 /**
721  * Struct mapping named tags (that don't occur in GST API) to LE tags.
722  */
723 struct NamedTag
724 {
725  /**
726  * tag.
727  */
728  const char *tag;
729 
730  /**
731  * Corresponding LE tag.
732  */
734 };
735 
736 
737 /**
738  * Mapping from GST tag names to LE types for tags that are not in
739  * the public GST API.
740  */
741 struct NamedTag named_tags[] = {
743  { "PLAY_COUNTER", EXTRACTOR_METATYPE_PLAY_COUNTER },
744  { "RATING", EXTRACTOR_METATYPE_RATING },
745  { "SUMMARY", EXTRACTOR_METATYPE_SUMMARY },
746  { "SUBJECT", EXTRACTOR_METATYPE_SUBJECT },
747  { "MOOD", EXTRACTOR_METATYPE_MOOD },
748  { "LEAD_PERFORMER", EXTRACTOR_METATYPE_PERFORMER },
749  { "DIRECTOR", EXTRACTOR_METATYPE_MOVIE_DIRECTOR },
750  { "WRITTEN_BY", EXTRACTOR_METATYPE_WRITER },
751  { "PRODUCER", EXTRACTOR_METATYPE_PRODUCER },
752  { "PUBLISHER", EXTRACTOR_METATYPE_PUBLISHER },
753  { "ORIGINAL/ARTIST", EXTRACTOR_METATYPE_ORIGINAL_ARTIST },
754  { "ORIGINAL/TITLE", EXTRACTOR_METATYPE_ORIGINAL_TITLE },
756 };
757 
758 
759 /**
760  *
761  */
763 {
764  /**
765  *
766  */
768 
769  /**
770  *
771  */
773 
774  /**
775  *
776  */
778 
779  /**
780  *
781  */
783 
784  /**
785  *
786  */
788 
789  /**
790  *
791  */
793 };
794 
795 
796 /**
797  * Closure we pass when processing a request.
798  */
800 {
801  /**
802  * Current read-offset in the 'ec' context (based on our read/seek calls).
803  */
804  guint64 offset;
805 
806  /**
807  * Overall size of the file we're processing, UINT64_MAX if unknown.
808  */
809  uint64_t length;
810 
811  /**
812  *
813  */
814  GstElement *source;
815 
816  /**
817  * Extraction context for IO on the underlying data.
818  */
820 
821  /**
822  * Glib main loop.
823  */
824  GMainLoop *loop;
825 
826  /**
827  * Discoverer object we are using.
828  */
829  GstDiscoverer *dc;
830 
831  /**
832  * Location for building the XML 'table of contents' (EXTRACTOR_METATYPE_TOC) for
833  * the input. Used only during 'send_info'.
834  */
835  gchar *toc;
836 
837  /**
838  * Length of the 'toc' string.
839  */
840  size_t toc_length;
841 
842  /**
843  * Current position (used when creating the 'toc' string).
844  */
845  size_t toc_pos;
846 
847  /**
848  * Identifier of the timeout event source
849  */
850  guint timeout_id;
851 
852  /**
853  * Counter used to determine our current depth in the TOC hierarchy.
854  */
856 
857  /**
858  *
859  */
860  enum CurrentStreamType st;
861 
862  /**
863  * Last return value from the meta data processor. Set to
864  * 1 to abort, 0 to continue extracting.
865  */
867 
868  /**
869  * TOC generation is executed in two phases. First phase determines
870  * the size of the string and the second phase actually does the
871  * 'printing' (string construction). This bit is TRUE if we are
872  * in the 'printing' phase.
873  */
874  gboolean toc_print_phase;
875 
876 };
877 
878 
879 /**
880  *
881  */
882 static GQuark *audio_quarks;
883 
884 /**
885  *
886  */
887 static GQuark *video_quarks;
888 
889 /**
890  *
891  */
892 static GQuark *subtitle_quarks;
893 
894 /**
895  *
896  */
897 static GQuark duration_quark;
898 
899 
900 static gboolean
902 {
903  GST_ERROR ("GstDiscoverer I/O timed out");
904  ps->timeout_id = 0;
905  g_main_loop_quit (ps->loop);
906  return FALSE;
907 }
908 
909 
910 /**
911  * Implementation of GstElement's "need-data" callback. Reads data from
912  * the extraction context and passes it to GStreamer.
913  *
914  * @param appsrc the GstElement for which we are implementing "need-data"
915  * @param size number of bytes requested
916  * @param ps our execution context
917  */
918 static void
919 feed_data (GstElement *appsrc,
920  guint size,
921  struct PrivStruct *ps)
922 {
923  ssize_t data_len;
924  uint8_t *le_data;
925  guint accumulated;
926  GstMemory *mem;
927  GstMapInfo mi;
928  GstBuffer *buffer;
929 
930  GST_DEBUG ("Request %u bytes", size);
931 
932  if (ps->timeout_id > 0)
933  g_source_remove (ps->timeout_id);
934  ps->timeout_id = g_timeout_add (DATA_TIMEOUT, (GSourceFunc) _data_timeout,
935  ps);
936 
937  if ( (ps->length > 0) && (ps->offset >= ps->length) )
938  {
939  /* we are at the EOS, send end-of-stream */
940  gst_app_src_end_of_stream (GST_APP_SRC (ps->source));
941  return;
942  }
943 
944  if ((ps->length > 0) && (ps->offset + size > ps->length))
945  size = ps->length - ps->offset;
946 
947  mem = gst_allocator_alloc (NULL, size, NULL);
948  if (! gst_memory_map (mem, &mi, GST_MAP_WRITE))
949  {
950  gst_memory_unref (mem);
951  GST_DEBUG ("Failed to map the memory");
952  gst_app_src_end_of_stream (GST_APP_SRC (ps->source));
953  return;
954  }
955 
956  accumulated = 0;
957  data_len = 1;
958  pthread_mutex_lock (&pipe_mutex);
959  while ( (accumulated < size) && (data_len > 0) )
960  {
961  data_len = ps->ec->read (ps->ec->cls, (void **) &le_data, size
962  - accumulated);
963  if (data_len > 0)
964  {
965  memcpy (&mi.data[accumulated], le_data, data_len);
966  accumulated += data_len;
967  }
968  }
969  pthread_mutex_unlock (&pipe_mutex);
970  gst_memory_unmap (mem, &mi);
971  if (size == accumulated)
972  {
973  buffer = gst_buffer_new ();
974  gst_buffer_append_memory (buffer, mem);
975 
976  /* we need to set an offset for random access */
977  GST_BUFFER_OFFSET (buffer) = ps->offset;
978  GST_BUFFER_OFFSET_END (buffer) = ps->offset + size;
979 
980  GST_DEBUG ("feed buffer %p, offset %" G_GUINT64_FORMAT "-%u",
981  buffer, ps->offset, size);
982  gst_app_src_push_buffer (GST_APP_SRC (ps->source), buffer);
983  ps->offset += size;
984  }
985  else
986  {
987  gst_memory_unref (mem);
988  gst_app_src_end_of_stream (GST_APP_SRC (ps->source));
989  ps->offset = UINT64_MAX; /* set to invalid value */
990  }
991 
992  if (ps->timeout_id > 0)
993  g_source_remove (ps->timeout_id);
994  ps->timeout_id = g_timeout_add (DATA_TIMEOUT, (GSourceFunc) _data_timeout,
995  ps);
996 }
997 
998 
999 /**
1000  * Implementation of GstElement's "seek-data" callback. Seeks to a new
1001  * position in the extraction context.
1002  *
1003  * @param appsrc the GstElement for which we are implementing "need-data"
1004  * @param position new desired absolute position in the file
1005  * @param ps our execution context
1006  * @return TRUE if seeking succeeded, FALSE if not
1007  */
1008 static gboolean
1009 seek_data (GstElement *appsrc,
1010  guint64 position,
1011  struct PrivStruct *ps)
1012 {
1013  GST_DEBUG ("seek to offset %" G_GUINT64_FORMAT, position);
1014  pthread_mutex_lock (&pipe_mutex);
1015  ps->offset = ps->ec->seek (ps->ec->cls, position, SEEK_SET);
1016  pthread_mutex_unlock (&pipe_mutex);
1017  if (ps->timeout_id > 0)
1018  g_source_remove (ps->timeout_id);
1019  ps->timeout_id = g_timeout_add (DATA_TIMEOUT, (GSourceFunc) _data_timeout,
1020  ps);
1021  return ps->offset == position;
1022 }
1023 
1024 
1025 /**
1026  * FIXME
1027  *
1028  * @param field_id FIXME
1029  * @param value FIXME
1030  * @param user_data our 'struct PrivStruct'
1031  * @return TRUE to continue processing, FALSE to abort
1032  */
1033 static gboolean
1034 send_structure_foreach (GQuark field_id,
1035  const GValue *value,
1036  gpointer user_data)
1037 {
1038  struct PrivStruct *ps = user_data;
1039  gchar *str;
1040  const gchar *field_name = g_quark_to_string (field_id);
1041  GType gst_fraction = GST_TYPE_FRACTION;
1042  GQuark *quark;
1043 
1044  switch (ps->st)
1045  {
1046  case STREAM_TYPE_AUDIO:
1047  if (NULL == audio_quarks)
1048  return FALSE;
1049  for (quark = audio_quarks; *quark != 0; quark++)
1050  if (*quark == field_id)
1051  return TRUE;
1052  break;
1053  case STREAM_TYPE_VIDEO:
1054  case STREAM_TYPE_IMAGE:
1055  if (NULL == video_quarks)
1056  return FALSE;
1057  for (quark = video_quarks; *quark != 0; quark++)
1058  if (*quark == field_id)
1059  return TRUE;
1060  break;
1061  case STREAM_TYPE_SUBTITLE:
1062  if (NULL == subtitle_quarks)
1063  return FALSE;
1064  for (quark = subtitle_quarks; *quark != 0; quark++)
1065  if (*quark == field_id)
1066  return TRUE;
1067  break;
1068  case STREAM_TYPE_CONTAINER:
1069  case STREAM_TYPE_NONE:
1070  break;
1071  }
1072 
1073  switch (G_VALUE_TYPE (value))
1074  {
1075  case G_TYPE_STRING:
1076  str = g_value_dup_string (value);
1077  break;
1078  case G_TYPE_UINT:
1079  case G_TYPE_INT:
1080  case G_TYPE_DOUBLE:
1081  case G_TYPE_BOOLEAN:
1082  str = gst_value_serialize (value);
1083  break;
1084  default:
1085  if (G_VALUE_TYPE (value) == gst_fraction)
1086  {
1087  str = gst_value_serialize (value);
1088  break;
1089  }
1090  /* This is a potential source of invalid characters */
1091  /* And it also might attempt to serialize binary data - such as images. */
1092  str = gst_value_serialize (value);
1093  if (NULL != str)
1094  {
1095  g_free (str);
1096  str = NULL;
1097  }
1098  break;
1099  }
1100  if (NULL != str)
1101  {
1102  unsigned int i;
1103 
1104  for (i = 0; NULL != named_tags[i].tag; i++)
1105  if (0 == strcmp (named_tags[i].tag, field_name))
1106  {
1107  ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
1108  named_tags[i].le_type,
1110  "text/plain",
1111  (const char *) str, strlen (str) + 1);
1112  if (NULL != str)
1113  {
1114  g_free (str);
1115  str = NULL;
1116  }
1117  break;
1118  }
1119  }
1120  if (NULL != str)
1121  {
1122  gchar *senddata = g_strdup_printf ("%s=%s",
1123  field_name,
1124  str);
1125  if (NULL != senddata)
1126  {
1127  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1128  "gstreamer",
1131  "text/plain",
1132  (const char *) senddata,
1133  strlen (senddata) + 1);
1134  g_free (senddata);
1135  }
1136  }
1137  if (NULL != str)
1138  g_free (str);
1139 
1140  return ! ps->time_to_leave;
1141 }
1142 
1143 
1144 /**
1145  * FIXME
1146  *
1147  * @param info FIXME
1148  * @param ps processing context
1149  * @return FALSE to continue processing, TRUE to abort
1150  */
1151 static gboolean
1152 send_audio_info (GstDiscovererAudioInfo *info,
1153  struct PrivStruct *ps)
1154 {
1155  gchar *tmp;
1156  const gchar *ctmp;
1157  guint u;
1158 
1159  ctmp = gst_discoverer_audio_info_get_language (info);
1160  if (ctmp)
1161  if ((ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
1164  "text/plain",
1165  (const char *) ctmp, strlen (ctmp)
1166  + 1)))
1167  return TRUE;
1168 
1169  u = gst_discoverer_audio_info_get_channels (info);
1170  if (u > 0)
1171  {
1172  tmp = g_strdup_printf ("%u", u);
1173  if (NULL != tmp)
1174  {
1175  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1176  "gstreamer",
1179  "text/plain",
1180  (const char *) tmp,
1181  strlen (tmp) + 1);
1182  g_free (tmp);
1183  }
1184  if (ps->time_to_leave)
1185  return TRUE;
1186  }
1187 
1188  u = gst_discoverer_audio_info_get_sample_rate (info);
1189  if (u > 0)
1190  {
1191  tmp = g_strdup_printf ("%u", u);
1192  if (NULL != tmp)
1193  {
1194  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1195  "gstreamer",
1198  "text/plain",
1199  (const char *) tmp,
1200  strlen (tmp) + 1);
1201  g_free (tmp);
1202  }
1203  if (ps->time_to_leave)
1204  return TRUE;
1205  }
1206 
1207  u = gst_discoverer_audio_info_get_depth (info);
1208  if (u > 0)
1209  {
1210  tmp = g_strdup_printf ("%u", u);
1211  if (NULL != tmp)
1212  {
1213  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1214  "gstreamer",
1217  "text/plain",
1218  (const char *) tmp,
1219  strlen (tmp) + 1);
1220  g_free (tmp);
1221  }
1222  if (ps->time_to_leave)
1223  return TRUE;
1224  }
1225 
1226  u = gst_discoverer_audio_info_get_bitrate (info);
1227  if (u > 0)
1228  {
1229  tmp = g_strdup_printf ("%u", u);
1230  if (NULL != tmp)
1231  {
1232  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1233  "gstreamer",
1236  "text/plain",
1237  (const char *) tmp,
1238  strlen (tmp) + 1);
1239  g_free (tmp);
1240  }
1241  if (ps->time_to_leave)
1242  return TRUE;
1243  }
1244 
1245  u = gst_discoverer_audio_info_get_max_bitrate (info);
1246  if (u > 0)
1247  {
1248  tmp = g_strdup_printf ("%u", u);
1249  if (NULL != tmp)
1250  {
1251  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1252  "gstreamer",
1255  "text/plain",
1256  (const char *) tmp,
1257  strlen (tmp) + 1);
1258  g_free (tmp);
1259  }
1260  if (ps->time_to_leave)
1261  return TRUE;
1262  }
1263 
1264  return FALSE;
1265 }
1266 
1267 
1268 /**
1269  * FIXME
1270  *
1271  * @param info FIXME
1272  * @param ps processing context
1273  * @return FALSE to continue processing, TRUE to abort
1274  */
1275 static int
1276 send_video_info (GstDiscovererVideoInfo *info,
1277  struct PrivStruct *ps)
1278 {
1279  gchar *tmp;
1280  guint u;
1281  guint u2;
1282 
1283  u = gst_discoverer_video_info_get_width (info);
1284  u2 = gst_discoverer_video_info_get_height (info);
1285  if ( (u > 0) && (u2 > 0) )
1286  {
1287  tmp = g_strdup_printf ("%ux%u", u, u2);
1288  if (NULL != tmp)
1289  {
1290  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1291  "gstreamer",
1294  "text/plain",
1295  (const char *) tmp,
1296  strlen (tmp) + 1);
1297  g_free (tmp);
1298  }
1299  if (ps->time_to_leave)
1300  return TRUE;
1301  }
1302 
1303  u = gst_discoverer_video_info_get_depth (info);
1304  if (u > 0)
1305  {
1306  tmp = g_strdup_printf ("%u", u);
1307  if (NULL != tmp)
1308  {
1309  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1310  "gstreamer",
1313  "text/plain",
1314  (const char *) tmp,
1315  strlen (tmp) + 1);
1316  g_free (tmp);
1317  }
1318  if (ps->time_to_leave)
1319  return TRUE;
1320  }
1321 
1322  u = gst_discoverer_video_info_get_framerate_num (info);
1323  u2 = gst_discoverer_video_info_get_framerate_denom (info);
1324  if ( (u > 0) && (u2 > 0) )
1325  {
1326  tmp = g_strdup_printf ("%u/%u", u, u2);
1327  if (NULL != tmp)
1328  {
1329  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1330  "gstreamer",
1333  "text/plain",
1334  (const char *) tmp,
1335  strlen (tmp) + 1);
1336  g_free (tmp);
1337  }
1338  if (ps->time_to_leave)
1339  return TRUE;
1340  }
1341 
1342  u = gst_discoverer_video_info_get_par_num (info);
1343  u2 = gst_discoverer_video_info_get_par_denom (info);
1344  if ( (u > 0) && (u2 > 0) )
1345  {
1346  tmp = g_strdup_printf ("%u/%u", u, u2);
1347  if (NULL != tmp)
1348  {
1349  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1350  "gstreamer",
1353  "text/plain",
1354  (const char *) tmp,
1355  strlen (tmp) + 1);
1356  g_free (tmp);
1357  }
1358  if (ps->time_to_leave)
1359  return TRUE;
1360  }
1361 
1362  /* gst_discoverer_video_info_is_interlaced (info) I don't trust it... */
1363 
1364  u = gst_discoverer_video_info_get_bitrate (info);
1365  if (u > 0)
1366  {
1367  tmp = g_strdup_printf ("%u", u);
1368  if (NULL != tmp)
1369  {
1370  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1371  "gstreamer",
1374  "text/plain",
1375  (const char *) tmp,
1376  strlen (tmp) + 1);
1377  g_free (tmp);
1378  }
1379  if (ps->time_to_leave)
1380  return TRUE;
1381  }
1382 
1383  u = gst_discoverer_video_info_get_max_bitrate (info);
1384  if (u > 0)
1385  {
1386  tmp = g_strdup_printf ("%u", u);
1387  if (NULL != tmp)
1388  {
1389  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1390  "gstreamer",
1393  "text/plain",
1394  (const char *) tmp,
1395  strlen (tmp) + 1);
1396  g_free (tmp);
1397  }
1398  if (ps->time_to_leave)
1399  return TRUE;
1400  }
1401 
1402  return FALSE;
1403 }
1404 
1405 
1406 /**
1407  * FIXME
1408  *
1409  * @param info FIXME
1410  * @param ps processing context
1411  * @return FALSE to continue processing, TRUE to abort
1412  */
1413 static int
1414 send_subtitle_info (GstDiscovererSubtitleInfo *info,
1415  struct PrivStruct *ps)
1416 {
1417  const gchar *ctmp;
1418 
1419  ctmp = gst_discoverer_subtitle_info_get_language (info);
1420  if ( (NULL != ctmp) &&
1421  (0 != (ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
1424  "text/plain",
1425  (const char *) ctmp, strlen (
1426  ctmp) + 1))) )
1427  return TRUE;
1428  return FALSE;
1429 }
1430 
1431 
1432 static void
1433 send_tag_foreach (const GstTagList *tags,
1434  const gchar *tag,
1435  gpointer user_data)
1436 {
1437  static struct KnownTag unknown_tag = {NULL, EXTRACTOR_METATYPE_UNKNOWN};
1438  struct PrivStruct *ps = user_data;
1439  size_t i;
1440  size_t tagl = sizeof (__known_tags) / sizeof (struct KnownTag);
1441  const struct KnownTag *kt = NULL;
1442  GQuark tag_quark;
1443  guint vallen;
1444  GstSample *sample;
1445 
1446  if (ps->time_to_leave)
1447  return;
1448 
1449  for (i = 0; i < tagl; i++)
1450  {
1451  if (strcmp (__known_tags[i].gst_tag_id, tag) != 0)
1452  continue;
1453  kt = &__known_tags[i];
1454  break;
1455  }
1456  if (kt == NULL)
1457  kt = &unknown_tag;
1458 
1459  vallen = gst_tag_list_get_tag_size (tags, tag);
1460  if (vallen == 0)
1461  return;
1462 
1463  tag_quark = g_quark_from_string (tag);
1464 
1465  for (i = 0; i < vallen; i++)
1466  {
1467  GValue val = { 0, };
1468  const GValue *val_ref;
1469  gchar *str = NULL;
1470 
1471  val_ref = gst_tag_list_get_value_index (tags, tag, i);
1472  if (val_ref == NULL)
1473  {
1474  g_value_unset (&val);
1475  continue;
1476  }
1477  g_value_init (&val, G_VALUE_TYPE (val_ref));
1478  g_value_copy (val_ref, &val);
1479 
1480  switch (G_VALUE_TYPE (&val))
1481  {
1482  case G_TYPE_STRING:
1483  str = g_value_dup_string (&val);
1484  break;
1485  case G_TYPE_UINT:
1486  case G_TYPE_INT:
1487  case G_TYPE_DOUBLE:
1488  case G_TYPE_BOOLEAN:
1489  str = gst_value_serialize (&val);
1490  break;
1491  default:
1492  if ((G_VALUE_TYPE (&val) == GST_TYPE_SAMPLE) && (sample =
1493  gst_value_get_sample (
1494  &val)))
1495  {
1496  GstMapInfo mi;
1497  GstCaps *caps;
1498 
1499  caps = gst_sample_get_caps (sample);
1500  if (caps)
1501  {
1502  GstTagImageType imagetype;
1503  const GstStructure *info;
1504  GstBuffer *buf;
1505  const gchar *mime_type;
1507 
1508  mime_type = gst_structure_get_name (gst_caps_get_structure (caps, 0));
1509  info = gst_sample_get_info (sample);
1510 
1511  if ( (NULL == info) ||
1512  (! gst_structure_get (info, "image-type",
1513  GST_TYPE_TAG_IMAGE_TYPE, &imagetype,
1514  NULL)) )
1516  else
1517  {
1518  switch (imagetype)
1519  {
1520  case GST_TAG_IMAGE_TYPE_NONE:
1521  case GST_TAG_IMAGE_TYPE_UNDEFINED:
1522  case GST_TAG_IMAGE_TYPE_FISH:
1523  case GST_TAG_IMAGE_TYPE_ILLUSTRATION:
1524  default:
1526  break;
1527  case GST_TAG_IMAGE_TYPE_FRONT_COVER:
1528  case GST_TAG_IMAGE_TYPE_BACK_COVER:
1529  case GST_TAG_IMAGE_TYPE_LEAFLET_PAGE:
1530  case GST_TAG_IMAGE_TYPE_MEDIUM:
1532  break;
1533  case GST_TAG_IMAGE_TYPE_LEAD_ARTIST:
1534  case GST_TAG_IMAGE_TYPE_ARTIST:
1535  case GST_TAG_IMAGE_TYPE_CONDUCTOR:
1536  case GST_TAG_IMAGE_TYPE_BAND_ORCHESTRA:
1537  case GST_TAG_IMAGE_TYPE_COMPOSER:
1538  case GST_TAG_IMAGE_TYPE_LYRICIST:
1540  break;
1541  case GST_TAG_IMAGE_TYPE_RECORDING_LOCATION:
1542  case GST_TAG_IMAGE_TYPE_DURING_RECORDING:
1543  case GST_TAG_IMAGE_TYPE_DURING_PERFORMANCE:
1544  case GST_TAG_IMAGE_TYPE_VIDEO_CAPTURE:
1546  break;
1547  case GST_TAG_IMAGE_TYPE_BAND_ARTIST_LOGO:
1548  case GST_TAG_IMAGE_TYPE_PUBLISHER_STUDIO_LOGO:
1550  break;
1551  }
1552  }
1553 
1554  buf = gst_sample_get_buffer (sample);
1555  gst_buffer_map (buf, &mi, GST_MAP_READ);
1556  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1557  "gstreamer",
1558  le_type,
1560  mime_type,
1561  (const char *) mi.data, mi.size);
1562  gst_buffer_unmap (buf, &mi);
1563  }
1564  }
1565  else if ((G_VALUE_TYPE (&val) == G_TYPE_UINT64) &&
1566  (tag_quark == duration_quark))
1567  {
1568  GstClockTime duration = (GstClockTime) g_value_get_uint64 (&val);
1569  if ((GST_CLOCK_TIME_IS_VALID (duration)) && (duration > 0))
1570  str = g_strdup_printf ("%" GST_TIME_FORMAT, GST_TIME_ARGS (duration));
1571  }
1572  else
1573  str = gst_value_serialize (&val);
1574  break;
1575  }
1576  if (NULL != str)
1577  {
1578  /* Discoverer internally uses some tags to provide streaminfo;
1579  * ignore these tags to avoid duplicates.
1580  * This MIGHT be fixed in new GStreamer versions, but won't affect
1581  * this code (we simply won't get the tags that we think we should skip).
1582  */gboolean skip = FALSE;
1583  /* We have one tag-processing routine and use it for different
1584  * stream types. However, tags themselves don't know the type of the
1585  * stream they are attached to. We remember that before listing the
1586  * tags, and adjust LE type accordingly.
1587  */enum EXTRACTOR_MetaType le_type = kt->le_type;
1588  switch (kt->le_type)
1589  {
1591  switch (ps->st)
1592  {
1593  case STREAM_TYPE_AUDIO:
1594  skip = TRUE;
1595  break;
1596  case STREAM_TYPE_SUBTITLE:
1597  skip = TRUE;
1598  break;
1599  case STREAM_TYPE_VIDEO:
1601  break;
1602  default:
1603  break;
1604  }
1605  break;
1607  switch (ps->st)
1608  {
1609  case STREAM_TYPE_AUDIO:
1610  skip = TRUE;
1611  break;
1612  case STREAM_TYPE_VIDEO:
1613  skip = TRUE;
1614  break;
1615  default:
1616  break;
1617  }
1618  break;
1620  switch (ps->st)
1621  {
1622  case STREAM_TYPE_AUDIO:
1623  skip = TRUE;
1624  break;
1625  case STREAM_TYPE_VIDEO:
1626  skip = TRUE;
1627  break;
1628  default:
1629  break;
1630  }
1631  break;
1633  switch (ps->st)
1634  {
1635  case STREAM_TYPE_AUDIO:
1636  skip = TRUE;
1637  break;
1638  case STREAM_TYPE_VIDEO:
1639  skip = TRUE;
1640  break;
1641  default:
1642  break;
1643  }
1644  break;
1646  switch (ps->st)
1647  {
1648  case STREAM_TYPE_VIDEO:
1650  break;
1651  default:
1652  break;
1653  }
1654  break;
1656  switch (ps->st)
1657  {
1658  case STREAM_TYPE_VIDEO:
1660  break;
1661  case STREAM_TYPE_AUDIO:
1663  break;
1664  case STREAM_TYPE_SUBTITLE:
1666  break;
1667  default:
1668  break;
1669  }
1670  break;
1672  /* Convert to "key=value" form */
1673  {
1674  gchar *new_str;
1675  /* GST_TAG_EXTENDED_COMMENT is already in key=value form */
1676  if ((0 != strcmp (tag, "extended-comment")) || ! strchr (str, '='))
1677  {
1678  new_str = g_strdup_printf ("%s=%s", tag, str);
1679  if (NULL != str)
1680  g_free (str);
1681  str = new_str;
1682  }
1683  }
1684  break;
1685  default:
1686  break;
1687  }
1688  if ( (! skip) &&
1689  (NULL != str) )
1690  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1691  "gstreamer",
1692  le_type,
1694  "text/plain",
1695  (const char *) str,
1696  strlen (str) + 1);
1697  }
1698  if (NULL != str)
1699  g_free (str);
1700  g_value_unset (&val);
1701  }
1702 }
1703 
1704 
1705 static void
1706 send_streams (GstDiscovererStreamInfo *info,
1707  struct PrivStruct *ps);
1708 
1709 
1710 static void
1711 send_stream_info (GstDiscovererStreamInfo *info,
1712  struct PrivStruct *ps)
1713 {
1714  const GstStructure *misc;
1715  GstCaps *caps;
1716  const GstTagList *tags;
1717 
1718  caps = gst_discoverer_stream_info_get_caps (info);
1719 
1720  if (GST_IS_DISCOVERER_AUDIO_INFO (info))
1721  ps->st = STREAM_TYPE_AUDIO;
1722  else if (GST_IS_DISCOVERER_VIDEO_INFO (info))
1723  ps->st = STREAM_TYPE_VIDEO;
1724  else if (GST_IS_DISCOVERER_SUBTITLE_INFO (info))
1725  ps->st = STREAM_TYPE_SUBTITLE;
1726  else if (GST_IS_DISCOVERER_CONTAINER_INFO (info))
1727  ps->st = STREAM_TYPE_CONTAINER;
1728 
1729  if (caps)
1730  {
1731  GstStructure *structure = gst_caps_get_structure (caps, 0);
1732  const gchar *structname = gst_structure_get_name (structure);
1733  if (g_str_has_prefix (structname, "image/"))
1734  ps->st = STREAM_TYPE_IMAGE;
1735  ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer",
1737  EXTRACTOR_METAFORMAT_UTF8, "text/plain",
1738  (const char *) structname, strlen (
1739  structname) + 1);
1740  if (! ps->time_to_leave)
1741  {
1742  gst_structure_foreach (structure, send_structure_foreach, ps);
1743  }
1744  gst_caps_unref (caps);
1745  }
1746 
1747  if (ps->time_to_leave)
1748  {
1749  ps->st = STREAM_TYPE_NONE;
1750  return;
1751  }
1752 
1753  misc = gst_discoverer_stream_info_get_misc (info);
1754  if (misc)
1755  {
1756  gst_structure_foreach (misc, send_structure_foreach, ps);
1757  }
1758 
1759  if (ps->time_to_leave)
1760  {
1761  ps->st = STREAM_TYPE_NONE;
1762  return;
1763  }
1764 
1765  tags = gst_discoverer_stream_info_get_tags (info);
1766  if (tags)
1767  {
1768  gst_tag_list_foreach (tags, send_tag_foreach, ps);
1769  }
1770  ps->st = STREAM_TYPE_NONE;
1771 
1772  if (ps->time_to_leave)
1773  return;
1774 
1775  if (GST_IS_DISCOVERER_AUDIO_INFO (info))
1776  send_audio_info (GST_DISCOVERER_AUDIO_INFO (info), ps);
1777  else if (GST_IS_DISCOVERER_VIDEO_INFO (info))
1778  send_video_info (GST_DISCOVERER_VIDEO_INFO (info), ps);
1779  else if (GST_IS_DISCOVERER_SUBTITLE_INFO (info))
1780  send_subtitle_info (GST_DISCOVERER_SUBTITLE_INFO (info), ps);
1781  else if (GST_IS_DISCOVERER_CONTAINER_INFO (info))
1782  {
1783  GList *child;
1784  GstDiscovererContainerInfo *c = GST_DISCOVERER_CONTAINER_INFO (info);
1785  GList *children = gst_discoverer_container_info_get_streams (c);
1786  for (child = children; (NULL != child) && (! ps->time_to_leave);
1787  child = child->next)
1788  {
1789  GstDiscovererStreamInfo *sinfo = child->data;
1790  /* send_streams () will unref it */
1791  sinfo = gst_discoverer_stream_info_ref (sinfo);
1792  send_streams (sinfo, ps);
1793  }
1794  if (children)
1795  gst_discoverer_stream_info_list_free (children);
1796  }
1797 }
1798 
1799 
1800 static void
1801 send_streams (GstDiscovererStreamInfo *info,
1802  struct PrivStruct *ps)
1803 {
1804  GstDiscovererStreamInfo *next;
1805 
1806  while ( (NULL != info) && (! ps->time_to_leave) )
1807  {
1808  send_stream_info (info, ps);
1809  next = gst_discoverer_stream_info_get_next (info);
1810  gst_discoverer_stream_info_unref (info);
1811  info = next;
1812  }
1813 }
1814 
1815 
1816 /**
1817  * Callback used to construct the XML 'toc'.
1818  *
1819  * @param tags FIXME
1820  * @param tag FIXME
1821  * @param user_data the 'struct PrivStruct' with the 'toc' string we are assembling
1822  */
1823 static void
1824 send_toc_tags_foreach (const GstTagList *tags,
1825  const gchar *tag,
1826  gpointer user_data)
1827 {
1828  struct PrivStruct *ps = user_data;
1829  GValue val = { 0 };
1830  gchar *topen, *str, *tclose;
1831  GType gst_fraction = GST_TYPE_FRACTION;
1832 
1833  gst_tag_list_copy_value (&val, tags, tag);
1834  switch (G_VALUE_TYPE (&val))
1835  {
1836  case G_TYPE_STRING:
1837  str = g_value_dup_string (&val);
1838  break;
1839  case G_TYPE_UINT:
1840  case G_TYPE_INT:
1841  case G_TYPE_DOUBLE:
1842  str = gst_value_serialize (&val);
1843  break;
1844  default:
1845  if (G_VALUE_TYPE (&val) == gst_fraction)
1846  {
1847  str = gst_value_serialize (&val);
1848  break;
1849  }
1850  /* This is a potential source of invalid characters */
1851  /* And it also might attempt to serialize binary data - such as images. */
1852  str = gst_value_serialize (&val);
1853  if (NULL != str)
1854  {
1855  g_free (str);
1856  str = NULL;
1857  }
1858  break;
1859  }
1860  if (NULL != str)
1861  {
1862  topen = g_strdup_printf ("%*.*s<%s>",
1863  ps->toc_depth * 2,
1864  ps->toc_depth * 2, " ", tag);
1865  tclose = g_strdup_printf ("%*.*s</%s>\n",
1866  ps->toc_depth * 2,
1867  ps->toc_depth * 2, " ",
1868  tag);
1869  if ( (NULL != topen) &&
1870  (NULL != tclose) )
1871  {
1872  if (ps->toc_print_phase)
1873  ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos],
1874  ps->toc_length - ps->toc_pos,
1875  "%s%s%s",
1876  topen,
1877  str,
1878  tclose);
1879  else
1880  ps->toc_length += strlen (topen) + strlen (str) + strlen (tclose);
1881  }
1882  if (NULL != topen)
1883  g_free (topen);
1884  if (NULL != tclose)
1885  g_free (tclose);
1886  g_free (str);
1887  }
1888  g_value_unset (&val);
1889 }
1890 
1891 
1892 /**
1893  * Top-level callback used to construct the XML 'toc'.
1894  *
1895  * @param data the GstTocEntry we're processing
1896  * @param user_data the 'struct PrivStruct' with the 'toc' string we are assembling
1897  */
1898 static void
1899 send_toc_foreach (gpointer data, gpointer user_data)
1900 {
1901  GstTocEntry *entry = data;
1902  struct PrivStruct *ps = user_data;
1903  GstTagList *tags;
1904  GList *subentries;
1905  gint64 start;
1906  gint64 stop;
1907  GstTocEntryType entype;
1908  gchar *s;
1909 
1910  entype = gst_toc_entry_get_entry_type (entry);
1911  if (GST_TOC_ENTRY_TYPE_INVALID == entype)
1912  return;
1913  gst_toc_entry_get_start_stop_times (entry, &start, &stop);
1914  s = g_strdup_printf ("%*.*s<%s start=\"%" GST_TIME_FORMAT "\" stop=\"%"
1915  GST_TIME_FORMAT "\">\n", ps->toc_depth * 2,
1916  ps->toc_depth * 2, " ",
1917  gst_toc_entry_type_get_nick (entype), GST_TIME_ARGS (
1918  start),
1919  GST_TIME_ARGS (stop));
1920  if (NULL != s)
1921  {
1922  if (ps->toc_print_phase)
1923  ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos],
1924  ps->toc_length - ps->toc_pos,
1925  "%s",
1926  s);
1927  else
1928  ps->toc_length += strlen (s);
1929  g_free (s);
1930  }
1931  ps->toc_depth++;
1932  tags = gst_toc_entry_get_tags (entry);
1933  if (tags)
1934  {
1935  if (ps->toc_print_phase)
1936  ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos], ps->toc_length
1937  - ps->toc_pos,
1938  "%*.*s<tags>\n", ps->toc_depth * 2,
1939  ps->toc_depth * 2, " ");
1940  else
1941  ps->toc_length += strlen ("<tags>\n") + ps->toc_depth * 2;
1942  ps->toc_depth++;
1943  gst_tag_list_foreach (tags, &send_toc_tags_foreach, ps);
1944  ps->toc_depth--;
1945  if (ps->toc_print_phase)
1946  ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos], ps->toc_length
1947  - ps->toc_pos,
1948  "%*.*s</tags>\n", ps->toc_depth * 2,
1949  ps->toc_depth * 2, " ");
1950  else
1951  ps->toc_length += strlen ("</tags>\n") + ps->toc_depth * 2;
1952  }
1953 
1954  subentries = gst_toc_entry_get_sub_entries (entry);
1955  g_list_foreach (subentries, send_toc_foreach, ps);
1956  ps->toc_depth--;
1957 
1958  s = g_strdup_printf ("%*.*s</%s>\n",
1959  ps->toc_depth * 2,
1960  ps->toc_depth * 2, " ",
1961  gst_toc_entry_type_get_nick (entype));
1962  if (NULL != s)
1963  {
1964  if (ps->toc_print_phase)
1965  ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos], ps->toc_length
1966  - ps->toc_pos, "%s", s);
1967  else
1968  ps->toc_length += strlen (s);
1969  g_free (s);
1970  }
1971 }
1972 
1973 
1974 /**
1975  * XML header for the table-of-contents meta data.
1976  */
1977 #define TOC_XML_HEADER "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
1978 
1979 
1980 static void
1981 send_info (GstDiscovererInfo *info,
1982  struct PrivStruct *ps)
1983 {
1984  const GstToc *toc;
1985  gchar *s;
1986  GstDiscovererStreamInfo *sinfo;
1987  GstClockTime duration;
1988  GList *entries;
1989 
1990  duration = gst_discoverer_info_get_duration (info);
1991  if ((GST_CLOCK_TIME_IS_VALID (duration)) && (duration > 0))
1992  {
1993  s = g_strdup_printf ("%" GST_TIME_FORMAT, GST_TIME_ARGS (duration));
1994  if (NULL != s)
1995  {
1996  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
1997  "gstreamer",
2000  "text/plain",
2001  (const char *) s,
2002  strlen (s) + 1);
2003  g_free (s);
2004  }
2005  }
2006 
2007  if (ps->time_to_leave)
2008  return;
2009 
2010  /* Disable this for now (i.e. only print per-stream tags)
2011  if ((tags = gst_discoverer_info_get_tags (info)))
2012  {
2013  gst_tag_list_foreach (tags, send_tag_foreach, ps);
2014  }
2015  */if (ps->time_to_leave)
2016  return;
2017 
2018  if ((toc = gst_discoverer_info_get_toc (info)))
2019  {
2020  entries = gst_toc_get_entries (toc);
2021  ps->toc_print_phase = FALSE;
2022  ps->toc_length = 0;
2023  g_list_foreach (entries, &send_toc_foreach, ps);
2024 
2025  if (ps->toc_length > 0)
2026  {
2027  ps->toc_print_phase = TRUE;
2028  ps->toc_length += 1 + strlen (TOC_XML_HEADER);
2029  ps->toc = g_malloc (ps->toc_length);
2030  if (NULL != ps->toc)
2031  {
2032  ps->toc_pos = 0;
2033  ps->toc_pos += g_snprintf (&ps->toc[ps->toc_pos],
2034  ps->toc_length - ps->toc_pos,
2035  "%s",
2036  TOC_XML_HEADER);
2037  g_list_foreach (entries, &send_toc_foreach, ps);
2038  ps->toc[ps->toc_length - 1] = '\0';
2039  ps->time_to_leave = ps->ec->proc (ps->ec->cls,
2040  "gstreamer",
2043  "application/xml",
2044  (const char *) ps->toc,
2045  ps->toc_length);
2046  g_free (ps->toc);
2047  ps->toc = NULL;
2048  }
2049  }
2050  }
2051 
2052  if (0 != ps->time_to_leave)
2053  return;
2054 
2055  sinfo = gst_discoverer_info_get_stream_info (info);
2056  send_streams (sinfo, ps);
2057 }
2058 
2059 
2060 static void
2061 send_discovered_info (GstDiscovererInfo *info,
2062  struct PrivStruct *ps)
2063 {
2064  GstDiscovererResult result;
2065 
2066  /* Docs don't say that info is guaranteed to be non-NULL */
2067  if (NULL == info)
2068  return;
2069  result = gst_discoverer_info_get_result (info);
2070 
2071  switch (result)
2072  {
2073  case GST_DISCOVERER_OK:
2074  break;
2075  case GST_DISCOVERER_URI_INVALID:
2076  break;
2077  case GST_DISCOVERER_ERROR:
2078  break;
2079  case GST_DISCOVERER_TIMEOUT:
2080  break;
2081  case GST_DISCOVERER_BUSY:
2082  break;
2083  case GST_DISCOVERER_MISSING_PLUGINS:
2084  break;
2085  }
2086  pthread_mutex_lock (&pipe_mutex);
2087  send_info (info, ps);
2088  pthread_mutex_unlock (&pipe_mutex);
2089 }
2090 
2091 
2092 static void
2093 _new_discovered_uri (GstDiscoverer *dc,
2094  GstDiscovererInfo *info,
2095  GError *err,
2096  struct PrivStruct *ps)
2097 {
2098  send_discovered_info (info, ps);
2099  if (ps->timeout_id > 0)
2100  g_source_remove (ps->timeout_id);
2101  ps->timeout_id = g_timeout_add (DATA_TIMEOUT, (GSourceFunc) _data_timeout,
2102  ps);
2103 }
2104 
2105 
2106 static void
2107 _discoverer_finished (GstDiscoverer *dc, struct PrivStruct *ps)
2108 {
2109  if (ps->timeout_id > 0)
2110  g_source_remove (ps->timeout_id);
2111  ps->timeout_id = 0;
2112  g_main_loop_quit (ps->loop);
2113 }
2114 
2115 
2116 /**
2117  * This callback is called when discoverer has constructed a source object to
2118  * read from. Since we provided the appsrc:// uri to discoverer, this will be
2119  * the appsrc that we must handle. We set up some signals - one to push data
2120  * into appsrc and one to perform a seek.
2121  *
2122  * @param dc
2123  * @param source
2124  * @param ps
2125  */
2126 static void
2127 _source_setup (GstDiscoverer *dc,
2128  GstElement *source,
2129  struct PrivStruct *ps)
2130 {
2131  if (ps->source)
2132  gst_object_unref (GST_OBJECT (ps->source));
2133  ps->source = source;
2134  gst_object_ref (source);
2135 
2136  /* we can set the length in appsrc. This allows some elements to estimate the
2137  * total duration of the stream. It's a good idea to set the property when you
2138  * can but it's not required. */
2139  if (ps->length > 0)
2140  {
2141  g_object_set (ps->source, "size", (gint64) ps->length, NULL);
2142  gst_util_set_object_arg (G_OBJECT (ps->source), "stream-type",
2143  "random-access");
2144  }
2145  else
2146  gst_util_set_object_arg (G_OBJECT (ps->source), "stream-type", "seekable");
2147 
2148  /* configure the appsrc, we will push a buffer to appsrc when it needs more
2149  * data */
2150  g_signal_connect (ps->source, "need-data", G_CALLBACK (feed_data), ps);
2151  g_signal_connect (ps->source, "seek-data", G_CALLBACK (seek_data), ps);
2152  ps->timeout_id = g_timeout_add (DATA_TIMEOUT, (GSourceFunc) _data_timeout,
2153  ps);
2154 }
2155 
2156 
2157 static void
2158 log_handler (const gchar *log_domain,
2159  GLogLevelFlags log_level,
2160  const gchar *message,
2161  gpointer unused_data)
2162 {
2163  /* do nothing */
2164 }
2165 
2166 
2167 /**
2168  * Task run from the main loop to call 'gst_discoverer_uri_async'.
2169  *
2170  * @param ps our execution context
2171  * @return FALSE (always)
2172  */
2173 static gboolean
2175 {
2176  g_log_set_default_handler (&log_handler, NULL);
2177  g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
2178  | G_LOG_FLAG_RECURSION,
2179  &log_handler, NULL);
2180  gst_discoverer_discover_uri_async (ps->dc, "appsrc://");
2181  return FALSE;
2182 }
2183 
2184 
2185 /**
2186  * This will be the main method of your plugin.
2187  * Describe a bit what it does here.
2188  *
2189  * @param ec extraction context, here you get the API
2190  * for accessing the file data and for returning
2191  * meta data
2192  */
2193 void
2195 {
2196  struct PrivStruct ps;
2197  GError *err = NULL;
2198 
2199  memset (&ps, 0, sizeof (ps));
2200  ps.dc = gst_discoverer_new (8 * GST_SECOND, &err);
2201  if (NULL == ps.dc)
2202  {
2203  if (NULL != err)
2204  g_error_free (err);
2205  return;
2206  }
2207  if (NULL != err)
2208  g_error_free (err);
2209  /* connect signals */
2210  g_signal_connect (ps.dc, "discovered", G_CALLBACK (_new_discovered_uri), &ps);
2211  g_signal_connect (ps.dc, "finished", G_CALLBACK (_discoverer_finished), &ps);
2212  g_signal_connect (ps.dc, "source-setup", G_CALLBACK (_source_setup), &ps);
2213  ps.loop = g_main_loop_new (NULL, TRUE);
2214  ps.ec = ec;
2215  ps.length = ps.ec->get_size (ps.ec->cls);
2216  if (ps.length == UINT_MAX)
2217  ps.length = 0;
2218  g_log_set_default_handler (&log_handler, NULL);
2219  g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
2220  | G_LOG_FLAG_RECURSION,
2221  &log_handler, NULL);
2222  gst_discoverer_start (ps.dc);
2223  g_idle_add ((GSourceFunc) & _run_async, &ps);
2224  g_main_loop_run (ps.loop);
2225  if (ps.timeout_id > 0)
2226  g_source_remove (ps.timeout_id);
2227  gst_discoverer_stop (ps.dc);
2228  g_object_unref (ps.dc);
2229  g_main_loop_unref (ps.loop);
2230 }
2231 
2232 
2233 /**
2234  * Initialize glib and globals.
2235  */
2236 void __attribute__ ((constructor))
2238 {
2239  gst_init (NULL, NULL);
2240  g_log_set_default_handler (&log_handler, NULL);
2241  g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
2242  | G_LOG_FLAG_RECURSION,
2243  &log_handler, NULL);
2244  GST_DEBUG_CATEGORY_INIT (gstreamer_extractor, "GstExtractor",
2245  0, "GStreamer-based libextractor plugin");
2246 
2247  audio_quarks = g_new0 (GQuark, 4);
2248  if (NULL != audio_quarks)
2249  {
2250  audio_quarks[0] = g_quark_from_string ("rate");
2251  audio_quarks[1] = g_quark_from_string ("channels");
2252  audio_quarks[2] = g_quark_from_string ("depth");
2253  audio_quarks[3] = g_quark_from_string (NULL);
2254  }
2255  video_quarks = g_new0 (GQuark, 6);
2256  if (NULL != video_quarks)
2257  {
2258  video_quarks[0] = g_quark_from_string ("width");
2259  video_quarks[1] = g_quark_from_string ("height");
2260  video_quarks[2] = g_quark_from_string ("framerate");
2261  video_quarks[3] = g_quark_from_string ("max-framerate");
2262  video_quarks[4] = g_quark_from_string ("pixel-aspect-ratio");
2263  video_quarks[5] = g_quark_from_string (NULL);
2264  }
2265  subtitle_quarks = g_new0 (GQuark, 2);
2266  if (NULL != subtitle_quarks)
2267  {
2268  subtitle_quarks[0] = g_quark_from_string ("language-code");
2269  subtitle_quarks[1] = g_quark_from_string (NULL);
2270  }
2271 
2272  duration_quark = g_quark_from_string ("duration");
2273 
2274  pthread_mutex_init (&pipe_mutex, NULL);
2275 }
2276 
2277 
2278 /* end of gstreamer_extractor.c */
@ EXTRACTOR_METAFORMAT_BINARY
Definition: extractor.h:107
@ EXTRACTOR_METAFORMAT_C_STRING
Definition: extractor.h:113
@ EXTRACTOR_METAFORMAT_UTF8
Definition: extractor.h:102
#define NULL
Definition: getopt1.c:60
EXTRACTOR_MetaType
Definition: extractor.h:126
@ EXTRACTOR_METATYPE_DISC_COUNT
Definition: extractor.h:333
@ EXTRACTOR_METATYPE_LOGO
Definition: extractor.h:290
@ EXTRACTOR_METATYPE_LOCATION_MOVEMENT_SPEED
Definition: extractor.h:361
@ EXTRACTOR_METATYPE_MAXIMUM_AUDIO_BITRATE
Definition: extractor.h:378
@ EXTRACTOR_METATYPE_MOVIE_DIRECTOR
Definition: extractor.h:299
@ EXTRACTOR_METATYPE_SUMMARY
Definition: extractor.h:187
@ EXTRACTOR_METATYPE_LOCATION_ELEVATION
Definition: extractor.h:359
@ EXTRACTOR_METATYPE_DISC_NUMBER
Definition: extractor.h:282
@ EXTRACTOR_METATYPE_PRODUCT_VERSION
Definition: extractor.h:297
@ EXTRACTOR_METATYPE_SHOW_NAME
Definition: extractor.h:301
@ EXTRACTOR_METATYPE_BITRATE
Definition: extractor.h:342
@ EXTRACTOR_METATYPE_CHANNELS
Definition: extractor.h:374
@ EXTRACTOR_METATYPE_GENRE
Definition: extractor.h:280
@ EXTRACTOR_METATYPE_THUMBNAIL
Definition: extractor.h:259
@ EXTRACTOR_METATYPE_UNKNOWN
Definition: extractor.h:181
@ EXTRACTOR_METATYPE_VIDEO_BITRATE
Definition: extractor.h:384
@ EXTRACTOR_METATYPE_CODEC
Definition: extractor.h:335
@ EXTRACTOR_METATYPE_NOMINAL_BITRATE
Definition: extractor.h:343
@ EXTRACTOR_METATYPE_SHOW_EPISODE_NUMBER
Definition: extractor.h:365
@ EXTRACTOR_METATYPE_ENCODER_VERSION
Definition: extractor.h:350
@ EXTRACTOR_METATYPE_RATING
Definition: extractor.h:326
@ EXTRACTOR_METATYPE_EVENT_PICTURE
Definition: extractor.h:289
@ EXTRACTOR_METATYPE_TRACK_NUMBER
Definition: extractor.h:281
@ EXTRACTOR_METATYPE_AUDIO_LANGUAGE
Definition: extractor.h:373
@ EXTRACTOR_METATYPE_GPS_LONGITUDE
Definition: extractor.h:174
@ EXTRACTOR_METATYPE_LANGUAGE
Definition: extractor.h:157
@ EXTRACTOR_METATYPE_MOOD
Definition: extractor.h:320
@ EXTRACTOR_METATYPE_FRAME_RATE
Definition: extractor.h:382
@ EXTRACTOR_METATYPE_VIDEO_DEPTH
Definition: extractor.h:381
@ EXTRACTOR_METATYPE_COVER_PICTURE
Definition: extractor.h:287
@ EXTRACTOR_METATYPE_PLAY_COUNTER
Definition: extractor.h:305
@ EXTRACTOR_METATYPE_ALBUM_PEAK
Definition: extractor.h:355
@ EXTRACTOR_METATYPE_COMMENT
Definition: extractor.h:131
@ EXTRACTOR_METATYPE_WRITER
Definition: extractor.h:296
@ EXTRACTOR_METATYPE_POPULARITY_METER
Definition: extractor.h:317
@ EXTRACTOR_METATYPE_TITLE
Definition: extractor.h:134
@ EXTRACTOR_METATYPE_ARTIST
Definition: extractor.h:279
@ EXTRACTOR_METATYPE_GPS_LATITUDE
Definition: extractor.h:172
@ EXTRACTOR_METATYPE_AUDIO_BITRATE
Definition: extractor.h:377
@ EXTRACTOR_METATYPE_CREATED_BY_SOFTWARE
Definition: extractor.h:194
@ EXTRACTOR_METATYPE_PERFORMER
Definition: extractor.h:283
@ EXTRACTOR_METATYPE_SUBTITLE_DURATION
Definition: extractor.h:394
@ EXTRACTOR_METATYPE_PRODUCER
Definition: extractor.h:329
@ EXTRACTOR_METATYPE_AUDIO_DEPTH
Definition: extractor.h:376
@ EXTRACTOR_METATYPE_ISRC
Definition: extractor.h:163
@ EXTRACTOR_METATYPE_ENCODER
Definition: extractor.h:349
@ EXTRACTOR_METATYPE_LOCATION_NAME
Definition: extractor.h:358
@ EXTRACTOR_METATYPE_GROUPING
Definition: extractor.h:368
@ EXTRACTOR_METATYPE_VIDEO_DIMENSIONS
Definition: extractor.h:380
@ EXTRACTOR_METATYPE_SUBTITLE_CODEC
Definition: extractor.h:338
@ EXTRACTOR_METATYPE_AUDIO_CODEC
Definition: extractor.h:337
@ EXTRACTOR_METATYPE_COMPANY
Definition: extractor.h:272
@ EXTRACTOR_METATYPE_LOCATION_CITY
Definition: extractor.h:175
@ EXTRACTOR_METATYPE_LOCATION_HORIZONTAL_ERROR
Definition: extractor.h:360
@ EXTRACTOR_METATYPE_MAXIMUM_VIDEO_BITRATE
Definition: extractor.h:385
@ EXTRACTOR_METATYPE_KEYWORDS
Definition: extractor.h:185
@ EXTRACTOR_METATYPE_LICENSE
Definition: extractor.h:226
@ EXTRACTOR_METATYPE_SERIAL
Definition: extractor.h:347
@ EXTRACTOR_METATYPE_CREATION_TIME
Definition: extractor.h:158
@ EXTRACTOR_METATYPE_COPYRIGHT
Definition: extractor.h:183
@ EXTRACTOR_METATYPE_AUDIO_DURATION
Definition: extractor.h:393
@ EXTRACTOR_METATYPE_ORIENTATION
Definition: extractor.h:253
@ EXTRACTOR_METATYPE_ENCODED_BY
Definition: extractor.h:310
@ EXTRACTOR_METATYPE_SAMPLE_RATE
Definition: extractor.h:375
@ EXTRACTOR_METATYPE_TOC
Definition: extractor.h:390
@ EXTRACTOR_METATYPE_VIDEO_CODEC
Definition: extractor.h:336
@ EXTRACTOR_METATYPE_CONTRIBUTOR_PICTURE
Definition: extractor.h:288
@ EXTRACTOR_METATYPE_SHOW_SEASON_NUMBER
Definition: extractor.h:366
@ EXTRACTOR_METATYPE_DEVICE_MODEL
Definition: extractor.h:371
@ EXTRACTOR_METATYPE_VIDEO_DURATION
Definition: extractor.h:392
@ EXTRACTOR_METATYPE_MAXIMUM_BITRATE
Definition: extractor.h:345
@ EXTRACTOR_METATYPE_MINIMUM_BITRATE
Definition: extractor.h:344
@ EXTRACTOR_METATYPE_VIDEO_LANGUAGE
Definition: extractor.h:388
@ EXTRACTOR_METATYPE_LOCATION_COUNTRY
Definition: extractor.h:177
@ EXTRACTOR_METATYPE_REFERENCE_LEVEL
Definition: extractor.h:356
@ EXTRACTOR_METATYPE_TRACK_GAIN
Definition: extractor.h:352
@ EXTRACTOR_METATYPE_ORIGINAL_ARTIST
Definition: extractor.h:312
@ EXTRACTOR_METATYPE_MIMETYPE
Definition: extractor.h:129
@ EXTRACTOR_METATYPE_BEATS_PER_MINUTE
Definition: extractor.h:309
@ EXTRACTOR_METATYPE_COMPOSER
Definition: extractor.h:308
@ EXTRACTOR_METATYPE_PUBLISHER
Definition: extractor.h:146
@ EXTRACTOR_METATYPE_ALBUM
Definition: extractor.h:278
@ EXTRACTOR_METATYPE_CONTAINER_FORMAT
Definition: extractor.h:340
@ EXTRACTOR_METATYPE_ORIGINAL_TITLE
Definition: extractor.h:311
@ EXTRACTOR_METATYPE_SUBTITLE_LANGUAGE
Definition: extractor.h:387
@ EXTRACTOR_METATYPE_DEVICE_MANUFACTURER
Definition: extractor.h:370
@ EXTRACTOR_METATYPE_SONG_COUNT
Definition: extractor.h:303
@ EXTRACTOR_METATYPE_SUBJECT
Definition: extractor.h:188
@ EXTRACTOR_METATYPE_ALBUM_GAIN
Definition: extractor.h:354
@ EXTRACTOR_METATYPE_LOCATION_SUBLOCATION
Definition: extractor.h:176
@ EXTRACTOR_METATYPE_PIXEL_ASPECT_RATIO
Definition: extractor.h:383
@ EXTRACTOR_METATYPE_URL
Definition: extractor.h:159
@ EXTRACTOR_METATYPE_LOCATION_CAPTURE_DIRECTION
Definition: extractor.h:363
@ EXTRACTOR_METATYPE_LOCATION_MOVEMENT_DIRECTION
Definition: extractor.h:362
@ EXTRACTOR_METATYPE_IMAGE_DIMENSIONS
Definition: extractor.h:257
@ EXTRACTOR_METATYPE_CONTACT_INFORMATION
Definition: extractor.h:284
@ EXTRACTOR_METATYPE_DURATION
Definition: extractor.h:277
@ EXTRACTOR_METATYPE_LYRICS
Definition: extractor.h:316
@ EXTRACTOR_METATYPE_TRACK_PEAK
Definition: extractor.h:353
@ EXTRACTOR_METATYPE_DESCRIPTION
Definition: extractor.h:182
@ EXTRACTOR_METATYPE_PICTURE
Definition: extractor.h:286
static gboolean _data_timeout(struct PrivStruct *ps)
static GQuark * video_quarks
static void send_toc_tags_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
static void _source_setup(GstDiscoverer *dc, GstElement *source, struct PrivStruct *ps)
void gstreamer_init()
static void send_toc_foreach(gpointer data, gpointer user_data)
static struct KnownTag __known_tags[]
static gboolean send_structure_foreach(GQuark field_id, const GValue *value, gpointer user_data)
static void _discoverer_finished(GstDiscoverer *dc, struct PrivStruct *ps)
static void send_info(GstDiscovererInfo *info, struct PrivStruct *ps)
void EXTRACTOR_gstreamer_extract_method(struct EXTRACTOR_ExtractContext *ec)
static int send_subtitle_info(GstDiscovererSubtitleInfo *info, struct PrivStruct *ps)
GST_DEBUG_CATEGORY_STATIC(gstreamer_extractor)
struct NamedTag named_tags[]
static void _new_discovered_uri(GstDiscoverer *dc, GstDiscovererInfo *info, GError *err, struct PrivStruct *ps)
static gboolean seek_data(GstElement *appsrc, guint64 position, struct PrivStruct *ps)
static GQuark * subtitle_quarks
static GQuark duration_quark
static int send_video_info(GstDiscovererVideoInfo *info, struct PrivStruct *ps)
static gboolean send_audio_info(GstDiscovererAudioInfo *info, struct PrivStruct *ps)
pthread_mutex_t pipe_mutex
#define DATA_TIMEOUT
static void send_streams(GstDiscovererStreamInfo *info, struct PrivStruct *ps)
static void feed_data(GstElement *appsrc, guint size, struct PrivStruct *ps)
static void send_stream_info(GstDiscovererStreamInfo *info, struct PrivStruct *ps)
#define TOC_XML_HEADER
CurrentStreamType
@ STREAM_TYPE_AUDIO
@ STREAM_TYPE_VIDEO
@ STREAM_TYPE_SUBTITLE
@ STREAM_TYPE_IMAGE
@ STREAM_TYPE_NONE
@ STREAM_TYPE_CONTAINER
static gboolean _run_async(struct PrivStruct *ps)
static void send_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
static void send_discovered_info(GstDiscovererInfo *info, struct PrivStruct *ps)
static GQuark * audio_quarks
static void log_handler(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer unused_data)
plaform specifics
static unsigned char * buffer
int64_t(* seek)(void *cls, int64_t pos, int whence)
Definition: extractor.h:509
uint64_t(* get_size)(void *cls)
Definition: extractor.h:520
EXTRACTOR_MetaDataProcessor proc
Definition: extractor.h:525
ssize_t(* read)(void *cls, void **data, size_t size)
Definition: extractor.h:494
enum EXTRACTOR_MetaType le_type
const char * gst_tag_id
enum EXTRACTOR_MetaType le_type
const char * tag
gboolean toc_print_phase
GstDiscoverer * dc
GMainLoop * loop
enum CurrentStreamType st
struct EXTRACTOR_ExtractContext * ec
GstElement * source