~ubuntu-branches/ubuntu/oneiric/rhythmbox/oneiric

« back to all changes in this revision

Viewing changes to shell/rb-track-transfer-batch.c

  • Committer: Bazaar Package Importer
  • Author(s): Rico Tzschichholz
  • Date: 2011-07-29 16:41:38 UTC
  • mto: This revision was merged to the branch mainline in revision 191.
  • Revision ID: james.westby@ubuntu.com-20110729164138-wwicy8nqalm18ck7
Tags: upstream-2.90.1~20110802
ImportĀ upstreamĀ versionĀ 2.90.1~20110802

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
 
31
31
#include <glib/gi18n.h>
32
32
 
 
33
#include <gst/pbutils/install-plugins.h>
 
34
 
33
35
#include "rb-source.h"
34
36
#include "rb-track-transfer-batch.h"
35
37
#include "rb-track-transfer-queue.h"
37
39
#include "rb-marshal.h"
38
40
#include "rb-debug.h"
39
41
#include "rb-util.h"
 
42
#include "rb-gst-media-types.h"
40
43
 
41
44
enum
42
45
{
54
57
enum
55
58
{
56
59
        PROP_0,
57
 
        PROP_MEDIA_TYPES,
58
 
        PROP_MEDIA_TYPES_STRV,
 
60
        PROP_ENCODING_TARGET,
59
61
        PROP_SOURCE,
60
62
        PROP_DESTINATION,
61
63
        PROP_TOTAL_ENTRIES,
75
77
{
76
78
        RBTrackTransferQueue *queue;
77
79
 
78
 
        GList *media_types;
 
80
        GstEncodingTarget *target;
 
81
        GList *missing_plugin_profiles;
79
82
 
80
83
        RBSource *source;
81
84
        RBSource *destination;
107
110
 
108
111
/**
109
112
 * rb_track_transfer_batch_new:
110
 
 * @media_types: array containing media type strings describing allowable output formats
111
 
 * @media_type_list: (element-type utf8): GList containing media type strings.
 
113
 * @target: a #GstEncodingTarget describing allowable encodings (or NULL for defaults)
112
114
 * @source: the #RBSource from which the entries are to be transferred
113
115
 * @destination: the #RBSource to which the entries are to be transferred
114
116
 *
115
 
 * Creates a new transfer batch with the specified output types.  Only one of media_types
116
 
 * and media_types_list may be specified.
 
117
 * Creates a new transfer batch with the specified encoding target.  If no target
 
118
 * is specified, the default target will be used with the user's preferred
 
119
 * encoding type.
117
120
 *
118
121
 * One or more entries must be added to the batch (using #rb_track_transfer_batch_add)
119
122
 * before the batch can be started (#rb_track_transfer_manager_start_batch).
121
124
 * Return value: new #RBTrackTransferBatch object
122
125
 */
123
126
RBTrackTransferBatch *
124
 
rb_track_transfer_batch_new (GList *media_types,
125
 
                             const char * const *media_types_strv,
 
127
rb_track_transfer_batch_new (GstEncodingTarget *target,
126
128
                             GObject *source,
127
129
                             GObject *destination)
128
130
{
129
131
        GObject *obj;
130
132
 
131
 
        /* can't specify both, can specify neither */
132
 
        g_assert (media_types == NULL || media_types_strv == NULL);
133
 
 
134
 
        if (media_types != NULL) {
135
 
                obj = g_object_new (RB_TYPE_TRACK_TRANSFER_BATCH,
136
 
                                    "media-types", media_types,
137
 
                                    "source", source,
138
 
                                    "destination", destination,
139
 
                                    NULL);
140
 
        } else {
141
 
                obj = g_object_new (RB_TYPE_TRACK_TRANSFER_BATCH,
142
 
                                    "media-types-strv", &media_types_strv,
143
 
                                    "source", source,
144
 
                                    "destination", destination,
145
 
                                    NULL);
146
 
        }
 
133
        obj = g_object_new (RB_TYPE_TRACK_TRANSFER_BATCH,
 
134
                            "encoding-target", target,
 
135
                            "source", source,
 
136
                            "destination", destination,
 
137
                            NULL);
147
138
        return RB_TRACK_TRANSFER_BATCH (obj);
148
139
}
149
140
 
160
151
        batch->priv->entries = g_list_append (batch->priv->entries, rhythmdb_entry_ref (entry));
161
152
}
162
153
 
 
154
static gboolean
 
155
select_profile_for_entry (RBTrackTransferBatch *batch, RhythmDBEntry *entry, GstEncodingProfile **rprofile, gboolean allow_missing)
 
156
{
 
157
        /* probably want a way to pass in some policy about lossless encoding
 
158
         * here.  possibilities:
 
159
         * - convert everything to lossy
 
160
         * - if transcoding is required, use lossy
 
161
         * - keep lossless encoded files lossless
 
162
         * - if transcoding is required, use lossless
 
163
         * - convert everything to lossless
 
164
         *
 
165
         * of course this only applies to targets that include lossless profiles..
 
166
         */
 
167
 
 
168
        const char *media_type = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MEDIA_TYPE);
 
169
        const GList *p;
 
170
 
 
171
        for (p = gst_encoding_target_get_profiles (batch->priv->target); p != NULL; p = p->next) {
 
172
                GstEncodingProfile *profile = GST_ENCODING_PROFILE (p->data);
 
173
                char *profile_media_type;
 
174
                gboolean skip;
 
175
 
 
176
                if (g_str_has_prefix (media_type, "audio/x-raw") == FALSE &&
 
177
                    rb_gst_media_type_matches_profile (profile, media_type)) {
 
178
                        /* source file is already in a supported encoding, so just copy it */
 
179
                        *rprofile = NULL;
 
180
                        return TRUE;
 
181
                }
 
182
 
 
183
                skip = FALSE;
 
184
                /* ignore lossless encodings for now */
 
185
                profile_media_type = rb_gst_encoding_profile_get_media_type (profile);
 
186
                if (profile_media_type == NULL) {
 
187
                        if (g_str_has_prefix (media_type, "audio/x-raw")) {
 
188
                                skip = TRUE;
 
189
                        }
 
190
                } else if (rb_gst_media_type_is_lossless (profile_media_type)) {
 
191
                        skip = TRUE;
 
192
                } else if (allow_missing == FALSE) {
 
193
                        if (g_list_find (batch->priv->missing_plugin_profiles, profile)) {
 
194
                                skip = TRUE;
 
195
                        }
 
196
                }
 
197
 
 
198
                if (skip == FALSE && *rprofile == NULL) {
 
199
                        *rprofile = profile;
 
200
                }
 
201
                g_free (profile_media_type);
 
202
        }
 
203
 
 
204
        return (*rprofile != NULL);
 
205
}
 
206
 
163
207
/**
164
 
 * rb_track_transfer_batch_check_media_types:
 
208
 * rb_track_transfer_batch_check_profiles:
165
209
 * @batch: a #RBTrackTransferBatch
 
210
 * @missing_plugin_profiles: holds a #GList of #GstEncodingProfiles on return
 
211
 * @error_count: holds the number of entries that cannot be transferred on return
166
212
 *
167
213
 * Checks that all entries in the batch can be transferred in a format
168
 
 * supported by the destination.
 
214
 * supported by the destination.  If no encoding profile is available for
 
215
 * some entries, but installing additional plugins could make a profile
 
216
 * available, a list of profiles that require additional plugins is returned.
169
217
 *
170
 
 * Return value: number of entries that cannot be transferred
 
218
 * Return value: %TRUE if some entries can be transferred without additional plugins
171
219
 */
172
 
guint
173
 
rb_track_transfer_batch_check_media_types (RBTrackTransferBatch *batch)
 
220
gboolean
 
221
rb_track_transfer_batch_check_profiles (RBTrackTransferBatch *batch, GList **missing_plugin_profiles, int *error_count)
174
222
{
175
223
        RBEncoder *encoder = rb_encoder_new ();
176
 
        guint count = 0;
177
 
        GList *l;
 
224
        gboolean ret = FALSE;
 
225
        const GList *l;
 
226
 
 
227
        rb_debug ("checking profiles");
 
228
 
 
229
        /* first, figure out which profiles that we care about would require additional plugins to use */
 
230
        g_list_free (batch->priv->missing_plugin_profiles);
 
231
        batch->priv->missing_plugin_profiles = NULL;
 
232
 
 
233
        for (l = gst_encoding_target_get_profiles (batch->priv->target); l != NULL; l = l->next) {
 
234
                GstEncodingProfile *profile = GST_ENCODING_PROFILE (l->data);
 
235
                char *profile_media_type;
 
236
                profile_media_type = rb_gst_encoding_profile_get_media_type (profile);
 
237
                if ((rb_gst_media_type_is_lossless (profile_media_type) == FALSE) &&
 
238
                    rb_encoder_get_missing_plugins (encoder, profile, NULL, NULL)) {
 
239
                        batch->priv->missing_plugin_profiles = g_list_append (batch->priv->missing_plugin_profiles, profile);
 
240
                }
 
241
                g_free (profile_media_type);
 
242
        }
 
243
        g_object_unref (encoder);
 
244
 
 
245
        rb_debug ("have %d profiles with missing plugins", g_list_length (batch->priv->missing_plugin_profiles));
178
246
 
179
247
        for (l = batch->priv->entries; l != NULL; l = l->next) {
180
248
                RhythmDBEntry *entry = (RhythmDBEntry *)l->data;
181
 
                /* check that we can transfer this entry to the device */
182
 
                if (rb_encoder_get_media_type (encoder,
183
 
                                               entry,
184
 
                                               batch->priv->media_types,
185
 
                                               NULL,
186
 
                                               NULL) == FALSE) {
 
249
                GstEncodingProfile *profile;
 
250
 
 
251
                profile = NULL;
 
252
                if (select_profile_for_entry (batch, entry, &profile, FALSE) == TRUE) {
 
253
                        if (profile != NULL) {
 
254
                                rb_debug ("found profile %s for %s",
 
255
                                          gst_encoding_profile_get_name (profile),
 
256
                                          rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
 
257
                        } else {
 
258
                                rb_debug ("copying entry %s", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
 
259
                        }
 
260
                        ret = TRUE;
 
261
                        continue;
 
262
                }
 
263
 
 
264
                (*error_count)++;
 
265
                if (select_profile_for_entry (batch, entry, &profile, TRUE) == FALSE) {
187
266
                        rb_debug ("unable to transfer %s (media type %s)",
188
267
                                  rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION),
189
 
                                  rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MIMETYPE));
190
 
                        count++;
 
268
                                  rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MEDIA_TYPE));
 
269
                } else {
 
270
                        rb_debug ("require additional plugins to transfer %s (media type %s)",
 
271
                                  rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION),
 
272
                                  rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MEDIA_TYPE));
 
273
                        if (*missing_plugin_profiles == NULL) {
 
274
                                *missing_plugin_profiles = g_list_copy (batch->priv->missing_plugin_profiles);
 
275
                        }
191
276
                }
192
277
        }
193
 
        g_object_unref (encoder);
194
 
        return count;
 
278
        return ret;
195
279
}
196
280
 
197
281
/**
384
468
        return overwrite;
385
469
}
386
470
 
 
471
static char *
 
472
get_extension_from_location (RhythmDBEntry *entry)
 
473
{
 
474
        char *extension = NULL;
 
475
        const char *ext;
 
476
        GFile *f;
 
477
        char *b;
 
478
 
 
479
        f = g_file_new_for_uri (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
 
480
        b = g_file_get_basename (f);
 
481
        g_object_unref (f);
 
482
 
 
483
        ext = strrchr (b, '.');
 
484
        if (ext != NULL) {
 
485
                extension = g_strdup (ext+1);
 
486
        }
 
487
        g_free (b);
 
488
 
 
489
        return extension;
 
490
}
 
491
 
387
492
static gboolean
388
493
start_next (RBTrackTransferBatch *batch)
389
494
{
390
 
        char *media_type = NULL;
391
 
        char *extension = NULL;
 
495
        GstEncodingProfile *profile = NULL;
392
496
 
393
497
        if (batch->priv->cancelled == TRUE) {
394
498
                return FALSE;
402
506
 
403
507
        batch->priv->current_fraction = 0.0;
404
508
        batch->priv->current_encoder = rb_encoder_new ();
 
509
 
405
510
        g_signal_connect_object (batch->priv->current_encoder, "progress",
406
511
                                 G_CALLBACK (encoder_progress_cb),
407
512
                                 batch, 0);
420
525
                gulong duration;
421
526
                double fraction;
422
527
                GList *n;
 
528
                char *media_type;
 
529
                char *extension;
423
530
 
424
531
                n = batch->priv->entries;
425
532
                batch->priv->entries = g_list_remove_link (batch->priv->entries, n);
443
550
                        fraction = 1.0 / ((double)count);
444
551
                }
445
552
 
446
 
                g_free (media_type);
447
 
                g_free (extension);
448
 
                media_type = NULL;
449
 
                extension = NULL;
450
 
                if (rb_encoder_get_media_type (batch->priv->current_encoder,
451
 
                                               entry,
452
 
                                               batch->priv->media_types,
453
 
                                               &media_type,
454
 
                                               &extension) == FALSE) {
455
 
                        rb_debug ("skipping entry %s, can't find a destination format",
 
553
                profile = NULL;
 
554
                if (select_profile_for_entry (batch, entry, &profile, FALSE) == FALSE) {
 
555
                        rb_debug ("skipping entry %s, can't find an encoding profile",
456
556
                                  rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
457
557
                        rhythmdb_entry_unref (entry);
458
558
                        batch->priv->total_fraction += fraction;
459
559
                        continue;
460
560
                }
461
561
 
 
562
                if (profile != NULL) {
 
563
                        media_type = rb_gst_encoding_profile_get_media_type (profile);
 
564
                        extension = g_strdup (rb_gst_media_type_to_extension (media_type));
 
565
                } else {
 
566
                        media_type = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_MEDIA_TYPE);
 
567
                        extension = g_strdup (rb_gst_media_type_to_extension (media_type));
 
568
                        if (extension == NULL) {
 
569
                                extension = get_extension_from_location (entry);
 
570
                        }
 
571
                }
 
572
 
462
573
                g_free (batch->priv->current_dest_uri);
463
574
                batch->priv->current_dest_uri = NULL;
464
575
                g_signal_emit (batch, signals[GET_DEST_URI], 0,
466
577
                               media_type,
467
578
                               extension,
468
579
                               &batch->priv->current_dest_uri);
 
580
                g_free (media_type);
 
581
                g_free (extension);
 
582
 
469
583
                if (batch->priv->current_dest_uri == NULL) {
470
584
                        rb_debug ("unable to build destination URI for %s, skipping",
471
585
                                  rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
490
604
                rb_encoder_encode (batch->priv->current_encoder,
491
605
                                   batch->priv->current,
492
606
                                   batch->priv->current_dest_uri,
493
 
                                   media_type);
 
607
                                   profile);
494
608
        }
495
 
        g_free (media_type);
496
 
        g_free (extension);
497
609
 
498
610
        return TRUE;
499
611
}
515
627
                   GParamSpec *pspec)
516
628
{
517
629
        RBTrackTransferBatch *batch = RB_TRACK_TRANSFER_BATCH (object);
518
 
        const char * const *strv;
519
 
        int i;
520
630
        switch (prop_id) {
521
 
        case PROP_MEDIA_TYPES:
522
 
                batch->priv->media_types = rb_string_list_copy (g_value_get_pointer (value));
523
 
                break;
524
 
        case PROP_MEDIA_TYPES_STRV:
525
 
                strv = g_value_get_boxed (value);
526
 
                if (strv != NULL) {
527
 
                        for (i = 0; strv[i] != NULL; i++) {
528
 
                                batch->priv->media_types = g_list_append (batch->priv->media_types, g_strdup (strv[i]));
529
 
                        }
530
 
                }
 
631
        case PROP_ENCODING_TARGET:
 
632
                batch->priv->target = GST_ENCODING_TARGET (gst_value_dup_mini_object (value));
531
633
                break;
532
634
        case PROP_SOURCE:
533
635
                batch->priv->source = g_value_dup_object (value);
549
651
{
550
652
        RBTrackTransferBatch *batch = RB_TRACK_TRANSFER_BATCH (object);
551
653
        switch (prop_id) {
552
 
        case PROP_MEDIA_TYPES:
553
 
                g_value_set_pointer (value, batch->priv->media_types);
 
654
        case PROP_ENCODING_TARGET:
 
655
                gst_value_set_mini_object (value, GST_MINI_OBJECT (batch->priv->target));
554
656
                break;
555
657
        case PROP_SOURCE:
556
658
                g_value_set_object (value, batch->priv->source);
614
716
                batch->priv->destination = NULL;
615
717
        }
616
718
 
 
719
        if (batch->priv->target != NULL) {
 
720
                gst_encoding_target_unref (batch->priv->target);
 
721
                batch->priv->target = NULL;
 
722
        }
 
723
 
617
724
        G_OBJECT_CLASS (rb_track_transfer_batch_parent_class)->dispose (object);
618
725
}
619
726
 
622
729
{
623
730
        RBTrackTransferBatch *batch = RB_TRACK_TRANSFER_BATCH (object);
624
731
 
625
 
        rb_list_deep_free (batch->priv->media_types);
626
732
        rb_list_destroy_free (batch->priv->entries, (GDestroyNotify) rhythmdb_entry_unref);
627
733
        rb_list_destroy_free (batch->priv->done_entries, (GDestroyNotify) rhythmdb_entry_unref);
628
 
        rhythmdb_entry_unref (batch->priv->current);
 
734
        if (batch->priv->current != NULL) {
 
735
                rhythmdb_entry_unref (batch->priv->current);
 
736
        }
629
737
 
630
738
        G_OBJECT_CLASS (rb_track_transfer_batch_parent_class)->finalize (object);
631
739
}
641
749
        object_class->dispose = impl_dispose;
642
750
 
643
751
        /**
644
 
         * RBTrackTransferBatch:media-types
645
 
         *
646
 
         * Array of media type strings describing the acceptable
647
 
         * destination formats.  If NULL, no format conversion will
648
 
         * be done.
649
 
         */
650
 
        g_object_class_install_property (object_class,
651
 
                                         PROP_MEDIA_TYPES_STRV,
652
 
                                         g_param_spec_boxed ("media-types-strv",
653
 
                                                             "media types",
654
 
                                                             "Set of allowable destination media types",
655
 
                                                             G_TYPE_STRV,
656
 
                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
657
 
        /**
658
 
         * RBTrackTransferBatch:media-types
659
 
         *
660
 
         * GList of media type strings describing the acceptable
661
 
         * destination formats.  If NULL, no format conversion will
662
 
         * be done.
663
 
         */
664
 
        g_object_class_install_property (object_class,
665
 
                                         PROP_MEDIA_TYPES,
666
 
                                         g_param_spec_pointer ("media-types",
667
 
                                                               "media types",
668
 
                                                               "Set of allowable destination media types",
669
 
                                                               G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
 
752
         * RBTrackTransferBatch:encoding-target
 
753
         *
 
754
         * A GstEncodingTarget describing allowable target formats.
 
755
         * If NULL, the default set of profiles will be used.
 
756
         */
 
757
        g_object_class_install_property (object_class,
 
758
                                         PROP_ENCODING_TARGET,
 
759
                                         gst_param_spec_mini_object ("encoding-target",
 
760
                                                                     "encoding target",
 
761
                                                                     "GstEncodingTarget",
 
762
                                                                     GST_TYPE_ENCODING_TARGET,
 
763
                                                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
670
764
        /**
671
765
         * RBTrackTransferBatch:source
672
766
         *