static void brasero_transcode_wavparse_pad_added_cb (GstElement *wavparse, GstPad *new_pad, gpointer user_data) { GstPad *pad = NULL; BraseroTranscodePrivate *priv; priv = BRASERO_TRANSCODE_PRIVATE (user_data); pad = gst_element_get_static_pad (priv->sink, "sink"); if (!pad) goto error; if (gst_pad_link (new_pad, pad) != GST_PAD_LINK_OK) goto error; gst_element_set_state (priv->sink, GST_STATE_PLAYING); return; error: if (pad) gst_object_unref (pad); brasero_transcode_error_on_pad_linking (BRASERO_TRANSCODE (user_data), "Sent by brasero_transcode_wavparse_pad_added_cb"); }
static void brasero_transcode_send_volume_event (BraseroTranscode *transcode) { BraseroTranscodePrivate *priv; gdouble track_peak = 0.0; gdouble track_gain = 0.0; GstTagList *tag_list; BraseroTrack *track; GstEvent *event; GValue *value; priv = BRASERO_TRANSCODE_PRIVATE (transcode); brasero_job_get_current_track (BRASERO_JOB (transcode), &track); BRASERO_JOB_LOG (transcode, "Sending audio levels tags"); if (brasero_track_tag_lookup (track, BRASERO_TRACK_PEAK_VALUE, &value) == BRASERO_BURN_OK) track_peak = g_value_get_double (value); if (brasero_track_tag_lookup (track, BRASERO_TRACK_GAIN_VALUE, &value) == BRASERO_BURN_OK) track_gain = g_value_get_double (value); /* it's possible we fail */ tag_list = gst_tag_list_new (GST_TAG_TRACK_GAIN, track_gain, GST_TAG_TRACK_PEAK, track_peak, NULL); /* NOTE: that event is goind downstream */ event = gst_event_new_tag (tag_list); if (!gst_element_send_event (priv->convert, event)) BRASERO_JOB_LOG (transcode, "Couldn't send tags to rgvolume"); BRASERO_JOB_LOG (transcode, "Set volume level %lf %lf", track_gain, track_peak); }
static void brasero_transcode_stop_pipeline (BraseroTranscode *transcode) { BraseroTranscodePrivate *priv; GstPad *sinkpad; priv = BRASERO_TRANSCODE_PRIVATE (transcode); if (!priv->pipeline) return; sinkpad = gst_element_get_static_pad (priv->sink, "sink"); if (priv->probe) gst_pad_remove_probe (sinkpad, priv->probe); gst_object_unref (sinkpad); gst_element_set_state (priv->pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (priv->pipeline)); priv->link = NULL; priv->sink = NULL; priv->source = NULL; priv->convert = NULL; priv->pipeline = NULL; priv->set_active_state = 0; }
static gboolean brasero_transcode_is_mp3 (BraseroTranscode *transcode) { BraseroTranscodePrivate *priv; GstElement *typefind; GstCaps *caps = NULL; const gchar *mime; priv = BRASERO_TRANSCODE_PRIVATE (transcode); /* find the type of the file */ typefind = gst_bin_get_by_name (GST_BIN (priv->decode), "typefind"); g_object_get (typefind, "caps", &caps, NULL); if (!caps) { gst_object_unref (typefind); return TRUE; } if (caps && gst_caps_get_size (caps) > 0) { mime = gst_structure_get_name (gst_caps_get_structure (caps, 0)); gst_object_unref (typefind); if (mime && !strcmp (mime, "application/x-id3")) return TRUE; if (!strcmp (mime, "audio/mpeg")) return TRUE; } else gst_object_unref (typefind); return FALSE; }
static gint64 brasero_transcode_get_duration (BraseroTranscode *transcode) { gint64 duration = -1; BraseroTranscodePrivate *priv; priv = BRASERO_TRANSCODE_PRIVATE (transcode); /* This part is specific to MP3s */ if (priv->mp3_size_pipeline) { /* This is the most reliable way to get the duration for mp3 * read them till the end and get the position. */ gst_element_query_position (priv->pipeline, GST_FORMAT_TIME, &duration); } /* This is for any sort of files */ if (duration == -1 || duration == 0) gst_element_query_duration (priv->pipeline, GST_FORMAT_TIME, &duration); BRASERO_JOB_LOG (transcode, "got duration %" GST_TIME_FORMAT, GST_TIME_ARGS (duration)); if (duration == -1 || duration == 0) brasero_job_error (BRASERO_JOB (transcode), g_error_new (BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, "%s", _("Error while getting duration"))); return duration; }
static gboolean brasero_transcode_pad_idle (BraseroTranscode *transcode) { gint64 bytes2write; GError *error = NULL; BraseroTranscodePrivate *priv; priv = BRASERO_TRANSCODE_PRIVATE (transcode); bytes2write = brasero_transcode_pad_real (transcode, priv->pad_fd, priv->pad_size, &error); if (bytes2write == -1) { priv->pad_id = 0; brasero_job_error (BRASERO_JOB (transcode), error); return FALSE; } if (bytes2write) { priv->pad_size = bytes2write; return TRUE; } /* we are finished with padding */ priv->pad_id = 0; close (priv->pad_fd); priv->pad_fd = -1; /* set the next song or finish */ brasero_transcode_push_track (transcode); return FALSE; }
static void brasero_transcode_error_on_pad_linking (BraseroTranscode *self, const gchar *function_name) { BraseroTranscodePrivate *priv; GstMessage *message; GstBus *bus; priv = BRASERO_TRANSCODE_PRIVATE (self); BRASERO_JOB_LOG (self, "Error on pad linking"); message = gst_message_new_error (GST_OBJECT (priv->pipeline), g_error_new (BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, /* Translators: This message is sent * when brasero could not link together * two gstreamer plugins so that one * sends its data to the second for further * processing. This data transmission is * done through a pad. Maybe this is a bit * too technical and should be removed? */ _("Impossible to link plugin pads")), function_name); bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline)); gst_bus_post (bus, message); g_object_unref (bus); }
static BraseroBurnResult brasero_transcode_set_boundaries (BraseroTranscode *transcode) { BraseroTranscodePrivate *priv; BraseroTrack *track; gint64 start; gint64 end; priv = BRASERO_TRANSCODE_PRIVATE (transcode); /* we need to reach the song start and set a possible end; this is only * needed when it is decoding a song. Otherwise*/ brasero_job_get_current_track (BRASERO_JOB (transcode), &track); start = brasero_track_stream_get_start (BRASERO_TRACK_STREAM (track)); end = brasero_track_stream_get_end (BRASERO_TRACK_STREAM (track)); priv->segment_start = BRASERO_DURATION_TO_BYTES (start); priv->segment_end = BRASERO_DURATION_TO_BYTES (end); BRASERO_JOB_LOG (transcode, "settings track boundaries time = %lli %lli / bytes = %lli %lli", start, end, priv->segment_start, priv->segment_end); return BRASERO_BURN_OK; }
static gboolean brasero_transcode_create_pipeline_size_mp3 (BraseroTranscode *transcode, GstElement *pipeline, GstElement *source, GError **error) { BraseroTranscodePrivate *priv; GstElement *parse; GstElement *sink; priv = BRASERO_TRANSCODE_PRIVATE (transcode); BRASERO_JOB_LOG (transcode, "Creating specific pipeline for MP3s"); parse = gst_element_factory_make ("mpegaudioparse", NULL); if (!parse) { g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("%s element could not be created"), "\"mpegaudioparse\""); g_object_unref (pipeline); return FALSE; } gst_bin_add (GST_BIN (pipeline), parse); sink = gst_element_factory_make ("fakesink", NULL); if (!sink) { g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("%s element could not be created"), "\"Fakesink\""); g_object_unref (pipeline); return FALSE; } gst_bin_add (GST_BIN (pipeline), sink); /* Link */ if (!gst_element_link_many (source, parse, sink, NULL)) { g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("Impossible to link plugin pads")); BRASERO_JOB_LOG (transcode, "Impossible to link elements"); g_object_unref (pipeline); return FALSE; } priv->convert = NULL; priv->sink = sink; priv->source = source; priv->pipeline = pipeline; /* Get it going */ gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); return TRUE; }
static gboolean brasero_transcode_bus_messages (GstBus *bus, GstMessage *msg, BraseroTranscode *transcode) { BraseroTranscodePrivate *priv; GstTagList *tags = NULL; GError *error = NULL; GstState state; gchar *debug; priv = BRASERO_TRANSCODE_PRIVATE (transcode); switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_TAG: /* we use the information to write an .inf file * for the time being just store the information */ gst_message_parse_tag (msg, &tags); gst_tag_list_foreach (tags, (GstTagForeachFunc) foreach_tag, transcode); gst_tag_list_free (tags); return TRUE; case GST_MESSAGE_ERROR: gst_message_parse_error (msg, &error, &debug); BRASERO_JOB_LOG (transcode, debug); g_free (debug); brasero_job_error (BRASERO_JOB (transcode), error); return FALSE; case GST_MESSAGE_EOS: brasero_transcode_song_end_reached (transcode); return FALSE; case GST_MESSAGE_STATE_CHANGED: { GstStateChangeReturn result; result = gst_element_get_state (priv->pipeline, &state, NULL, 1); if (result != GST_STATE_CHANGE_SUCCESS) return TRUE; if (state == GST_STATE_PLAYING) return brasero_transcode_active_state (transcode); break; } default: return TRUE; } return TRUE; }
static BraseroBurnResult brasero_transcode_clock_tick (BraseroJob *job) { BraseroTranscodePrivate *priv; priv = BRASERO_TRANSCODE_PRIVATE (job); if (!priv->pipeline) return BRASERO_BURN_ERR; brasero_job_set_written_track (job, priv->pos); return BRASERO_BURN_OK; }
static void brasero_transcode_finalize (GObject *object) { BraseroTranscodePrivate *priv; priv = BRASERO_TRANSCODE_PRIVATE (object); if (priv->pad_id) { g_source_remove (priv->pad_id); priv->pad_id = 0; } brasero_transcode_stop_pipeline (BRASERO_TRANSCODE (object)); G_OBJECT_CLASS (parent_class)->finalize (object); }
static BraseroBurnResult brasero_transcode_stop (BraseroJob *job, GError **error) { BraseroTranscodePrivate *priv; priv = BRASERO_TRANSCODE_PRIVATE (job); priv->mp3_size_pipeline = 0; if (priv->pad_id) { g_source_remove (priv->pad_id); priv->pad_id = 0; } brasero_transcode_stop_pipeline (BRASERO_TRANSCODE (job)); return BRASERO_BURN_OK; }
static gboolean brasero_transcode_create_pipeline (BraseroTranscode *transcode, GError **error) { gchar *uri; gboolean keep_dts; GstElement *decode; GstElement *source; GstBus *bus = NULL; GstCaps *filtercaps; GValue *value = NULL; GstElement *pipeline; GstElement *sink = NULL; BraseroJobAction action; GstElement *filter = NULL; GstElement *volume = NULL; GstElement *convert = NULL; BraseroTrack *track = NULL; GstElement *resample = NULL; BraseroTranscodePrivate *priv; priv = BRASERO_TRANSCODE_PRIVATE (transcode); BRASERO_JOB_LOG (transcode, "Creating new pipeline"); priv->set_active_state = 0; /* free the possible current pipeline and create a new one */ if (priv->pipeline) { gst_element_set_state (priv->pipeline, GST_STATE_NULL); gst_object_unref (G_OBJECT (priv->pipeline)); priv->link = NULL; priv->sink = NULL; priv->source = NULL; priv->convert = NULL; priv->pipeline = NULL; } /* create three types of pipeline according to the needs: (possibly adding grvolume) * - filesrc ! decodebin ! audioconvert ! fakesink (find size) and filesrc!mp3parse!fakesink for mp3s * - filesrc ! decodebin ! audioresample ! audioconvert ! audio/x-raw,format=S16BE,rate=44100 ! filesink * - filesrc ! decodebin ! audioresample ! audioconvert ! audio/x-raw,format=S16BE,rate=44100 ! fdsink */ pipeline = gst_pipeline_new (NULL); bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_add_watch (bus, (GstBusFunc) brasero_transcode_bus_messages, transcode); gst_object_unref (bus); /* source */ brasero_job_get_current_track (BRASERO_JOB (transcode), &track); uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), TRUE); source = gst_element_make_from_uri (GST_URI_SRC, uri, NULL, NULL); g_free (uri); if (source == NULL) { g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, /* Translators: %s is the name of the object (as in * GObject) from the Gstreamer library that could * not be created */ _("%s element could not be created"), "\"Source\""); goto error; } gst_bin_add (GST_BIN (pipeline), source); g_object_set (source, "typefind", FALSE, NULL); /* sink */ brasero_job_get_action (BRASERO_JOB (transcode), &action); switch (action) { case BRASERO_JOB_ACTION_SIZE: if (priv->mp3_size_pipeline) return brasero_transcode_create_pipeline_size_mp3 (transcode, pipeline, source, error); sink = gst_element_factory_make ("fakesink", NULL); break; case BRASERO_JOB_ACTION_IMAGE: volume = brasero_transcode_create_volume (transcode, track); if (brasero_job_get_fd_out (BRASERO_JOB (transcode), NULL) != BRASERO_BURN_OK) { gchar *output; brasero_job_get_image_output (BRASERO_JOB (transcode), &output, NULL); sink = gst_element_factory_make ("filesink", NULL); g_object_set (sink, "location", output, NULL); g_free (output); } else { int fd; brasero_job_get_fd_out (BRASERO_JOB (transcode), &fd); sink = gst_element_factory_make ("fdsink", NULL); g_object_set (sink, "fd", fd, NULL); } break; default: goto error; } if (!sink) { g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("%s element could not be created"), "\"Sink\""); goto error; } gst_bin_add (GST_BIN (pipeline), sink); g_object_set (sink, "sync", FALSE, NULL); brasero_job_tag_lookup (BRASERO_JOB (transcode), BRASERO_SESSION_STREAM_AUDIO_FORMAT, &value); if (value) keep_dts = (g_value_get_int (value) & BRASERO_AUDIO_FORMAT_DTS) != 0; else keep_dts = FALSE; if (keep_dts && action == BRASERO_JOB_ACTION_IMAGE && (brasero_track_stream_get_format (BRASERO_TRACK_STREAM (track)) & BRASERO_AUDIO_FORMAT_DTS) != 0) { GstElement *wavparse; GstPad *sinkpad; BRASERO_JOB_LOG (transcode, "DTS wav pipeline"); /* FIXME: volume normalization won't work here. We'd need to * reencode it afterwards otherwise. */ /* This is a special case. This is DTS wav. So we only decode wav. */ wavparse = gst_element_factory_make ("wavparse", NULL); if (wavparse == NULL) { g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("%s element could not be created"), "\"Wavparse\""); goto error; } gst_bin_add (GST_BIN (pipeline), wavparse); if (!gst_element_link_many (source, wavparse, sink, NULL)) { g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("Impossible to link plugin pads")); goto error; } /* This is an ugly workaround for the lack of accuracy with * gstreamer. Yet this is unfortunately a necessary evil. */ /* FIXME: this does not look like it makes sense... (tpm) */ priv->pos = 0; priv->size = 0; sinkpad = gst_element_get_static_pad (sink, "sink"); priv->probe = gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER, brasero_transcode_buffer_handler, transcode, NULL); gst_object_unref (sinkpad); priv->link = NULL; priv->sink = sink; priv->decode = NULL; priv->source = source; priv->convert = NULL; priv->pipeline = pipeline; gst_element_set_state (pipeline, GST_STATE_PLAYING); return TRUE; } /* audioconvert */ convert = gst_element_factory_make ("audioconvert", NULL); if (convert == NULL) { g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("%s element could not be created"), "\"Audioconvert\""); goto error; } gst_bin_add (GST_BIN (pipeline), convert); if (action == BRASERO_JOB_ACTION_IMAGE) { BraseroStreamFormat session_format; BraseroTrackType *output_type; output_type = brasero_track_type_new (); brasero_job_get_output_type (BRASERO_JOB (transcode), output_type); session_format = brasero_track_type_get_stream_format (output_type); brasero_track_type_free (output_type); /* audioresample */ resample = gst_element_factory_make ("audioresample", NULL); if (resample == NULL) { g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("%s element could not be created"), "\"Audioresample\""); goto error; } gst_bin_add (GST_BIN (pipeline), resample); /* filter */ filter = gst_element_factory_make ("capsfilter", NULL); if (!filter) { g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("%s element could not be created"), "\"Filter\""); goto error; } gst_bin_add (GST_BIN (pipeline), filter); filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw", /* NOTE: we use little endianness only for libburn which requires little */ "format", G_TYPE_STRING, (session_format & BRASERO_AUDIO_FORMAT_RAW_LITTLE_ENDIAN) != 0 ? "S16LE" : "S16BE", "channels", G_TYPE_INT, 2, "rate", G_TYPE_INT, 44100, NULL), NULL); g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL); gst_caps_unref (filtercaps); } /* decode */ decode = gst_element_factory_make ("decodebin", NULL); if (decode == NULL) { g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("%s element could not be created"), "\"Decodebin\""); goto error; } gst_bin_add (GST_BIN (pipeline), decode); if (action == BRASERO_JOB_ACTION_IMAGE) { GstPad *sinkpad; gboolean res; if (!gst_element_link (source, decode)) { BRASERO_JOB_LOG (transcode, "Impossible to link plugin pads"); g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("Impossible to link plugin pads")); goto error; } priv->link = resample; g_signal_connect (G_OBJECT (decode), "pad-added", G_CALLBACK (brasero_transcode_new_decoded_pad_cb), transcode); if (volume) { gst_bin_add (GST_BIN (pipeline), volume); res = gst_element_link_many (resample, volume, convert, filter, sink, NULL); } else res = gst_element_link_many (resample, convert, filter, sink, NULL); if (!res) { BRASERO_JOB_LOG (transcode, "Impossible to link plugin pads"); g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("Impossible to link plugin pads")); goto error; } /* This is an ugly workaround for the lack of accuracy with * gstreamer. Yet this is unfortunately a necessary evil. */ /* FIXME: this does not look like it makes sense... (tpm) */ priv->pos = 0; priv->size = 0; sinkpad = gst_element_get_static_pad (sink, "sink"); priv->probe = gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER, brasero_transcode_buffer_handler, transcode, NULL); gst_object_unref (sinkpad); } else { if (!gst_element_link (source, decode) || !gst_element_link (convert, sink)) { BRASERO_JOB_LOG (transcode, "Impossible to link plugin pads"); g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, _("Impossible to link plugin pads")); goto error; } priv->link = convert; g_signal_connect (G_OBJECT (decode), "pad-added", G_CALLBACK (brasero_transcode_new_decoded_pad_cb), transcode); } priv->sink = sink; priv->decode = decode; priv->source = source; priv->convert = convert; priv->pipeline = pipeline; gst_element_set_state (pipeline, GST_STATE_PLAYING); return TRUE; error: if (error && (*error)) BRASERO_JOB_LOG (transcode, "can't create object : %s \n", (*error)->message); gst_object_unref (GST_OBJECT (pipeline)); return FALSE; }
static gboolean brasero_transcode_pad (BraseroTranscode *transcode, int fd, GError **error) { guint64 length = 0; gint64 bytes2write = 0; BraseroTrack *track = NULL; BraseroTranscodePrivate *priv; priv = BRASERO_TRANSCODE_PRIVATE (transcode); if (priv->pos < 0) return TRUE; /* Padding is important for two reasons: * - first if didn't output enough bytes compared to what we should have * - second we must output a multiple of 2352 to respect sector * boundaries */ brasero_job_get_current_track (BRASERO_JOB (transcode), &track); brasero_track_stream_get_length (BRASERO_TRACK_STREAM (track), &length); if (priv->pos < BRASERO_DURATION_TO_BYTES (length)) { gint64 b_written = 0; /* Check bytes boundary for length */ b_written = BRASERO_DURATION_TO_BYTES (length); b_written += (b_written % 2352) ? 2352 - (b_written % 2352):0; bytes2write = b_written - priv->pos; BRASERO_JOB_LOG (transcode, "wrote %lli bytes (= %lli ns) out of %lli (= %lli ns)" "\n=> padding %lli bytes", priv->pos, BRASERO_BYTES_TO_DURATION (priv->pos), BRASERO_DURATION_TO_BYTES (length), length, bytes2write); } else { gint64 b_written = 0; /* wrote more or the exact amount of bytes. Check bytes boundary */ b_written = priv->pos; bytes2write = (b_written % 2352) ? 2352 - (b_written % 2352):0; BRASERO_JOB_LOG (transcode, "wrote %lli bytes (= %lli ns)" "\n=> padding %lli bytes", b_written, priv->pos, bytes2write); } if (!bytes2write) return TRUE; bytes2write = brasero_transcode_pad_real (transcode, fd, bytes2write, error); if (bytes2write == -1) return TRUE; if (bytes2write) { BraseroTranscodePrivate *priv; priv = BRASERO_TRANSCODE_PRIVATE (transcode); /* when writing to a pipe it can happen that its buffer is full * because cdrecord is not fast enough. Therefore we couldn't * write/pad it and we'll have to wait for the pipe to become * available again */ priv->pad_fd = fd; priv->pad_size = bytes2write; priv->pad_id = g_timeout_add (50, (GSourceFunc) brasero_transcode_pad_idle, transcode); return FALSE; } return TRUE; }
/* FIXME: this entire function looks completely wrong, if there is or * was a bug in GStreamer it should be fixed there (tpm) */ static GstPadProbeReturn brasero_transcode_buffer_handler (GstPad *pad, GstPadProbeInfo *info, gpointer user_data) { BraseroTranscodePrivate *priv; BraseroTranscode *self = user_data; GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info); GstPad *peer; gint64 size; priv = BRASERO_TRANSCODE_PRIVATE (self); size = gst_buffer_get_size (buffer); if (priv->segment_start <= 0 && priv->segment_end <= 0) return GST_PAD_PROBE_OK; /* what we do here is more or less what gstreamer does when seeking: * it reads and process from 0 to the seek position (I tried). * It even forwards the data before the seek position to the sink (which * is a problem in our case as it would be written) */ if (priv->size > priv->segment_end) { priv->size += size; return GST_PAD_PROBE_DROP; } if (priv->size + size > priv->segment_end) { GstBuffer *new_buffer; int data_size; /* the entire the buffer is not interesting for us */ /* create a new buffer and push it on the pad: * NOTE: we're going to receive it ... */ data_size = priv->segment_end - priv->size; new_buffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_METADATA, 0, data_size); /* FIXME: we can now modify the probe buffer in 0.11 */ /* Recursive: the following calls ourselves BEFORE we finish */ peer = gst_pad_get_peer (pad); gst_pad_push (peer, new_buffer); priv->size += size - data_size; /* post an EOS event to stop pipeline */ gst_pad_push_event (peer, gst_event_new_eos ()); gst_object_unref (peer); return GST_PAD_PROBE_DROP; } /* see if the buffer is in the segment */ if (priv->size < priv->segment_start) { GstBuffer *new_buffer; gint data_size; /* see if all the buffer is interesting for us */ if (priv->size + size < priv->segment_start) { priv->size += size; return GST_PAD_PROBE_DROP; } /* create a new buffer and push it on the pad: * NOTE: we're going to receive it ... */ data_size = priv->size + size - priv->segment_start; new_buffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_METADATA, size - data_size, data_size); /* FIXME: this looks dodgy (tpm) */ GST_BUFFER_TIMESTAMP (new_buffer) = GST_BUFFER_TIMESTAMP (buffer) + data_size; /* move forward by the size of bytes we dropped */ priv->size += size - data_size; /* FIXME: we can now modify the probe buffer in 0.11 */ /* this is recursive the following calls ourselves * BEFORE we finish */ peer = gst_pad_get_peer (pad); gst_pad_push (peer, new_buffer); gst_object_unref (peer); return GST_PAD_PROBE_DROP; } priv->size += size; priv->pos += size; return GST_PAD_PROBE_OK; }
/* NOTE: the return value is whether or not we should stop the bus callback */ static gboolean brasero_transcode_active_state (BraseroTranscode *transcode) { BraseroTranscodePrivate *priv; gchar *name, *string, *uri; BraseroJobAction action; BraseroTrack *track; priv = BRASERO_TRANSCODE_PRIVATE (transcode); if (priv->set_active_state) return TRUE; priv->set_active_state = TRUE; brasero_job_get_current_track (BRASERO_JOB (transcode), &track); uri = brasero_track_stream_get_source (BRASERO_TRACK_STREAM (track), FALSE); brasero_job_get_action (BRASERO_JOB (transcode), &action); if (action == BRASERO_JOB_ACTION_SIZE) { BRASERO_JOB_LOG (transcode, "Analysing Track %s", uri); if (priv->mp3_size_pipeline) { gchar *escaped_basename; /* Run the pipeline till the end */ escaped_basename = g_path_get_basename (uri); name = g_uri_unescape_string (escaped_basename, NULL); g_free (escaped_basename); string = g_strdup_printf (_("Analysing \"%s\""), name); g_free (name); brasero_job_set_current_action (BRASERO_JOB (transcode), BRASERO_BURN_ACTION_ANALYSING, string, TRUE); g_free (string); brasero_job_start_progress (BRASERO_JOB (transcode), FALSE); g_free (uri); return TRUE; } if (brasero_transcode_is_mp3 (transcode)) { GError *error = NULL; /* Rebuild another pipeline which is specific to MP3s. */ priv->mp3_size_pipeline = TRUE; brasero_transcode_stop_pipeline (transcode); if (!brasero_transcode_create_pipeline (transcode, &error)) brasero_job_error (BRASERO_JOB (transcode), error); } else brasero_transcode_song_end_reached (transcode); g_free (uri); return FALSE; } else { gchar *escaped_basename; escaped_basename = g_path_get_basename (uri); name = g_uri_unescape_string (escaped_basename, NULL); g_free (escaped_basename); string = g_strdup_printf (_("Transcoding \"%s\""), name); g_free (name); brasero_job_set_current_action (BRASERO_JOB (transcode), BRASERO_BURN_ACTION_TRANSCODING, string, TRUE); g_free (string); brasero_job_start_progress (BRASERO_JOB (transcode), FALSE); if (brasero_job_get_fd_out (BRASERO_JOB (transcode), NULL) != BRASERO_BURN_OK) { gchar *dest = NULL; brasero_job_get_audio_output (BRASERO_JOB (transcode), &dest); BRASERO_JOB_LOG (transcode, "start decoding %s to %s", uri, dest); g_free (dest); } else BRASERO_JOB_LOG (transcode, "start piping %s", uri) } g_free (uri); return TRUE; }
static void brasero_transcode_new_decoded_pad_cb (GstElement *decode, GstPad *pad, BraseroTranscode *transcode) { GstCaps *caps; GstStructure *structure; BraseroTranscodePrivate *priv; priv = BRASERO_TRANSCODE_PRIVATE (transcode); BRASERO_JOB_LOG (transcode, "New pad"); /* make sure we only have audio */ /* FIXME: get_current_caps() doesn't always seem to work yet here */ caps = gst_pad_query_caps (pad, NULL); if (!caps) return; structure = gst_caps_get_structure (caps, 0); if (structure) { if (g_strrstr (gst_structure_get_name (structure), "audio")) { GstPad *sink; GstElement *queue; GstPadLinkReturn res; /* before linking pads (before any data reach grvolume), send tags */ brasero_transcode_send_volume_event (transcode); /* This is necessary in case there is a video stream * (see brasero-metadata.c). we need to queue to avoid * a deadlock. */ queue = gst_element_factory_make ("queue", NULL); gst_bin_add (GST_BIN (priv->pipeline), queue); if (!gst_element_link (queue, priv->link)) { brasero_transcode_error_on_pad_linking (transcode, "Sent by brasero_transcode_new_decoded_pad_cb"); goto end; } sink = gst_element_get_static_pad (queue, "sink"); if (GST_PAD_IS_LINKED (sink)) { brasero_transcode_error_on_pad_linking (transcode, "Sent by brasero_transcode_new_decoded_pad_cb"); goto end; } res = gst_pad_link (pad, sink); if (res == GST_PAD_LINK_OK) gst_element_set_state (queue, GST_STATE_PLAYING); else brasero_transcode_error_on_pad_linking (transcode, "Sent by brasero_transcode_new_decoded_pad_cb"); gst_object_unref (sink); } /* For video streams add a fakesink (see brasero-metadata.c) */ else if (g_strrstr (gst_structure_get_name (structure), "video")) { GstPad *sink; GstElement *fakesink; GstPadLinkReturn res; BRASERO_JOB_LOG (transcode, "Adding a fakesink for video stream"); fakesink = gst_element_factory_make ("fakesink", NULL); if (!fakesink) { brasero_transcode_error_on_pad_linking (transcode, "Sent by brasero_transcode_new_decoded_pad_cb"); goto end; } sink = gst_element_get_static_pad (fakesink, "sink"); if (!sink) { brasero_transcode_error_on_pad_linking (transcode, "Sent by brasero_transcode_new_decoded_pad_cb"); gst_object_unref (fakesink); goto end; } gst_bin_add (GST_BIN (priv->pipeline), fakesink); res = gst_pad_link (pad, sink); if (res == GST_PAD_LINK_OK) gst_element_set_state (fakesink, GST_STATE_PLAYING); else brasero_transcode_error_on_pad_linking (transcode, "Sent by brasero_transcode_new_decoded_pad_cb"); gst_object_unref (sink); } } end: gst_caps_unref (caps); }
static gboolean brasero_transcode_buffer_handler (GstPad *pad, GstBuffer *buffer, BraseroTranscode *self) { BraseroTranscodePrivate *priv; GstPad *peer; gint64 size; priv = BRASERO_TRANSCODE_PRIVATE (self); size = GST_BUFFER_SIZE (buffer); if (priv->segment_start <= 0 && priv->segment_end <= 0) return TRUE; /* what we do here is more or less what gstreamer does when seeking: * it reads and process from 0 to the seek position (I tried). * It even forwards the data before the seek position to the sink (which * is a problem in our case as it would be written) */ if (priv->size > priv->segment_end) { priv->size += size; return FALSE; } if (priv->size + size > priv->segment_end) { GstBuffer *new_buffer; int data_size; /* the entire the buffer is not interesting for us */ /* create a new buffer and push it on the pad: * NOTE: we're going to receive it ... */ data_size = priv->segment_end - priv->size; new_buffer = gst_buffer_new_and_alloc (data_size); memcpy (GST_BUFFER_DATA (new_buffer), GST_BUFFER_DATA (buffer), data_size); /* Recursive: the following calls ourselves BEFORE we finish */ peer = gst_pad_get_peer (pad); gst_pad_push (peer, new_buffer); priv->size += size - data_size; /* post an EOS event to stop pipeline */ gst_pad_push_event (peer, gst_event_new_eos ()); gst_object_unref (peer); return FALSE; } /* see if the buffer is in the segment */ if (priv->size < priv->segment_start) { GstBuffer *new_buffer; gint data_size; /* see if all the buffer is interesting for us */ if (priv->size + size < priv->segment_start) { priv->size += size; return FALSE; } /* create a new buffer and push it on the pad: * NOTE: we're going to receive it ... */ data_size = priv->size + size - priv->segment_start; new_buffer = gst_buffer_new_and_alloc (data_size); memcpy (GST_BUFFER_DATA (new_buffer), GST_BUFFER_DATA (buffer) + GST_BUFFER_SIZE (buffer) - data_size, data_size); GST_BUFFER_TIMESTAMP (new_buffer) = GST_BUFFER_TIMESTAMP (buffer) + data_size; /* move forward by the size of bytes we dropped */ priv->size += size - data_size; /* this is recursive the following calls ourselves * BEFORE we finish */ peer = gst_pad_get_peer (pad); gst_pad_push (peer, new_buffer); gst_object_unref (peer); return FALSE; } priv->size += size; priv->pos += size; return TRUE; }