1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * arch-tag: Implementation of GStreamer encoding backend
5 * Based on Sound-Juicer's ripping code
7 * Copyright (C) 2003 Ross Burton <ross@burtonini.com>
8 * Copyright (C) 2006 James Livingston <jrl@ids.org.au>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public
21 * License along with this program; if not, write to the
22 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23 * Boston, MA 02110-1301 USA.
28 #include <glib/gi18n.h>
29 #include <libgnomevfs/gnome-vfs-utils.h>
30 #include <libgnomevfs/gnome-vfs-uri.h>
31 #include <libgnomevfs/gnome-vfs-ops.h>
34 #include <profiles/gnome-media-profiles.h>
37 #ifdef HAVE_GSTREAMER_0_10
38 #include <gst/tag/tag.h>
42 #include "eel-gconf-extensions.h"
43 #include "rb-preferences.h"
44 #include "rb-encoder.h"
45 #include "rb-encoder-gst.h"
48 #ifdef HAVE_GSTREAMER_0_8
49 #define GstStateChangeReturn GstElementStateReturn
50 #define GstState GstElementState
51 #define GST_STATE_CHANGE_FAILURE GST_STATE_FAILURE
52 #define gst_caps_unref gst_caps_free
55 static void rb_encoder_gst_class_init (RBEncoderGstClass
*klass
);
56 static void rb_encoder_gst_init (RBEncoderGst
*encoder
);
57 static void rb_encoder_gst_finalize (GObject
*object
);
58 static void rb_encoder_init (RBEncoderIface
*iface
);
60 struct _RBEncoderGstPrivate
{
67 gboolean error_emitted
;
68 gboolean completion_emitted
;
74 G_DEFINE_TYPE_WITH_CODE(RBEncoderGst
, rb_encoder_gst
, G_TYPE_OBJECT
,
75 G_IMPLEMENT_INTERFACE(RB_TYPE_ENCODER
,
77 #define RB_ENCODER_GST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_ENCODER_GST, RBEncoderGstPrivate))
79 static gboolean
rb_encoder_gst_encode (RBEncoder
*encoder
,
82 const char *mime_type
);
83 static void rb_encoder_gst_cancel (RBEncoder
*encoder
);
84 static void rb_encoder_gst_emit_completed (RBEncoderGst
*encoder
);
87 rb_encoder_gst_class_init (RBEncoderGstClass
*klass
)
89 GObjectClass
*object_class
= (GObjectClass
*) klass
;
91 object_class
->finalize
= rb_encoder_gst_finalize
;
93 g_type_class_add_private (klass
, sizeof (RBEncoderGstPrivate
));
97 rb_encoder_gst_init (RBEncoderGst
*encoder
)
99 encoder
->priv
= RB_ENCODER_GST_GET_PRIVATE (encoder
);
103 rb_encoder_init (RBEncoderIface
*iface
)
105 iface
->encode
= rb_encoder_gst_encode
;
106 iface
->cancel
= rb_encoder_gst_cancel
;
110 rb_encoder_gst_finalize (GObject
*object
)
112 RBEncoderGst
*encoder
= RB_ENCODER_GST (object
);
114 if (encoder
->priv
->progress_id
!= 0)
115 g_source_remove (encoder
->priv
->progress_id
);
117 if (encoder
->priv
->pipeline
) {
118 gst_element_set_state (encoder
->priv
->pipeline
, GST_STATE_NULL
);
119 g_object_unref (encoder
->priv
->pipeline
);
120 encoder
->priv
->pipeline
= NULL
;
123 G_OBJECT_CLASS (rb_encoder_gst_parent_class
)->finalize (object
);
127 rb_encoder_gst_new (void)
129 return RB_ENCODER (g_object_new (RB_TYPE_ENCODER_GST
, NULL
));
133 rb_encoder_gst_emit_error (RBEncoderGst
*encoder
, GError
*error
)
135 encoder
->priv
->error_emitted
= TRUE
;
136 _rb_encoder_emit_error (RB_ENCODER (encoder
), error
);
140 rb_encoder_gst_emit_completed (RBEncoderGst
*encoder
)
142 GError
*error
= NULL
;
144 g_return_if_fail (encoder
->priv
->completion_emitted
== FALSE
);
146 if (encoder
->priv
->progress_id
!= 0)
147 g_source_remove (encoder
->priv
->progress_id
);
149 /* emit an error if no audio pad has been found and it wasn't due to an
151 if (encoder
->priv
->error_emitted
== FALSE
&&
152 encoder
->priv
->transcoding
&&
153 encoder
->priv
->decoded_pads
== 0) {
154 rb_debug ("received EOS and no decoded pad");
157 RB_ENCODER_ERROR_FORMAT_UNSUPPORTED
,
158 "no decodable audio pad found");
160 rb_encoder_gst_emit_error (encoder
, error
);
161 g_error_free (error
);
164 encoder
->priv
->completion_emitted
= TRUE
;
165 _rb_encoder_emit_completed (RB_ENCODER (encoder
));
168 #ifdef HAVE_GSTREAMER_0_10
170 bus_watch_cb (GstBus
*bus
, GstMessage
*message
, gpointer data
)
172 RBEncoderGst
*encoder
= RB_ENCODER_GST (data
);
174 GError
*error
= NULL
;
176 /* ref ourselves, in case one of the signal handler unrefs us */
177 g_object_ref (G_OBJECT (encoder
));
179 switch (GST_MESSAGE_TYPE (message
)) {
180 case GST_MESSAGE_ERROR
:
181 gst_message_parse_error (message
, &error
, &string
);
182 rb_encoder_gst_emit_error (encoder
, error
);
183 rb_debug ("received error %s", string
);
184 g_error_free (error
);
187 rb_encoder_cancel (RB_ENCODER (encoder
));
190 case GST_MESSAGE_WARNING
:
191 gst_message_parse_warning (message
, &error
, &string
);
192 rb_debug ("received warning %s", string
);
193 g_error_free (error
);
197 case GST_MESSAGE_EOS
:
198 rb_debug ("received EOS");
200 gst_element_set_state (encoder
->priv
->pipeline
, GST_STATE_NULL
);
202 rb_encoder_gst_emit_completed (encoder
);
204 g_object_unref (encoder
->priv
->pipeline
);
205 encoder
->priv
->pipeline
= NULL
;
209 rb_debug ("message of type %s", gst_message_type_get_name (GST_MESSAGE_TYPE (message
)));
213 g_object_unref (G_OBJECT (encoder
));
218 #ifdef HAVE_GSTREAMER_0_8
220 gst_eos_cb (GstElement
*element
, RBEncoderGst
*encoder
)
222 rb_debug ("received EOS");
224 gst_element_set_state (encoder
->priv
->pipeline
, GST_STATE_NULL
);
226 rb_encoder_gst_emit_completed (encoder
);
228 g_object_unref (encoder
->priv
->pipeline
);
229 encoder
->priv
->pipeline
= NULL
;
233 gst_error_cb (GstElement
*element
,
237 RBEncoderGst
*encoder
)
239 rb_encoder_gst_emit_error (encoder
, error
);
240 rb_debug ("received error %s", debug
);
242 rb_encoder_cancel (RB_ENCODER (encoder
));
248 progress_timeout_cb (RBEncoderGst
*encoder
)
252 static GstFormat format
= GST_FORMAT_TIME
;
255 if (encoder
->priv
->pipeline
== NULL
)
258 #ifdef HAVE_GSTREAMER_0_10
259 gst_element_get_state (encoder
->priv
->pipeline
, &state
, NULL
, GST_CLOCK_TIME_NONE
);
260 if (state
!= GST_STATE_PLAYING
)
263 if (!gst_element_query_position (encoder
->priv
->pipeline
, &format
, &nanos
)) {
264 g_warning ("Could not get current track position");
267 #elif HAVE_GSTREAMER_0_8
268 state
= gst_element_get_state (encoder
->priv
->pipeline
);
269 if (state
!= GST_STATE_PLAYING
)
272 if (!gst_element_query (encoder
->priv
->pipeline
, GST_QUERY_POSITION
, &format
, &nanos
)) {
273 g_warning ("Could not get current track position");
278 secs
= nanos
/ GST_SECOND
;
279 rb_debug ("encoding progress at %d out of %lu", secs
, encoder
->priv
->total_length
);
280 _rb_encoder_emit_progress (RB_ENCODER (encoder
), ((double)secs
) / encoder
->priv
->total_length
);
286 start_pipeline (RBEncoderGst
*encoder
, GError
**error
)
288 GstStateChangeReturn result
;
289 #ifdef HAVE_GSTREAMER_0_10
292 g_return_val_if_fail (encoder
->priv
->pipeline
!= NULL
, FALSE
);
294 bus
= gst_pipeline_get_bus (GST_PIPELINE (encoder
->priv
->pipeline
));
295 gst_bus_add_watch (bus
, bus_watch_cb
, encoder
);
297 result
= gst_element_set_state (encoder
->priv
->pipeline
, GST_STATE_PLAYING
);
298 #elif HAVE_GSTREAMER_0_8
300 g_return_val_if_fail (encoder
->priv
->pipeline
!= NULL
, FALSE
);
302 g_signal_connect_object (G_OBJECT (encoder
->priv
->pipeline
),
303 "error", G_CALLBACK (gst_error_cb
),
305 g_signal_connect_object (G_OBJECT (encoder
->priv
->pipeline
),
306 "eos", G_CALLBACK (gst_eos_cb
),
308 result
= gst_element_set_state (encoder
->priv
->pipeline
, GST_STATE_PLAYING
);
311 if (result
!= GST_STATE_CHANGE_FAILURE
) {
312 /* start reporting progress */
313 if (encoder
->priv
->total_length
> 0) {
314 _rb_encoder_emit_progress (RB_ENCODER (encoder
), 0.0);
315 encoder
->priv
->progress_id
= g_timeout_add (250, (GSourceFunc
)progress_timeout_cb
, encoder
);
317 _rb_encoder_emit_progress (RB_ENCODER (encoder
), -1);
321 return (result
!= GST_STATE_CHANGE_FAILURE
);
324 #ifdef HAVE_GSTREAMER_0_8
325 /* this is basically what the function in 0.10 does */
327 rb_gst_bin_find_unconnected_pad (GstBin
*bin
, GstPadDirection dir
)
329 const GList
*elements
, *el
;
331 elements
= gst_bin_get_list (GST_BIN (bin
));
332 for (el
= elements
; el
!= NULL
; el
= el
->next
) {
333 GstElement
*element
= GST_ELEMENT (el
->data
);
334 const GList
*pads
, *pl
;
336 pads
= gst_element_get_pad_list (element
);
338 for (pl
= pads
; pl
!= NULL
; pl
= pl
->next
) {
339 GstPad
*pad
= GST_PAD (pl
->data
);
341 if (!GST_PAD_IS_LINKED (pad
) && GST_PAD_DIRECTION (pad
) == dir
)
349 #define gst_bin_find_unconnected_pad rb_gst_bin_find_unconnected_pad
351 const char *GST_ENCODING_PROFILE
= "audioscale ! audioconvert ! %s";
352 #elif HAVE_GSTREAMER_0_10
353 const char *GST_ENCODING_PROFILE
= "audioresample ! audioconvert ! %s";
357 add_encoding_pipeline (RBEncoderGst
*encoder
,
358 GMAudioProfile
*profile
,
361 GstElement
*queue
, *encoding_bin
, *queue2
;
365 queue
= gst_element_factory_make ("queue", NULL
);
368 gst_bin_add (GST_BIN (encoder
->priv
->pipeline
), queue
);
370 queue2
= gst_element_factory_make ("queue", NULL
);
373 gst_bin_add (GST_BIN (encoder
->priv
->pipeline
), queue2
);
375 /* Nice big buffers... */
376 g_object_set (queue
, "max-size-time", 120 * GST_SECOND
, NULL
);
378 tmp
= g_strdup_printf (GST_ENCODING_PROFILE
, gm_audio_profile_get_pipeline (profile
));
379 encoding_bin
= GST_ELEMENT (gst_parse_launch (tmp
, error
));
382 if (encoding_bin
== NULL
)
385 /* find pads and ghost them if necessary */
386 if ((pad
= gst_bin_find_unconnected_pad (GST_BIN (encoding_bin
), GST_PAD_SRC
)))
387 gst_element_add_pad (encoding_bin
, gst_ghost_pad_new ("src", pad
));
388 if ((pad
= gst_bin_find_unconnected_pad (GST_BIN (encoding_bin
), GST_PAD_SINK
)))
389 gst_element_add_pad (encoding_bin
, gst_ghost_pad_new ("sink", pad
));
391 gst_bin_add (GST_BIN (encoder
->priv
->pipeline
), encoding_bin
);
393 if (gst_element_link_many (queue
, encoding_bin
, queue2
, NULL
) == FALSE
)
396 /* store the first element of the encoding graph. new_decoded_pad_cb
397 * will link to this once a decoded pad is found */
398 encoder
->priv
->enc
= queue
;
404 add_tags_from_entry (RBEncoderGst
*encoder
,
405 RhythmDBEntry
*entry
,
409 gboolean result
= TRUE
;
412 tags
= gst_tag_list_new ();
414 gst_tag_list_add (tags
, GST_TAG_MERGE_REPLACE_ALL
,
415 /* TODO: compute replay-gain */
416 GST_TAG_TITLE
, rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_TITLE
),
417 GST_TAG_ARTIST
, rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ARTIST
),
418 GST_TAG_TRACK_NUMBER
, rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_TRACK_NUMBER
),
419 GST_TAG_ALBUM_VOLUME_NUMBER
, rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_DISC_NUMBER
),
420 GST_TAG_ALBUM
, rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ALBUM
),
421 GST_TAG_GENRE
, rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_GENRE
),
422 GST_TAG_ENCODER
, "Rhythmbox",
423 GST_TAG_ENCODER_VERSION
, VERSION
,
426 day
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_DATE
);
431 date
= g_date_new_julian (day
);
432 gst_tag_list_add (tags
, GST_TAG_MERGE_APPEND
,
437 #ifdef GST_TAG_MUSICBRAINZ_TRACKID
438 if (rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_MUSICBRAINZ_TRACKID
)) {
439 gst_tag_list_add (tags
, GST_TAG_MERGE_APPEND
,
440 GST_TAG_MUSICBRAINZ_TRACKID
, rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_MUSICBRAINZ_TRACKID
),
445 #ifdef HAVE_GSTREAMER_0_10
450 iter
= gst_bin_iterate_all_by_interface (GST_BIN (encoder
->priv
->pipeline
), GST_TYPE_TAG_SETTER
);
453 GstTagSetter
*tagger
= NULL
;
454 GstTagSetter
**tagger_ptr
= &tagger
;
456 switch (gst_iterator_next (iter
, (gpointer
*)tagger_ptr
)) {
457 case GST_ITERATOR_OK
:
458 gst_tag_setter_merge_tags (tagger
, tags
, GST_TAG_MERGE_REPLACE_ALL
);
460 case GST_ITERATOR_RESYNC
:
461 gst_iterator_resync (iter
);
463 case GST_ITERATOR_ERROR
:
465 RB_ENCODER_ERROR
, RB_ENCODER_ERROR_INTERNAL
,
466 "Could not add tags to tag-setter");
470 case GST_ITERATOR_DONE
:
476 gst_object_unref (tagger
);
478 gst_iterator_free (iter
);
480 #elif HAVE_GSTREAMER_0_8
484 tagger
= gst_bin_get_by_interface (GST_BIN (encoder
->priv
->pipeline
), GST_TYPE_TAG_SETTER
);
486 gst_tag_setter_merge (GST_TAG_SETTER (tagger
), tags
, GST_TAG_MERGE_REPLACE_ALL
);
490 gst_tag_list_free (tags
);
495 gnomevfs_allow_overwrite_cb (GstElement
*element
, GnomeVFSURI
*uri
, RBEncoderGst
*encoder
)
502 name
= gnome_vfs_uri_to_string (uri
, GNOME_VFS_URI_HIDE_USER_NAME
| GNOME_VFS_URI_HIDE_PASSWORD
);
503 display_name
= gnome_vfs_format_uri_for_display (name
);
505 dialog
= gtk_message_dialog_new (NULL
, 0,
506 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_YES_NO
,
507 _("Do you want to overwrite the file \"%s\"?"),
509 response
= gtk_dialog_run (GTK_DIALOG (dialog
));
510 gtk_widget_destroy (dialog
);
512 g_free (display_name
);
515 return (response
== GTK_RESPONSE_YES
);
519 new_decoded_pad_cb (GstElement
*decodebin
,
520 GstPad
*new_pad
, gboolean arg1
,
521 RBEncoderGst
*encoder
)
527 rb_debug ("new decoded pad");
529 /* transcode only the first audio track. multitrack audio files are not
530 * so common anyway */
531 if (encoder
->priv
->decoded_pads
> 0)
534 caps
= gst_pad_get_caps (new_pad
);
535 caps_string
= gst_caps_to_string (caps
);
536 gst_caps_unref (caps
);
538 /* only process audio data */
539 if (strncmp (caps_string
, "audio/", 6) == 0) {
540 encoder
->priv
->decoded_pads
++;
541 enc_sinkpad
= gst_element_get_pad (encoder
->priv
->enc
,
543 if (gst_pad_link (new_pad
, enc_sinkpad
) != GST_PAD_LINK_OK
)
544 rb_debug ("error linking pads");
547 g_free (caps_string
);
551 add_decoding_pipeline (RBEncoderGst
*encoder
,
554 GstElement
*decodebin
;
556 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, NULL
);
558 encoder
->priv
->transcoding
= TRUE
;
559 decodebin
= gst_element_factory_make ("decodebin", NULL
);
560 if (decodebin
== NULL
) {
563 RB_ENCODER_ERROR_INTERNAL
,
564 "Could not create decodebin");
569 gst_bin_add (GST_BIN (encoder
->priv
->pipeline
), decodebin
);
571 g_signal_connect_object (decodebin
,
573 G_CALLBACK (new_decoded_pad_cb
),
580 attach_output_pipeline (RBEncoderGst
*encoder
,
587 sink
= gst_element_make_from_uri (GST_URI_SINK
, dest
, "sink");
589 /* handle overwriting if we are using gnomevfssink
590 * it would be nice if GST had an interface for sinks with thi, but it doesn't
592 if (g_type_is_a (G_OBJECT_TYPE (sink
), g_type_from_name ("GstGnomeVFSSink"))) {
593 g_signal_connect_object (G_OBJECT (sink
),
594 "allow-overwrite", G_CALLBACK (gnomevfs_allow_overwrite_cb
),
598 gst_bin_add (GST_BIN (encoder
->priv
->pipeline
), sink
);
599 gst_element_link (end
, sink
);
605 encoder_match_mime (GstElement
*encoder
, const gchar
*mime_type
)
609 GstStructure
*structure
;
610 const gchar
*pad_mime
;
613 srcpad
= gst_element_get_pad (encoder
, "src");
614 caps
= gst_pad_get_caps (srcpad
);
615 structure
= gst_caps_get_structure (caps
, 0);
616 pad_mime
= gst_structure_get_name (structure
);
617 match
= strcmp (mime_type
, pad_mime
) == 0;
618 gst_caps_unref (caps
);
619 gst_object_unref (GST_OBJECT (srcpad
));
625 profile_bin_find_encoder (GstBin
*profile_bin
)
627 #ifdef HAVE_GSTREAMER_0_10
628 GstElementFactory
*factory
;
629 GstElement
*encoder
= NULL
;
631 gboolean done
= FALSE
;
633 iter
= gst_bin_iterate_elements (profile_bin
);
637 switch (gst_iterator_next (iter
, &data
)) {
638 case GST_ITERATOR_OK
:
639 factory
= gst_element_get_factory (GST_ELEMENT (data
));
640 if (strcmp (factory
->details
.klass
,
641 "Codec/Encoder/Audio") == 0) {
642 encoder
= GST_ELEMENT (data
);
646 case GST_ITERATOR_RESYNC
:
647 gst_iterator_resync (iter
);
649 case GST_ITERATOR_ERROR
:
651 rb_debug ("iterator error");
654 case GST_ITERATOR_DONE
:
659 gst_iterator_free (iter
);
667 static GMAudioProfile
*
668 get_profile_from_mime_type (const char *mime_type
)
670 GList
*profiles
, *walk
;
671 gchar
*pipeline_description
;
672 GstElement
*pipeline
;
674 GMAudioProfile
*profile
;
675 GMAudioProfile
*matching_profile
= NULL
;
676 GError
*error
= NULL
;
678 profiles
= gm_audio_profile_get_active_list ();
679 for (walk
= profiles
; walk
; walk
= g_list_next (walk
)) {
680 profile
= (GMAudioProfile
*) walk
->data
;
681 pipeline_description
=
682 g_strdup_printf ("fakesrc ! %s ! fakesink",
683 gm_audio_profile_get_pipeline (profile
));
684 pipeline
= gst_parse_launch (pipeline_description
, &error
);
685 g_free (pipeline_description
);
687 g_error_free (error
);
692 encoder
= profile_bin_find_encoder (GST_BIN (pipeline
));
693 if (encoder
== NULL
) {
694 g_object_unref (pipeline
);
698 if (encoder_match_mime (encoder
, mime_type
)) {
699 matching_profile
= profile
;
700 gst_object_unref (GST_OBJECT (encoder
));
701 gst_object_unref (GST_OBJECT (pipeline
));
705 gst_object_unref (GST_OBJECT (encoder
));
706 gst_object_unref (GST_OBJECT (pipeline
));
709 return matching_profile
;
713 create_pipeline_and_source (RBEncoderGst
*encoder
,
714 RhythmDBEntry
*entry
,
720 uri
= rhythmdb_entry_get_playback_uri (entry
);
724 src
= gst_element_make_from_uri (GST_URI_SRC
, uri
, "source");
727 RB_ENCODER_ERROR
, RB_ENCODER_ERROR_INTERNAL
,
728 "could not create source element for '%s'", uri
);
733 encoder
->priv
->pipeline
= gst_pipeline_new ("pipeline");
734 gst_bin_add (GST_BIN (encoder
->priv
->pipeline
), src
);
736 /* TODO: add progress reporting */
744 copy_track (RBEncoderGst
*encoder
,
745 RhythmDBEntry
*entry
,
752 g_assert (encoder
->priv
->pipeline
== NULL
);
754 src
= create_pipeline_and_source (encoder
, entry
, error
);
758 if (!attach_output_pipeline (encoder
, src
, dest
, error
))
761 if (!start_pipeline (encoder
, error
))
768 extract_track (RBEncoderGst
*encoder
,
769 RhythmDBEntry
*entry
,
773 /* cdsrc ! encoder ! sink */
776 const char *profile_name
;
777 GMAudioProfile
*profile
;
778 GstElement
*src
, *end
;
780 g_assert (encoder
->priv
->pipeline
== NULL
);
782 profile_name
= eel_gconf_get_string (CONF_LIBRARY_PREFERRED_FORMAT
);
783 profile
= gm_audio_profile_lookup (profile_name
);
784 if (profile
== NULL
) {
786 RB_ENCODER_ERROR
, RB_ENCODER_ERROR_FORMAT_UNSUPPORTED
,
787 "Could not find encoding profile '%s'", profile_name
);
791 src
= create_pipeline_and_source (encoder
, entry
, error
);
795 /* setup cd extraction properties */
796 uri
= rhythmdb_entry_get_playback_uri (entry
);
800 device
= g_utf8_strrchr (uri
, -1, '#');
801 g_object_set (G_OBJECT (src
),
802 "device", device
+ 1, /* skip the '#' */
803 "track", rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_TRACK_NUMBER
),
805 if (g_object_class_find_property (G_OBJECT_GET_CLASS (src
), "paranoia-mode")) {
808 paranoia_mode
= 255; /* TODO: make configurable */
809 g_object_set (G_OBJECT (src
), "paranoia-mode", paranoia_mode
, NULL
);
813 end
= add_encoding_pipeline (encoder
, profile
, error
);
816 if (gst_element_link (src
, encoder
->priv
->enc
) == FALSE
)
819 if (!attach_output_pipeline (encoder
, end
, dest
, error
))
821 if (!add_tags_from_entry (encoder
, entry
, error
))
823 if (!start_pipeline (encoder
, error
))
830 transcode_track (RBEncoderGst
*encoder
,
831 RhythmDBEntry
*entry
,
833 const char *mime_type
,
836 /* src ! decodebin ! queue ! encoding_profile ! queue ! sink */
837 GMAudioProfile
*profile
;
838 GstElement
*src
, *decoder
, *end
;
840 g_assert (encoder
->priv
->pipeline
== NULL
);
842 profile
= get_profile_from_mime_type (mime_type
);
843 if (profile
== NULL
) {
846 RB_ENCODER_ERROR_FORMAT_UNSUPPORTED
,
847 "Unable to locate encoding profile for mime-type "
851 rb_debug ("selected profile %s",
852 gm_audio_profile_get_name (profile
));
855 src
= create_pipeline_and_source (encoder
, entry
, error
);
859 decoder
= add_decoding_pipeline (encoder
, error
);
863 if (gst_element_link (src
, decoder
) == FALSE
)
866 end
= add_encoding_pipeline (encoder
, profile
, error
);
870 if (!attach_output_pipeline (encoder
, end
, dest
, error
))
872 if (!add_tags_from_entry (encoder
, entry
, error
))
874 if (!start_pipeline (encoder
, error
))
880 static GnomeVFSResult
881 create_parent_dirs_uri (GnomeVFSURI
*uri
)
883 GnomeVFSURI
*parent_uri
;
884 GnomeVFSResult result
;
886 if (gnome_vfs_uri_exists (uri
))
889 parent_uri
= gnome_vfs_uri_get_parent (uri
);
890 result
= create_parent_dirs_uri (parent_uri
);
891 gnome_vfs_uri_unref (parent_uri
);
892 if (result
!= GNOME_VFS_OK
)
895 return gnome_vfs_make_directory_for_uri (uri
, 0750);
898 static GnomeVFSResult
899 create_parent_dirs (const char *uri
)
901 GnomeVFSURI
*vfs_uri
;
902 GnomeVFSURI
*parent_uri
;
903 GnomeVFSResult result
;
905 vfs_uri
= gnome_vfs_uri_new (uri
);
906 parent_uri
= gnome_vfs_uri_get_parent (vfs_uri
);
908 result
= create_parent_dirs_uri (parent_uri
);
910 gnome_vfs_uri_unref (parent_uri
);
911 gnome_vfs_uri_unref (vfs_uri
);
916 rb_encoder_gst_cancel (RBEncoder
*encoder
)
918 RBEncoderGstPrivate
*priv
= RB_ENCODER_GST (encoder
)->priv
;
920 if (priv
->pipeline
== NULL
)
923 gst_element_set_state (priv
->pipeline
, GST_STATE_NULL
);
924 g_object_unref (priv
->pipeline
);
925 priv
->pipeline
= NULL
;
927 rb_encoder_gst_emit_completed (RB_ENCODER_GST (encoder
));
931 rb_encoder_gst_encode (RBEncoder
*encoder
,
932 RhythmDBEntry
*entry
,
934 const char *mime_type
)
936 RBEncoderGstPrivate
*priv
= RB_ENCODER_GST (encoder
)->priv
;
937 const char *entry_mime_type
;
940 GError
*error
= NULL
;
941 GnomeVFSResult vfsresult
;
943 g_return_val_if_fail (priv
->pipeline
== NULL
, FALSE
);
945 entry_mime_type
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_MIMETYPE
);
946 was_raw
= g_str_has_prefix (entry_mime_type
, "audio/x-raw");
948 priv
->total_length
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_DURATION
);
950 vfsresult
= create_parent_dirs (dest
);
951 if (vfsresult
!= GNOME_VFS_OK
) {
952 error
= g_error_new_literal (RB_ENCODER_ERROR
,
953 RB_ENCODER_ERROR_FILE_ACCESS
,
954 gnome_vfs_result_to_string (vfsresult
));
956 _rb_encoder_emit_error (encoder
, error
);
957 _rb_encoder_emit_completed (encoder
);
958 g_error_free (error
);
962 if ((mime_type
== NULL
&& !was_raw
) || (mime_type
&& (strcmp (mime_type
, entry_mime_type
) == 0))) {
963 result
= copy_track (RB_ENCODER_GST (encoder
), entry
, dest
, &error
);
965 if (mime_type
== NULL
) {
966 result
= extract_track (RB_ENCODER_GST (encoder
), entry
, dest
, &error
);
968 result
= transcode_track (RB_ENCODER_GST (encoder
), entry
, dest
, mime_type
, &error
);
973 RBEncoderGst
*enc
= RB_ENCODER_GST (encoder
);
975 rb_encoder_gst_emit_error (enc
, error
);
976 g_error_free (error
);
977 if (enc
->priv
->pipeline
== NULL
)
978 rb_encoder_gst_emit_completed (enc
);
980 /* this will unref the pipeline and call emit_completed
982 rb_encoder_gst_cancel (encoder
);