2 * Copyright (C) 2009 Igalia S.L.
3 * Author: Iago Toral Quiroga <itoral@igalia.com>
4 * Copyright (C) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>.
5 * Copyright (C) 2011 Nokia Corporation. All rights reserved.
6 * Contact: Stefan Kost <stefan.kost@nokia.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 * SECTION:gstaudiodecoder
26 * @short_description: Base class for audio decoders
27 * @see_also: #GstBaseTransform
30 * This base class is for audio decoders turning encoded data into
33 * GstAudioDecoder and subclass should cooperate as follows.
36 * <itemizedlist><title>Configuration</title>
38 * Initially, GstAudioDecoder calls @start when the decoder element
39 * is activated, which allows subclass to perform any global setup.
40 * Base class (context) parameters can already be set according to subclass
41 * capabilities (or possibly upon receive more information in subsequent
45 * GstAudioDecoder calls @set_format to inform subclass of the format
46 * of input audio data that it is about to receive.
47 * While unlikely, it might be called more than once, if changing input
48 * parameters require reconfiguration.
51 * GstAudioDecoder calls @stop at end of all processing.
55 * As of configuration stage, and throughout processing, GstAudioDecoder
56 * provides various (context) parameters, e.g. describing the format of
57 * output audio data (valid when output caps have been set) or current parsing state.
58 * Conversely, subclass can and should configure context to inform
59 * base class of its expectation w.r.t. buffer handling.
62 * <title>Data processing</title>
64 * Base class gathers input data, and optionally allows subclass
65 * to parse this into subsequently manageable (as defined by subclass)
66 * chunks. Such chunks are subsequently referred to as 'frames',
67 * though they may or may not correspond to 1 (or more) audio format frame.
70 * Input frame is provided to subclass' @handle_frame.
73 * If codec processing results in decoded data, subclass should call
74 * @gst_audio_decoder_finish_frame to have decoded data pushed
78 * Just prior to actually pushing a buffer downstream,
79 * it is passed to @pre_push. Subclass should either use this callback
80 * to arrange for additional downstream pushing or otherwise ensure such
81 * custom pushing occurs after at least a method call has finished since
82 * setting src pad caps.
85 * During the parsing process GstAudioDecoderClass will handle both
86 * srcpad and sinkpad events. Sink events will be passed to subclass
87 * if @event callback has been provided.
92 * <itemizedlist><title>Shutdown phase</title>
94 * GstAudioDecoder class calls @stop to inform the subclass that data
95 * parsing will be stopped.
101 * Subclass is responsible for providing pad template caps for
102 * source and sink pads. The pads need to be named "sink" and "src". It also
103 * needs to set the fixed caps on srcpad, when the format is ensured. This
104 * is typically when base class calls subclass' @set_format function, though
105 * it might be delayed until calling @gst_audio_decoder_finish_frame.
107 * In summary, above process should have subclass concentrating on
108 * codec data processing while leaving other matters to base class,
109 * such as most notably timestamp handling. While it may exert more control
110 * in this area (see e.g. @pre_push), it is very much not recommended.
112 * In particular, base class will try to arrange for perfect output timestamps
113 * as much as possible while tracking upstream timestamps.
114 * To this end, if deviation between the next ideal expected perfect timestamp
115 * and upstream exceeds #GstAudioDecoder:tolerance, then resync to upstream
116 * occurs (which would happen always if the tolerance mechanism is disabled).
118 * In non-live pipelines, baseclass can also (configurably) arrange for
119 * output buffer aggregation which may help to redue large(r) numbers of
120 * small(er) buffers being pushed and processed downstream.
122 * On the other hand, it should be noted that baseclass only provides limited
123 * seeking support (upon explicit subclass request), as full-fledged support
124 * should rather be left to upstream demuxer, parser or alike. This simple
125 * approach caters for seeking and duration reporting using estimated input
128 * Things that subclass need to take care of:
130 * <listitem><para>Provide pad templates</para></listitem>
132 * Set source pad caps when appropriate
135 * Set user-configurable properties to sane defaults for format and
136 * implementing codec at hand, and convey some subclass capabilities and
137 * expectations in context.
140 * Accept data in @handle_frame and provide encoded results to
141 * @gst_audio_decoder_finish_frame. If it is prepared to perform
142 * PLC, it should also accept NULL data in @handle_frame and provide for
143 * data for indicated duration.
152 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
153 * with newer GLib versions (>= 2.31.0) */
154 #define GLIB_DISABLE_DEPRECATION_WARNINGS
156 #include "gstaudiodecoder.h"
157 #include <gst/pbutils/descriptions.h>
161 GST_DEBUG_CATEGORY (audiodecoder_debug);
162 #define GST_CAT_DEFAULT audiodecoder_debug
164 #define GST_AUDIO_DECODER_GET_PRIVATE(obj) \
165 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_AUDIO_DECODER, \
166 GstAudioDecoderPrivate))
181 #define DEFAULT_LATENCY 0
182 #define DEFAULT_TOLERANCE 0
183 #define DEFAULT_PLC FALSE
185 typedef struct _GstAudioDecoderContext
188 /* (output) audio format */
200 gboolean do_byte_time;
202 /* MT-protected (with LOCK) */
203 GstClockTime min_latency;
204 GstClockTime max_latency;
205 } GstAudioDecoderContext;
207 struct _GstAudioDecoderPrivate
209 /* activation status */
212 /* input base/first ts as basis for output ts */
213 GstClockTime base_ts;
214 /* input samples processed and sent downstream so far (w.r.t. base_ts) */
217 /* collected input data */
219 /* tracking input ts for changes */
220 GstClockTime prev_ts;
221 /* frames obtained from input */
223 /* collected output data */
224 GstAdapter *adapter_out;
225 /* ts and duration for output data collected above */
226 GstClockTime out_ts, out_dur;
227 /* mark outgoing discont */
230 /* subclass gave all it could already */
232 /* subclass currently being forcibly drained */
235 /* input bps estimatation */
236 /* global in bytes seen */
238 /* global samples sent out */
240 /* bytes flushed during parsing */
247 /* whether circumstances allow output aggregation */
250 /* reverse playback queues */
255 /* reversed output */
258 /* context storage */
259 GstAudioDecoderContext ctx;
262 GstClockTime latency;
263 GstClockTime tolerance;
266 /* pending serialized sink events, will be sent from finish_frame() */
267 GList *pending_events;
271 static void gst_audio_decoder_finalize (GObject * object);
272 static void gst_audio_decoder_set_property (GObject * object,
273 guint prop_id, const GValue * value, GParamSpec * pspec);
274 static void gst_audio_decoder_get_property (GObject * object,
275 guint prop_id, GValue * value, GParamSpec * pspec);
277 static void gst_audio_decoder_clear_queues (GstAudioDecoder * dec);
278 static GstFlowReturn gst_audio_decoder_chain_reverse (GstAudioDecoder *
279 dec, GstBuffer * buf);
281 static GstStateChangeReturn gst_audio_decoder_change_state (GstElement *
282 element, GstStateChange transition);
283 static gboolean gst_audio_decoder_sink_event (GstPad * pad, GstObject * parent,
285 static gboolean gst_audio_decoder_src_event (GstPad * pad, GstObject * parent,
287 static gboolean gst_audio_decoder_sink_setcaps (GstAudioDecoder * dec,
289 gboolean gst_audio_decoder_src_setcaps (GstAudioDecoder * dec, GstCaps * caps);
290 static GstFlowReturn gst_audio_decoder_chain (GstPad * pad, GstObject * parent,
292 static gboolean gst_audio_decoder_src_query (GstPad * pad, GstObject * parent,
294 static gboolean gst_audio_decoder_sink_query (GstPad * pad, GstObject * parent,
296 static void gst_audio_decoder_reset (GstAudioDecoder * dec, gboolean full);
298 static GstElementClass *parent_class = NULL;
300 static void gst_audio_decoder_class_init (GstAudioDecoderClass * klass);
301 static void gst_audio_decoder_init (GstAudioDecoder * dec,
302 GstAudioDecoderClass * klass);
305 gst_audio_decoder_get_type (void)
307 static volatile gsize audio_decoder_type = 0;
309 if (g_once_init_enter (&audio_decoder_type)) {
311 static const GTypeInfo audio_decoder_info = {
312 sizeof (GstAudioDecoderClass),
315 (GClassInitFunc) gst_audio_decoder_class_init,
318 sizeof (GstAudioDecoder),
320 (GInstanceInitFunc) gst_audio_decoder_init,
323 _type = g_type_register_static (GST_TYPE_ELEMENT,
324 "GstAudioDecoder", &audio_decoder_info, G_TYPE_FLAG_ABSTRACT);
325 g_once_init_leave (&audio_decoder_type, _type);
327 return audio_decoder_type;
332 gst_audio_decoder_class_init (GstAudioDecoderClass * klass)
334 GObjectClass *gobject_class;
335 GstElementClass *element_class;
337 gobject_class = G_OBJECT_CLASS (klass);
338 element_class = GST_ELEMENT_CLASS (klass);
340 parent_class = g_type_class_peek_parent (klass);
342 g_type_class_add_private (klass, sizeof (GstAudioDecoderPrivate));
344 GST_DEBUG_CATEGORY_INIT (audiodecoder_debug, "audiodecoder", 0,
345 "audio decoder base class");
347 gobject_class->set_property = gst_audio_decoder_set_property;
348 gobject_class->get_property = gst_audio_decoder_get_property;
349 gobject_class->finalize = gst_audio_decoder_finalize;
351 element_class->change_state = gst_audio_decoder_change_state;
354 g_object_class_install_property (gobject_class, PROP_LATENCY,
355 g_param_spec_int64 ("min-latency", "Minimum Latency",
356 "Aggregate output data to a minimum of latency time (ns)",
357 0, G_MAXINT64, DEFAULT_LATENCY,
358 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
360 g_object_class_install_property (gobject_class, PROP_TOLERANCE,
361 g_param_spec_int64 ("tolerance", "Tolerance",
362 "Perfect ts while timestamp jitter/imperfection within tolerance (ns)",
363 0, G_MAXINT64, DEFAULT_TOLERANCE,
364 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
366 g_object_class_install_property (gobject_class, PROP_PLC,
367 g_param_spec_boolean ("plc", "Packet Loss Concealment",
368 "Perform packet loss concealment (if supported)",
369 DEFAULT_PLC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
373 gst_audio_decoder_init (GstAudioDecoder * dec, GstAudioDecoderClass * klass)
375 GstPadTemplate *pad_template;
377 GST_DEBUG_OBJECT (dec, "gst_audio_decoder_init");
379 dec->priv = GST_AUDIO_DECODER_GET_PRIVATE (dec);
383 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink");
384 g_return_if_fail (pad_template != NULL);
386 dec->sinkpad = gst_pad_new_from_template (pad_template, "sink");
387 gst_pad_set_event_function (dec->sinkpad,
388 GST_DEBUG_FUNCPTR (gst_audio_decoder_sink_event));
389 gst_pad_set_chain_function (dec->sinkpad,
390 GST_DEBUG_FUNCPTR (gst_audio_decoder_chain));
391 gst_pad_set_query_function (dec->sinkpad,
392 GST_DEBUG_FUNCPTR (gst_audio_decoder_sink_query));
393 gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
394 GST_DEBUG_OBJECT (dec, "sinkpad created");
396 /* Setup source pad */
398 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "src");
399 g_return_if_fail (pad_template != NULL);
401 dec->srcpad = gst_pad_new_from_template (pad_template, "src");
402 gst_pad_set_event_function (dec->srcpad,
403 GST_DEBUG_FUNCPTR (gst_audio_decoder_src_event));
404 gst_pad_set_query_function (dec->srcpad,
405 GST_DEBUG_FUNCPTR (gst_audio_decoder_src_query));
406 gst_pad_use_fixed_caps (dec->srcpad);
407 gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
408 GST_DEBUG_OBJECT (dec, "srcpad created");
410 dec->priv->adapter = gst_adapter_new ();
411 dec->priv->adapter_out = gst_adapter_new ();
412 g_queue_init (&dec->priv->frames);
414 g_static_rec_mutex_init (&dec->stream_lock);
416 /* property default */
417 dec->priv->latency = DEFAULT_LATENCY;
418 dec->priv->tolerance = DEFAULT_TOLERANCE;
419 dec->priv->plc = DEFAULT_PLC;
422 gst_audio_decoder_reset (dec, TRUE);
423 GST_DEBUG_OBJECT (dec, "init ok");
427 gst_audio_decoder_reset (GstAudioDecoder * dec, gboolean full)
429 GST_DEBUG_OBJECT (dec, "gst_audio_decoder_reset");
431 GST_AUDIO_DECODER_STREAM_LOCK (dec);
434 dec->priv->active = FALSE;
435 dec->priv->bytes_in = 0;
436 dec->priv->samples_out = 0;
438 dec->priv->error_count = 0;
439 gst_audio_decoder_clear_queues (dec);
441 gst_audio_info_init (&dec->priv->ctx.info);
442 memset (&dec->priv->ctx, 0, sizeof (dec->priv->ctx));
444 if (dec->priv->taglist) {
445 gst_tag_list_free (dec->priv->taglist);
446 dec->priv->taglist = NULL;
449 gst_segment_init (&dec->segment, GST_FORMAT_TIME);
451 g_list_foreach (dec->priv->pending_events, (GFunc) gst_event_unref, NULL);
452 g_list_free (dec->priv->pending_events);
453 dec->priv->pending_events = NULL;
456 g_queue_foreach (&dec->priv->frames, (GFunc) gst_buffer_unref, NULL);
457 g_queue_clear (&dec->priv->frames);
458 gst_adapter_clear (dec->priv->adapter);
459 gst_adapter_clear (dec->priv->adapter_out);
460 dec->priv->out_ts = GST_CLOCK_TIME_NONE;
461 dec->priv->out_dur = 0;
462 dec->priv->prev_ts = GST_CLOCK_TIME_NONE;
463 dec->priv->drained = TRUE;
464 dec->priv->base_ts = GST_CLOCK_TIME_NONE;
465 dec->priv->samples = 0;
466 dec->priv->discont = TRUE;
467 dec->priv->sync_flush = FALSE;
469 GST_AUDIO_DECODER_STREAM_UNLOCK (dec);
473 gst_audio_decoder_finalize (GObject * object)
475 GstAudioDecoder *dec;
477 g_return_if_fail (GST_IS_AUDIO_DECODER (object));
478 dec = GST_AUDIO_DECODER (object);
480 if (dec->priv->adapter) {
481 g_object_unref (dec->priv->adapter);
483 if (dec->priv->adapter_out) {
484 g_object_unref (dec->priv->adapter_out);
487 g_static_rec_mutex_free (&dec->stream_lock);
489 G_OBJECT_CLASS (parent_class)->finalize (object);
493 * gst_audio_decoder_set_outcaps:
494 * @dec: a #GstAudioDecoder
497 * Configure output @caps on the srcpad of @dec. Also perform
498 * sanity checking of @caps and extracts output data format
500 * Returns: %TRUE on success.
503 gst_audio_decoder_set_outcaps (GstAudioDecoder * dec, GstCaps * caps)
508 GST_DEBUG_OBJECT (dec, "setting src caps %" GST_PTR_FORMAT, caps);
510 GST_AUDIO_DECODER_STREAM_LOCK (dec);
512 /* parse caps here to check subclass;
513 * also makes us aware of output format */
514 if (!gst_caps_is_fixed (caps))
517 /* adjust ts tracking to new sample rate */
518 old_rate = GST_AUDIO_INFO_RATE (&dec->priv->ctx.info);
519 if (GST_CLOCK_TIME_IS_VALID (dec->priv->base_ts) && old_rate) {
520 dec->priv->base_ts +=
521 GST_FRAMES_TO_CLOCK_TIME (dec->priv->samples, old_rate);
522 dec->priv->samples = 0;
525 if (!gst_audio_info_from_caps (&dec->priv->ctx.info, caps))
529 GST_AUDIO_DECODER_STREAM_UNLOCK (dec);
531 res = gst_pad_set_caps (dec->srcpad, caps);
538 GST_WARNING_OBJECT (dec, "rejected caps %" GST_PTR_FORMAT, caps);
545 gst_audio_decoder_sink_setcaps (GstAudioDecoder * dec, GstCaps * caps)
547 GstAudioDecoderClass *klass;
550 klass = GST_AUDIO_DECODER_GET_CLASS (dec);
552 GST_DEBUG_OBJECT (dec, "caps: %" GST_PTR_FORMAT, caps);
554 GST_AUDIO_DECODER_STREAM_LOCK (dec);
555 /* NOTE pbutils only needed here */
556 /* TODO maybe (only) upstream demuxer/parser etc should handle this ? */
558 if (dec->priv->taglist)
559 gst_tag_list_free (dec->priv->taglist);
560 dec->priv->taglist = gst_tag_list_new ();
561 gst_pb_utils_add_codec_description_to_tag_list (dec->priv->taglist,
562 GST_TAG_AUDIO_CODEC, caps);
565 if (klass->set_format)
566 res = klass->set_format (dec, caps);
568 GST_AUDIO_DECODER_STREAM_UNLOCK (dec);
574 gst_audio_decoder_setup (GstAudioDecoder * dec)
579 /* check if in live pipeline, then latency messing is no-no */
580 query = gst_query_new_latency ();
581 res = gst_pad_peer_query (dec->sinkpad, query);
583 gst_query_parse_latency (query, &res, NULL, NULL);
586 gst_query_unref (query);
588 /* normalize to bool */
589 dec->priv->agg = ! !res;
593 gst_audio_decoder_push_forward (GstAudioDecoder * dec, GstBuffer * buf)
595 GstAudioDecoderClass *klass;
596 GstAudioDecoderPrivate *priv;
597 GstAudioDecoderContext *ctx;
598 GstFlowReturn ret = GST_FLOW_OK;
600 klass = GST_AUDIO_DECODER_GET_CLASS (dec);
602 ctx = &dec->priv->ctx;
604 g_return_val_if_fail (ctx->info.bpf != 0, GST_FLOW_ERROR);
606 if (G_UNLIKELY (!buf)) {
607 g_assert_not_reached ();
612 "clipping buffer of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT
613 ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buf),
614 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
615 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
618 buf = gst_audio_buffer_clip (buf, &dec->segment, ctx->info.rate,
620 if (G_UNLIKELY (!buf)) {
621 GST_DEBUG_OBJECT (dec, "no data after clipping to segment");
626 if (G_UNLIKELY (priv->discont)) {
627 GST_LOG_OBJECT (dec, "marking discont");
628 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
629 priv->discont = FALSE;
632 /* track where we are */
633 if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) {
634 /* duration should always be valid for raw audio */
635 g_assert (GST_BUFFER_DURATION_IS_VALID (buf));
636 dec->segment.position =
637 GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
640 if (klass->pre_push) {
641 /* last chance for subclass to do some dirty stuff */
642 ret = klass->pre_push (dec, &buf);
643 if (ret != GST_FLOW_OK || !buf) {
644 GST_DEBUG_OBJECT (dec, "subclass returned %s, buf %p",
645 gst_flow_get_name (ret), buf);
647 gst_buffer_unref (buf);
653 "pushing buffer of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT
654 ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buf),
655 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
656 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
658 ret = gst_pad_push (dec->srcpad, buf);
664 /* mini aggregator combining output buffers into fewer larger ones,
665 * if so allowed/configured */
667 gst_audio_decoder_output (GstAudioDecoder * dec, GstBuffer * buf)
669 GstAudioDecoderPrivate *priv;
670 GstFlowReturn ret = GST_FLOW_OK;
671 GstBuffer *inbuf = NULL;
675 if (G_UNLIKELY (priv->agg < 0))
676 gst_audio_decoder_setup (dec);
678 if (G_LIKELY (buf)) {
680 "output buffer of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT
681 ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buf),
682 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
683 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
688 if (priv->agg && dec->priv->latency > 0) {
690 gboolean assemble = FALSE;
691 const GstClockTimeDiff tol = 10 * GST_MSECOND;
692 GstClockTimeDiff diff = -100 * GST_MSECOND;
694 av = gst_adapter_available (priv->adapter_out);
695 if (G_UNLIKELY (!buf)) {
696 /* forcibly send current */
698 GST_LOG_OBJECT (dec, "forcing fragment flush");
699 } else if (av && (!GST_BUFFER_TIMESTAMP_IS_VALID (buf) ||
700 !GST_CLOCK_TIME_IS_VALID (priv->out_ts) ||
701 ((diff = GST_CLOCK_DIFF (GST_BUFFER_TIMESTAMP (buf),
702 priv->out_ts + priv->out_dur)) > tol) || diff < -tol)) {
704 GST_LOG_OBJECT (dec, "buffer %d ms apart from current fragment",
705 (gint) (diff / GST_MSECOND));
707 /* add or start collecting */
709 GST_LOG_OBJECT (dec, "starting new fragment");
710 priv->out_ts = GST_BUFFER_TIMESTAMP (buf);
712 GST_LOG_OBJECT (dec, "adding to fragment");
714 gst_adapter_push (priv->adapter_out, buf);
715 priv->out_dur += GST_BUFFER_DURATION (buf);
716 av += gst_buffer_get_size (buf);
719 if (priv->out_dur > dec->priv->latency)
721 if (av && assemble) {
722 GST_LOG_OBJECT (dec, "assembling fragment");
724 buf = gst_adapter_take_buffer (priv->adapter_out, av);
725 GST_BUFFER_TIMESTAMP (buf) = priv->out_ts;
726 GST_BUFFER_DURATION (buf) = priv->out_dur;
727 priv->out_ts = GST_CLOCK_TIME_NONE;
732 if (G_LIKELY (buf)) {
733 if (dec->segment.rate > 0.0) {
734 ret = gst_audio_decoder_push_forward (dec, buf);
735 GST_LOG_OBJECT (dec, "buffer pushed: %s", gst_flow_get_name (ret));
738 priv->queued = g_list_prepend (priv->queued, buf);
739 GST_LOG_OBJECT (dec, "buffer queued");
752 * gst_audio_decoder_finish_frame:
753 * @dec: a #GstAudioDecoder
755 * @frames: number of decoded frames represented by decoded data
757 * Collects decoded data and pushes it downstream.
759 * @buf may be NULL in which case the indicated number of frames
760 * are discarded and considered to have produced no output
761 * (e.g. lead-in or setup frames).
762 * Otherwise, source pad caps must be set when it is called with valid
765 * Note that a frame received in gst_audio_decoder_handle_frame() may be
766 * invalidated by a call to this function.
768 * Returns: a #GstFlowReturn that should be escalated to caller (of caller)
773 gst_audio_decoder_finish_frame (GstAudioDecoder * dec, GstBuffer * buf,
776 GstAudioDecoderPrivate *priv;
777 GstAudioDecoderContext *ctx;
779 GstClockTime ts, next_ts;
781 GstFlowReturn ret = GST_FLOW_OK;
783 /* subclass should know what it is producing by now */
784 g_return_val_if_fail (buf == NULL || gst_pad_has_current_caps (dec->srcpad),
786 /* subclass should not hand us no data */
787 g_return_val_if_fail (buf == NULL || gst_buffer_get_size (buf) > 0,
789 /* no dummy calls please */
790 g_return_val_if_fail (frames != 0, GST_FLOW_ERROR);
793 ctx = &dec->priv->ctx;
794 size = buf ? gst_buffer_get_size (buf) : 0;
796 /* must know the output format by now */
797 g_return_val_if_fail (buf == NULL || GST_AUDIO_INFO_IS_VALID (&ctx->info),
801 "accepting %" G_GSIZE_FORMAT " bytes == %" G_GSIZE_FORMAT
802 " samples for %d frames", buf ? size : -1,
803 buf ? size / ctx->info.bpf : -1, frames);
805 GST_AUDIO_DECODER_STREAM_LOCK (dec);
807 if (priv->pending_events) {
808 GList *pending_events, *l;
810 pending_events = priv->pending_events;
811 priv->pending_events = NULL;
813 GST_DEBUG_OBJECT (dec, "Pushing pending events");
814 for (l = pending_events; l; l = l->next)
815 gst_pad_push_event (dec->srcpad, l->data);
816 g_list_free (pending_events);
819 /* output shoud be whole number of sample frames */
820 if (G_LIKELY (buf && ctx->info.bpf)) {
821 if (size % ctx->info.bpf)
823 /* per channel least */
824 samples = size / ctx->info.bpf;
827 /* frame and ts book-keeping */
828 if (G_UNLIKELY (frames < 0)) {
829 if (G_UNLIKELY (-frames - 1 > priv->frames.length))
831 frames = priv->frames.length + frames + 1;
832 } else if (G_UNLIKELY (frames > priv->frames.length)) {
833 if (G_LIKELY (!priv->force)) {
834 /* no way we can let this pass */
835 g_assert_not_reached ();
841 if (G_LIKELY (priv->frames.length))
842 ts = GST_BUFFER_TIMESTAMP (priv->frames.head->data);
844 ts = GST_CLOCK_TIME_NONE;
846 GST_DEBUG_OBJECT (dec, "leading frame ts %" GST_TIME_FORMAT,
849 while (priv->frames.length && frames) {
850 gst_buffer_unref (g_queue_pop_head (&priv->frames));
851 dec->priv->ctx.delay = dec->priv->frames.length;
855 if (G_UNLIKELY (!buf))
859 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (priv->base_ts))) {
861 GST_DEBUG_OBJECT (dec, "base_ts now %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
864 /* slightly convoluted approach caters for perfect ts if subclass desires */
865 if (GST_CLOCK_TIME_IS_VALID (ts)) {
866 if (dec->priv->tolerance > 0) {
867 GstClockTimeDiff diff;
869 g_assert (GST_CLOCK_TIME_IS_VALID (priv->base_ts));
870 next_ts = priv->base_ts +
871 gst_util_uint64_scale (priv->samples, GST_SECOND, ctx->info.rate);
873 "buffer is %" G_GUINT64_FORMAT " samples past base_ts %"
874 GST_TIME_FORMAT ", expected ts %" GST_TIME_FORMAT, priv->samples,
875 GST_TIME_ARGS (priv->base_ts), GST_TIME_ARGS (next_ts));
876 diff = GST_CLOCK_DIFF (next_ts, ts);
877 GST_LOG_OBJECT (dec, "ts diff %d ms", (gint) (diff / GST_MSECOND));
878 /* if within tolerance,
879 * discard buffer ts and carry on producing perfect stream,
880 * otherwise resync to ts */
881 if (G_UNLIKELY (diff < (gint64) - dec->priv->tolerance ||
882 diff > (gint64) dec->priv->tolerance)) {
883 GST_DEBUG_OBJECT (dec, "base_ts resync");
888 GST_DEBUG_OBJECT (dec, "base_ts resync");
894 /* delayed one-shot stuff until confirmed data */
896 GST_DEBUG_OBJECT (dec, "codec tag %" GST_PTR_FORMAT, priv->taglist);
897 if (gst_tag_list_is_empty (priv->taglist)) {
898 gst_tag_list_free (priv->taglist);
900 gst_pad_push_event (dec->srcpad, gst_event_new_tag (priv->taglist));
902 priv->taglist = NULL;
905 buf = gst_buffer_make_writable (buf);
906 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (priv->base_ts))) {
907 GST_BUFFER_TIMESTAMP (buf) =
909 GST_FRAMES_TO_CLOCK_TIME (priv->samples, ctx->info.rate);
910 GST_BUFFER_DURATION (buf) = priv->base_ts +
911 GST_FRAMES_TO_CLOCK_TIME (priv->samples + samples, ctx->info.rate) -
912 GST_BUFFER_TIMESTAMP (buf);
914 GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
915 GST_BUFFER_DURATION (buf) =
916 GST_FRAMES_TO_CLOCK_TIME (samples, ctx->info.rate);
918 priv->samples += samples;
919 priv->samples_out += samples;
921 /* we got data, so note things are looking up */
922 if (G_UNLIKELY (dec->priv->error_count))
923 dec->priv->error_count--;
926 ret = gst_audio_decoder_output (dec, buf);
928 GST_AUDIO_DECODER_STREAM_UNLOCK (dec);
935 GST_ELEMENT_ERROR (dec, STREAM, ENCODE, (NULL),
936 ("buffer size %" G_GSIZE_FORMAT " not a multiple of %d", size,
938 gst_buffer_unref (buf);
939 ret = GST_FLOW_ERROR;
944 GST_ELEMENT_ERROR (dec, STREAM, ENCODE,
945 ("received more decoded frames %d than provided %d", frames,
946 priv->frames.length), (NULL));
948 gst_buffer_unref (buf);
949 ret = GST_FLOW_ERROR;
955 gst_audio_decoder_handle_frame (GstAudioDecoder * dec,
956 GstAudioDecoderClass * klass, GstBuffer * buffer)
958 if (G_LIKELY (buffer)) {
959 gsize size = gst_buffer_get_size (buffer);
960 /* keep around for admin */
962 "tracking frame size %" G_GSIZE_FORMAT ", ts %" GST_TIME_FORMAT, size,
963 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
964 g_queue_push_tail (&dec->priv->frames, buffer);
965 dec->priv->ctx.delay = dec->priv->frames.length;
966 dec->priv->bytes_in += size;
968 GST_LOG_OBJECT (dec, "providing subclass with NULL frame");
971 return klass->handle_frame (dec, buffer);
974 /* maybe subclass configurable instead, but this allows for a whole lot of
975 * raw samples, so at least quite some encoded ... */
976 #define GST_AUDIO_DECODER_MAX_SYNC 10 * 8 * 2 * 1024
979 gst_audio_decoder_push_buffers (GstAudioDecoder * dec, gboolean force)
981 GstAudioDecoderClass *klass;
982 GstAudioDecoderPrivate *priv;
983 GstAudioDecoderContext *ctx;
984 GstFlowReturn ret = GST_FLOW_OK;
988 klass = GST_AUDIO_DECODER_GET_CLASS (dec);
990 ctx = &dec->priv->ctx;
992 g_return_val_if_fail (klass->handle_frame != NULL, GST_FLOW_ERROR);
994 av = gst_adapter_available (priv->adapter);
995 GST_DEBUG_OBJECT (dec, "available: %d", av);
997 while (ret == GST_FLOW_OK) {
1002 if (G_LIKELY (av)) {
1006 /* parse if needed */
1010 /* limited (legacy) parsing; avoid whole of baseparse */
1011 GST_DEBUG_OBJECT (dec, "parsing available: %d", av);
1012 /* piggyback sync state on discont */
1013 ctx->sync = !priv->discont;
1014 ret = klass->parse (dec, priv->adapter, &offset, &len);
1016 g_assert (offset <= av);
1019 GST_DEBUG_OBJECT (dec, "setting DISCONT");
1020 gst_adapter_flush (priv->adapter, offset);
1022 /* avoid parsing indefinitely */
1023 priv->sync_flush += offset;
1024 if (priv->sync_flush > GST_AUDIO_DECODER_MAX_SYNC)
1028 if (ret == GST_FLOW_EOS) {
1029 GST_LOG_OBJECT (dec, "no frame yet");
1032 } else if (ret == GST_FLOW_OK) {
1033 GST_LOG_OBJECT (dec, "frame at offset %d of length %d", offset, len);
1034 g_assert (offset + len <= av);
1035 priv->sync_flush = 0;
1042 /* track upstream ts, but do not get stuck if nothing new upstream */
1043 ts = gst_adapter_prev_timestamp (priv->adapter, NULL);
1044 if (ts == priv->prev_ts) {
1045 GST_LOG_OBJECT (dec, "ts == prev_ts; discarding");
1046 ts = GST_CLOCK_TIME_NONE;
1050 buffer = gst_adapter_take_buffer (priv->adapter, len);
1051 buffer = gst_buffer_make_writable (buffer);
1052 GST_BUFFER_TIMESTAMP (buffer) = ts;
1060 ret = gst_audio_decoder_handle_frame (dec, klass, buffer);
1062 /* do not keep pushing it ... */
1063 if (G_UNLIKELY (!av)) {
1064 priv->drained = TRUE;
1072 GST_LOG_OBJECT (dec, "done pushing to subclass");
1078 GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("failed to parse stream"));
1079 return GST_FLOW_ERROR;
1083 static GstFlowReturn
1084 gst_audio_decoder_drain (GstAudioDecoder * dec)
1088 if (dec->priv->drained && !dec->priv->gather)
1091 /* dispatch reverse pending buffers */
1092 /* chain eventually calls upon drain as well, but by that time
1093 * gather list should be clear, so ok ... */
1094 if (dec->segment.rate < 0.0 && dec->priv->gather)
1095 gst_audio_decoder_chain_reverse (dec, NULL);
1096 /* have subclass give all it can */
1097 ret = gst_audio_decoder_push_buffers (dec, TRUE);
1098 /* ensure all output sent */
1099 ret = gst_audio_decoder_output (dec, NULL);
1100 /* everything should be away now */
1101 if (dec->priv->frames.length) {
1102 /* not fatal/impossible though if subclass/codec eats stuff */
1103 GST_WARNING_OBJECT (dec, "still %d frames left after draining",
1104 dec->priv->frames.length);
1105 g_queue_foreach (&dec->priv->frames, (GFunc) gst_buffer_unref, NULL);
1106 g_queue_clear (&dec->priv->frames);
1108 /* discard (unparsed) leftover */
1109 gst_adapter_clear (dec->priv->adapter);
1115 /* hard == FLUSH, otherwise discont */
1116 static GstFlowReturn
1117 gst_audio_decoder_flush (GstAudioDecoder * dec, gboolean hard)
1119 GstAudioDecoderClass *klass;
1120 GstFlowReturn ret = GST_FLOW_OK;
1122 klass = GST_AUDIO_DECODER_GET_CLASS (dec);
1124 GST_LOG_OBJECT (dec, "flush hard %d", hard);
1127 ret = gst_audio_decoder_drain (dec);
1129 gst_audio_decoder_clear_queues (dec);
1130 gst_segment_init (&dec->segment, GST_FORMAT_TIME);
1131 dec->priv->error_count = 0;
1133 /* only bother subclass with flushing if known it is already alive
1134 * and kicking out stuff */
1135 if (klass->flush && dec->priv->samples_out > 0)
1136 klass->flush (dec, hard);
1137 /* and get (re)set for the sequel */
1138 gst_audio_decoder_reset (dec, FALSE);
1143 static GstFlowReturn
1144 gst_audio_decoder_chain_forward (GstAudioDecoder * dec, GstBuffer * buffer)
1146 GstFlowReturn ret = GST_FLOW_OK;
1148 /* discard silly case, though maybe ts may be of value ?? */
1149 if (G_UNLIKELY (gst_buffer_get_size (buffer) == 0)) {
1150 GST_DEBUG_OBJECT (dec, "discarding empty buffer");
1151 gst_buffer_unref (buffer);
1156 gst_adapter_push (dec->priv->adapter, buffer);
1158 /* new stuff, so we can push subclass again */
1159 dec->priv->drained = FALSE;
1161 /* hand to subclass */
1162 ret = gst_audio_decoder_push_buffers (dec, FALSE);
1165 GST_LOG_OBJECT (dec, "chain-done");
1170 gst_audio_decoder_clear_queues (GstAudioDecoder * dec)
1172 GstAudioDecoderPrivate *priv = dec->priv;
1174 g_list_foreach (priv->queued, (GFunc) gst_mini_object_unref, NULL);
1175 g_list_free (priv->queued);
1176 priv->queued = NULL;
1177 g_list_foreach (priv->gather, (GFunc) gst_mini_object_unref, NULL);
1178 g_list_free (priv->gather);
1179 priv->gather = NULL;
1180 g_list_foreach (priv->decode, (GFunc) gst_mini_object_unref, NULL);
1181 g_list_free (priv->decode);
1182 priv->decode = NULL;
1187 * Buffer decoding order: 7 8 9 4 5 6 3 1 2 EOS
1188 * Discont flag: D D D D
1190 * - Each Discont marks a discont in the decoding order.
1192 * for vorbis, each buffer is a keyframe when we have the previous
1193 * buffer. This means that to decode buffer 7, we need buffer 6, which
1194 * arrives out of order.
1196 * we first gather buffers in the gather queue until we get a DISCONT. We
1197 * prepend each incomming buffer so that they are in reversed order.
1199 * gather queue: 9 8 7
1203 * When a DISCONT is received (buffer 4), we move the gather queue to the
1204 * decode queue. This is simply done be taking the head of the gather queue
1205 * and prepending it to the decode queue. This yields:
1208 * decode queue: 7 8 9
1211 * Then we decode each buffer in the decode queue in order and put the output
1212 * buffer in the output queue. The first buffer (7) will not produce any output
1213 * because it needs the previous buffer (6) which did not arrive yet. This
1217 * decode queue: 7 8 9
1220 * Then we remove the consumed buffers from the decode queue. Buffer 7 is not
1221 * completely consumed, we need to keep it around for when we receive buffer
1228 * Then we accumulate more buffers:
1230 * gather queue: 6 5 4
1234 * prepending to the decode queue on DISCONT yields:
1237 * decode queue: 4 5 6 7
1240 * after decoding and keeping buffer 4:
1244 * output queue: 7 6 5
1248 static GstFlowReturn
1249 gst_audio_decoder_flush_decode (GstAudioDecoder * dec)
1251 GstAudioDecoderPrivate *priv = dec->priv;
1252 GstFlowReturn res = GST_FLOW_OK;
1253 GstClockTime timestamp;
1256 walk = priv->decode;
1258 GST_DEBUG_OBJECT (dec, "flushing buffers to decoder");
1260 /* clear buffer and decoder state */
1261 gst_audio_decoder_flush (dec, FALSE);
1265 GstBuffer *buf = GST_BUFFER_CAST (walk->data);
1267 GST_DEBUG_OBJECT (dec, "decoding buffer %p, ts %" GST_TIME_FORMAT,
1268 buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1270 next = g_list_next (walk);
1271 /* decode buffer, resulting data prepended to output queue */
1272 gst_buffer_ref (buf);
1273 res = gst_audio_decoder_chain_forward (dec, buf);
1275 /* if we generated output, we can discard the buffer, else we
1276 * keep it in the queue */
1278 GST_DEBUG_OBJECT (dec, "decoded buffer to %p", priv->queued->data);
1279 priv->decode = g_list_delete_link (priv->decode, walk);
1280 gst_buffer_unref (buf);
1282 GST_DEBUG_OBJECT (dec, "buffer did not decode, keeping");
1287 /* drain any aggregation (or otherwise) leftover */
1288 gst_audio_decoder_drain (dec);
1290 /* now send queued data downstream */
1291 timestamp = GST_CLOCK_TIME_NONE;
1292 while (priv->queued) {
1293 GstBuffer *buf = GST_BUFFER_CAST (priv->queued->data);
1295 /* duration should always be valid for raw audio */
1296 g_assert (GST_BUFFER_DURATION_IS_VALID (buf));
1298 /* interpolate (backward) if needed */
1299 if (G_LIKELY (timestamp != -1))
1300 timestamp -= GST_BUFFER_DURATION (buf);
1302 if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1303 GST_LOG_OBJECT (dec, "applying reverse interpolated ts %"
1304 GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
1305 GST_BUFFER_TIMESTAMP (buf) = timestamp;
1307 /* track otherwise */
1308 timestamp = GST_BUFFER_TIMESTAMP (buf);
1309 GST_LOG_OBJECT (dec, "tracking ts %" GST_TIME_FORMAT,
1310 GST_TIME_ARGS (timestamp));
1313 if (G_LIKELY (res == GST_FLOW_OK)) {
1314 GST_DEBUG_OBJECT (dec, "pushing buffer %p of size %" G_GSIZE_FORMAT ", "
1315 "time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf,
1316 gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1317 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
1318 /* should be already, but let's be sure */
1319 buf = gst_buffer_make_writable (buf);
1320 /* avoid stray DISCONT from forward processing,
1321 * which have no meaning in reverse pushing */
1322 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
1323 res = gst_audio_decoder_push_forward (dec, buf);
1325 gst_buffer_unref (buf);
1328 priv->queued = g_list_delete_link (priv->queued, priv->queued);
1334 static GstFlowReturn
1335 gst_audio_decoder_chain_reverse (GstAudioDecoder * dec, GstBuffer * buf)
1337 GstAudioDecoderPrivate *priv = dec->priv;
1338 GstFlowReturn result = GST_FLOW_OK;
1340 /* if we have a discont, move buffers to the decode list */
1341 if (!buf || GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
1342 GST_DEBUG_OBJECT (dec, "received discont");
1343 while (priv->gather) {
1346 gbuf = GST_BUFFER_CAST (priv->gather->data);
1347 /* remove from the gather list */
1348 priv->gather = g_list_delete_link (priv->gather, priv->gather);
1349 /* copy to decode queue */
1350 priv->decode = g_list_prepend (priv->decode, gbuf);
1352 /* decode stuff in the decode queue */
1353 gst_audio_decoder_flush_decode (dec);
1356 if (G_LIKELY (buf)) {
1357 GST_DEBUG_OBJECT (dec, "gathering buffer %p of size %" G_GSIZE_FORMAT ", "
1358 "time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf,
1359 gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1360 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
1362 /* add buffer to gather queue */
1363 priv->gather = g_list_prepend (priv->gather, buf);
1369 static GstFlowReturn
1370 gst_audio_decoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1372 GstAudioDecoder *dec;
1375 dec = GST_AUDIO_DECODER (parent);
1377 GST_LOG_OBJECT (dec,
1378 "received buffer of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT
1379 ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buffer),
1380 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1381 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
1383 GST_AUDIO_DECODER_STREAM_LOCK (dec);
1385 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1388 /* track present position */
1389 ts = dec->priv->base_ts;
1390 samples = dec->priv->samples;
1392 GST_DEBUG_OBJECT (dec, "handling discont");
1393 gst_audio_decoder_flush (dec, FALSE);
1394 dec->priv->discont = TRUE;
1396 /* buffer may claim DISCONT loudly, if it can't tell us where we are now,
1397 * we'll stick to where we were ...
1398 * Particularly useful/needed for upstream BYTE based */
1399 if (dec->segment.rate > 0.0 && !GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
1400 GST_DEBUG_OBJECT (dec, "... but restoring previous ts tracking");
1401 dec->priv->base_ts = ts;
1402 dec->priv->samples = samples;
1406 if (dec->segment.rate > 0.0)
1407 ret = gst_audio_decoder_chain_forward (dec, buffer);
1409 ret = gst_audio_decoder_chain_reverse (dec, buffer);
1411 GST_AUDIO_DECODER_STREAM_UNLOCK (dec);
1416 /* perform upstream byte <-> time conversion (duration, seeking)
1417 * if subclass allows and if enough data for moderately decent conversion */
1418 static inline gboolean
1419 gst_audio_decoder_do_byte (GstAudioDecoder * dec)
1421 return dec->priv->ctx.do_byte_time && dec->priv->ctx.info.bpf &&
1422 dec->priv->ctx.info.rate <= dec->priv->samples_out;
1426 gst_audio_decoder_sink_eventfunc (GstAudioDecoder * dec, GstEvent * event)
1428 gboolean handled = FALSE;
1430 switch (GST_EVENT_TYPE (event)) {
1431 case GST_EVENT_SEGMENT:
1435 GST_AUDIO_DECODER_STREAM_LOCK (dec);
1436 gst_event_copy_segment (event, &seg);
1438 if (seg.format == GST_FORMAT_TIME) {
1439 GST_DEBUG_OBJECT (dec, "received TIME SEGMENT %" GST_SEGMENT_FORMAT,
1443 GST_DEBUG_OBJECT (dec, "received SEGMENT %" GST_SEGMENT_FORMAT, &seg);
1444 /* handle newsegment resulting from legacy simple seeking */
1445 /* note that we need to convert this whether or not enough data
1446 * to handle initial newsegment */
1447 if (dec->priv->ctx.do_byte_time &&
1448 gst_pad_query_convert (dec->sinkpad, GST_FORMAT_BYTES, seg.start,
1449 GST_FORMAT_TIME, &nstart)) {
1450 /* best attempt convert */
1451 /* as these are only estimates, stop is kept open-ended to avoid
1452 * premature cutting */
1453 GST_DEBUG_OBJECT (dec, "converted to TIME start %" GST_TIME_FORMAT,
1454 GST_TIME_ARGS (nstart));
1455 seg.format = GST_FORMAT_TIME;
1458 seg.stop = GST_CLOCK_TIME_NONE;
1460 gst_event_unref (event);
1461 event = gst_event_new_segment (&seg);
1463 GST_DEBUG_OBJECT (dec, "unsupported format; ignoring");
1464 GST_AUDIO_DECODER_STREAM_UNLOCK (dec);
1469 /* finish current segment */
1470 gst_audio_decoder_drain (dec);
1474 /* time progressed without data, see if we can fill the gap with
1475 * some concealment data */
1476 GST_DEBUG_OBJECT (dec,
1477 "segment update: plc %d, do_plc %d, position %" GST_TIME_FORMAT,
1478 dec->priv->plc, dec->priv->ctx.do_plc,
1479 GST_TIME_ARGS (dec->segment.position));
1480 if (dec->priv->plc && dec->priv->ctx.do_plc &&
1481 dec->segment.rate > 0.0 && dec->segment.position < start) {
1482 GstAudioDecoderClass *klass;
1485 klass = GST_AUDIO_DECODER_GET_CLASS (dec);
1486 /* hand subclass empty frame with duration that needs covering */
1487 buf = gst_buffer_new ();
1488 GST_BUFFER_DURATION (buf) = start - dec->segment.position;
1489 /* best effort, not much error handling */
1490 gst_audio_decoder_handle_frame (dec, klass, buf);
1495 /* prepare for next one */
1496 gst_audio_decoder_flush (dec, FALSE);
1497 /* and that's where we time from,
1498 * in case upstream does not come up with anything better
1499 * (e.g. upstream BYTE) */
1500 if (seg.format != GST_FORMAT_TIME) {
1501 dec->priv->base_ts = seg.start;
1502 dec->priv->samples = 0;
1506 /* and follow along with segment */
1508 dec->priv->pending_events =
1509 g_list_append (dec->priv->pending_events, event);
1511 GST_AUDIO_DECODER_STREAM_UNLOCK (dec);
1515 case GST_EVENT_FLUSH_START:
1518 case GST_EVENT_FLUSH_STOP:
1519 GST_AUDIO_DECODER_STREAM_LOCK (dec);
1520 /* prepare for fresh start */
1521 gst_audio_decoder_flush (dec, TRUE);
1523 g_list_foreach (dec->priv->pending_events, (GFunc) gst_event_unref, NULL);
1524 g_list_free (dec->priv->pending_events);
1525 dec->priv->pending_events = NULL;
1526 GST_AUDIO_DECODER_STREAM_UNLOCK (dec);
1530 GST_AUDIO_DECODER_STREAM_LOCK (dec);
1531 gst_audio_decoder_drain (dec);
1532 GST_AUDIO_DECODER_STREAM_UNLOCK (dec);
1535 case GST_EVENT_CAPS:
1539 gst_event_parse_caps (event, &caps);
1540 gst_audio_decoder_sink_setcaps (dec, caps);
1541 gst_event_unref (event);
1553 gst_audio_decoder_sink_event (GstPad * pad, GstObject * parent,
1556 GstAudioDecoder *dec;
1557 GstAudioDecoderClass *klass;
1558 gboolean handled = FALSE;
1559 gboolean ret = TRUE;
1561 dec = GST_AUDIO_DECODER (parent);
1562 klass = GST_AUDIO_DECODER_GET_CLASS (dec);
1564 GST_DEBUG_OBJECT (dec, "received event %d, %s", GST_EVENT_TYPE (event),
1565 GST_EVENT_TYPE_NAME (event));
1568 handled = klass->event (dec, event);
1571 handled = gst_audio_decoder_sink_eventfunc (dec, event);
1574 /* Forward non-serialized events and EOS/FLUSH_STOP immediately.
1575 * For EOS this is required because no buffer or serialized event
1576 * will come after EOS and nothing could trigger another
1577 * _finish_frame() call.
1579 * For FLUSH_STOP this is required because it is expected
1580 * to be forwarded immediately and no buffers are queued anyway.
1582 if (!GST_EVENT_IS_SERIALIZED (event)
1583 || GST_EVENT_TYPE (event) == GST_EVENT_EOS
1584 || GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
1585 ret = gst_pad_event_default (pad, parent, event);
1587 GST_AUDIO_DECODER_STREAM_LOCK (dec);
1588 dec->priv->pending_events =
1589 g_list_append (dec->priv->pending_events, event);
1590 GST_AUDIO_DECODER_STREAM_UNLOCK (dec);
1595 GST_DEBUG_OBJECT (dec, "event handled");
1601 gst_audio_decoder_do_seek (GstAudioDecoder * dec, GstEvent * event)
1604 GstSeekType start_type, end_type;
1607 gint64 start, start_time, end_time;
1608 GstSegment seek_segment;
1611 gst_event_parse_seek (event, &rate, &format, &flags, &start_type,
1612 &start_time, &end_type, &end_time);
1614 /* we'll handle plain open-ended flushing seeks with the simple approach */
1616 GST_DEBUG_OBJECT (dec, "unsupported seek: rate");
1620 if (start_type != GST_SEEK_TYPE_SET) {
1621 GST_DEBUG_OBJECT (dec, "unsupported seek: start time");
1625 if (end_type != GST_SEEK_TYPE_NONE ||
1626 (end_type == GST_SEEK_TYPE_SET && end_time != GST_CLOCK_TIME_NONE)) {
1627 GST_DEBUG_OBJECT (dec, "unsupported seek: end time");
1631 if (!(flags & GST_SEEK_FLAG_FLUSH)) {
1632 GST_DEBUG_OBJECT (dec, "unsupported seek: not flushing");
1636 memcpy (&seek_segment, &dec->segment, sizeof (seek_segment));
1637 gst_segment_do_seek (&seek_segment, rate, format, flags, start_type,
1638 start_time, end_type, end_time, NULL);
1639 start_time = seek_segment.position;
1641 if (!gst_pad_query_convert (dec->sinkpad, GST_FORMAT_TIME, start_time,
1642 GST_FORMAT_BYTES, &start)) {
1643 GST_DEBUG_OBJECT (dec, "conversion failed");
1647 seqnum = gst_event_get_seqnum (event);
1648 event = gst_event_new_seek (1.0, GST_FORMAT_BYTES, flags,
1649 GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_NONE, -1);
1650 gst_event_set_seqnum (event, seqnum);
1652 GST_DEBUG_OBJECT (dec, "seeking to %" GST_TIME_FORMAT " at byte offset %"
1653 G_GINT64_FORMAT, GST_TIME_ARGS (start_time), start);
1655 return gst_pad_push_event (dec->sinkpad, event);
1659 gst_audio_decoder_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1661 GstAudioDecoder *dec;
1662 gboolean res = FALSE;
1664 dec = GST_AUDIO_DECODER (parent);
1666 GST_DEBUG_OBJECT (dec, "received event %d, %s", GST_EVENT_TYPE (event),
1667 GST_EVENT_TYPE_NAME (event));
1669 switch (GST_EVENT_TYPE (event)) {
1670 case GST_EVENT_SEEK:
1675 GstSeekType cur_type, stop_type;
1680 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
1682 seqnum = gst_event_get_seqnum (event);
1684 /* upstream gets a chance first */
1685 if ((res = gst_pad_push_event (dec->sinkpad, event)))
1688 /* if upstream fails for a time seek, maybe we can help if allowed */
1689 if (format == GST_FORMAT_TIME) {
1690 if (gst_audio_decoder_do_byte (dec))
1691 res = gst_audio_decoder_do_seek (dec, event);
1695 /* ... though a non-time seek can be aided as well */
1696 /* First bring the requested format to time */
1698 gst_pad_query_convert (pad, format, cur, GST_FORMAT_TIME, &tcur)))
1701 gst_pad_query_convert (pad, format, stop, GST_FORMAT_TIME,
1705 /* then seek with time on the peer */
1706 event = gst_event_new_seek (rate, GST_FORMAT_TIME,
1707 flags, cur_type, tcur, stop_type, tstop);
1708 gst_event_set_seqnum (event, seqnum);
1710 res = gst_pad_push_event (dec->sinkpad, event);
1714 res = gst_pad_push_event (dec->sinkpad, event);
1723 GST_DEBUG_OBJECT (dec, "cannot convert start/stop for seek");
1729 * gst_audio_encoded_audio_convert:
1730 * @fmt: audio format of the encoded audio
1731 * @bytes: number of encoded bytes
1732 * @samples: number of encoded samples
1733 * @src_format: source format
1734 * @src_value: source value
1735 * @dest_format: destination format
1736 * @dest_value: destination format
1738 * Helper function to convert @src_value in @src_format to @dest_value in
1739 * @dest_format for encoded audio data. Conversion is possible between
1740 * BYTE and TIME format by using estimated bitrate based on
1741 * @samples and @bytes (and @fmt).
1743 /* FIXME: make gst_audio_encoded_audio_convert() public? */
1745 gst_audio_encoded_audio_convert (GstAudioInfo * fmt,
1746 gint64 bytes, gint64 samples, GstFormat src_format,
1747 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
1749 gboolean res = FALSE;
1751 g_return_val_if_fail (dest_format != NULL, FALSE);
1752 g_return_val_if_fail (dest_value != NULL, FALSE);
1754 if (G_UNLIKELY (src_format == *dest_format || src_value == 0 ||
1757 *dest_value = src_value;
1761 if (samples == 0 || bytes == 0 || fmt->rate == 0) {
1762 GST_DEBUG ("not enough metadata yet to convert");
1768 switch (src_format) {
1769 case GST_FORMAT_BYTES:
1770 switch (*dest_format) {
1771 case GST_FORMAT_TIME:
1772 *dest_value = gst_util_uint64_scale (src_value,
1773 GST_SECOND * samples, bytes);
1780 case GST_FORMAT_TIME:
1781 switch (*dest_format) {
1782 case GST_FORMAT_BYTES:
1783 *dest_value = gst_util_uint64_scale (src_value, bytes,
1784 samples * GST_SECOND);
1800 gst_audio_decoder_sink_query (GstPad * pad, GstObject * parent,
1803 gboolean res = FALSE;
1804 GstAudioDecoder *dec;
1806 dec = GST_AUDIO_DECODER (parent);
1808 switch (GST_QUERY_TYPE (query)) {
1809 case GST_QUERY_FORMATS:
1811 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
1815 case GST_QUERY_CONVERT:
1817 GstFormat src_fmt, dest_fmt;
1818 gint64 src_val, dest_val;
1820 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
1821 if (!(res = gst_audio_encoded_audio_convert (&dec->priv->ctx.info,
1822 dec->priv->bytes_in, dec->priv->samples_out,
1823 src_fmt, src_val, &dest_fmt, &dest_val)))
1825 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
1829 res = gst_pad_query_default (pad, parent, query);
1837 /* FIXME ? are any of these queries (other than latency) a decoder's business ??
1838 * also, the conversion stuff might seem to make sense, but seems to not mind
1839 * segment stuff etc at all
1840 * Supposedly that's backward compatibility ... */
1842 gst_audio_decoder_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
1844 GstAudioDecoder *dec;
1845 gboolean res = FALSE;
1847 dec = GST_AUDIO_DECODER (parent);
1849 GST_LOG_OBJECT (dec, "handling query: %" GST_PTR_FORMAT, query);
1851 switch (GST_QUERY_TYPE (query)) {
1852 case GST_QUERY_DURATION:
1856 /* upstream in any case */
1857 if ((res = gst_pad_query_default (pad, parent, query)))
1860 gst_query_parse_duration (query, &format, NULL);
1861 /* try answering TIME by converting from BYTE if subclass allows */
1862 if (format == GST_FORMAT_TIME && gst_audio_decoder_do_byte (dec)) {
1865 if (gst_pad_peer_query_duration (dec->sinkpad, GST_FORMAT_BYTES,
1867 GST_LOG_OBJECT (dec, "upstream size %" G_GINT64_FORMAT, value);
1868 if (gst_pad_query_convert (dec->sinkpad, GST_FORMAT_BYTES, value,
1869 GST_FORMAT_TIME, &value)) {
1870 gst_query_set_duration (query, GST_FORMAT_TIME, value);
1877 case GST_QUERY_POSITION:
1882 if ((res = gst_pad_peer_query (dec->sinkpad, query))) {
1883 GST_LOG_OBJECT (dec, "returning peer response");
1887 /* we start from the last seen time */
1888 time = dec->segment.position;
1889 /* correct for the segment values */
1890 time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, time);
1892 GST_LOG_OBJECT (dec,
1893 "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time));
1895 /* and convert to the final format */
1896 gst_query_parse_position (query, &format, NULL);
1897 if (!(res = gst_pad_query_convert (pad, GST_FORMAT_TIME, time,
1901 gst_query_set_position (query, format, value);
1903 GST_LOG_OBJECT (dec,
1904 "query %p: we return %" G_GINT64_FORMAT " (format %u)", query, value,
1908 case GST_QUERY_FORMATS:
1910 gst_query_set_formats (query, 3,
1911 GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT);
1915 case GST_QUERY_CONVERT:
1917 GstFormat src_fmt, dest_fmt;
1918 gint64 src_val, dest_val;
1920 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
1921 if (!(res = gst_audio_info_convert (&dec->priv->ctx.info,
1922 src_fmt, src_val, dest_fmt, &dest_val)))
1924 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
1927 case GST_QUERY_LATENCY:
1929 if ((res = gst_pad_peer_query (dec->sinkpad, query))) {
1931 GstClockTime min_latency, max_latency;
1933 gst_query_parse_latency (query, &live, &min_latency, &max_latency);
1934 GST_DEBUG_OBJECT (dec, "Peer latency: live %d, min %"
1935 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
1936 GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
1938 GST_OBJECT_LOCK (dec);
1939 /* add our latency */
1940 if (min_latency != -1)
1941 min_latency += dec->priv->ctx.min_latency;
1942 if (max_latency != -1)
1943 max_latency += dec->priv->ctx.max_latency;
1944 GST_OBJECT_UNLOCK (dec);
1946 gst_query_set_latency (query, live, min_latency, max_latency);
1951 res = gst_pad_query_default (pad, parent, query);
1959 gst_audio_decoder_stop (GstAudioDecoder * dec)
1961 GstAudioDecoderClass *klass;
1962 gboolean ret = TRUE;
1964 GST_DEBUG_OBJECT (dec, "gst_audio_decoder_stop");
1966 klass = GST_AUDIO_DECODER_GET_CLASS (dec);
1969 ret = klass->stop (dec);
1973 gst_audio_decoder_reset (dec, TRUE);
1976 dec->priv->active = FALSE;
1982 gst_audio_decoder_start (GstAudioDecoder * dec)
1984 GstAudioDecoderClass *klass;
1985 gboolean ret = TRUE;
1987 GST_DEBUG_OBJECT (dec, "gst_audio_decoder_start");
1989 klass = GST_AUDIO_DECODER_GET_CLASS (dec);
1991 /* arrange clean state */
1992 gst_audio_decoder_reset (dec, TRUE);
1995 ret = klass->start (dec);
1999 dec->priv->active = TRUE;
2005 gst_audio_decoder_get_property (GObject * object, guint prop_id,
2006 GValue * value, GParamSpec * pspec)
2008 GstAudioDecoder *dec;
2010 dec = GST_AUDIO_DECODER (object);
2014 g_value_set_int64 (value, dec->priv->latency);
2016 case PROP_TOLERANCE:
2017 g_value_set_int64 (value, dec->priv->tolerance);
2020 g_value_set_boolean (value, dec->priv->plc);
2023 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2029 gst_audio_decoder_set_property (GObject * object, guint prop_id,
2030 const GValue * value, GParamSpec * pspec)
2032 GstAudioDecoder *dec;
2034 dec = GST_AUDIO_DECODER (object);
2038 dec->priv->latency = g_value_get_int64 (value);
2040 case PROP_TOLERANCE:
2041 dec->priv->tolerance = g_value_get_int64 (value);
2044 dec->priv->plc = g_value_get_boolean (value);
2047 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2052 static GstStateChangeReturn
2053 gst_audio_decoder_change_state (GstElement * element, GstStateChange transition)
2055 GstAudioDecoder *codec;
2056 GstStateChangeReturn ret;
2058 codec = GST_AUDIO_DECODER (element);
2060 switch (transition) {
2061 case GST_STATE_CHANGE_NULL_TO_READY:
2063 case GST_STATE_CHANGE_READY_TO_PAUSED:
2064 if (!gst_audio_decoder_start (codec)) {
2068 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2074 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2076 switch (transition) {
2077 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2079 case GST_STATE_CHANGE_PAUSED_TO_READY:
2080 if (!gst_audio_decoder_stop (codec)) {
2084 case GST_STATE_CHANGE_READY_TO_NULL:
2094 GST_ELEMENT_ERROR (codec, LIBRARY, INIT, (NULL), ("Failed to start codec"));
2095 return GST_STATE_CHANGE_FAILURE;
2099 GST_ELEMENT_ERROR (codec, LIBRARY, INIT, (NULL), ("Failed to stop codec"));
2100 return GST_STATE_CHANGE_FAILURE;
2105 _gst_audio_decoder_error (GstAudioDecoder * dec, gint weight,
2106 GQuark domain, gint code, gchar * txt, gchar * dbg, const gchar * file,
2107 const gchar * function, gint line)
2110 GST_WARNING_OBJECT (dec, "error: %s", txt);
2112 GST_WARNING_OBJECT (dec, "error: %s", dbg);
2113 dec->priv->error_count += weight;
2114 dec->priv->discont = TRUE;
2115 if (dec->priv->ctx.max_errors < dec->priv->error_count) {
2116 gst_element_message_full (GST_ELEMENT (dec), GST_MESSAGE_ERROR,
2117 domain, code, txt, dbg, file, function, line);
2118 return GST_FLOW_ERROR;
2125 * gst_audio_decoder_get_audio_info:
2126 * @dec: a #GstAudioDecoder
2128 * Returns: a #GstAudioInfo describing the input audio format
2133 gst_audio_decoder_get_audio_info (GstAudioDecoder * dec)
2135 g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), NULL);
2137 return &dec->priv->ctx.info;
2141 * gst_audio_decoder_set_plc_aware:
2142 * @dec: a #GstAudioDecoder
2143 * @plc: new plc state
2145 * Indicates whether or not subclass handles packet loss concealment (plc).
2150 gst_audio_decoder_set_plc_aware (GstAudioDecoder * dec, gboolean plc)
2152 g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
2154 dec->priv->ctx.do_plc = plc;
2158 * gst_audio_decoder_get_plc_aware:
2159 * @dec: a #GstAudioDecoder
2161 * Returns: currently configured plc handling
2166 gst_audio_decoder_get_plc_aware (GstAudioDecoder * dec)
2168 g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), 0);
2170 return dec->priv->ctx.do_plc;
2174 * gst_audio_decoder_set_byte_time:
2175 * @dec: a #GstAudioDecoder
2176 * @enabled: whether to enable byte to time conversion
2178 * Allows baseclass to perform byte to time estimated conversion.
2183 gst_audio_decoder_set_byte_time (GstAudioDecoder * dec, gboolean enabled)
2185 g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
2187 dec->priv->ctx.do_byte_time = enabled;
2191 * gst_audio_decoder_get_byte_time:
2192 * @dec: a #GstAudioDecoder
2194 * Returns: currently configured byte to time conversion setting
2199 gst_audio_decoder_get_byte_time (GstAudioDecoder * dec)
2201 g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), 0);
2203 return dec->priv->ctx.do_byte_time;
2207 * gst_audio_decoder_get_delay:
2208 * @dec: a #GstAudioDecoder
2210 * Returns: currently configured decoder delay
2215 gst_audio_decoder_get_delay (GstAudioDecoder * dec)
2217 g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), 0);
2219 return dec->priv->ctx.delay;
2223 * gst_audio_decoder_set_max_errors:
2224 * @dec: a #GstAudioDecoder
2225 * @num: max tolerated errors
2227 * Sets numbers of tolerated decoder errors, where a tolerated one is then only
2228 * warned about, but more than tolerated will lead to fatal error.
2233 gst_audio_decoder_set_max_errors (GstAudioDecoder * dec, gint num)
2235 g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
2237 dec->priv->ctx.max_errors = num;
2241 * gst_audio_decoder_get_max_errors:
2242 * @dec: a #GstAudioDecoder
2244 * Returns: currently configured decoder tolerated error count.
2249 gst_audio_decoder_get_max_errors (GstAudioDecoder * dec)
2251 g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), 0);
2253 return dec->priv->ctx.max_errors;
2257 * gst_audio_decoder_set_latency:
2258 * @dec: a #GstAudioDecoder
2259 * @min: minimum latency
2260 * @max: maximum latency
2262 * Sets decoder latency.
2267 gst_audio_decoder_set_latency (GstAudioDecoder * dec,
2268 GstClockTime min, GstClockTime max)
2270 g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
2272 GST_OBJECT_LOCK (dec);
2273 dec->priv->ctx.min_latency = min;
2274 dec->priv->ctx.max_latency = max;
2275 GST_OBJECT_UNLOCK (dec);
2279 * gst_audio_decoder_get_latency:
2280 * @dec: a #GstAudioDecoder
2281 * @min: (out) (allow-none): a pointer to storage to hold minimum latency
2282 * @max: (out) (allow-none): a pointer to storage to hold maximum latency
2284 * Sets the variables pointed to by @min and @max to the currently configured
2290 gst_audio_decoder_get_latency (GstAudioDecoder * dec,
2291 GstClockTime * min, GstClockTime * max)
2293 g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
2295 GST_OBJECT_LOCK (dec);
2297 *min = dec->priv->ctx.min_latency;
2299 *max = dec->priv->ctx.max_latency;
2300 GST_OBJECT_UNLOCK (dec);
2304 * gst_audio_decoder_get_parse_state:
2305 * @dec: a #GstAudioDecoder
2306 * @sync: a pointer to a variable to hold the current sync state
2307 * @eos: a pointer to a variable to hold the current eos state
2309 * Return current parsing (sync and eos) state.
2314 gst_audio_decoder_get_parse_state (GstAudioDecoder * dec,
2315 gboolean * sync, gboolean * eos)
2317 g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
2320 *sync = dec->priv->ctx.sync;
2322 *eos = dec->priv->ctx.eos;
2326 * gst_audio_decoder_set_plc:
2327 * @dec: a #GstAudioDecoder
2328 * @enabled: new state
2330 * Enable or disable decoder packet loss concealment, provided subclass
2331 * and codec are capable and allow handling plc.
2338 gst_audio_decoder_set_plc (GstAudioDecoder * dec, gboolean enabled)
2340 g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
2342 GST_LOG_OBJECT (dec, "enabled: %d", enabled);
2344 GST_OBJECT_LOCK (dec);
2345 dec->priv->plc = enabled;
2346 GST_OBJECT_UNLOCK (dec);
2350 * gst_audio_decoder_get_plc:
2351 * @dec: a #GstAudioDecoder
2353 * Queries decoder packet loss concealment handling.
2355 * Returns: TRUE if packet loss concealment is enabled.
2362 gst_audio_decoder_get_plc (GstAudioDecoder * dec)
2366 g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), FALSE);
2368 GST_OBJECT_LOCK (dec);
2369 result = dec->priv->plc;
2370 GST_OBJECT_UNLOCK (dec);
2376 * gst_audio_decoder_set_min_latency:
2377 * @dec: a #GstAudioDecoder
2378 * @num: new minimum latency
2380 * Sets decoder minimum aggregation latency.
2387 gst_audio_decoder_set_min_latency (GstAudioDecoder * dec, gint64 num)
2389 g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
2391 GST_OBJECT_LOCK (dec);
2392 dec->priv->latency = num;
2393 GST_OBJECT_UNLOCK (dec);
2397 * gst_audio_decoder_get_min_latency:
2398 * @dec: a #GstAudioDecoder
2400 * Queries decoder's latency aggregation.
2402 * Returns: aggregation latency.
2409 gst_audio_decoder_get_min_latency (GstAudioDecoder * dec)
2413 g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), FALSE);
2415 GST_OBJECT_LOCK (dec);
2416 result = dec->priv->latency;
2417 GST_OBJECT_UNLOCK (dec);
2423 * gst_audio_decoder_set_tolerance:
2424 * @dec: a #GstAudioDecoder
2425 * @tolerance: new tolerance
2427 * Configures decoder audio jitter tolerance threshold.
2434 gst_audio_decoder_set_tolerance (GstAudioDecoder * dec, gint64 tolerance)
2436 g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
2438 GST_OBJECT_LOCK (dec);
2439 dec->priv->tolerance = tolerance;
2440 GST_OBJECT_UNLOCK (dec);
2444 * gst_audio_decoder_get_tolerance:
2445 * @dec: a #GstAudioDecoder
2447 * Queries current audio jitter tolerance threshold.
2449 * Returns: decoder audio jitter tolerance threshold.
2456 gst_audio_decoder_get_tolerance (GstAudioDecoder * dec)
2460 g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), 0);
2462 GST_OBJECT_LOCK (dec);
2463 result = dec->priv->tolerance;
2464 GST_OBJECT_UNLOCK (dec);