1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * arch-tag: Implementation of metadata reading using GStreamer
5 * Copyright (C) 2003,2004 Colin Walters <walters@verbum.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <glib/gi18n.h>
28 #include <gst/tag/tag.h>
29 #include <gst/gsturi.h>
31 #ifdef HAVE_GSTREAMER_0_8
32 #include <gst/gsttag.h>
33 #define gst_caps_unref gst_caps_free
34 #define gst_tag_setter_add_tag_values gst_tag_setter_add_values
35 #define gst_tag_setter_set_tag_merge_mode gst_tag_setter_set_merge_mode
36 #define gst_tag_setter_merge_tags gst_tag_setter_merge
38 #ifdef HAVE_GSTREAMER_0_10
39 #include <gst/gsttagsetter.h>
42 #include "rb-metadata.h"
45 #include "rb-file-helpers.h"
47 G_DEFINE_TYPE(RBMetaData
, rb_metadata
, G_TYPE_OBJECT
)
49 static void rb_metadata_finalize (GObject
*object
);
51 typedef GstElement
*(*RBAddTaggerElem
) (RBMetaData
*, GstElement
*);
54 * The list of mine type prefixes for files that shouldn't display errors about being non-audio.
55 * Useful for people who have cover art, et cetera, in their music directories
57 const char * ignore_mime_types
[] = {
65 * File size below which we will simply ignore files that can't be identified.
66 * This is mostly here so we ignore the various text files that are packaged
67 * with many netlabel releases and other downloads.
69 #define REALLY_SMALL_FILE_SIZE (4096)
71 struct RBMetadataGstType
74 RBAddTaggerElem tag_func
;
78 struct RBMetaDataPrivate
86 gulong typefind_cb_id
;
89 /* Array of RBMetadataGstType */
90 GPtrArray
*supported_types
;
100 #define RB_METADATA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_METADATA, RBMetaDataPrivate))
102 #ifdef HAVE_GSTREAMER_0_10
104 gst_date_gulong_transform (const GValue
*src
, GValue
*dest
)
106 const GDate
*date
= gst_value_get_date (src
);
108 g_value_set_ulong (dest
, (date
) ? g_date_get_julian (date
) : 0);
112 gulong_gst_date_transform (const GValue
*src
, GValue
*dest
)
114 gulong day
= g_value_get_ulong (src
);
115 GDate
*date
= g_date_new_julian (day
);
117 gst_value_set_date (dest
, date
);
124 rb_metadata_class_init (RBMetaDataClass
*klass
)
126 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
128 object_class
->finalize
= rb_metadata_finalize
;
130 g_type_class_add_private (klass
, sizeof (RBMetaDataPrivate
));
131 #ifdef HAVE_GSTREAMER_0_10
132 g_value_register_transform_func (GST_TYPE_DATE
, G_TYPE_ULONG
, gst_date_gulong_transform
);
133 g_value_register_transform_func (G_TYPE_ULONG
, GST_TYPE_DATE
, gulong_gst_date_transform
);
138 rb_add_flac_tagger (RBMetaData
*md
, GstElement
*element
)
140 GstElement
*tagger
= NULL
;
142 if (!(tagger
= gst_element_factory_make ("flactag", "flactag")))
145 gst_bin_add (GST_BIN (md
->priv
->pipeline
), tagger
);
146 gst_element_link_many (element
, tagger
, NULL
);
148 gst_tag_setter_merge_tags (GST_TAG_SETTER (tagger
), md
->priv
->tags
, GST_TAG_MERGE_REPLACE_ALL
);
153 #ifdef HAVE_GSTREAMER_0_10
155 id3_pad_added_cb (GstElement
*demux
, GstPad
*pad
, GstElement
*mux
)
159 mux_pad
= gst_element_get_compatible_pad (mux
, pad
, NULL
);
160 if (gst_pad_link (pad
, mux_pad
) != GST_PAD_LINK_OK
)
161 rb_debug ("unable to link pad from id3demux to id3mux");
163 rb_debug ("linked pad from id3de to id3mux");
167 rb_gst_plugin_greater (const char *plugin
, const char *element
, gint major
, gint minor
, gint micro
)
174 if (gst_default_registry_check_feature_version (element
, major
, minor
, micro
+ 1))
177 if (!gst_default_registry_check_feature_version (element
, major
, minor
, micro
))
180 p
= gst_default_registry_find_plugin (plugin
);
184 version
= gst_plugin_get_version (p
);
186 /* check if it's not a release */
187 count
= sscanf (version
, "%u.%u.%u.%u", &i
, &i
, &i
, &i
);
192 rb_add_id3_tagger (RBMetaData
*md
, GstElement
*element
)
194 GstElement
*demux
= NULL
;
195 GstElement
*mux
= NULL
;
197 demux
= gst_element_factory_make ("id3demux", NULL
);
199 mux
= gst_element_factory_make ("id3v2mux", NULL
);
201 /* check for backwards id3v2mux merge-mode */
202 if (!rb_gst_plugin_greater ("taglib", "id3v2mux", 0, 10, 3)) {
203 rb_debug ("using id3v2mux with backwards merge mode");
204 gst_tag_setter_set_tag_merge_mode (GST_TAG_SETTER (mux
), GST_TAG_MERGE_REPLACE
);
206 rb_debug ("using id3v2mux");
209 mux
= gst_element_factory_make ("id3mux", NULL
);
211 /* check for backwards id3mux merge-mode */
212 if (mux
&& !rb_gst_plugin_greater ("mad", "id3mux", 0, 10, 3)) {
213 rb_debug ("using id3mux with backwards merge mode");
214 gst_tag_setter_set_tag_merge_mode (GST_TAG_SETTER (mux
), GST_TAG_MERGE_REPLACE
);
216 rb_debug ("using id3mux");
220 if (demux
== NULL
|| mux
== NULL
)
223 gst_bin_add_many (GST_BIN (md
->priv
->pipeline
), demux
, mux
, NULL
);
224 if (!gst_element_link (element
, demux
))
227 g_signal_connect (demux
, "pad-added", (GCallback
)id3_pad_added_cb
, mux
);
229 gst_tag_setter_merge_tags (GST_TAG_SETTER (mux
), md
->priv
->tags
, GST_TAG_MERGE_REPLACE_ALL
);
234 g_object_unref (demux
);
235 g_object_unref (mux
);
240 ogg_pad_added_cb (GstElement
*demux
, GstPad
*pad
, RBMetaData
*md
)
243 GstStructure
*structure
;
244 const gchar
*mimetype
;
245 GstPad
*conn_pad
= NULL
;
248 caps
= gst_pad_get_caps (pad
);
249 structure
= gst_caps_get_structure (caps
, 0);
250 mimetype
= gst_structure_get_name (structure
);
252 mux
= g_object_get_data (G_OBJECT (demux
), "mux");
254 if (strcmp (mimetype
, "audio/x-vorbis") == 0) {
255 GstElement
*tagger
, *parser
;
259 rb_debug ("found vorbis stream in ogg container, using vorbistag");
261 parser
= gst_element_factory_make ("vorbisparse", NULL
);
262 if (parser
== NULL
) {
263 rb_debug ("could not create vorbisparse element");
267 tagger
= gst_element_factory_make ("vorbistag", NULL
);
268 if (tagger
== NULL
) {
269 rb_debug ("could not create vorbistag element");
270 gst_object_unref (parser
);
274 bin
= GST_BIN (gst_element_get_parent (mux
));
275 gst_bin_add_many (bin
, tagger
, parser
, NULL
);
276 gst_object_unref (GST_OBJECT (bin
));
278 /* connect and bring them up to the same state */
279 gst_element_link_many (tagger
, parser
, mux
, NULL
);
280 gst_element_get_state (mux
, &state
, NULL
, 0);
281 gst_element_set_state (parser
, state
);
282 gst_element_set_state (tagger
, state
);
284 conn_pad
= gst_element_get_compatible_pad (tagger
, pad
, NULL
);
285 gst_pad_link (pad
, conn_pad
);
287 gst_tag_setter_merge_tags (GST_TAG_SETTER (tagger
), md
->priv
->tags
, GST_TAG_MERGE_REPLACE_ALL
);
289 conn_pad
= gst_element_get_compatible_pad (mux
, pad
, NULL
);
290 gst_pad_link (pad
, conn_pad
);
291 rb_debug ("found stream in ogg container with no known tagging element");
295 gst_caps_unref (caps
);
299 rb_add_ogg_tagger (RBMetaData
*md
, GstElement
*element
)
301 GstElement
*demux
= NULL
;
302 GstElement
*mux
= NULL
;
304 demux
= gst_element_factory_make ("oggdemux", NULL
);
305 mux
= gst_element_factory_make ("oggmux", NULL
);
307 if (demux
== NULL
|| mux
== NULL
)
310 gst_bin_add_many (GST_BIN (md
->priv
->pipeline
), demux
, mux
, NULL
);
311 if (!gst_element_link (element
, demux
))
314 g_object_set_data (G_OBJECT (demux
), "mux", mux
);
315 g_signal_connect (demux
, "pad-added", (GCallback
)ogg_pad_added_cb
, md
);
320 g_object_unref (demux
);
321 g_object_unref (mux
);
325 #elif HAVE_GSTREAMER_0_8
327 rb_add_id3_tagger (RBMetaData
*md
, GstElement
*element
)
329 GstElement
*tagger
, *identity
;
330 GstCaps
*filtercaps
= NULL
;
332 if (!(tagger
= gst_element_factory_make ("id3tag", "tagger")))
335 if (!(identity
= gst_element_factory_make ("identity", "identity"))) {
336 gst_object_unref (GST_OBJECT (tagger
));
340 gst_bin_add_many (GST_BIN (md
->priv
->pipeline
), tagger
, identity
, NULL
);
342 filtercaps
= gst_caps_new_simple ("application/x-id3", NULL
);
343 if (!gst_element_link_filtered (tagger
, identity
, filtercaps
)) {
344 g_warning ("Linking id3tag and identity failed");
345 gst_caps_free (filtercaps
);
346 gst_object_unref (GST_OBJECT(tagger
));
347 gst_object_unref (GST_OBJECT(identity
));
350 gst_caps_free (filtercaps
);
352 gst_element_link_many(element
, tagger
, NULL
);
354 gst_tag_setter_merge_tags (GST_TAG_SETTER (tagger
), md
->priv
->tags
, GST_TAG_MERGE_REPLACE_ALL
);
361 add_supported_type (RBMetaData
*md
,
363 RBAddTaggerElem add_tagger_func
,
364 const char *human_name
)
366 struct RBMetadataGstType
*type
= g_new0 (struct RBMetadataGstType
, 1);
367 type
->mimetype
= g_strdup (mime
);
368 type
->tag_func
= add_tagger_func
;
369 type
->human_name
= g_strdup (human_name
);
370 g_ptr_array_add (md
->priv
->supported_types
, type
);
374 rb_metadata_init (RBMetaData
*md
)
376 RBAddTaggerElem tagger
;
377 gboolean has_gnomevfssink
= FALSE
;
378 gboolean has_id3
= FALSE
;
380 md
->priv
= RB_METADATA_GET_PRIVATE (md
);
382 md
->priv
->supported_types
= g_ptr_array_new ();
384 /* the list of supported types serves two purposes:
385 * - it knows how to construct elements for tag writing
386 * - it knows human-readable names for MIME types so we can say
387 * "There is no plugin available to play WMV files"
388 * rather than " .. play video/x-ms-asf files".
390 * only registering types we have plugins for defeats the second
393 has_gnomevfssink
= (gst_element_factory_find ("gnomevfssrc") != NULL
&&
394 gst_element_factory_find ("gnomevfssink") != NULL
);
395 #ifdef HAVE_GSTREAMER_0_10
396 has_id3
= (gst_element_factory_find ("id3demux") != NULL
) &&
397 (gst_default_registry_check_feature_version ("id3mux", 0, 10, 2) ||
398 (gst_element_factory_find ("id3v2mux") != NULL
));
399 #elif HAVE_GSTREAMER_0_8
400 has_id3
= (gst_element_factory_find ("id3tag") != NULL
);
403 tagger
= (has_gnomevfssink
&& has_id3
) ? rb_add_id3_tagger
: NULL
;
404 add_supported_type (md
, "application/x-id3", tagger
, "MP3");
405 add_supported_type (md
, "audio/mpeg", tagger
, "MP3");
407 #ifdef HAVE_GSTREAMER_0_10
411 has_vorbis
= ((gst_element_factory_find ("vorbistag") != NULL
) &&
412 gst_default_registry_check_feature_version ("vorbisparse", 0, 10, 6) &&
413 gst_default_registry_check_feature_version ("oggmux", 0, 10, 6) &&
414 gst_default_registry_check_feature_version ("oggdemux", 0, 10, 6));
415 tagger
= (has_gnomevfssink
&& has_vorbis
) ? rb_add_ogg_tagger
: NULL
;
420 add_supported_type (md
, "application/ogg", tagger
, "Ogg Vorbis");
421 add_supported_type (md
, "audio/x-vorbis", tagger
, "Ogg Vorbis");
423 add_supported_type (md
, "audio/x-mod", NULL
, "MOD");
424 add_supported_type (md
, "audio/x-wav", NULL
, "WAV");
425 add_supported_type (md
, "video/x-ms-asf", NULL
, "ASF");
427 tagger
= (has_gnomevfssink
&& gst_element_factory_find ("flactag")) ? rb_add_flac_tagger
: NULL
;
428 add_supported_type (md
, "audio/x-flac", tagger
, "FLAC");
433 rb_metadata_finalize (GObject
*object
)
438 md
= RB_METADATA (object
);
440 for (i
= 0; i
< md
->priv
->supported_types
->len
; i
++) {
441 struct RBMetadataGstType
*type
= g_ptr_array_index (md
->priv
->supported_types
, i
);
442 g_free (type
->mimetype
);
443 g_free (type
->human_name
);
446 g_ptr_array_free (md
->priv
->supported_types
, TRUE
);
448 if (md
->priv
->metadata
)
449 g_hash_table_destroy (md
->priv
->metadata
);
451 if (md
->priv
->pipeline
)
452 gst_object_unref (GST_OBJECT (md
->priv
->pipeline
));
454 g_free (md
->priv
->type
);
455 g_free (md
->priv
->uri
);
456 g_clear_error (&md
->priv
->error
);
458 G_OBJECT_CLASS (rb_metadata_parent_class
)->finalize (object
);
462 rb_metadata_new (void)
464 return RB_METADATA (g_object_new (RB_TYPE_METADATA
, NULL
, NULL
));
468 free_gvalue (GValue
*val
)
475 rb_metadata_gst_tag_to_field (const char *tag
)
477 if (!strcmp (tag
, GST_TAG_TITLE
))
478 return RB_METADATA_FIELD_TITLE
;
479 else if (!strcmp (tag
, GST_TAG_ARTIST
))
480 return RB_METADATA_FIELD_ARTIST
;
481 else if (!strcmp (tag
, GST_TAG_ALBUM
))
482 return RB_METADATA_FIELD_ALBUM
;
483 else if (!strcmp (tag
, GST_TAG_DATE
))
484 return RB_METADATA_FIELD_DATE
;
485 else if (!strcmp (tag
, GST_TAG_GENRE
))
486 return RB_METADATA_FIELD_GENRE
;
487 else if (!strcmp (tag
, GST_TAG_COMMENT
))
488 return RB_METADATA_FIELD_COMMENT
;
489 else if (!strcmp (tag
, GST_TAG_TRACK_NUMBER
))
490 return RB_METADATA_FIELD_TRACK_NUMBER
;
491 else if (!strcmp (tag
, GST_TAG_TRACK_COUNT
))
492 return RB_METADATA_FIELD_MAX_TRACK_NUMBER
;
493 else if (!strcmp (tag
, GST_TAG_ALBUM_VOLUME_NUMBER
))
494 return RB_METADATA_FIELD_DISC_NUMBER
;
495 else if (!strcmp (tag
, GST_TAG_ALBUM_VOLUME_COUNT
))
496 return RB_METADATA_FIELD_MAX_TRACK_NUMBER
;
497 else if (!strcmp (tag
, GST_TAG_DESCRIPTION
))
498 return RB_METADATA_FIELD_DESCRIPTION
;
499 else if (!strcmp (tag
, GST_TAG_VERSION
))
500 return RB_METADATA_FIELD_VERSION
;
501 else if (!strcmp (tag
, GST_TAG_ISRC
))
502 return RB_METADATA_FIELD_ISRC
;
503 else if (!strcmp (tag
, GST_TAG_ORGANIZATION
))
504 return RB_METADATA_FIELD_ORGANIZATION
;
505 else if (!strcmp (tag
, GST_TAG_COPYRIGHT
))
506 return RB_METADATA_FIELD_COPYRIGHT
;
507 else if (!strcmp (tag
, GST_TAG_CONTACT
))
508 return RB_METADATA_FIELD_CONTACT
;
509 else if (!strcmp (tag
, GST_TAG_LICENSE
))
510 return RB_METADATA_FIELD_LICENSE
;
511 else if (!strcmp (tag
, GST_TAG_PERFORMER
))
512 return RB_METADATA_FIELD_PERFORMER
;
513 else if (!strcmp (tag
, GST_TAG_DURATION
))
514 return RB_METADATA_FIELD_DURATION
;
515 else if (!strcmp (tag
, GST_TAG_CODEC
))
516 return RB_METADATA_FIELD_CODEC
;
517 else if (!strcmp (tag
, GST_TAG_BITRATE
))
518 return RB_METADATA_FIELD_BITRATE
;
519 else if (!strcmp (tag
, GST_TAG_TRACK_GAIN
))
520 return RB_METADATA_FIELD_TRACK_GAIN
;
521 else if (!strcmp (tag
, GST_TAG_TRACK_PEAK
))
522 return RB_METADATA_FIELD_TRACK_PEAK
;
523 else if (!strcmp (tag
, GST_TAG_ALBUM_GAIN
))
524 return RB_METADATA_FIELD_ALBUM_GAIN
;
525 else if (!strcmp (tag
, GST_TAG_ALBUM_PEAK
))
526 return RB_METADATA_FIELD_ALBUM_PEAK
;
527 #ifdef GST_TAG_MUSICBRAINZ_TRACKID
528 else if (!strcmp (tag
, GST_TAG_MUSICBRAINZ_TRACKID
))
529 return RB_METADATA_FIELD_MUSICBRAINZ_TRACKID
;
536 rb_metadata_gst_field_to_gst_tag (RBMetaDataField field
)
540 case RB_METADATA_FIELD_TITLE
:
541 return GST_TAG_TITLE
;
542 case RB_METADATA_FIELD_ARTIST
:
543 return GST_TAG_ARTIST
;
544 case RB_METADATA_FIELD_ALBUM
:
545 return GST_TAG_ALBUM
;
546 case RB_METADATA_FIELD_DATE
:
548 case RB_METADATA_FIELD_GENRE
:
549 return GST_TAG_GENRE
;
550 case RB_METADATA_FIELD_COMMENT
:
551 return GST_TAG_COMMENT
;
552 case RB_METADATA_FIELD_TRACK_NUMBER
:
553 return GST_TAG_TRACK_NUMBER
;
554 case RB_METADATA_FIELD_MAX_TRACK_NUMBER
:
555 return GST_TAG_TRACK_COUNT
;
556 case RB_METADATA_FIELD_DISC_NUMBER
:
557 return GST_TAG_ALBUM_VOLUME_NUMBER
;
558 case RB_METADATA_FIELD_MAX_DISC_NUMBER
:
559 return GST_TAG_ALBUM_VOLUME_COUNT
;
560 case RB_METADATA_FIELD_DESCRIPTION
:
561 return GST_TAG_DESCRIPTION
;
562 case RB_METADATA_FIELD_VERSION
:
563 return GST_TAG_VERSION
;
564 case RB_METADATA_FIELD_ISRC
:
566 case RB_METADATA_FIELD_ORGANIZATION
:
567 return GST_TAG_ORGANIZATION
;
568 case RB_METADATA_FIELD_COPYRIGHT
:
569 return GST_TAG_COPYRIGHT
;
570 case RB_METADATA_FIELD_CONTACT
:
571 return GST_TAG_CONTACT
;
572 case RB_METADATA_FIELD_LICENSE
:
573 return GST_TAG_LICENSE
;
574 case RB_METADATA_FIELD_PERFORMER
:
575 return GST_TAG_PERFORMER
;
576 case RB_METADATA_FIELD_DURATION
:
577 return GST_TAG_DURATION
;
578 case RB_METADATA_FIELD_CODEC
:
579 return GST_TAG_CODEC
;
580 case RB_METADATA_FIELD_BITRATE
:
581 return GST_TAG_BITRATE
;
582 case RB_METADATA_FIELD_TRACK_GAIN
:
583 return GST_TAG_TRACK_GAIN
;
584 case RB_METADATA_FIELD_TRACK_PEAK
:
585 return GST_TAG_TRACK_PEAK
;
586 case RB_METADATA_FIELD_ALBUM_GAIN
:
587 return GST_TAG_ALBUM_GAIN
;
588 case RB_METADATA_FIELD_ALBUM_PEAK
:
589 return GST_TAG_ALBUM_PEAK
;
590 #ifdef GST_TAG_MUSICBRAINZ_TRACKID
591 case RB_METADATA_FIELD_MUSICBRAINZ_TRACKID
:
592 return GST_TAG_MUSICBRAINZ_TRACKID
;
600 rb_metadata_gst_type_to_name (RBMetaData
*md
, const char *mimetype
)
603 for (i
= 0; i
< md
->priv
->supported_types
->len
; i
++) {
604 struct RBMetadataGstType
*type
= g_ptr_array_index (md
->priv
->supported_types
, i
);
605 if (!strcmp (type
->mimetype
, mimetype
))
606 return type
->human_name
;
611 static RBAddTaggerElem
612 rb_metadata_gst_type_to_tag_function (RBMetaData
*md
, const char *mimetype
)
615 for (i
= 0; i
< md
->priv
->supported_types
->len
; i
++) {
616 struct RBMetadataGstType
*type
= g_ptr_array_index (md
->priv
->supported_types
, i
);
617 if (!strcmp (type
->mimetype
, mimetype
))
618 return type
->tag_func
;
624 make_undecodable_error (RBMetaData
*md
)
626 const char *human_name
;
628 human_name
= rb_metadata_gst_type_to_name (md
, md
->priv
->type
);
629 if (human_name
== NULL
)
630 human_name
= rb_mime_get_friendly_name (md
->priv
->type
);
633 return g_strdup_printf (_("The GStreamer plugins to decode \"%s\" files cannot be found"),
636 return g_strdup_printf (_("The file contains a stream of type %s, which is not decodable"),
642 rb_metadata_gst_load_tag (const GstTagList
*list
, const gchar
*tag
, RBMetaData
*md
)
644 int count
, tem
, type
;
645 RBMetaDataField field
;
649 rb_debug ("uri: %s tag: %s ", md
->priv
->uri
, tag
);
651 count
= gst_tag_list_get_tag_size (list
, tag
);
655 tem
= rb_metadata_gst_tag_to_field (tag
);
658 field
= (RBMetaDataField
) tem
;
660 type
= rb_metadata_get_field_type (field
);
661 val
= gst_tag_list_get_value_index (list
, tag
, 0);
662 newval
= g_new0 (GValue
, 1);
663 g_value_init (newval
, type
);
664 if (!g_value_transform (val
, newval
)) {
666 rb_debug ("Could not transform tag value type %s into %s",
667 g_type_name (G_VALUE_TYPE (val
)),
668 g_type_name (G_VALUE_TYPE (newval
)));
669 g_value_unset (newval
);
675 case G_TYPE_STRING
: {
676 /* Reject invalid utf-8 strings, and then
677 * remove leading and trailing whitespace.
680 str
= g_value_dup_string (newval
);
682 if (!g_utf8_validate (str
, -1, NULL
)) {
683 rb_debug ("Got invalid UTF-8 tag data");
685 g_value_unset (newval
);
689 str
= g_strstrip (str
);
690 g_value_take_string (newval
, str
);
698 case RB_METADATA_FIELD_BITRATE
: {
699 /* GStreamer sends us bitrate in bps, but we need it in kbps*/
701 bitrate
= g_value_get_ulong (newval
);
702 g_value_set_ulong (newval
, bitrate
/1000);
706 case RB_METADATA_FIELD_DURATION
: {
707 /* GStreamer sends us duration in ns,
708 * but we need it in seconds
711 duration
= g_value_get_uint64 (val
);
712 g_value_set_ulong (newval
, duration
/(1000*1000*1000));
720 g_hash_table_insert (md
->priv
->metadata
,
721 GINT_TO_POINTER (field
),
725 #ifdef HAVE_GSTREAMER_0_8
727 rb_metadata_gst_found_tag (GObject
*pipeline
, GstElement
*source
, GstTagList
*tags
, RBMetaData
*md
)
729 gst_tag_list_foreach (tags
, (GstTagForeachFunc
) rb_metadata_gst_load_tag
, md
);
733 rb_metadata_gst_fakesink_handoff_cb (GstElement
*fakesink
, GstBuffer
*buf
, GstPad
*pad
, RBMetaData
*md
)
735 if (md
->priv
->handoff
) {
736 /* we get lots of these with decodebin. why? */
737 /* rb_debug ("caught recursive handoff!"); */
739 } else if (md
->priv
->eos
) {
740 rb_debug ("caught handoff after eos!");
744 rb_debug ("in fakesink handoff");
745 md
->priv
->handoff
= TRUE
;
749 rb_metadata_gst_error_cb (GstElement
*element
,
755 if (error
->domain
== GST_STREAM_ERROR
&&
756 error
->code
== GST_STREAM_ERROR_TYPE_NOT_FOUND
) {
757 rb_debug ("caught type not found error");
760 rb_debug ("caught error: %s ", error
->message
);
761 md
->priv
->error
= g_error_new_literal (RB_METADATA_ERROR
,
762 RB_METADATA_ERROR_GENERAL
,
768 rb_metadata_gst_eos_cb (GstElement
*element
, RBMetaData
*md
)
770 rb_debug ("caught eos");
772 rb_debug ("RENTERED EOS!");
775 gst_element_set_state (md
->priv
->sink
, GST_STATE_NULL
);
776 md
->priv
->eos
= TRUE
;
782 rb_metadata_gst_typefind_cb (GstElement
*typefind
, guint probability
, GstCaps
*caps
, RBMetaData
*md
)
784 if (!(gst_caps_is_empty (caps
) || gst_caps_is_any (caps
))) {
785 g_free (md
->priv
->type
);
786 md
->priv
->type
= g_strdup (gst_structure_get_name (gst_caps_get_structure (caps
, 0)));
787 rb_debug ("found type %s", md
->priv
->type
);
790 g_signal_handler_disconnect (typefind
, md
->priv
->typefind_cb_id
);
794 rb_metadata_gst_new_decoded_pad_cb (GstElement
*decodebin
, GstPad
*pad
, gboolean last
, RBMetaData
*md
)
797 GstStructure
*structure
;
798 const gchar
*mimetype
;
799 gboolean cancel
= FALSE
;
801 caps
= gst_pad_get_caps (pad
);
803 /* we get "ANY" caps for text/plain files etc. */
804 if (gst_caps_is_empty (caps
) || gst_caps_is_any (caps
)) {
805 rb_debug ("decoded pad with no caps or any caps. this file is boring.");
806 md
->priv
->non_audio
= TRUE
;
811 sink_pad
= gst_element_get_pad (md
->priv
->sink
, "sink");
812 gst_pad_link (pad
, sink_pad
);
814 /* is this pad audio? */
815 structure
= gst_caps_get_structure (caps
, 0);
816 mimetype
= gst_structure_get_name (structure
);
818 if (g_str_has_prefix (mimetype
, "audio/x-raw")) {
819 rb_debug ("got decoded audio pad of type %s", mimetype
);
820 } else if (g_str_has_prefix (mimetype
, "video/")) {
821 rb_debug ("got decoded video pad of type %s", mimetype
);
822 md
->priv
->non_audio
= TRUE
;
823 md
->priv
->has_video
= TRUE
;
825 /* assume anything we can get a video or text stream out of is
826 * something that should be fed to totem rather than rhythmbox.
828 rb_debug ("got decoded pad of non-audio type %s", mimetype
);
829 md
->priv
->non_audio
= TRUE
;
833 gst_caps_unref (caps
);
835 #ifdef HAVE_GSTREAMER_0_10
836 /* if this is non-audio, cancel the operation
837 * under 0.8 this causes assertion faliures when a pad with no caps in found
838 * it isn't /needed/ under 0.8, so we don't do it.
840 * This seems to cause some deadlocks with video files, so only do it
841 * when we get no/any caps.
844 gst_element_set_state (md
->priv
->pipeline
, GST_STATE_NULL
);
849 rb_metadata_gst_unknown_type_cb (GstElement
*decodebin
, GstPad
*pad
, GstCaps
*caps
, RBMetaData
*md
)
851 /* try to shortcut it a bit */
852 md
->priv
->non_audio
= TRUE
;
854 if (!gst_caps_is_empty (caps
) && !gst_caps_is_any (caps
)) {
855 GstStructure
*structure
;
856 const gchar
*mimetype
;
858 structure
= gst_caps_get_structure (caps
, 0);
859 mimetype
= gst_structure_get_name (structure
);
861 g_free (md
->priv
->type
);
862 md
->priv
->type
= g_strdup (mimetype
);
864 rb_debug ("decodebin emitted unknown type signal for %s", mimetype
);
866 rb_debug ("decodebin emitted unknown type signal");
869 #ifdef HAVE_GSTREAMER_0_10
873 msg
= make_undecodable_error (md
);
874 GST_ELEMENT_ERROR (md
->priv
->pipeline
, STREAM
, CODEC_NOT_FOUND
, ("%s", msg
), (NULL
));
880 static GstElement
*make_pipeline_element (GstElement
*pipeline
, const char *element
, GError
**error
)
882 GstElement
*elem
= gst_element_factory_make (element
, element
);
886 RB_METADATA_ERROR_MISSING_PLUGIN
,
887 _("Failed to create %s element; check your installation"),
892 gst_bin_add (GST_BIN (pipeline
), elem
);
896 #ifdef HAVE_GSTREAMER_0_10
898 rb_metadata_bus_handler (GstBus
*bus
, GstMessage
*message
, RBMetaData
*md
)
900 switch (GST_MESSAGE_TYPE (message
)) {
901 case GST_MESSAGE_EOS
:
902 rb_debug ("EOS reached");
903 md
->priv
->eos
= TRUE
;
905 case GST_MESSAGE_ERROR
:
910 gst_message_parse_error (message
, &gerror
, &debug
);
911 if (gerror
->domain
== GST_STREAM_ERROR
&&
912 gerror
->code
== GST_STREAM_ERROR_TYPE_NOT_FOUND
) {
913 rb_debug ("caught type not found error");
914 } else if (md
->priv
->error
) {
915 rb_debug ("caught error: %s, but we've already got one", gerror
->message
);
917 rb_debug ("caught error: %s ", gerror
->message
);
919 g_clear_error (&md
->priv
->error
);
920 md
->priv
->error
= g_error_new_literal (RB_METADATA_ERROR
,
921 RB_METADATA_ERROR_GENERAL
,
925 g_error_free (gerror
);
929 case GST_MESSAGE_TAG
:
933 gst_message_parse_tag (message
, &tags
);
935 gst_tag_list_foreach (tags
, (GstTagForeachFunc
) rb_metadata_gst_load_tag
, md
);
936 gst_tag_list_free (tags
);
938 const gchar
*errmsg
= "Could not retrieve tag list";
940 rb_debug ("caught error: %s ", errmsg
);
941 md
->priv
->error
= g_error_new_literal (RB_METADATA_ERROR
,
942 RB_METADATA_ERROR_GENERAL
,
948 rb_debug ("message of type %d", GST_MESSAGE_TYPE (message
));
956 rb_metadata_event_loop (RBMetaData
*md
, GstElement
*element
, gboolean block
)
959 gboolean done
= FALSE
;
961 bus
= gst_element_get_bus (element
);
962 g_return_if_fail (bus
!= NULL
);
964 while (!done
&& !md
->priv
->eos
) {
968 message
= gst_bus_poll (bus
, GST_MESSAGE_ANY
, -1);
970 message
= gst_bus_pop (bus
);
972 if (message
== NULL
) {
973 gst_object_unref (bus
);
977 done
= rb_metadata_bus_handler (bus
, message
, md
);
978 gst_message_unref (message
);
980 gst_object_unref (bus
);
985 rb_metadata_load (RBMetaData
*md
,
989 GstElement
*pipeline
= NULL
;
990 GstElement
*urisrc
= NULL
;
991 GstElement
*decodebin
= NULL
;
992 GstElement
*typefind
= NULL
;
993 gint64 file_size
= -1;
994 GstFormat file_size_format
= GST_FORMAT_BYTES
;
995 #ifdef HAVE_GSTREAMER_0_10
996 GstStateChangeReturn state_ret
;
1000 g_free (md
->priv
->uri
);
1001 md
->priv
->uri
= NULL
;
1002 g_free (md
->priv
->type
);
1003 md
->priv
->type
= NULL
;
1004 md
->priv
->error
= NULL
;
1005 md
->priv
->eos
= FALSE
;
1006 md
->priv
->handoff
= FALSE
;
1007 md
->priv
->non_audio
= FALSE
;
1008 md
->priv
->has_video
= FALSE
;
1010 if (md
->priv
->pipeline
) {
1011 gst_object_unref (GST_OBJECT (md
->priv
->pipeline
));
1012 md
->priv
->pipeline
= NULL
;
1018 rb_debug ("loading metadata for uri: %s", uri
);
1019 md
->priv
->uri
= g_strdup (uri
);
1021 if (md
->priv
->metadata
)
1022 g_hash_table_destroy (md
->priv
->metadata
);
1023 md
->priv
->metadata
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
1024 NULL
, (GDestroyNotify
) free_gvalue
);
1026 /* The main tagfinding pipeline looks like this:
1027 * gnomevfssrc ! decodebin ! fakesink
1029 * filesrc ! decodebin ! fakesink
1031 * but we can only link the fakesink in when the decodebin
1032 * creates an audio source pad. we do this in the 'new-decoded-pad'
1035 pipeline
= gst_pipeline_new ("pipeline");
1037 urisrc
= gst_element_make_from_uri (GST_URI_SRC
, uri
, "urisrc");
1038 if (urisrc
== NULL
) {
1041 RB_METADATA_ERROR_MISSING_PLUGIN
,
1042 _("Failed to create a source element; check your installation"));
1043 rb_debug ("missing an element to load the uri, sadly");
1046 gst_bin_add (GST_BIN (pipeline
), urisrc
);
1048 decodebin
= make_pipeline_element (pipeline
, "decodebin", error
);
1049 md
->priv
->sink
= make_pipeline_element (pipeline
, "fakesink", error
);
1050 if (!(urisrc
&& decodebin
&& md
->priv
->sink
)) {
1051 rb_debug ("missing an element, sadly");
1055 #ifdef HAVE_GSTREAMER_0_8
1056 g_object_set (G_OBJECT (md
->priv
->sink
), "signal-handoffs", TRUE
, NULL
);
1058 g_signal_connect_object (pipeline
, "error", G_CALLBACK (rb_metadata_gst_error_cb
), md
, 0);
1059 g_signal_connect_object (pipeline
, "found-tag", G_CALLBACK (rb_metadata_gst_found_tag
), md
, 0);
1061 g_signal_connect_object (md
->priv
->sink
, "handoff", G_CALLBACK (rb_metadata_gst_fakesink_handoff_cb
), md
, 0);
1062 g_signal_connect_object (md
->priv
->sink
, "eos", G_CALLBACK (rb_metadata_gst_eos_cb
), md
, 0);
1064 g_signal_connect_object (decodebin
, "new-decoded-pad", G_CALLBACK (rb_metadata_gst_new_decoded_pad_cb
), md
, 0);
1065 g_signal_connect_object (decodebin
, "unknown-type", G_CALLBACK (rb_metadata_gst_unknown_type_cb
), md
, 0);
1067 /* locate the decodebin's typefind, so we can get the have_type signal too.
1068 * this is kind of nasty, since it relies on an essentially arbitrary string
1069 * in the decodebin code not changing. the alternative is to have our own
1070 * typefind instance before the decodebin. it might not like that.
1072 typefind
= gst_bin_get_by_name (GST_BIN (decodebin
), "typefind");
1073 g_assert (typefind
!= NULL
);
1074 md
->priv
->typefind_cb_id
= g_signal_connect_object (typefind
,
1076 G_CALLBACK (rb_metadata_gst_typefind_cb
),
1079 gst_object_unref (GST_OBJECT (typefind
));
1081 gst_element_link (urisrc
, decodebin
);
1083 md
->priv
->pipeline
= pipeline
;
1084 #ifdef HAVE_GSTREAMER_0_8
1085 gst_element_set_state (pipeline
, GST_STATE_PLAYING
);
1086 while (gst_bin_iterate (GST_BIN (pipeline
))
1087 && md
->priv
->error
== NULL
1088 && !md
->priv
->handoff
1092 if (md
->priv
->handoff
) {
1094 #ifdef HAVE_GSTREAMER_0_10
1095 rb_debug ("going to PAUSED for metadata, uri: %s", uri
);
1096 state_ret
= gst_element_set_state (pipeline
, GST_STATE_PAUSED
);
1098 while (state_ret
== GST_STATE_CHANGE_ASYNC
&&
1100 !md
->priv
->non_audio
&&
1101 change_timeout
> 0) {
1103 rb_debug ("element state changing asynchronously: %d, %d", state_ret
, state
);
1104 state_ret
= gst_element_get_state (GST_ELEMENT (pipeline
),
1105 &state
, NULL
, 1 * GST_SECOND
);
1108 if (state_ret
!= GST_STATE_CHANGE_SUCCESS
) {
1109 rb_debug ("failed to go to PAUSED for %s", uri
);
1110 rb_metadata_event_loop (md
, GST_ELEMENT (pipeline
), FALSE
);
1111 if (!md
->priv
->non_audio
&& md
->priv
->error
== NULL
)
1114 RB_METADATA_ERROR_INTERNAL
,
1115 _("GStreamer error: failed to change state"));
1117 rb_debug ("gone to PAUSED for %s", uri
);
1119 if (state_ret
== GST_STATE_CHANGE_SUCCESS
) {
1120 /* Post application specific message so we'll know when to stop
1121 * the message loop */
1123 bus
= gst_element_get_bus (GST_ELEMENT (pipeline
));
1126 gst_message_new_application (GST_OBJECT (pipeline
), NULL
));
1127 gst_object_unref (bus
);
1130 /* Poll the bus for messages */
1131 rb_metadata_event_loop (md
, GST_ELEMENT (pipeline
), FALSE
);
1133 /* We caught the first buffer(0.8) or went to PAUSED (0.10),
1134 * which means the decoder should have read all
1135 * of the metadata, and should know the length now.
1137 if (g_hash_table_lookup (md
->priv
->metadata
, GINT_TO_POINTER (RB_METADATA_FIELD_DURATION
)) == NULL
) {
1138 GstFormat format
= GST_FORMAT_TIME
;
1142 #ifdef HAVE_GSTREAMER_0_8
1143 if (gst_element_query (md
->priv
->sink
, GST_QUERY_TOTAL
, &format
, &length
)) {
1145 #ifdef HAVE_GSTREAMER_0_10
1146 if (gst_element_query_duration (md
->priv
->sink
, &format
, &length
)) {
1147 g_assert (format
== GST_FORMAT_TIME
);
1149 newval
= g_new0 (GValue
, 1);
1151 rb_debug ("duration query succeeded");
1153 g_value_init (newval
, G_TYPE_ULONG
);
1154 /* FIXME - use guint64 for duration? */
1155 g_value_set_ulong (newval
, (long) (length
/ GST_SECOND
));
1156 g_hash_table_insert (md
->priv
->metadata
, GINT_TO_POINTER (RB_METADATA_FIELD_DURATION
),
1159 rb_debug ("duration query failed!");
1163 #ifdef HAVE_GSTREAMER_0_8
1164 else if (md
->priv
->eos
) {
1165 g_warning ("caught eos without handoff!");
1169 /* Get the file size, since it might be interesting, and return
1170 * the pipeline to NULL state.
1172 #ifdef HAVE_GSTREAMER_0_8
1173 gst_element_query (urisrc
, GST_QUERY_TOTAL
, &file_size_format
, &file_size
);
1174 gst_element_set_state (pipeline
, GST_STATE_NULL
);
1176 #ifdef HAVE_GSTREAMER_0_10
1177 if (gst_element_query_duration (urisrc
, &file_size_format
, &file_size
))
1178 g_assert (file_size_format
== GST_FORMAT_BYTES
);
1180 state_ret
= gst_element_set_state (pipeline
, GST_STATE_NULL
);
1181 if (state_ret
== GST_STATE_CHANGE_ASYNC
) {
1182 g_warning ("Failed to return metadata reader to NULL state");
1184 md
->priv
->handoff
= (state_ret
== GST_STATE_CHANGE_SUCCESS
);
1187 /* report errors for various failure cases.
1188 * these don't include the URI as the import errors source
1189 * already displays it.
1191 if (md
->priv
->non_audio
|| !md
->priv
->handoff
) {
1192 gboolean ignore
= FALSE
;
1195 if (md
->priv
->has_video
) {
1198 for (i
= 0; i
< G_N_ELEMENTS (ignore_mime_types
); i
++) {
1199 if (g_str_has_prefix (md
->priv
->type
, ignore_mime_types
[i
])) {
1207 char *msg
= make_undecodable_error (md
);
1210 RB_METADATA_ERROR_NOT_AUDIO
,
1214 /* we don't need an error message here (it'll never be
1215 * displayed). using NULL causes crashes with some C
1216 * libraries, and gcc doesn't like zero-length format
1217 * strings, so we use a single space instead.
1221 RB_METADATA_ERROR_NOT_AUDIO_IGNORE
,
1224 } else if (md
->priv
->error
) {
1225 g_propagate_error (error
, md
->priv
->error
);
1226 } else if (!md
->priv
->type
) {
1227 /* ignore really small files that can't be identified */
1228 gint error_code
= RB_METADATA_ERROR_UNRECOGNIZED
;
1229 if (file_size
> 0 && file_size
< REALLY_SMALL_FILE_SIZE
) {
1230 rb_debug ("ignoring %s because it's too small to care about", md
->priv
->uri
);
1231 error_code
= RB_METADATA_ERROR_NOT_AUDIO_IGNORE
;
1234 g_clear_error (error
);
1238 _("The MIME type of the file could not be identified"));
1240 /* yay, it worked */
1241 rb_debug ("successfully read metadata for %s", uri
);
1243 /* it doesn't matter if we don't recognise the format,
1244 * as long as gstreamer can play it, we can put it in
1247 if (!rb_metadata_gst_type_to_name (md
, md
->priv
->type
)) {
1248 rb_debug ("we don't know what type %s (from file %s) is, but we'll play it anyway",
1249 md
->priv
->type
, uri
);
1254 if (pipeline
!= NULL
)
1255 gst_object_unref (GST_OBJECT (pipeline
));
1256 md
->priv
->pipeline
= NULL
;
1260 rb_metadata_can_save (RBMetaData
*md
, const char *mimetype
)
1262 #ifdef ENABLE_TAG_WRITING
1263 return rb_metadata_gst_type_to_tag_function (md
, mimetype
) != NULL
;
1270 rb_metadata_gst_add_tag_data (gpointer key
, const GValue
*val
, RBMetaData
*md
)
1272 RBMetaDataField field
= GPOINTER_TO_INT (key
);
1273 const char *tag
= rb_metadata_gst_field_to_gst_tag (field
);
1275 /* don't write this out */
1276 if (field
== RB_METADATA_FIELD_DURATION
)
1280 if (field
== RB_METADATA_FIELD_DATE
&& g_value_get_ulong (val
) == 0) {
1281 /* we should ask gstreamer to remove the tag,
1282 * but there is no easy way of doing so
1285 GValue newval
= {0,};
1287 g_value_init (&newval
, gst_tag_get_type (tag
));
1288 if (g_value_transform (val
, &newval
)) {
1289 rb_debug("Setting %s",tag
);
1291 gst_tag_list_add_values (md
->priv
->tags
,
1292 GST_TAG_MERGE_APPEND
,
1296 g_value_unset (&newval
);
1302 rb_metadata_file_valid (char *original
, char *newfile
)
1304 RBMetaData
*md
= rb_metadata_new ();
1305 GError
*error
= NULL
;
1308 rb_metadata_load (md
, newfile
, &error
);
1309 ret
= (error
== NULL
);
1311 /* TODO: check that the tags are correct? */
1314 g_error_free (error
);
1315 g_object_unref (G_OBJECT (md
));
1320 rb_metadata_save (RBMetaData
*md
, GError
**error
)
1322 GstElement
*pipeline
= NULL
;
1323 GstElement
*gnomevfssrc
= NULL
;
1324 GstElement
*retag_end
= NULL
; /* the last elemet after retagging subpipeline */
1325 const char *plugin_name
= NULL
;
1326 char *tmpname
= NULL
;
1327 GnomeVFSHandle
*handle
= NULL
;
1328 GnomeVFSResult result
;
1329 RBAddTaggerElem add_tagger_func
;
1331 g_return_if_fail (md
->priv
->uri
!= NULL
);
1332 g_return_if_fail (md
->priv
->type
!= NULL
);
1334 rb_debug ("saving metadata for uri: %s", md
->priv
->uri
);
1336 if ((result
= rb_uri_mkstemp (md
->priv
->uri
, &tmpname
, &handle
)) != GNOME_VFS_OK
)
1339 pipeline
= gst_pipeline_new ("pipeline");
1340 md
->priv
->pipeline
= pipeline
;
1342 #ifdef HAVE_GSTREAMER_0_8
1343 g_signal_connect_object (pipeline
, "error", G_CALLBACK (rb_metadata_gst_error_cb
), md
, 0);
1347 plugin_name
= "gnomevfssrc";
1348 if (!(gnomevfssrc
= gst_element_factory_make (plugin_name
, plugin_name
)))
1349 goto missing_plugin
;
1350 gst_bin_add (GST_BIN (pipeline
), gnomevfssrc
);
1351 g_object_set (G_OBJECT (gnomevfssrc
), "location", md
->priv
->uri
, NULL
);
1354 plugin_name
= "gnomevfssink";
1355 if (!(md
->priv
->sink
= gst_element_factory_make (plugin_name
, plugin_name
)))
1356 goto missing_plugin
;
1358 g_object_set (G_OBJECT (md
->priv
->sink
), "handle", handle
, NULL
);
1359 #if HAVE_GSTREAMER_0_8
1360 g_signal_connect_object (md
->priv
->sink
, "eos", G_CALLBACK (rb_metadata_gst_eos_cb
), md
, 0);
1363 md
->priv
->tags
= gst_tag_list_new ();
1364 g_hash_table_foreach (md
->priv
->metadata
,
1365 (GHFunc
) rb_metadata_gst_add_tag_data
,
1368 /* Tagger element(s) */
1369 add_tagger_func
= rb_metadata_gst_type_to_tag_function (md
, md
->priv
->type
);
1371 if (!add_tagger_func
) {
1374 RB_METADATA_ERROR_UNSUPPORTED
,
1375 _("Unsupported file type: %s"), md
->priv
->type
);
1379 retag_end
= add_tagger_func (md
, gnomevfssrc
);
1383 RB_METADATA_ERROR_UNSUPPORTED
,
1384 _("Unable to create tag-writing elements"));
1388 gst_bin_add (GST_BIN (pipeline
), md
->priv
->sink
);
1389 gst_element_link_many (retag_end
, md
->priv
->sink
, NULL
);
1391 gst_element_set_state (pipeline
, GST_STATE_PLAYING
);
1393 #ifdef HAVE_GSTREAMER_0_8
1394 while (gst_bin_iterate (GST_BIN (pipeline
))
1395 && md
->priv
->error
== NULL
1398 gst_element_set_state (pipeline
, GST_STATE_NULL
);
1400 #ifdef HAVE_GSTREAMER_0_10
1401 rb_metadata_event_loop (md
, GST_ELEMENT (pipeline
), TRUE
);
1402 if (gst_element_set_state (pipeline
, GST_STATE_NULL
) == GST_STATE_CHANGE_ASYNC
) {
1403 if (gst_element_get_state (pipeline
, NULL
, NULL
, 3 * GST_SECOND
) != GST_STATE_CHANGE_SUCCESS
) {
1406 RB_METADATA_ERROR_INTERNAL
,
1407 _("Timeout while setting pipeline to NULL"));
1413 if (md
->priv
->error
) {
1414 g_propagate_error (error
, md
->priv
->error
);
1417 if (handle
!= NULL
) {
1418 if ((result
= gnome_vfs_close (handle
)) != GNOME_VFS_OK
)
1422 /* check to ensure the file isn't corrupt */
1423 if (!rb_metadata_file_valid (md
->priv
->uri
, tmpname
)) {
1426 RB_METADATA_ERROR_INTERNAL
,
1427 _("File corrupted during write"));
1431 if ((result
= gnome_vfs_move (tmpname
, md
->priv
->uri
, TRUE
)) != GNOME_VFS_OK
)
1439 RB_METADATA_ERROR_GNOMEVFS
,
1441 gnome_vfs_result_to_string (result
));
1446 RB_METADATA_ERROR_MISSING_PLUGIN
,
1447 _("Failed to create %s element; check your installation"),
1451 gnome_vfs_close (handle
);
1452 if (tmpname
!= NULL
)
1453 gnome_vfs_unlink (tmpname
);
1457 gst_tag_list_free (md
->priv
->tags
);
1458 md
->priv
->tags
= NULL
;
1460 if (pipeline
!= NULL
)
1461 gst_object_unref (GST_OBJECT (pipeline
));
1462 md
->priv
->pipeline
= NULL
;
1466 rb_metadata_get (RBMetaData
*md
, RBMetaDataField field
,
1470 if ((val
= g_hash_table_lookup (md
->priv
->metadata
,
1471 GINT_TO_POINTER (field
)))) {
1472 g_value_init (ret
, G_VALUE_TYPE (val
));
1473 g_value_copy (val
, ret
);
1480 rb_metadata_get_mime (RBMetaData
*md
)
1482 return md
->priv
->type
;
1486 rb_metadata_set (RBMetaData
*md
, RBMetaDataField field
,
1492 if (rb_metadata_gst_field_to_gst_tag (field
) == NULL
) {
1496 type
= rb_metadata_get_field_type (field
);
1497 g_return_val_if_fail (type
== G_VALUE_TYPE (val
), FALSE
);
1499 newval
= g_new0 (GValue
, 1);
1500 g_value_init (newval
, type
);
1501 g_value_copy (val
, newval
);
1503 g_hash_table_insert (md
->priv
->metadata
, GINT_TO_POINTER (field
),