diff --git a/ext/vorbis/gstvorbisenc.c b/ext/vorbis/gstvorbisenc.c index ab309af161..eae99a1ae9 100644 --- a/ext/vorbis/gstvorbisenc.c +++ b/ext/vorbis/gstvorbisenc.c @@ -248,6 +248,8 @@ gst_vorbis_enc_stop (GstAudioEncoder * enc) g_slist_foreach (vorbisenc->headers, (GFunc) gst_buffer_unref, NULL); vorbisenc->headers = NULL; + gst_tag_setter_reset_tags (GST_TAG_SETTER (enc)); + return TRUE; } diff --git a/gst-libs/gst/audio/gstaudiodecoder.c b/gst-libs/gst/audio/gstaudiodecoder.c index c9a1ab6cd0..6fb3ebed51 100644 --- a/gst-libs/gst/audio/gstaudiodecoder.c +++ b/gst-libs/gst/audio/gstaudiodecoder.c @@ -585,47 +585,95 @@ gst_audio_decoder_setup (GstAudioDecoder * dec) dec->priv->agg = ! !res; } -/* mini aggregator combining output buffers into fewer larger ones, - * if so allowed/configured */ static GstFlowReturn -gst_audio_decoder_output (GstAudioDecoder * dec, GstBuffer * buf) +gst_audio_decoder_push_forward (GstAudioDecoder * dec, GstBuffer * buf) { GstAudioDecoderClass *klass; GstAudioDecoderPrivate *priv; GstAudioDecoderContext *ctx; GstFlowReturn ret = GST_FLOW_OK; - GstBuffer *inbuf = NULL; klass = GST_AUDIO_DECODER_GET_CLASS (dec); priv = dec->priv; ctx = &dec->priv->ctx; + g_return_val_if_fail (ctx->info.bpf != 0, GST_FLOW_ERROR); + + if (G_UNLIKELY (!buf)) { + g_assert_not_reached (); + return GST_FLOW_OK; + } + + GST_LOG_OBJECT (dec, "clipping buffer of size %d with ts %" GST_TIME_FORMAT + ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buf), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); + + /* clip buffer */ + buf = gst_audio_buffer_clip (buf, &dec->segment, ctx->info.rate, + ctx->info.bpf); + if (G_UNLIKELY (!buf)) { + GST_DEBUG_OBJECT (dec, "no data after clipping to segment"); + goto exit; + } + + /* decorate */ + if (G_UNLIKELY (priv->discont)) { + GST_LOG_OBJECT (dec, "marking discont"); + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); + priv->discont = FALSE; + } + + /* track where we are */ + if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) { + /* duration should always be valid for raw audio */ + g_assert (GST_BUFFER_DURATION_IS_VALID (buf)); + dec->segment.position = + GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf); + } + + if (klass->pre_push) { + /* last chance for subclass to do some dirty stuff */ + ret = klass->pre_push (dec, &buf); + if (ret != GST_FLOW_OK || !buf) { + GST_DEBUG_OBJECT (dec, "subclass returned %s, buf %p", + gst_flow_get_name (ret), buf); + if (buf) + gst_buffer_unref (buf); + goto exit; + } + } + + GST_LOG_OBJECT (dec, "pushing buffer of size %d with ts %" GST_TIME_FORMAT + ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buf), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); + + ret = gst_pad_push (dec->srcpad, buf); + +exit: + return ret; +} + +/* mini aggregator combining output buffers into fewer larger ones, + * if so allowed/configured */ +static GstFlowReturn +gst_audio_decoder_output (GstAudioDecoder * dec, GstBuffer * buf) +{ + GstAudioDecoderPrivate *priv; + GstFlowReturn ret = GST_FLOW_OK; + GstBuffer *inbuf = NULL; + + priv = dec->priv; + if (G_UNLIKELY (priv->agg < 0)) gst_audio_decoder_setup (dec); if (G_LIKELY (buf)) { - g_return_val_if_fail (ctx->info.bpf != 0, GST_FLOW_ERROR); - - GST_LOG_OBJECT (dec, - "output buffer of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT + GST_LOG_OBJECT (dec, "output buffer of size %d with ts %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - - /* clip buffer */ - buf = gst_audio_buffer_clip (buf, &dec->segment, ctx->info.rate, - ctx->info.bpf); - if (G_UNLIKELY (!buf)) { - GST_DEBUG_OBJECT (dec, "no data after clipping to segment"); - } else { - GST_LOG_OBJECT (dec, - "buffer after segment clipping has size %" G_GSIZE_FORMAT " with ts %" - GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, - gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - } - } else { - GST_DEBUG_OBJECT (dec, "no output buffer"); } again: @@ -675,39 +723,8 @@ again: } if (G_LIKELY (buf)) { - - if (G_UNLIKELY (priv->discont)) { - GST_LOG_OBJECT (dec, "marking discont"); - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - priv->discont = FALSE; - } - - if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) { - /* duration should always be valid for raw audio */ - g_assert (GST_BUFFER_DURATION_IS_VALID (buf)); - dec->segment.position = - GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf); - } - - if (klass->pre_push) { - /* last chance for subclass to do some dirty stuff */ - ret = klass->pre_push (dec, &buf); - if (ret != GST_FLOW_OK || !buf) { - GST_DEBUG_OBJECT (dec, "subclass returned %s, buf %p", - gst_flow_get_name (ret), buf); - if (buf) - gst_buffer_unref (buf); - goto exit; - } - } - - GST_LOG_OBJECT (dec, "pushing buffer of size %d with ts %" GST_TIME_FORMAT - ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - if (dec->segment.rate > 0.0) { - ret = gst_pad_push (dec->srcpad, buf); + ret = gst_audio_decoder_push_forward (dec, buf); GST_LOG_OBJECT (dec, "buffer pushed: %s", gst_flow_get_name (ret)); } else { ret = GST_FLOW_OK; @@ -715,7 +732,6 @@ again: GST_LOG_OBJECT (dec, "buffer queued"); } - exit: if (inbuf) { buf = inbuf; goto again; @@ -1202,6 +1218,7 @@ gst_audio_decoder_flush_decode (GstAudioDecoder * dec) { GstAudioDecoderPrivate *priv = dec->priv; GstFlowReturn res = GST_FLOW_OK; + GstClockTime timestamp; GList *walk; walk = priv->decode; @@ -1239,9 +1256,28 @@ gst_audio_decoder_flush_decode (GstAudioDecoder * dec) gst_audio_decoder_drain (dec); /* now send queued data downstream */ + timestamp = GST_CLOCK_TIME_NONE; while (priv->queued) { GstBuffer *buf = GST_BUFFER_CAST (priv->queued->data); + /* duration should always be valid for raw audio */ + g_assert (GST_BUFFER_DURATION_IS_VALID (buf)); + + /* interpolate (backward) if needed */ + if (G_LIKELY (timestamp != -1)) + timestamp -= GST_BUFFER_DURATION (buf); + + if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { + GST_LOG_OBJECT (dec, "applying reverse interpolated ts %" + GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); + GST_BUFFER_TIMESTAMP (buf) = timestamp; + } else { + /* track otherwise */ + timestamp = GST_BUFFER_TIMESTAMP (buf); + GST_LOG_OBJECT (dec, "tracking ts %" GST_TIME_FORMAT, + GST_TIME_ARGS (timestamp)); + } + if (G_LIKELY (res == GST_FLOW_OK)) { GST_DEBUG_OBJECT (dec, "pushing buffer %p of size %u, " "time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf, @@ -1252,7 +1288,7 @@ gst_audio_decoder_flush_decode (GstAudioDecoder * dec) /* avoid stray DISCONT from forward processing, * which have no meaning in reverse pushing */ GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT); - res = gst_pad_push (dec->srcpad, buf); + res = gst_audio_decoder_push_forward (dec, buf); } else { gst_buffer_unref (buf); } diff --git a/gst-libs/gst/audio/gstaudioencoder.c b/gst-libs/gst/audio/gstaudioencoder.c index 485087228f..81f61b5f1b 100644 --- a/gst-libs/gst/audio/gstaudioencoder.c +++ b/gst-libs/gst/audio/gstaudioencoder.c @@ -1087,6 +1087,13 @@ gst_audio_encoder_sink_setcaps (GstAudioEncoder * enc, GstCaps * caps) if (res) ctx->info = state; + /* invalidate state to ensure no casual carrying on */ + if (!res) { + GST_DEBUG_OBJECT (enc, "subclass did not accept format"); + gst_audio_info_init (&state); + goto exit; + } + /* notify if new latency */ GST_OBJECT_LOCK (enc); if ((ctx->min_latency > 0 && ctx->min_latency != old_min_latency) || diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.h b/gst-libs/gst/rtp/gstrtcpbuffer.h index 2a9d41ae3d..da8dce26d1 100644 --- a/gst-libs/gst/rtp/gstrtcpbuffer.h +++ b/gst-libs/gst/rtp/gstrtcpbuffer.h @@ -63,10 +63,17 @@ typedef enum * GstRTCPFBType: * @GST_RTCP_FB_TYPE_INVALID: Invalid type * @GST_RTCP_RTPFB_TYPE_NACK: Generic NACK + * @GST_RTCP_RTPFB_TYPE_TMMBR: Temporary Maximum Media Stream Bit Rate Request + * @GST_RTCP_RTPFB_TYPE_TMMBN: Temporary Maximum Media Stream Bit Rate + * Notification * @GST_RTCP_PSFB_TYPE_PLI: Picture Loss Indication * @GST_RTCP_PSFB_TYPE_SLI: Slice Loss Indication * @GST_RTCP_PSFB_TYPE_RPSI: Reference Picture Selection Indication * @GST_RTCP_PSFB_TYPE_AFB: Application layer Feedback + * @GST_RTCP_PSFB_TYPE_FIR: Full Intra Request Command + * @GST_RTCP_PSFB_TYPE_TSTR: Temporal-Spatial Trade-off Request + * @GST_RTCP_PSFB_TYPE_TSTN: Temporal-Spatial Trade-off Notification + * @GST_RTCP_PSFB_TYPE_VBCN: Video Back Channel Message * * Different types of feedback messages. * @@ -78,11 +85,19 @@ typedef enum GST_RTCP_FB_TYPE_INVALID = 0, /* RTPFB types */ GST_RTCP_RTPFB_TYPE_NACK = 1, + /* RTPFB types assigned in RFC 5104 */ + GST_RTCP_RTPFB_TYPE_TMMBR = 3, + GST_RTCP_RTPFB_TYPE_TMMBN = 4, /* PSFB types */ GST_RTCP_PSFB_TYPE_PLI = 1, GST_RTCP_PSFB_TYPE_SLI = 2, GST_RTCP_PSFB_TYPE_RPSI = 3, - GST_RTCP_PSFB_TYPE_AFB = 15 + GST_RTCP_PSFB_TYPE_AFB = 15, + /* PSFB types assigned in RFC 5104 */ + GST_RTCP_PSFB_TYPE_FIR = 4, + GST_RTCP_PSFB_TYPE_TSTR = 5, + GST_RTCP_PSFB_TYPE_TSTN = 6, + GST_RTCP_PSFB_TYPE_VBCN = 7, } GstRTCPFBType; /**