static void populate_profile_combo (GtkComboBox *combo) { GstEncodingTarget *target; const GList *p; GtkTreeModel *model; model = GTK_TREE_MODEL (gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING)); target = rb_gst_get_default_encoding_target (); for (p = gst_encoding_target_get_profiles (target); p != NULL; p = p->next) { GstEncodingProfile *profile = GST_ENCODING_PROFILE (p->data); char *media_type; media_type = rb_gst_encoding_profile_get_media_type (profile); if (media_type == NULL) { continue; } gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), NULL, NULL, -1, 0, media_type, 1, gst_encoding_profile_get_description (profile), -1); g_free (media_type); } gtk_combo_box_set_model (GTK_COMBO_BOX (combo), model); g_object_unref (model); }
static gboolean start_next (RBTrackTransferBatch *batch) { GstEncodingProfile *profile = NULL; if (batch->priv->cancelled == TRUE) { return FALSE; } if (batch->priv->entries == NULL) { /* guess we must be done.. */ g_signal_emit (batch, signals[COMPLETE], 0); g_object_notify (G_OBJECT (batch), "task-outcome"); return FALSE; } batch->priv->current_fraction = 0.0; rb_debug ("%d entries remain in the batch", g_list_length (batch->priv->entries)); while ((batch->priv->entries != NULL) && (batch->priv->cancelled == FALSE)) { RhythmDBEntry *entry; guint64 filesize; gulong duration; double fraction; GList *n; char *media_type; char *extension; n = batch->priv->entries; batch->priv->entries = g_list_remove_link (batch->priv->entries, n); entry = (RhythmDBEntry *)n->data; g_list_free_1 (n); rb_debug ("attempting to transfer %s", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); /* calculate the fraction of the transfer that this entry represents */ filesize = rhythmdb_entry_get_uint64 (entry, RHYTHMDB_PROP_FILE_SIZE); duration = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION); if (batch->priv->total_duration > 0) { g_assert (duration > 0); /* otherwise total_duration would be 0 */ fraction = ((double)duration) / (double) batch->priv->total_duration; } else if (batch->priv->total_size > 0) { g_assert (filesize > 0); /* otherwise total_size would be 0 */ fraction = ((double)filesize) / (double) batch->priv->total_size; } else { int count = g_list_length (batch->priv->entries) + g_list_length (batch->priv->done_entries) + 1; fraction = 1.0 / ((double)count); } profile = NULL; if (select_profile_for_entry (batch, entry, &profile, FALSE) == FALSE) { rb_debug ("skipping entry %s, can't find an encoding profile", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); rhythmdb_entry_unref (entry); batch->priv->total_fraction += fraction; continue; } if (profile != NULL) { media_type = rb_gst_encoding_profile_get_media_type (profile); extension = g_strdup (rb_gst_media_type_to_extension (media_type)); rb_gst_encoding_profile_set_preset (profile, NULL); if (batch->priv->settings != NULL) { GVariant *preset_settings; char *active_preset; preset_settings = g_settings_get_value (batch->priv->settings, "media-type-presets"); active_preset = NULL; g_variant_lookup (preset_settings, media_type, "s", &active_preset); rb_debug ("setting preset %s for media type %s", active_preset, media_type); rb_gst_encoding_profile_set_preset (profile, active_preset); g_free (active_preset); } } else { media_type = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_MEDIA_TYPE); extension = g_strdup (rb_gst_media_type_to_extension (media_type)); if (extension == NULL) { extension = get_extension_from_location (entry); } } g_free (batch->priv->current_dest_uri); batch->priv->current_dest_uri = NULL; g_signal_emit (batch, signals[GET_DEST_URI], 0, entry, media_type, extension, &batch->priv->current_dest_uri); g_free (media_type); g_free (extension); if (batch->priv->current_dest_uri == NULL) { rb_debug ("unable to build destination URI for %s, skipping", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); rhythmdb_entry_unref (entry); batch->priv->total_fraction += fraction; continue; } batch->priv->current = entry; batch->priv->current_entry_fraction = fraction; batch->priv->current_profile = profile; break; } if (batch->priv->current != NULL) { g_signal_emit (batch, signals[TRACK_STARTED], 0, batch->priv->current, batch->priv->current_dest_uri); start_encoding (batch, FALSE); g_object_notify (G_OBJECT (batch), "task-detail"); } return TRUE; }
/** * rb_track_transfer_batch_check_profiles: * @batch: a #RBTrackTransferBatch * @missing_plugin_profiles: (out) (element-type GstPbutils.EncodingProfile): holds a #GList of #GstEncodingProfiles on return * @error_count: holds the number of entries that cannot be transferred on return * * Checks that all entries in the batch can be transferred in a format * supported by the destination. If no encoding profile is available for * some entries, but installing additional plugins could make a profile * available, a list of profiles that require additional plugins is returned. * * Return value: %TRUE if some entries can be transferred without additional plugins */ gboolean rb_track_transfer_batch_check_profiles (RBTrackTransferBatch *batch, GList **missing_plugin_profiles, int *error_count) { RBEncoder *encoder = rb_encoder_new (); gboolean ret = FALSE; const GList *l; rb_debug ("checking profiles"); /* first, figure out which profiles that we care about would require additional plugins to use */ g_list_free (batch->priv->missing_plugin_profiles); batch->priv->missing_plugin_profiles = NULL; for (l = gst_encoding_target_get_profiles (batch->priv->target); l != NULL; l = l->next) { GstEncodingProfile *profile = GST_ENCODING_PROFILE (l->data); char *profile_media_type; profile_media_type = rb_gst_encoding_profile_get_media_type (profile); if (profile_media_type != NULL && (rb_gst_media_type_is_lossless (profile_media_type) == FALSE) && rb_encoder_get_missing_plugins (encoder, profile, NULL, NULL)) { batch->priv->missing_plugin_profiles = g_list_append (batch->priv->missing_plugin_profiles, profile); } g_free (profile_media_type); } g_object_unref (encoder); rb_debug ("have %d profiles with missing plugins", g_list_length (batch->priv->missing_plugin_profiles)); for (l = batch->priv->entries; l != NULL; l = l->next) { RhythmDBEntry *entry = (RhythmDBEntry *)l->data; GstEncodingProfile *profile; profile = NULL; if (select_profile_for_entry (batch, entry, &profile, FALSE) == TRUE) { if (profile != NULL) { rb_debug ("found profile %s for %s", gst_encoding_profile_get_name (profile), rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); } else { rb_debug ("copying entry %s", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); } ret = TRUE; continue; } (*error_count)++; if (select_profile_for_entry (batch, entry, &profile, TRUE) == FALSE) { rb_debug ("unable to transfer %s (media type %s)", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION), rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MEDIA_TYPE)); } else { rb_debug ("require additional plugins to transfer %s (media type %s)", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION), rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MEDIA_TYPE)); if (*missing_plugin_profiles == NULL) { *missing_plugin_profiles = g_list_copy (batch->priv->missing_plugin_profiles); } } } return ret; }
static gboolean select_profile_for_entry (RBTrackTransferBatch *batch, RhythmDBEntry *entry, GstEncodingProfile **rprofile, gboolean allow_missing) { const char *source_media_type = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MEDIA_TYPE); const GList *p; int best = 0; for (p = gst_encoding_target_get_profiles (batch->priv->target); p != NULL; p = p->next) { GstEncodingProfile *profile = GST_ENCODING_PROFILE (p->data); char *profile_media_type; const char *preferred_media_type; gboolean transcode_lossless; gboolean is_preferred; gboolean is_lossless; gboolean is_source; gboolean is_missing; int rank; profile_media_type = rb_gst_encoding_profile_get_media_type (profile); if (batch->priv->settings) { preferred_media_type = g_settings_get_string (batch->priv->settings, "media-type"); if (rb_gst_media_type_is_lossless (preferred_media_type)) { transcode_lossless = FALSE; } else { transcode_lossless = g_settings_get_boolean (batch->priv->settings, "transcode-lossless"); } is_preferred = (rb_gst_media_type_matches_profile (profile, preferred_media_type)); } else { preferred_media_type = NULL; transcode_lossless = FALSE; is_preferred = FALSE; } is_missing = (g_list_find (batch->priv->missing_plugin_profiles, profile) != NULL); if (g_str_has_prefix (source_media_type, "audio/x-raw") == FALSE) { is_source = rb_gst_media_type_matches_profile (profile, source_media_type); } else { /* always transcode raw audio */ is_source = FALSE; } if (profile_media_type != NULL) { is_lossless = (rb_gst_media_type_is_lossless (profile_media_type)); } else { is_lossless = (rb_gst_media_type_is_lossless (source_media_type)); } if (is_missing && allow_missing == FALSE && is_source == FALSE) { /* this only applies if transcoding would be required */ rb_debug ("can't use encoding %s due to missing plugins", profile_media_type); rank = 0; } else if (transcode_lossless && is_lossless) { /* this overrides is_source so all lossless files get transcoded */ rb_debug ("don't want lossless encoding %s", profile_media_type); rank = 0; } else if (is_source) { /* this overrides is_preferred so we don't transcode unneccessarily */ rb_debug ("can use source encoding %s", profile_media_type); rank = 100; profile = NULL; } else if (is_preferred) { /* otherwise, always use the preferred encoding if available */ rb_debug ("can use preferred encoding %s", profile_media_type); rank = 50; } else if (is_lossless == FALSE) { /* if we can't use the preferred encoding, we prefer lossy encodings over lossless, for space reasons */ rb_debug ("can use lossy encoding %s", profile_media_type); rank = 25; } else { rb_debug ("can use lossless encoding %s", profile_media_type); rank = 10; } g_free (profile_media_type); if (rank > best) { *rprofile = profile; best = rank; } } return (best > 0); }
static void missing_encoder_response_cb (GtkDialog *dialog, gint response, RBTrackTransferQueue *queue) { GClosure *retry; GstEncodingTarget *target; GPtrArray *details; GList *profiles; const GList *l; RBEncoder *encoder; switch (response) { case GTK_RESPONSE_YES: /* 'continue' -> start the batch */ rb_debug ("starting batch regardless of missing plugins"); actually_start_batch (queue); break; case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_DELETE_EVENT: /* 'cancel' -> cancel the batch and start the next one */ rb_debug ("cancelling batch"); _rb_track_transfer_batch_cancel (queue->priv->current); g_object_unref (queue->priv->current); queue->priv->current = NULL; start_next_batch (queue); break; case GTK_RESPONSE_ACCEPT: /* 'install plugins' -> try to install encoder/muxer */ /* get profiles that need plugins installed */ profiles = NULL; encoder = rb_encoder_new (); g_object_get (queue->priv->current, "encoding-target", &target, NULL); for (l = gst_encoding_target_get_profiles (target); l != NULL; l = l->next) { GstEncodingProfile *profile = GST_ENCODING_PROFILE (l->data); char *profile_media_type; profile_media_type = rb_gst_encoding_profile_get_media_type (profile); if (profile_media_type != NULL && (rb_gst_media_type_is_lossless (profile_media_type) == FALSE) && rb_encoder_get_missing_plugins (encoder, profile, NULL, NULL)) { profiles = g_list_append (profiles, profile); } g_free (profile_media_type); } g_object_unref (encoder); g_object_unref (target); if (profiles == NULL) { rb_debug ("apparently we don't need any plugins any more"); actually_start_batch (queue); break; } rb_debug ("attempting plugin installation"); details = get_missing_plugin_strings (profiles, FALSE); retry = g_cclosure_new ((GCallback) missing_plugins_retry_cb, g_object_ref (queue), (GClosureNotify) g_object_unref); g_closure_set_marshal (retry, g_cclosure_marshal_VOID__BOOLEAN); if (rb_missing_plugins_install ((const char **)details->pdata, FALSE, retry)) { rb_debug ("attempting to install missing plugins for transcoding"); } else { rb_debug ("proceeding without the missing plugins for transcoding"); actually_start_batch (queue); } g_closure_sink (retry); g_ptr_array_free (details, TRUE); g_list_free (profiles); break; default: g_assert_not_reached (); } gtk_widget_destroy (GTK_WIDGET (dialog)); }
static void pattern_label_update (void) { char *file_pattern, *path_pattern; char *file_value, *path_value, *example, *format; char *media_type; GstEncodingProfile *profile; /* Disable -Wdiscarded-quantifiers to prevent warnings as we're initalizing gchar* from const gchar*. This is safe as the strings are never changed. */ SJ_BEGIN_IGNORE_DISCARDED_QUANTIFIERS static const AlbumDetails sample_album = { .title = "Help!", /* title */ .artist = "The Beatles", /* artist */ .artist_sortname = "Beatles, The", /* artist_sortname */ .genre = NULL, /* genre */ .number = 0, /* number of tracks*/ .disc_number = 1, /* disc number */ .tracks = NULL, /* track list */ .release_date = NULL, /* release date */ .album_id = NULL, /* album ID */ .artist_id = NULL /* artist ID */ }; static const TrackDetails sample_track = { .album = (AlbumDetails*)&sample_album, /*album */ .number = 7, /* track number */ .title = "Ticket To Ride", /* title */ .artist = "The Beatles", /* artist */ .artist_sortname = "Beatles, The", /* artist_sortname */ .composer = "John Lennon and Paul McCartney", /* composer */ .composer_sortname = "Lennon, John", /* composer_sortname */ .duration = 0, /* duration */ .track_id = NULL, /* track ID */ .artist_id = NULL, /* artist ID */ }; SJ_END_IGNORE_DISCARDED_QUANTIFIERS g_object_get (sj_extractor, "profile", &profile, NULL); /* It's possible the profile isn't set, in which case do nothing */ if (!profile) { return; } media_type = rb_gst_encoding_profile_get_media_type (profile); gst_encoding_profile_unref (profile); /* TODO: sucky. Replace with get-gconf-key-with-default mojo */ file_pattern = g_settings_get_string (sj_settings, SJ_SETTINGS_FILE_PATTERN); if (file_pattern == NULL) { file_pattern = g_strdup (sj_get_default_file_pattern ()); } path_pattern = g_settings_get_string (sj_settings, SJ_SETTINGS_PATH_PATTERN); if (path_pattern == NULL) { path_pattern = g_strdup (sj_get_default_path_pattern ()); } file_value = filepath_parse_pattern (file_pattern, &sample_track); path_value = filepath_parse_pattern (path_pattern, &sample_track); example = g_build_filename (G_DIR_SEPARATOR_S, path_value, file_value, NULL); g_free (file_value); g_free (file_pattern); g_free (path_value); g_free (path_pattern); format = g_strconcat ("<small><i><b>", _("Example Path: "), "</b>", example, ".", rb_gst_media_type_to_extension (media_type), "</i></small>", NULL); g_free (example); g_free (media_type); gtk_label_set_markup (GTK_LABEL (path_example_label), format); g_free (format); } static void settings_changed_cb (GSettings *settings, const gchar *key, gpointer combo) { char *value; value = g_settings_get_string (settings, key); if (!gtk_combo_box_set_active_id (combo, value)) gtk_combo_box_set_active_id (combo, NULL); g_free (value); pattern_label_update (); } /** * Default device changed (either GSettings key or the widget) */ static void device_changed_cb (GSettings *settings, const gchar *key, gpointer user_data) { BraseroDrive *drive; BraseroMediumMonitor *monitor; char *value; g_return_if_fail (strcmp (key, SJ_SETTINGS_DEVICE) == 0); value = g_settings_get_string (settings, key); if ((value != NULL) && (*value != '\0')) { monitor = brasero_medium_monitor_get_default (); drive = brasero_medium_monitor_get_drive (monitor, value); brasero_drive_selection_set_active (BRASERO_DRIVE_SELECTION (cd_option), drive); g_object_unref (drive); g_object_unref (monitor); } else { /* FIXME: see the FIXME in sj-main.c around one of the * device_changed_cb calls for a way to fix this */ g_warn_if_reached(); } g_free (value); }
static gboolean select_profile_for_entry (RBTrackTransferBatch *batch, RhythmDBEntry *entry, GstEncodingProfile **rprofile, gboolean allow_missing) { /* probably want a way to pass in some policy about lossless encoding * here. possibilities: * - convert everything to lossy * - if transcoding is required, use lossy * - keep lossless encoded files lossless * - if transcoding is required, use lossless * - convert everything to lossless * * of course this only applies to targets that include lossless profiles.. */ const char *media_type = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MEDIA_TYPE); GstEncodingProfile *lossless = NULL; gboolean found_lossy = FALSE; const GList *p; for (p = gst_encoding_target_get_profiles (batch->priv->target); p != NULL; p = p->next) { GstEncodingProfile *profile = GST_ENCODING_PROFILE (p->data); char *profile_media_type; gboolean is_missing; gboolean skip; if (g_str_has_prefix (media_type, "audio/x-raw") == FALSE && rb_gst_media_type_matches_profile (profile, media_type)) { /* source file is already in a supported encoding, so just copy it */ *rprofile = NULL; return TRUE; } skip = FALSE; is_missing = (g_list_find (batch->priv->missing_plugin_profiles, profile) != NULL); profile_media_type = rb_gst_encoding_profile_get_media_type (profile); if (profile_media_type == NULL) { if (g_str_has_prefix (media_type, "audio/x-raw")) { skip = TRUE; } } else if (rb_gst_media_type_is_lossless (profile_media_type)) { skip = TRUE; if (allow_missing == FALSE && is_missing) { /* ignore entirely */ } else if (lossless == NULL) { /* remember the first lossless profile that works */ lossless = profile; } } else { found_lossy = TRUE; if (allow_missing == FALSE && is_missing) { skip = TRUE; } } if (skip == FALSE && *rprofile == NULL) { *rprofile = profile; } g_free (profile_media_type); } /* if we only found a lossless encoding, use it */ if (*rprofile == NULL && found_lossy == FALSE && lossless != NULL) { *rprofile = lossless; } return (*rprofile != NULL); }