diff --git a/ChangeLog b/ChangeLog index d9755cb965..5f35c01647 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2005-10-24 Tim-Philipp Müller + + * ext/flac/gstflacenc.c: (gst_flacenc_base_init), + (gst_flacenc_init), (gst_flacenc_sink_setcaps), + (gst_flacenc_seek_callback), (gst_flacenc_write_callback), + (gst_flacenc_sink_event), (gst_flacenc_chain), + (gst_flacenc_set_property), (gst_flacenc_get_property), + (gst_flacenc_change_state): + * ext/flac/gstflacenc.h: + Fix seeking, so that flacenc can rewrite the header with the + correct duration and amount of samples and all that at EOS; + also set timestamps and granulepos on outgoing buffers; add + debug category; fix state change function. + 2005-10-24 Julien MOUTTE * gst/videomixer/videomixer.c: Don't restrict video geometry diff --git a/ext/flac/gstflacenc.c b/ext/flac/gstflacenc.c index 84a5682968..f947a7b5d3 100644 --- a/ext/flac/gstflacenc.c +++ b/ext/flac/gstflacenc.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include "flac_compat.h" @@ -37,6 +38,14 @@ GstElementDetails flacenc_details = { "Wim Taymans ", }; +#define FLAC_SINK_CAPS \ + "audio/x-raw-int, " \ + "endianness = (int) BYTE_ORDER, " \ + "signed = (boolean) TRUE, " \ + "width = (int) 16, " \ + "depth = (int) 16, " \ + "rate = (int) [ 11025, 48000 ], " \ + "channels = (int) [ 1, 2 ]" static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, @@ -47,15 +56,9 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "endianness = (int) BYTE_ORDER, " - "signed = (boolean) TRUE, " - "width = (int) 16, " - "depth = (int) 16, " - "rate = (int) [ 11025, 48000 ], " "channels = (int) [ 1, 2 ]") + GST_STATIC_CAPS (FLAC_SINK_CAPS) ); - enum { PROP_0, @@ -74,6 +77,9 @@ enum PROP_RICE_PARAMETER_SEARCH_DIST }; +GST_DEBUG_CATEGORY_STATIC (flacenc_debug); +#define GST_CAT_DEFAULT flacenc_debug + #define _do_init(type) \ G_STMT_START{ \ @@ -89,7 +95,6 @@ enum GST_BOILERPLATE_FULL (GstFlacEnc, gst_flacenc, GstElement, GST_TYPE_ELEMENT, _do_init); - static void gst_flacenc_finalize (GObject * object); static gboolean gst_flacenc_sink_setcaps (GstPad * pad, GstCaps * caps); @@ -183,6 +188,9 @@ gst_flacenc_base_init (gpointer g_class) gst_static_pad_template_get (&sink_factory)); gst_element_class_set_details (element_class, &flacenc_details); + + GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0, + "Flac encoding element"); } static void @@ -298,6 +306,7 @@ gst_flacenc_init (GstFlacEnc * flacenc, GstFlacEncClass * klass) flacenc->encoder = FLAC__seekable_stream_encoder_new (); flacenc->offset = 0; + flacenc->samples_written = 0; gst_flacenc_update_quality (flacenc, DEFAULT_QUALITY); flacenc->tags = gst_tag_list_new (); } @@ -378,7 +387,7 @@ gst_flacenc_sink_setcaps (GstPad * pad, GstCaps * caps) || !gst_structure_get_int (structure, "depth", &flacenc->depth) || !gst_structure_get_int (structure, "rate", &flacenc->sample_rate)) /* we got caps incompatible with the template? */ - g_assert_not_reached (); + g_return_val_if_reached (FALSE); caps = gst_caps_new_simple ("audio/x-flac", "channels", G_TYPE_INT, flacenc->channels, @@ -487,27 +496,30 @@ gst_flacenc_seek_callback (const FLAC__SeekableStreamEncoder * encoder, FLAC__uint64 absolute_byte_offset, void *client_data) { GstFlacEnc *flacenc; + GstEvent *event; + GstPad *peerpad; flacenc = GST_FLACENC (client_data); if (flacenc->stopped) return FLAC__STREAM_ENCODER_OK; - g_warning ("seeking has not been ported from 0.8 yet"); + event = gst_event_new_newsegment (TRUE, 1.0, GST_FORMAT_BYTES, + absolute_byte_offset, GST_BUFFER_OFFSET_NONE, 0); + if ((peerpad = gst_pad_get_peer (flacenc->srcpad))) { + gboolean ret = gst_pad_send_event (peerpad, event); -#if 0 - GstEvent *event; + gst_object_unref (peerpad); - event = - gst_event_new_seek ((GstSeekType) (int) (GST_FORMAT_BYTES | - GST_SEEK_METHOD_SET), absolute_byte_offset); - - if (event) { - gst_pad_push (flacenc->srcpad, GST_DATA (event)); - flacenc->offset = absolute_byte_offset; + GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s", absolute_byte_offset, + (ret) ? "succeeded" : "failed"); + } else { + GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " failed (no peer pad)", + absolute_byte_offset); } -#endif + + flacenc->offset = absolute_byte_offset; return FLAC__STREAM_ENCODER_OK; } @@ -517,23 +529,48 @@ gst_flacenc_write_callback (const FLAC__SeekableStreamEncoder * encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data) { + GstFlowReturn ret; GstFlacEnc *flacenc; GstBuffer *outbuf; flacenc = GST_FLACENC (client_data); if (flacenc->stopped) - return FLAC__STREAM_ENCODER_OK; + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; - outbuf = gst_buffer_new_and_alloc (bytes); + if (gst_pad_alloc_buffer (flacenc->srcpad, flacenc->offset, bytes, + GST_PAD_CAPS (flacenc->srcpad), &outbuf) != GST_FLOW_OK) { + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } memcpy (GST_BUFFER_DATA (outbuf), buffer, bytes); - /* fixme: set timestamps, offsets, durations, your mom's phone # */ - gst_pad_push (flacenc->srcpad, outbuf); + if (samples > 0 && flacenc->samples_written != (guint64) - 1) { + GST_BUFFER_TIMESTAMP (outbuf) = + GST_FRAMES_TO_CLOCK_TIME (flacenc->samples_written, + flacenc->sample_rate); + GST_BUFFER_DURATION (outbuf) = + GST_FRAMES_TO_CLOCK_TIME (samples, flacenc->sample_rate); + /* offset_end = granulepos for ogg muxer */ + GST_BUFFER_OFFSET_END (outbuf) = flacenc->samples_written + samples; + } else { + GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE; + GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; + } + + GST_DEBUG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, " + "pos=%" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), + samples, bytes, flacenc->offset); + + ret = gst_pad_push (flacenc->srcpad, outbuf); + flacenc->offset += bytes; + flacenc->samples_written += samples; - return FLAC__STREAM_ENCODER_OK; + if (ret != GST_FLOW_OK && GST_FLOW_IS_FATAL (ret)) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; } static FLAC__SeekableStreamEncoderTellStatus @@ -552,14 +589,48 @@ gst_flacenc_sink_event (GstPad * pad, GstEvent * event) { GstFlacEnc *flacenc; GstTagList *taglist; - gboolean ret; + gboolean ret = TRUE; flacenc = GST_FLACENC (gst_pad_get_parent (pad)); + GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event)); + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT:{ + GstFormat format; + gint64 start, stream_time; + + GST_STREAM_LOCK (pad); + if (flacenc->offset == 0) { + gst_event_parse_newsegment (event, NULL, NULL, &format, &start, NULL, + &stream_time); + } else { + start = -1; + } + if (start != 0) { + if (flacenc->offset > 0) + GST_DEBUG ("Not handling mid-stream newsegment event"); + else + GST_DEBUG ("Not handling newsegment event with non-zero start"); + } else { + GstEvent *e = gst_event_new_newsegment (FALSE, 1.0, GST_FORMAT_BYTES, + 0, -1, 0); + + ret = gst_pad_push_event (flacenc->srcpad, e); + } + if (stream_time != 0) { + GST_DEBUG ("Not handling non-zero stream time"); + } + gst_event_unref (event); + /* don't push it downstream, we'll generate our own via seek to 0 */ + GST_STREAM_UNLOCK (pad); + break; + } case GST_EVENT_EOS: + GST_STREAM_LOCK (pad); FLAC__seekable_stream_encoder_finish (flacenc->encoder); ret = gst_pad_event_default (pad, event); + GST_STREAM_UNLOCK (pad); break; case GST_EVENT_TAG: if (flacenc->tags) { @@ -568,7 +639,9 @@ gst_flacenc_sink_event (GstPad * pad, GstEvent * event) } else { g_assert_not_reached (); } + GST_STREAM_LOCK (pad); ret = gst_pad_event_default (pad, event); + GST_STREAM_UNLOCK (pad); break; default: ret = gst_pad_event_default (pad, event); @@ -590,7 +663,6 @@ gst_flacenc_chain (GstPad * pad, GstBuffer * buffer) gulong i; FLAC__bool res; - /* we now have a ref on flacenc */ flacenc = GST_FLACENC (gst_pad_get_parent (pad)); depth = flacenc->depth; @@ -635,6 +707,8 @@ gst_flacenc_set_property (GObject * object, guint prop_id, { GstFlacEnc *this = GST_FLACENC (object); + GST_LOCK (this); + switch (prop_id) { case PROP_QUALITY: gst_flacenc_update_quality (this, g_value_get_enum (value)); @@ -689,8 +763,10 @@ gst_flacenc_set_property (GObject * object, guint prop_id, break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - return; + break; } + + GST_UNLOCK (this); } static void @@ -699,6 +775,8 @@ gst_flacenc_get_property (GObject * object, guint prop_id, { GstFlacEnc *this = GST_FLACENC (object); + GST_LOCK (this); + switch (prop_id) { case PROP_QUALITY: g_value_set_enum (value, this->quality); @@ -762,11 +840,14 @@ gst_flacenc_get_property (GObject * object, guint prop_id, G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } + + GST_UNLOCK (this); } static GstStateChangeReturn gst_flacenc_change_state (GstElement * element, GstStateChange transition) { + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstFlacEnc *flacenc = GST_FLACENC (element); switch (transition) { @@ -775,6 +856,13 @@ gst_flacenc_change_state (GstElement * element, GstStateChange transition) flacenc->stopped = FALSE; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: @@ -784,6 +872,7 @@ gst_flacenc_change_state (GstElement * element, GstStateChange transition) FLAC__seekable_stream_encoder_finish (flacenc->encoder); } flacenc->offset = 0; + flacenc->samples_written = 0; if (flacenc->meta) { FLAC__metadata_object_delete (flacenc->meta[0]); g_free (flacenc->meta); @@ -795,8 +884,5 @@ gst_flacenc_change_state (GstElement * element, GstStateChange transition) break; } - if (GST_ELEMENT_CLASS (parent_class)->change_state) - return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - return GST_STATE_CHANGE_SUCCESS; + return ret; } diff --git a/ext/flac/gstflacenc.h b/ext/flac/gstflacenc.h index 82a6cb2cc3..73c402853b 100644 --- a/ext/flac/gstflacenc.h +++ b/ext/flac/gstflacenc.h @@ -47,6 +47,7 @@ struct _GstFlacEnc { gboolean first; GstBuffer *first_buf; guint64 offset; + guint64 samples_written; gboolean eos; gint channels; gint depth;