2 * Copyright (C) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>.
3 * Copyright (C) 2011 Nokia Corporation. All rights reserved.
4 * Contact: Stefan Kost <stefan.kost@nokia.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 * SECTION:gstbaseaudioencoder
24 * @short_description: Base class for audio encoders
25 * @see_also: #GstBaseTransform
27 * This base class is for audio encoders turning raw audio samples into
30 * GstBaseAudioEncoder and subclass should cooperate as follows.
33 * <itemizedlist><title>Configuration</title>
35 * Initially, GstBaseAudioEncoder calls @start when the encoder element
36 * is activated, which allows subclass to perform any global setup.
39 * GstBaseAudioEncoder calls @set_format to inform subclass of the format
40 * of input audio data that it is about to receive. Subclass should
41 * setup for encoding and configure various base class context parameters
42 * appropriately, notably those directing desired input data handling.
43 * While unlikely, it might be called more than once, if changing input
44 * parameters require reconfiguration.
47 * GstBaseAudioEncoder calls @stop at end of all processing.
51 * As of configuration stage, and throughout processing, GstBaseAudioEncoder
52 * provides a GstBaseAudioEncoderContext that provides required context,
53 * e.g. describing the format of input audio data.
54 * Conversely, subclass can and should configure context to inform
55 * base class of its expectation w.r.t. buffer handling.
58 * <title>Data processing</title>
60 * Base class gathers input sample data (as directed by the context's
61 * frame_samples and frame_max) and provides this to subclass' @handle_frame.
64 * If codec processing results in encoded data, subclass should call
65 * @gst_base_audio_encoder_finish_frame to have encoded data pushed
66 * downstream. Alternatively, it might also call to indicate dropped
67 * (non-encoded) samples.
70 * Just prior to actually pushing a buffer downstream,
71 * it is passed to @pre_push.
74 * During the parsing process GstBaseAudioEncoderClass will handle both
75 * srcpad and sinkpad events. Sink events will be passed to subclass
76 * if @event callback has been provided.
81 * <itemizedlist><title>Shutdown phase</title>
83 * GstBaseAudioEncoder class calls @stop to inform the subclass that data
84 * parsing will be stopped.
90 * Subclass is responsible for providing pad template caps for
91 * source and sink pads. The pads need to be named "sink" and "src". It also
92 * needs to set the fixed caps on srcpad, when the format is ensured. This
93 * is typically when base class calls subclass' @set_format function, though
94 * it might be delayed until calling @gst_base_audio_encoder_finish_frame.
96 * In summary, above process should have subclass concentrating on
97 * codec data processing while leaving other matters to base class,
98 * such as most notably timestamp handling. While it may exert more control
99 * in this area (see e.g. @pre_push), it is very much not recommended.
101 * In particular, base class will either favor tracking upstream timestamps
102 * (at the possible expense of jitter) or aim to arrange for a perfect stream of
103 * output timestamps, depending on #GstBaseAudioEncoder:perfect-ts.
104 * However, in the latter case, the input may not be so perfect or ideal, which
105 * is handled as follows. An input timestamp is compared with the expected
106 * timestamp as dictated by input sample stream and if the deviation is less
107 * than #GstBaseAudioEncoder:tolerance, the deviation is discarded.
108 * Otherwise, it is considered a discontuinity and subsequent output timestamp
109 * is resynced to the new position after performing configured discontinuity
110 * processing. In the non-perfect-ts case, an upstream variation exceeding
111 * tolerance only leads to marking DISCONT on subsequent outgoing
112 * (while timestamps are adjusted to upstream regardless of variation).
113 * While DISCONT is also marked in the perfect-ts case, this one optionally
114 * (see #GstBaseAudioEncoder:hard-resync)
115 * performs some additional steps, such as clipping of (early) input samples
116 * or draining all currently remaining input data, depending on the direction
117 * of the discontuinity.
119 * If perfect timestamps are arranged, it is also possible to request baseclass
120 * (usually set by subclass) to provide additional buffer metadata (in OFFSET
121 * and OFFSET_END) fields according to granule defined semantics currently
122 * needed by oggmux. Specifically, OFFSET is set to granulepos (= sample count
123 * including buffer) and OFFSET_END to corresponding timestamp (as determined
124 * by same sample count and sample rate).
126 * Things that subclass need to take care of:
128 * <listitem><para>Provide pad templates</para></listitem>
130 * Set source pad caps when appropriate
133 * Inform base class of buffer processing needs using context's
134 * frame_samples and frame_bytes.
137 * Set user-configurable properties to sane defaults for format and
138 * implementing codec at hand, e.g. those controlling timestamp behaviour
139 * and discontinuity processing.
142 * Accept data in @handle_frame and provide encoded results to
143 * @gst_base_audio_encoder_finish_frame.
153 #include "gstbaseaudioencoder.h"
154 #include <gst/base/gstadapter.h>
155 #include <gst/audio/audio.h>
161 GST_DEBUG_CATEGORY_STATIC (gst_base_audio_encoder_debug);
162 #define GST_CAT_DEFAULT gst_base_audio_encoder_debug
164 #define GST_BASE_AUDIO_ENCODER_GET_PRIVATE(obj) \
165 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_AUDIO_ENCODER, \
166 GstBaseAudioEncoderPrivate))
177 #define DEFAULT_PERFECT_TS FALSE
178 #define DEFAULT_GRANULE FALSE
179 #define DEFAULT_HARD_RESYNC FALSE
180 #define DEFAULT_TOLERANCE 40000000
182 struct _GstBaseAudioEncoderPrivate
184 /* activation status */
187 /* input base/first ts as basis for output ts;
188 * kept nearly constant for perfect_ts,
189 * otherwise resyncs to upstream ts */
190 GstClockTime base_ts;
191 /* corresponding base granulepos */
193 /* input samples processed and sent downstream so far (w.r.t. base_ts) */
196 /* currently collected sample data */
198 /* offset in adapter up to which already supplied to encoder */
200 /* mark outgoing discont */
202 /* to guess duration of drained data */
203 GstClockTime last_duration;
205 /* subclass provided data in processing round */
207 /* subclass gave all it could already */
209 /* subclass currently being forcibly drained */
212 /* output bps estimatation */
213 /* global in samples seen */
215 /* global bytes sent out */
218 /* context storage */
219 GstBaseAudioEncoderContext ctx;
223 static GstElementClass *parent_class = NULL;
225 static void gst_base_audio_encoder_class_init (GstBaseAudioEncoderClass *
227 static void gst_base_audio_encoder_init (GstBaseAudioEncoder * parse,
228 GstBaseAudioEncoderClass * klass);
231 gst_base_audio_encoder_get_type (void)
233 static GType base_audio_encoder_type = 0;
235 if (!base_audio_encoder_type) {
236 static const GTypeInfo base_audio_encoder_info = {
237 sizeof (GstBaseAudioEncoderClass),
238 (GBaseInitFunc) NULL,
239 (GBaseFinalizeFunc) NULL,
240 (GClassInitFunc) gst_base_audio_encoder_class_init,
243 sizeof (GstBaseAudioEncoder),
245 (GInstanceInitFunc) gst_base_audio_encoder_init,
247 const GInterfaceInfo preset_interface_info = {
248 NULL, /* interface_init */
249 NULL, /* interface_finalize */
250 NULL /* interface_data */
253 base_audio_encoder_type = g_type_register_static (GST_TYPE_ELEMENT,
254 "GstBaseAudioEncoder", &base_audio_encoder_info, G_TYPE_FLAG_ABSTRACT);
256 g_type_add_interface_static (base_audio_encoder_type, GST_TYPE_PRESET,
257 &preset_interface_info);
259 return base_audio_encoder_type;
262 static void gst_base_audio_encoder_finalize (GObject * object);
263 static void gst_base_audio_encoder_reset (GstBaseAudioEncoder * enc,
266 static void gst_base_audio_encoder_set_property (GObject * object,
267 guint prop_id, const GValue * value, GParamSpec * pspec);
268 static void gst_base_audio_encoder_get_property (GObject * object,
269 guint prop_id, GValue * value, GParamSpec * pspec);
271 static gboolean gst_base_audio_encoder_sink_activate_push (GstPad * pad,
274 static gboolean gst_base_audio_encoder_sink_event (GstPad * pad,
276 static gboolean gst_base_audio_encoder_sink_setcaps (GstPad * pad,
278 static GstFlowReturn gst_base_audio_encoder_chain (GstPad * pad,
280 static gboolean gst_base_audio_encoder_src_query (GstPad * pad,
282 static gboolean gst_base_audio_encoder_sink_query (GstPad * pad,
284 static const GstQueryType *gst_base_audio_encoder_get_query_types (GstPad *
286 static GstCaps *gst_base_audio_encoder_sink_getcaps (GstPad * pad);
290 gst_base_audio_encoder_class_init (GstBaseAudioEncoderClass * klass)
292 GObjectClass *gobject_class;
294 gobject_class = G_OBJECT_CLASS (klass);
295 parent_class = g_type_class_peek_parent (klass);
297 GST_DEBUG_CATEGORY_INIT (gst_base_audio_encoder_debug, "baseaudioencoder", 0,
298 "baseaudioencoder element");
300 g_type_class_add_private (klass, sizeof (GstBaseAudioEncoderPrivate));
302 gobject_class->set_property = gst_base_audio_encoder_set_property;
303 gobject_class->get_property = gst_base_audio_encoder_get_property;
305 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_audio_encoder_finalize);
308 g_object_class_install_property (gobject_class, PROP_PERFECT_TS,
309 g_param_spec_boolean ("perfect-ts", "Perfect Timestamps",
310 "Favour perfect timestamps over tracking upstream timestamps",
311 DEFAULT_PERFECT_TS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
312 g_object_class_install_property (gobject_class, PROP_GRANULE,
313 g_param_spec_boolean ("granule", "Granule Marking",
314 "Apply granule semantics to buffer metadata (implies perfect-ts)",
315 DEFAULT_GRANULE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
316 g_object_class_install_property (gobject_class, PROP_HARD_RESYNC,
317 g_param_spec_boolean ("hard-resync", "Hard Resync",
318 "Perform clipping and sample flushing upon discontinuity",
319 DEFAULT_HARD_RESYNC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
320 g_object_class_install_property (gobject_class, PROP_TOLERANCE,
321 g_param_spec_int64 ("tolerance", "Tolerance",
322 "Consider discontinuity if timestamp jitter/imperfection exceeds tolerance (ns)",
323 0, G_MAXINT64, DEFAULT_TOLERANCE,
324 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
328 gst_base_audio_encoder_init (GstBaseAudioEncoder * enc,
329 GstBaseAudioEncoderClass * bclass)
331 GstPadTemplate *pad_template;
333 GST_DEBUG_OBJECT (enc, "gst_base_audio_encoder_init");
335 enc->priv = GST_BASE_AUDIO_ENCODER_GET_PRIVATE (enc);
337 /* only push mode supported */
339 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
340 g_return_if_fail (pad_template != NULL);
341 enc->sinkpad = gst_pad_new_from_template (pad_template, "sink");
342 gst_pad_set_event_function (enc->sinkpad,
343 GST_DEBUG_FUNCPTR (gst_base_audio_encoder_sink_event));
344 gst_pad_set_setcaps_function (enc->sinkpad,
345 GST_DEBUG_FUNCPTR (gst_base_audio_encoder_sink_setcaps));
346 gst_pad_set_getcaps_function (enc->sinkpad,
347 GST_DEBUG_FUNCPTR (gst_base_audio_encoder_sink_getcaps));
348 gst_pad_set_query_function (enc->sinkpad,
349 GST_DEBUG_FUNCPTR (gst_base_audio_encoder_sink_query));
350 gst_pad_set_chain_function (enc->sinkpad,
351 GST_DEBUG_FUNCPTR (gst_base_audio_encoder_chain));
352 gst_pad_set_activatepush_function (enc->sinkpad,
353 GST_DEBUG_FUNCPTR (gst_base_audio_encoder_sink_activate_push));
354 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
356 GST_DEBUG_OBJECT (enc, "sinkpad created");
358 /* and we don't mind upstream traveling stuff that much ... */
360 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
361 g_return_if_fail (pad_template != NULL);
362 enc->srcpad = gst_pad_new_from_template (pad_template, "src");
363 gst_pad_set_query_function (enc->srcpad,
364 GST_DEBUG_FUNCPTR (gst_base_audio_encoder_src_query));
365 gst_pad_set_query_type_function (enc->srcpad,
366 GST_DEBUG_FUNCPTR (gst_base_audio_encoder_get_query_types));
367 gst_pad_use_fixed_caps (enc->srcpad);
368 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
369 GST_DEBUG_OBJECT (enc, "src created");
371 enc->priv->adapter = gst_adapter_new ();
372 enc->ctx = &enc->priv->ctx;
374 /* property default */
375 enc->perfect_ts = DEFAULT_PERFECT_TS;
376 enc->hard_resync = DEFAULT_HARD_RESYNC;
377 enc->tolerance = DEFAULT_TOLERANCE;
380 gst_base_audio_encoder_reset (enc, TRUE);
381 GST_DEBUG_OBJECT (enc, "init ok");
385 gst_base_audio_encoder_reset (GstBaseAudioEncoder * enc, gboolean full)
387 GST_OBJECT_LOCK (enc);
390 enc->priv->active = FALSE;
391 enc->priv->samples_in = 0;
392 enc->priv->bytes_out = 0;
393 g_free (enc->ctx->state.channel_pos);
394 memset (enc->ctx, 0, sizeof (enc->ctx));
397 gst_segment_init (&enc->segment, GST_FORMAT_TIME);
399 gst_adapter_clear (enc->priv->adapter);
400 enc->priv->got_data = FALSE;
401 enc->priv->drained = TRUE;
402 enc->priv->offset = 0;
403 enc->priv->base_ts = GST_CLOCK_TIME_NONE;
404 enc->priv->base_gp = -1;
405 enc->priv->samples = 0;
406 enc->priv->discont = FALSE;
408 GST_OBJECT_UNLOCK (enc);
412 gst_base_audio_encoder_finalize (GObject * object)
414 GstBaseAudioEncoder *enc = GST_BASE_AUDIO_ENCODER (object);
416 g_object_unref (enc->priv->adapter);
418 G_OBJECT_CLASS (parent_class)->finalize (object);
422 * gst_base_audio_encoder_finish_frame:
423 * @enc: a #GstBaseAudioEncoder
424 * @buffer: encoded data
425 * @samples: number of samples (per channel) represented by encoded data
427 * Collects encoded data and/or pushes encoded data downstream.
428 * Source pad caps must be set when this is called. Depending on the nature
429 * of the (framing of) the format, subclass can decide whether to push
430 * encoded data directly or to collect various "frames" in a single buffer.
431 * Note that the latter behaviour is recommended whenever the format is allowed,
432 * as it incurs no additional latency and avoids otherwise generating a
433 * a multitude of (small) output buffers. If not explicitly pushed,
434 * any available encoded data is pushed at the end of each processing cycle,
435 * i.e. which encodes as much data as available input data allows.
437 * If @samples < 0, then best estimate is all samples provided to encoder
438 * (subclass) so far. @buf may be NULL, in which case next number of @samples
439 * are considered discarded, e.g. as a result of discontinuous transmission,
440 * and a discontinuity is marked (note that @buf == NULL => push == TRUE).
442 * Returns: a #GstFlowReturn that should be escalated to caller (of caller)
445 gst_base_audio_encoder_finish_frame (GstBaseAudioEncoder * enc, GstBuffer * buf,
448 GstBaseAudioEncoderClass *klass;
449 GstBaseAudioEncoderPrivate *priv;
450 GstBaseAudioEncoderContext *ctx;
451 GstFlowReturn ret = GST_FLOW_OK;
453 klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
457 /* subclass should know what it is producing by now */
458 g_return_val_if_fail (GST_PAD_CAPS (enc->srcpad) != NULL, GST_FLOW_ERROR);
459 /* subclass should not hand us no data */
460 g_return_val_if_fail (buf == NULL || GST_BUFFER_SIZE (buf) > 0,
463 GST_LOG_OBJECT (enc, "accepting %d bytes encoded data as %d samples",
464 buf ? GST_BUFFER_SIZE (buf) : -1, samples);
466 /* mark subclass still alive and providing */
467 priv->got_data = TRUE;
469 /* remove corresponding samples from input */
471 samples = (enc->priv->offset / ctx->state.bpf);
473 if (G_LIKELY (samples)) {
474 /* track upstream ts if so configured */
475 if (!enc->perfect_ts) {
476 guint64 ts, distance;
478 ts = gst_adapter_prev_timestamp (priv->adapter, &distance);
479 g_assert (distance % ctx->state.bpf == 0);
480 distance /= ctx->state.bpf;
481 GST_LOG_OBJECT (enc, "%" G_GUINT64_FORMAT " samples past prev_ts %"
482 GST_TIME_FORMAT, distance, GST_TIME_ARGS (ts));
483 GST_LOG_OBJECT (enc, "%" G_GUINT64_FORMAT " samples past base_ts %"
484 GST_TIME_FORMAT, priv->samples, GST_TIME_ARGS (priv->base_ts));
485 /* when draining adapter might be empty and no ts to offer */
486 if (GST_CLOCK_TIME_IS_VALID (ts) && ts != priv->base_ts) {
487 GstClockTimeDiff diff;
488 GstClockTime old_ts, next_ts;
490 /* passed into another buffer;
491 * mild check for discontinuity and only mark if so */
493 gst_util_uint64_scale (distance, GST_SECOND, ctx->state.rate);
494 old_ts = priv->base_ts +
495 gst_util_uint64_scale (priv->samples, GST_SECOND, ctx->state.rate);
496 diff = GST_CLOCK_DIFF (next_ts, old_ts);
497 GST_LOG_OBJECT (enc, "ts diff %d ms", (gint) (diff / GST_MSECOND));
498 /* only mark discontinuity if beyond tolerance */
499 if (G_UNLIKELY (diff < -enc->tolerance || diff > enc->tolerance)) {
500 GST_DEBUG_OBJECT (enc, "marked discont");
501 priv->discont = TRUE;
503 GST_LOG_OBJECT (enc, "new upstream ts %" GST_TIME_FORMAT
504 " at distance %" G_GUINT64_FORMAT, GST_TIME_ARGS (ts), distance);
505 /* re-sync to upstream ts */
507 priv->samples = distance;
510 /* advance sample view */
511 if (G_UNLIKELY (samples * ctx->state.bpf > priv->offset)) {
512 if (G_LIKELY (!priv->force)) {
513 /* no way we can let this pass */
514 g_assert_not_reached ();
519 if (samples * ctx->state.bpf >= gst_adapter_available (priv->adapter))
520 gst_adapter_clear (priv->adapter);
522 gst_adapter_flush (priv->adapter, samples * ctx->state.bpf);
525 gst_adapter_flush (priv->adapter, samples * ctx->state.bpf);
526 priv->offset -= samples * ctx->state.bpf;
527 /* avoid subsequent stray prev_ts */
528 if (G_UNLIKELY (gst_adapter_available (priv->adapter) == 0))
529 gst_adapter_clear (priv->adapter);
531 /* sample count advanced below after buffer handling */
535 if (G_LIKELY (buf)) {
536 GST_LOG_OBJECT (enc, "taking %d bytes for output", GST_BUFFER_SIZE (buf));
537 buf = gst_buffer_make_metadata_writable (buf);
540 gst_buffer_set_caps (buf, GST_PAD_CAPS (enc->srcpad));
541 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (priv->base_ts))) {
542 /* FIXME ? lookahead could lead to weird ts and duration ?
543 * (particularly if not in perfect mode) */
544 /* mind sample rounding and produce perfect output */
545 GST_BUFFER_TIMESTAMP (buf) = priv->base_ts +
546 gst_util_uint64_scale (priv->samples - ctx->lookahead, GST_SECOND,
548 GST_DEBUG_OBJECT (enc, "out samples %d", samples);
549 if (G_LIKELY (samples > 0)) {
550 priv->samples += samples;
551 GST_BUFFER_DURATION (buf) = priv->base_ts +
552 gst_util_uint64_scale (priv->samples - ctx->lookahead, GST_SECOND,
553 ctx->state.rate) - GST_BUFFER_TIMESTAMP (buf);
554 priv->last_duration = GST_BUFFER_DURATION (buf);
556 /* duration forecast in case of handling remainder;
557 * the last one is probably like the previous one ... */
558 GST_BUFFER_DURATION (buf) = priv->last_duration;
560 if (priv->base_gp >= 0) {
562 /* FIXME: in longer run, muxer should take care of this ... */
563 /* offset_end = granulepos for ogg muxer */
564 GST_BUFFER_OFFSET_END (buf) = priv->base_gp + priv->samples -
566 /* offset = timestamp corresponding to granulepos for ogg muxer */
567 GST_BUFFER_OFFSET (buf) =
568 GST_FRAMES_TO_CLOCK_TIME (GST_BUFFER_OFFSET_END (buf),
571 GST_BUFFER_OFFSET (buf) = priv->bytes_out;
572 GST_BUFFER_OFFSET_END (buf) = priv->bytes_out + GST_BUFFER_SIZE (buf);
576 priv->bytes_out += GST_BUFFER_SIZE (buf);
578 if (G_UNLIKELY (priv->discont)) {
579 GST_LOG_OBJECT (enc, "marking discont");
580 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
581 priv->discont = FALSE;
584 if (klass->pre_push) {
585 /* last chance for subclass to do some dirty stuff */
586 ret = klass->pre_push (enc, &buf);
587 if (ret != GST_FLOW_OK || !buf) {
588 GST_DEBUG_OBJECT (enc, "subclass returned %s, buf %p",
589 gst_flow_get_name (ret), buf);
591 gst_buffer_unref (buf);
596 GST_LOG_OBJECT (enc, "pushing buffer of size %d with ts %" GST_TIME_FORMAT
597 ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buf),
598 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
599 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
601 ret = gst_pad_push (enc->srcpad, buf);
602 GST_LOG_OBJECT (enc, "buffer pushed: %s", gst_flow_get_name (ret));
604 /* merely advance samples, most work for that already done above */
605 priv->samples += samples;
614 GST_ELEMENT_ERROR (enc, STREAM, ENCODE,
615 ("received more encoded samples %d than provided %d",
616 samples, priv->offset / ctx->state.bpf), (NULL));
618 gst_buffer_unref (buf);
619 return GST_FLOW_ERROR;
623 /* adapter tracking idea:
624 * - start of adapter corresponds with what has already been encoded
625 * (i.e. really returned by encoder subclass)
626 * - start + offset is what needs to be fed to subclass next */
628 gst_base_audio_encoder_push_buffers (GstBaseAudioEncoder * enc, gboolean force)
630 GstBaseAudioEncoderClass *klass;
631 GstBaseAudioEncoderPrivate *priv;
632 GstBaseAudioEncoderContext *ctx;
635 GstFlowReturn ret = GST_FLOW_OK;
637 klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
639 g_return_val_if_fail (klass->handle_frame != NULL, GST_FLOW_ERROR);
644 while (ret == GST_FLOW_OK) {
647 av = gst_adapter_available (priv->adapter);
649 g_assert (priv->offset <= av);
652 need = ctx->frame_samples > 0 ? ctx->frame_samples * ctx->state.bpf : av;
653 GST_LOG_OBJECT (enc, "available: %d, needed: %d, force: %d",
656 if ((need > av) || !av) {
657 if (G_UNLIKELY (force)) {
667 /* if we have some extra metadata,
668 * provide for integer multiple of frames to allow for better granularity
670 if (ctx->frame_samples > 0 && need) {
671 if (ctx->frame_max > 1)
672 need = need * MIN ((av / need), ctx->frame_max);
673 else if (ctx->frame_max == 0)
674 need = need * (av / need);
678 buf = gst_buffer_new ();
679 GST_BUFFER_DATA (buf) = (guint8 *)
680 gst_adapter_peek (priv->adapter, priv->offset + need) + priv->offset;
681 GST_BUFFER_SIZE (buf) = need;
684 GST_LOG_OBJECT (enc, "providing subclass with %d bytes at offset %d",
687 /* mark this already as consumed,
688 * which it should be when subclass gives us data in exchange for samples */
689 priv->offset += need;
690 priv->samples_in += need / ctx->state.bpf;
692 priv->got_data = FALSE;
693 ret = klass->handle_frame (enc, buf);
696 gst_buffer_unref (buf);
698 /* no data to feed, no leftover provided, then bail out */
699 if (G_UNLIKELY (!buf && !priv->got_data)) {
700 priv->drained = TRUE;
701 GST_LOG_OBJECT (enc, "no more data drained from subclass");
710 gst_base_audio_encoder_drain (GstBaseAudioEncoder * enc)
712 if (enc->priv->drained)
715 return gst_base_audio_encoder_push_buffers (enc, TRUE);
719 gst_base_audio_encoder_set_base_gp (GstBaseAudioEncoder * enc)
726 /* use running time for granule */
727 /* incoming data is clipped, so a valid input should yield a valid output */
728 ts = gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME,
730 if (GST_CLOCK_TIME_IS_VALID (ts)) {
732 GST_CLOCK_TIME_TO_FRAMES (enc->priv->base_ts, enc->ctx->state.rate);
733 GST_DEBUG_OBJECT (enc, "new base gp %" G_GINT64_FORMAT,
734 GST_TIME_ARGS (enc->priv->base_gp));
736 /* should reasonably have a valid base,
737 * otherwise start at 0 if we did not already start there earlier */
738 if (enc->priv->base_gp < 0) {
739 enc->priv->base_gp = 0;
740 GST_DEBUG_OBJECT (enc, "new base gp %" G_GINT64_FORMAT,
741 GST_TIME_ARGS (enc->priv->base_gp));
747 gst_base_audio_encoder_chain (GstPad * pad, GstBuffer * buffer)
749 GstBaseAudioEncoderClass *bclass;
750 GstBaseAudioEncoder *enc;
751 GstBaseAudioEncoderPrivate *priv;
752 GstBaseAudioEncoderContext *ctx;
753 GstFlowReturn ret = GST_FLOW_OK;
756 enc = GST_BASE_AUDIO_ENCODER (GST_OBJECT_PARENT (pad));
757 bclass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
762 /* should know what is coming by now */
767 "received buffer of size %d with ts %" GST_TIME_FORMAT
768 ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buffer),
769 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
770 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
772 /* input shoud be whole number of sample frames */
773 if (GST_BUFFER_SIZE (buffer) % ctx->state.bpf)
776 #ifndef GST_DISABLE_GST_DEBUG
778 GstClockTime duration;
779 GstClockTimeDiff diff;
781 /* verify buffer duration */
782 duration = gst_util_uint64_scale (GST_BUFFER_SIZE (buffer), GST_SECOND,
783 ctx->state.rate * ctx->state.bpf);
784 diff = GST_CLOCK_DIFF (duration, GST_BUFFER_DURATION (buffer));
785 if (GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE &&
786 (diff > GST_SECOND / ctx->state.rate / 2 ||
787 diff < -GST_SECOND / ctx->state.rate / 2)) {
788 GST_DEBUG_OBJECT (enc, "incoming buffer had incorrect duration %"
789 GST_TIME_FORMAT ", expected duration %" GST_TIME_FORMAT,
790 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
791 GST_TIME_ARGS (duration));
796 discont = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT);
797 if (G_UNLIKELY (discont)) {
798 GST_LOG_OBJECT (buffer, "marked discont");
799 enc->priv->discont = discont;
802 /* clip to segment */
803 /* NOTE: slightly painful linking -laudio only for this one ... */
804 buffer = gst_audio_buffer_clip (buffer, &enc->segment, ctx->state.rate,
806 if (G_UNLIKELY (!buffer)) {
807 GST_DEBUG_OBJECT (buffer, "no data after clipping to segment");
812 "buffer after segment clipping has size %d with ts %" GST_TIME_FORMAT
813 ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buffer),
814 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
815 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
817 if (!GST_CLOCK_TIME_IS_VALID (priv->base_ts)) {
818 priv->base_ts = GST_BUFFER_TIMESTAMP (buffer);
819 GST_DEBUG_OBJECT (enc, "new base ts %" GST_TIME_FORMAT,
820 GST_TIME_ARGS (priv->base_ts));
821 gst_base_audio_encoder_set_base_gp (enc);
824 /* check for continuity;
825 * checked elsewhere in non-perfect case */
826 if (enc->perfect_ts) {
827 GstClockTimeDiff diff = 0;
828 GstClockTime next_ts = 0;
830 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
831 GST_CLOCK_TIME_IS_VALID (priv->base_ts)) {
834 samples = priv->samples +
835 gst_adapter_available (priv->adapter) / ctx->state.bpf;
836 next_ts = priv->base_ts +
837 gst_util_uint64_scale (samples, GST_SECOND, ctx->state.rate);
838 GST_LOG_OBJECT (enc, "buffer is %" G_GUINT64_FORMAT
839 " samples past base_ts %" GST_TIME_FORMAT
840 ", expected ts %" GST_TIME_FORMAT, samples,
841 GST_TIME_ARGS (priv->base_ts), GST_TIME_ARGS (next_ts));
842 diff = GST_CLOCK_DIFF (next_ts, GST_BUFFER_TIMESTAMP (buffer));
843 GST_LOG_OBJECT (enc, "ts diff %d ms", (gint) (diff / GST_MSECOND));
844 /* if within tolerance,
845 * discard buffer ts and carry on producing perfect stream,
846 * otherwise clip or resync to ts */
847 if (G_UNLIKELY (diff < -enc->tolerance || diff > enc->tolerance)) {
848 GST_DEBUG_OBJECT (enc, "marked discont");
853 /* do some fancy tweaking in hard resync case */
854 if (discont && enc->hard_resync) {
858 GST_WARNING_OBJECT (enc, "Buffer is older than expected ts %"
859 GST_TIME_FORMAT ". Clipping buffer", GST_TIME_ARGS (next_ts));
862 GST_CLOCK_TIME_TO_FRAMES (-diff, ctx->state.rate) * ctx->state.bpf;
863 if (diff_bytes >= GST_BUFFER_SIZE (buffer)) {
864 gst_buffer_unref (buffer);
867 buffer = gst_buffer_make_metadata_writable (buffer);
868 GST_BUFFER_DATA (buffer) += diff_bytes;
869 GST_BUFFER_SIZE (buffer) -= diff_bytes;
871 GST_BUFFER_TIMESTAMP (buffer) += diff;
872 /* care even less about duration after this */
874 /* drain stuff prior to resync */
875 gst_base_audio_encoder_drain (enc);
879 priv->base_ts += diff;
880 gst_base_audio_encoder_set_base_gp (enc);
881 priv->discont |= discont;
884 gst_adapter_push (enc->priv->adapter, buffer);
885 /* new stuff, so we can push subclass again */
886 enc->priv->drained = FALSE;
888 ret = gst_base_audio_encoder_push_buffers (enc, FALSE);
891 GST_LOG_OBJECT (enc, "chain leaving");
897 GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
898 ("encoder not initialized"));
899 gst_buffer_unref (buffer);
900 return GST_FLOW_NOT_NEGOTIATED;
904 GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
905 ("buffer size %d not a multiple of %d", GST_BUFFER_SIZE (buffer),
907 gst_buffer_unref (buffer);
908 return GST_FLOW_ERROR;
913 gst_base_audio_encoder_sink_setcaps (GstPad * pad, GstCaps * caps)
915 GstBaseAudioEncoder *enc;
916 GstBaseAudioEncoderClass *klass;
917 GstBaseAudioEncoderContext *ctx;
918 GstAudioState *state;
919 gboolean res = TRUE, changed = FALSE;
921 enc = GST_BASE_AUDIO_ENCODER (GST_PAD_PARENT (pad));
922 klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
924 /* subclass must do something here ... */
925 g_return_val_if_fail (klass->set_format != NULL, FALSE);
930 GST_DEBUG_OBJECT (enc, "caps: %" GST_PTR_FORMAT, caps);
932 if (!gst_caps_is_fixed (caps))
935 /* adjust ts tracking to new sample rate */
936 if (GST_CLOCK_TIME_IS_VALID (enc->priv->base_ts) && state->rate) {
937 enc->priv->base_ts +=
938 GST_FRAMES_TO_CLOCK_TIME (enc->priv->samples, state->rate);
939 enc->priv->samples = 0;
942 if (!gst_base_audio_parse_caps (caps, state, &changed))
946 GstClockTime old_min_latency;
947 GstClockTime old_max_latency;
949 /* drain any pending old data stuff */
950 gst_base_audio_encoder_drain (enc);
952 /* context defaults */
953 enc->ctx->frame_samples = 0;
954 enc->ctx->frame_max = 0;
955 enc->ctx->lookahead = 0;
957 /* element might report latency */
958 GST_OBJECT_LOCK (enc);
959 old_min_latency = ctx->min_latency;
960 old_max_latency = ctx->max_latency;
961 GST_OBJECT_UNLOCK (enc);
963 if (klass->set_format)
964 res = klass->set_format (enc, state);
966 /* notify if new latency */
967 GST_OBJECT_LOCK (enc);
968 if ((ctx->min_latency > 0 && ctx->min_latency != old_min_latency) ||
969 (ctx->max_latency > 0 && ctx->max_latency != old_max_latency)) {
970 GST_OBJECT_UNLOCK (enc);
971 /* post latency message on the bus */
972 gst_element_post_message (GST_ELEMENT (enc),
973 gst_message_new_latency (GST_OBJECT (enc)));
974 GST_OBJECT_LOCK (enc);
976 GST_OBJECT_UNLOCK (enc);
978 GST_DEBUG_OBJECT (enc, "new audio format identical to configured format");
986 GST_WARNING_OBJECT (enc, "rejected caps %" GST_PTR_FORMAT, caps);
993 * gst_base_audio_encoder_proxy_getcaps:
994 * @enc: a #GstBaseAudioEncoder
997 * Returns caps that express @caps (or sink template caps if @caps == NULL)
998 * restricted to channel/rate combinations supported by downstream elements
1001 * Returns: a #GstCaps owned by caller
1004 gst_base_audio_encoder_proxy_getcaps (GstBaseAudioEncoder * enc, GstCaps * caps)
1006 const GstCaps *templ_caps;
1007 GstCaps *allowed = NULL;
1008 GstCaps *fcaps, *filter_caps;
1011 /* we want to be able to communicate to upstream elements like audioconvert
1012 * and audioresample any rate/channel restrictions downstream (e.g. muxer
1013 * only accepting certain sample rates) */
1014 templ_caps = caps ? caps : gst_pad_get_pad_template_caps (enc->sinkpad);
1015 allowed = gst_pad_get_allowed_caps (enc->srcpad);
1016 if (!allowed || gst_caps_is_empty (allowed) || gst_caps_is_any (allowed)) {
1017 fcaps = gst_caps_copy (templ_caps);
1021 GST_LOG_OBJECT (enc, "template caps %" GST_PTR_FORMAT, templ_caps);
1022 GST_LOG_OBJECT (enc, "allowed caps %" GST_PTR_FORMAT, allowed);
1024 filter_caps = gst_caps_new_empty ();
1026 for (i = 0; i < gst_caps_get_size (templ_caps); i++) {
1029 q_name = gst_structure_get_name_id (gst_caps_get_structure (templ_caps, i));
1031 /* pick rate + channel fields from allowed caps */
1032 for (j = 0; j < gst_caps_get_size (allowed); j++) {
1033 const GstStructure *allowed_s = gst_caps_get_structure (allowed, j);
1037 s = gst_structure_id_empty_new (q_name);
1038 if ((val = gst_structure_get_value (allowed_s, "rate")))
1039 gst_structure_set_value (s, "rate", val);
1040 if ((val = gst_structure_get_value (allowed_s, "channels")))
1041 gst_structure_set_value (s, "channels", val);
1043 gst_caps_merge_structure (filter_caps, s);
1047 fcaps = gst_caps_intersect (filter_caps, templ_caps);
1048 gst_caps_unref (filter_caps);
1051 gst_caps_replace (&allowed, NULL);
1053 GST_LOG_OBJECT (enc, "proxy caps %" GST_PTR_FORMAT, fcaps);
1059 gst_base_audio_encoder_sink_getcaps (GstPad * pad)
1061 GstBaseAudioEncoder *enc;
1062 GstBaseAudioEncoderClass *klass;
1065 enc = GST_BASE_AUDIO_ENCODER (gst_pad_get_parent (pad));
1066 klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
1067 g_assert (pad == enc->sinkpad);
1070 caps = klass->getcaps (enc);
1072 caps = gst_base_audio_encoder_proxy_getcaps (enc, NULL);
1073 gst_object_unref (enc);
1075 GST_LOG_OBJECT (enc, "returning caps %" GST_PTR_FORMAT, caps);
1081 gst_base_audio_encoder_sink_eventfunc (GstBaseAudioEncoder * enc,
1084 GstBaseAudioEncoderClass *klass;
1085 gboolean handled = FALSE;
1087 klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
1089 switch (GST_EVENT_TYPE (event)) {
1090 case GST_EVENT_NEWSEGMENT:
1093 gdouble rate, arate;
1094 gint64 start, stop, time;
1097 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1098 &start, &stop, &time);
1100 if (format == GST_FORMAT_TIME) {
1101 GST_DEBUG_OBJECT (enc, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
1102 " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
1103 ", rate %g, applied_rate %g",
1104 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time),
1107 GST_DEBUG_OBJECT (enc, "received NEW_SEGMENT %" G_GINT64_FORMAT
1108 " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
1109 ", rate %g, applied_rate %g", start, stop, time, rate, arate);
1110 GST_DEBUG_OBJECT (enc, "unsupported format; ignoring");
1114 /* finish current segment */
1115 gst_base_audio_encoder_drain (enc);
1116 /* reset partially for new segment */
1117 gst_base_audio_encoder_reset (enc, FALSE);
1118 /* and follow along with segment */
1119 gst_segment_set_newsegment_full (&enc->segment, update, rate, arate,
1120 format, start, stop, time);
1124 case GST_EVENT_FLUSH_START:
1127 case GST_EVENT_FLUSH_STOP:
1128 /* discard any pending stuff */
1129 /* TODO route through drain ?? */
1130 if (!enc->priv->drained && klass->flush)
1132 /* and get (re)set for the sequel */
1133 gst_base_audio_encoder_reset (enc, FALSE);
1137 gst_base_audio_encoder_drain (enc);
1148 gst_base_audio_encoder_sink_event (GstPad * pad, GstEvent * event)
1150 GstBaseAudioEncoder *enc;
1151 GstBaseAudioEncoderClass *klass;
1152 gboolean handled = FALSE;
1153 gboolean ret = TRUE;
1155 enc = GST_BASE_AUDIO_ENCODER (gst_pad_get_parent (pad));
1156 klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
1158 GST_DEBUG_OBJECT (enc, "received event %d, %s", GST_EVENT_TYPE (event),
1159 GST_EVENT_TYPE_NAME (event));
1162 handled = klass->event (enc, event);
1165 handled = gst_base_audio_encoder_sink_eventfunc (enc, event);
1168 ret = gst_pad_event_default (pad, event);
1170 GST_DEBUG_OBJECT (enc, "event handled");
1172 gst_object_unref (enc);
1177 gst_base_audio_encoder_sink_query (GstPad * pad, GstQuery * query)
1179 gboolean res = TRUE;
1180 GstBaseAudioEncoder *enc;
1182 enc = GST_BASE_AUDIO_ENCODER (gst_pad_get_parent (pad));
1184 switch (GST_QUERY_TYPE (query)) {
1185 case GST_QUERY_FORMATS:
1187 gst_query_set_formats (query, 3,
1188 GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT);
1192 case GST_QUERY_CONVERT:
1194 GstFormat src_fmt, dest_fmt;
1195 gint64 src_val, dest_val;
1197 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
1198 if (!(res = gst_base_audio_raw_audio_convert (&enc->ctx->state,
1199 src_fmt, src_val, &dest_fmt, &dest_val)))
1201 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
1205 res = gst_pad_query_default (pad, query);
1210 gst_object_unref (enc);
1214 static const GstQueryType *
1215 gst_base_audio_encoder_get_query_types (GstPad * pad)
1217 static const GstQueryType gst_base_audio_encoder_src_query_types[] = {
1225 return gst_base_audio_encoder_src_query_types;
1228 /* FIXME ? are any of these queries (other than latency) an encoder's business
1229 * also, the conversion stuff might seem to make sense, but seems to not mind
1230 * segment stuff etc at all
1231 * Supposedly that's backward compatibility ... */
1233 gst_base_audio_encoder_src_query (GstPad * pad, GstQuery * query)
1235 GstBaseAudioEncoder *enc;
1237 gboolean res = FALSE;
1239 enc = GST_BASE_AUDIO_ENCODER (GST_PAD_PARENT (pad));
1240 peerpad = gst_pad_get_peer (GST_PAD (enc->sinkpad));
1242 GST_LOG_OBJECT (enc, "handling query: %" GST_PTR_FORMAT, query);
1244 switch (GST_QUERY_TYPE (query)) {
1245 case GST_QUERY_POSITION:
1247 GstFormat fmt, req_fmt;
1250 if ((res = gst_pad_peer_query (enc->sinkpad, query))) {
1251 GST_LOG_OBJECT (enc, "returning peer response");
1256 GST_LOG_OBJECT (enc, "no peer");
1260 gst_query_parse_position (query, &req_fmt, NULL);
1261 fmt = GST_FORMAT_TIME;
1262 if (!(res = gst_pad_query_position (peerpad, &fmt, &pos)))
1265 if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val))) {
1266 gst_query_set_position (query, req_fmt, val);
1270 case GST_QUERY_DURATION:
1272 GstFormat fmt, req_fmt;
1275 if ((res = gst_pad_peer_query (enc->sinkpad, query))) {
1276 GST_LOG_OBJECT (enc, "returning peer response");
1281 GST_LOG_OBJECT (enc, "no peer");
1285 gst_query_parse_duration (query, &req_fmt, NULL);
1286 fmt = GST_FORMAT_TIME;
1287 if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur)))
1290 if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) {
1291 gst_query_set_duration (query, req_fmt, val);
1295 case GST_QUERY_FORMATS:
1297 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
1301 case GST_QUERY_CONVERT:
1303 GstFormat src_fmt, dest_fmt;
1304 gint64 src_val, dest_val;
1306 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
1307 if (!(res = gst_base_audio_encoded_audio_convert (&enc->ctx->state,
1308 enc->priv->bytes_out, enc->priv->samples_in, src_fmt, src_val,
1309 &dest_fmt, &dest_val)))
1311 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
1314 case GST_QUERY_LATENCY:
1316 if ((res = gst_pad_peer_query (enc->sinkpad, query))) {
1318 GstClockTime min_latency, max_latency;
1320 gst_query_parse_latency (query, &live, &min_latency, &max_latency);
1321 GST_DEBUG_OBJECT (enc, "Peer latency: live %d, min %"
1322 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
1323 GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
1325 GST_OBJECT_LOCK (enc);
1326 /* add our latency */
1327 if (min_latency != -1)
1328 min_latency += enc->ctx->min_latency;
1329 if (max_latency != -1)
1330 max_latency += enc->ctx->max_latency;
1331 GST_OBJECT_UNLOCK (enc);
1333 gst_query_set_latency (query, live, min_latency, max_latency);
1338 res = gst_pad_query_default (pad, query);
1342 gst_object_unref (peerpad);
1347 gst_base_audio_encoder_set_property (GObject * object, guint prop_id,
1348 const GValue * value, GParamSpec * pspec)
1350 GstBaseAudioEncoder *enc;
1352 enc = GST_BASE_AUDIO_ENCODER (object);
1355 case PROP_PERFECT_TS:
1356 if (enc->granule && !g_value_get_boolean (value))
1357 GST_WARNING_OBJECT (enc, "perfect-ts can not be set FALSE");
1359 enc->perfect_ts = g_value_get_boolean (value);
1361 case PROP_HARD_RESYNC:
1362 enc->hard_resync = g_value_get_boolean (value);
1364 case PROP_TOLERANCE:
1365 enc->tolerance = g_value_get_int64 (value);
1368 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1374 gst_base_audio_encoder_get_property (GObject * object, guint prop_id,
1375 GValue * value, GParamSpec * pspec)
1377 GstBaseAudioEncoder *enc;
1379 enc = GST_BASE_AUDIO_ENCODER (object);
1382 case PROP_PERFECT_TS:
1383 g_value_set_boolean (value, enc->perfect_ts);
1386 g_value_set_boolean (value, enc->granule);
1388 case PROP_HARD_RESYNC:
1389 g_value_set_boolean (value, enc->hard_resync);
1391 case PROP_TOLERANCE:
1392 g_value_set_int64 (value, enc->tolerance);
1395 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1401 gst_base_audio_encoder_activate (GstBaseAudioEncoder * enc, gboolean active)
1403 GstBaseAudioEncoderClass *klass;
1404 gboolean result = FALSE;
1406 klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
1408 g_return_val_if_fail (!enc->granule || enc->perfect_ts, FALSE);
1410 GST_DEBUG_OBJECT (enc, "activate %d", active);
1413 if (!enc->priv->active && klass->start)
1414 result = klass->start (enc);
1416 /* We must make sure streaming has finished before resetting things
1417 * and calling the ::stop vfunc */
1418 GST_PAD_STREAM_LOCK (enc->sinkpad);
1419 GST_PAD_STREAM_UNLOCK (enc->sinkpad);
1421 if (enc->priv->active && klass->stop)
1422 result = klass->stop (enc);
1425 gst_base_audio_encoder_reset (enc, TRUE);
1427 GST_DEBUG_OBJECT (enc, "activate return: %d", result);
1433 gst_base_audio_encoder_sink_activate_push (GstPad * pad, gboolean active)
1435 gboolean result = TRUE;
1436 GstBaseAudioEncoder *enc;
1438 enc = GST_BASE_AUDIO_ENCODER (gst_pad_get_parent (pad));
1440 GST_DEBUG_OBJECT (enc, "sink activate push %d", active);
1442 result = gst_base_audio_encoder_activate (enc, active);
1445 enc->priv->active = active;
1447 GST_DEBUG_OBJECT (enc, "sink activate push return: %d", result);
1449 gst_object_unref (enc);