baseaudioencoder: replace context helper structure by various

_get/_set
This commit is contained in:
Mark Nauwelaerts 2011-08-16 18:23:14 +02:00 committed by Tim-Philipp Müller
parent d1ab04f029
commit 6302c9d31d
2 changed files with 228 additions and 79 deletions

View file

@ -38,7 +38,7 @@
* <listitem><para> * <listitem><para>
* GstBaseAudioEncoder calls @set_format to inform subclass of the format * GstBaseAudioEncoder calls @set_format to inform subclass of the format
* of input audio data that it is about to receive. Subclass should * of input audio data that it is about to receive. Subclass should
* setup for encoding and configure various base class context parameters * setup for encoding and configure various base class parameters
* appropriately, notably those directing desired input data handling. * appropriately, notably those directing desired input data handling.
* While unlikely, it might be called more than once, if changing input * While unlikely, it might be called more than once, if changing input
* parameters require reconfiguration. * parameters require reconfiguration.
@ -49,10 +49,10 @@
* </itemizedlist> * </itemizedlist>
* </listitem> * </listitem>
* As of configuration stage, and throughout processing, GstBaseAudioEncoder * As of configuration stage, and throughout processing, GstBaseAudioEncoder
* provides a GstBaseAudioEncoderContext that provides required context, * maintains various parameters that provide required context,
* e.g. describing the format of input audio data. * e.g. describing the format of input audio data.
* Conversely, subclass can and should configure context to inform * Conversely, subclass can and should configure these context parameters
* base class of its expectation w.r.t. buffer handling. * to inform base class of its expectation w.r.t. buffer handling.
* <listitem> * <listitem>
* <itemizedlist> * <itemizedlist>
* <title>Data processing</title> * <title>Data processing</title>
@ -179,6 +179,20 @@ enum
#define DEFAULT_HARD_RESYNC FALSE #define DEFAULT_HARD_RESYNC FALSE
#define DEFAULT_TOLERANCE 40000000 #define DEFAULT_TOLERANCE 40000000
typedef struct _GstBaseAudioEncoderContext
{
/* input */
GstAudioFormatInfo info;
/* output */
gint frame_samples;
gint frame_max;
gint lookahead;
/* MT-protected (with LOCK) */
GstClockTime min_latency;
GstClockTime max_latency;
} GstBaseAudioEncoderContext;
struct _GstBaseAudioEncoderPrivate struct _GstBaseAudioEncoderPrivate
{ {
/* activation status */ /* activation status */
@ -369,7 +383,6 @@ gst_base_audio_encoder_init (GstBaseAudioEncoder * enc,
GST_DEBUG_OBJECT (enc, "src created"); GST_DEBUG_OBJECT (enc, "src created");
enc->priv->adapter = gst_adapter_new (); enc->priv->adapter = gst_adapter_new ();
enc->ctx = &enc->priv->ctx;
/* property default */ /* property default */
enc->perfect_ts = DEFAULT_PERFECT_TS; enc->perfect_ts = DEFAULT_PERFECT_TS;
@ -390,8 +403,8 @@ gst_base_audio_encoder_reset (GstBaseAudioEncoder * enc, gboolean full)
enc->priv->active = FALSE; enc->priv->active = FALSE;
enc->priv->samples_in = 0; enc->priv->samples_in = 0;
enc->priv->bytes_out = 0; enc->priv->bytes_out = 0;
g_free (enc->ctx->state.channel_pos); g_free (enc->priv->ctx.info.channel_pos);
memset (enc->ctx, 0, sizeof (enc->ctx)); memset (&enc->priv->ctx, 0, sizeof (enc->priv->ctx));
} }
gst_segment_init (&enc->segment, GST_FORMAT_TIME); gst_segment_init (&enc->segment, GST_FORMAT_TIME);
@ -452,7 +465,7 @@ gst_base_audio_encoder_finish_frame (GstBaseAudioEncoder * enc, GstBuffer * buf,
klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc); klass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
priv = enc->priv; priv = enc->priv;
ctx = enc->ctx; ctx = &enc->priv->ctx;
/* subclass should know what it is producing by now */ /* subclass should know what it is producing by now */
g_return_val_if_fail (GST_PAD_CAPS (enc->srcpad) != NULL, GST_FLOW_ERROR); g_return_val_if_fail (GST_PAD_CAPS (enc->srcpad) != NULL, GST_FLOW_ERROR);
@ -468,7 +481,7 @@ gst_base_audio_encoder_finish_frame (GstBaseAudioEncoder * enc, GstBuffer * buf,
/* remove corresponding samples from input */ /* remove corresponding samples from input */
if (samples < 0) if (samples < 0)
samples = (enc->priv->offset / ctx->state.bpf); samples = (enc->priv->offset / ctx->info.bpf);
if (G_LIKELY (samples)) { if (G_LIKELY (samples)) {
/* track upstream ts if so configured */ /* track upstream ts if so configured */
@ -476,8 +489,8 @@ gst_base_audio_encoder_finish_frame (GstBaseAudioEncoder * enc, GstBuffer * buf,
guint64 ts, distance; guint64 ts, distance;
ts = gst_adapter_prev_timestamp (priv->adapter, &distance); ts = gst_adapter_prev_timestamp (priv->adapter, &distance);
g_assert (distance % ctx->state.bpf == 0); g_assert (distance % ctx->info.bpf == 0);
distance /= ctx->state.bpf; distance /= ctx->info.bpf;
GST_LOG_OBJECT (enc, "%" G_GUINT64_FORMAT " samples past prev_ts %" GST_LOG_OBJECT (enc, "%" G_GUINT64_FORMAT " samples past prev_ts %"
GST_TIME_FORMAT, distance, GST_TIME_ARGS (ts)); GST_TIME_FORMAT, distance, GST_TIME_ARGS (ts));
GST_LOG_OBJECT (enc, "%" G_GUINT64_FORMAT " samples past base_ts %" GST_LOG_OBJECT (enc, "%" G_GUINT64_FORMAT " samples past base_ts %"
@ -490,9 +503,9 @@ gst_base_audio_encoder_finish_frame (GstBaseAudioEncoder * enc, GstBuffer * buf,
/* passed into another buffer; /* passed into another buffer;
* mild check for discontinuity and only mark if so */ * mild check for discontinuity and only mark if so */
next_ts = ts + next_ts = ts +
gst_util_uint64_scale (distance, GST_SECOND, ctx->state.rate); gst_util_uint64_scale (distance, GST_SECOND, ctx->info.rate);
old_ts = priv->base_ts + old_ts = priv->base_ts +
gst_util_uint64_scale (priv->samples, GST_SECOND, ctx->state.rate); gst_util_uint64_scale (priv->samples, GST_SECOND, ctx->info.rate);
diff = GST_CLOCK_DIFF (next_ts, old_ts); diff = GST_CLOCK_DIFF (next_ts, old_ts);
GST_LOG_OBJECT (enc, "ts diff %d ms", (gint) (diff / GST_MSECOND)); GST_LOG_OBJECT (enc, "ts diff %d ms", (gint) (diff / GST_MSECOND));
/* only mark discontinuity if beyond tolerance */ /* only mark discontinuity if beyond tolerance */
@ -500,8 +513,8 @@ gst_base_audio_encoder_finish_frame (GstBaseAudioEncoder * enc, GstBuffer * buf,
GST_DEBUG_OBJECT (enc, "marked discont"); GST_DEBUG_OBJECT (enc, "marked discont");
priv->discont = TRUE; priv->discont = TRUE;
} }
if (TRUE || diff > GST_SECOND / ctx->state.rate / 2 || if (TRUE || diff > GST_SECOND / ctx->info.rate / 2 ||
diff < -GST_SECOND / ctx->state.rate / 2) { diff < -GST_SECOND / ctx->info.rate / 2) {
GST_LOG_OBJECT (enc, "new upstream ts %" GST_TIME_FORMAT GST_LOG_OBJECT (enc, "new upstream ts %" GST_TIME_FORMAT
" at distance %" G_GUINT64_FORMAT, GST_TIME_ARGS (ts), distance); " at distance %" G_GUINT64_FORMAT, GST_TIME_ARGS (ts), distance);
/* re-sync to upstream ts */ /* re-sync to upstream ts */
@ -513,7 +526,7 @@ gst_base_audio_encoder_finish_frame (GstBaseAudioEncoder * enc, GstBuffer * buf,
} }
} }
/* advance sample view */ /* advance sample view */
if (G_UNLIKELY (samples * ctx->state.bpf > priv->offset)) { if (G_UNLIKELY (samples * ctx->info.bpf > priv->offset)) {
if (G_LIKELY (!priv->force)) { if (G_LIKELY (!priv->force)) {
/* no way we can let this pass */ /* no way we can let this pass */
g_assert_not_reached (); g_assert_not_reached ();
@ -521,14 +534,14 @@ gst_base_audio_encoder_finish_frame (GstBaseAudioEncoder * enc, GstBuffer * buf,
goto overflow; goto overflow;
} else { } else {
priv->offset = 0; priv->offset = 0;
if (samples * ctx->state.bpf >= gst_adapter_available (priv->adapter)) if (samples * ctx->info.bpf >= gst_adapter_available (priv->adapter))
gst_adapter_clear (priv->adapter); gst_adapter_clear (priv->adapter);
else else
gst_adapter_flush (priv->adapter, samples * ctx->state.bpf); gst_adapter_flush (priv->adapter, samples * ctx->info.bpf);
} }
} else { } else {
gst_adapter_flush (priv->adapter, samples * ctx->state.bpf); gst_adapter_flush (priv->adapter, samples * ctx->info.bpf);
priv->offset -= samples * ctx->state.bpf; priv->offset -= samples * ctx->info.bpf;
/* avoid subsequent stray prev_ts */ /* avoid subsequent stray prev_ts */
if (G_UNLIKELY (gst_adapter_available (priv->adapter) == 0)) if (G_UNLIKELY (gst_adapter_available (priv->adapter) == 0))
gst_adapter_clear (priv->adapter); gst_adapter_clear (priv->adapter);
@ -549,13 +562,13 @@ gst_base_audio_encoder_finish_frame (GstBaseAudioEncoder * enc, GstBuffer * buf,
/* mind sample rounding and produce perfect output */ /* mind sample rounding and produce perfect output */
GST_BUFFER_TIMESTAMP (buf) = priv->base_ts + GST_BUFFER_TIMESTAMP (buf) = priv->base_ts +
gst_util_uint64_scale (priv->samples - ctx->lookahead, GST_SECOND, gst_util_uint64_scale (priv->samples - ctx->lookahead, GST_SECOND,
ctx->state.rate); ctx->info.rate);
GST_DEBUG_OBJECT (enc, "out samples %d", samples); GST_DEBUG_OBJECT (enc, "out samples %d", samples);
if (G_LIKELY (samples > 0)) { if (G_LIKELY (samples > 0)) {
priv->samples += samples; priv->samples += samples;
GST_BUFFER_DURATION (buf) = priv->base_ts + GST_BUFFER_DURATION (buf) = priv->base_ts +
gst_util_uint64_scale (priv->samples - ctx->lookahead, GST_SECOND, gst_util_uint64_scale (priv->samples - ctx->lookahead, GST_SECOND,
ctx->state.rate) - GST_BUFFER_TIMESTAMP (buf); ctx->info.rate) - GST_BUFFER_TIMESTAMP (buf);
priv->last_duration = GST_BUFFER_DURATION (buf); priv->last_duration = GST_BUFFER_DURATION (buf);
} else { } else {
/* duration forecast in case of handling remainder; /* duration forecast in case of handling remainder;
@ -567,11 +580,11 @@ gst_base_audio_encoder_finish_frame (GstBaseAudioEncoder * enc, GstBuffer * buf,
/* FIXME: in longer run, muxer should take care of this ... */ /* FIXME: in longer run, muxer should take care of this ... */
/* offset_end = granulepos for ogg muxer */ /* offset_end = granulepos for ogg muxer */
GST_BUFFER_OFFSET_END (buf) = priv->base_gp + priv->samples - GST_BUFFER_OFFSET_END (buf) = priv->base_gp + priv->samples -
enc->ctx->lookahead; enc->priv->ctx.lookahead;
/* offset = timestamp corresponding to granulepos for ogg muxer */ /* offset = timestamp corresponding to granulepos for ogg muxer */
GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET (buf) =
GST_FRAMES_TO_CLOCK_TIME (GST_BUFFER_OFFSET_END (buf), GST_FRAMES_TO_CLOCK_TIME (GST_BUFFER_OFFSET_END (buf),
ctx->state.rate); ctx->info.rate);
} else { } else {
GST_BUFFER_OFFSET (buf) = priv->bytes_out; GST_BUFFER_OFFSET (buf) = priv->bytes_out;
GST_BUFFER_OFFSET_END (buf) = priv->bytes_out + GST_BUFFER_SIZE (buf); GST_BUFFER_OFFSET_END (buf) = priv->bytes_out + GST_BUFFER_SIZE (buf);
@ -618,7 +631,7 @@ overflow:
{ {
GST_ELEMENT_ERROR (enc, STREAM, ENCODE, GST_ELEMENT_ERROR (enc, STREAM, ENCODE,
("received more encoded samples %d than provided %d", ("received more encoded samples %d than provided %d",
samples, priv->offset / ctx->state.bpf), (NULL)); samples, priv->offset / ctx->info.bpf), (NULL));
if (buf) if (buf)
gst_buffer_unref (buf); gst_buffer_unref (buf);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
@ -644,7 +657,7 @@ gst_base_audio_encoder_push_buffers (GstBaseAudioEncoder * enc, gboolean force)
g_return_val_if_fail (klass->handle_frame != NULL, GST_FLOW_ERROR); g_return_val_if_fail (klass->handle_frame != NULL, GST_FLOW_ERROR);
priv = enc->priv; priv = enc->priv;
ctx = enc->ctx; ctx = &enc->priv->ctx;
while (ret == GST_FLOW_OK) { while (ret == GST_FLOW_OK) {
@ -654,7 +667,7 @@ gst_base_audio_encoder_push_buffers (GstBaseAudioEncoder * enc, gboolean force)
g_assert (priv->offset <= av); g_assert (priv->offset <= av);
av -= priv->offset; av -= priv->offset;
need = ctx->frame_samples > 0 ? ctx->frame_samples * ctx->state.bpf : av; need = ctx->frame_samples > 0 ? ctx->frame_samples * ctx->info.bpf : av;
GST_LOG_OBJECT (enc, "available: %d, needed: %d, force: %d", GST_LOG_OBJECT (enc, "available: %d, needed: %d, force: %d",
av, need, force); av, need, force);
@ -692,7 +705,7 @@ gst_base_audio_encoder_push_buffers (GstBaseAudioEncoder * enc, gboolean force)
/* mark this already as consumed, /* mark this already as consumed,
* which it should be when subclass gives us data in exchange for samples */ * which it should be when subclass gives us data in exchange for samples */
priv->offset += need; priv->offset += need;
priv->samples_in += need / ctx->state.bpf; priv->samples_in += need / ctx->info.bpf;
priv->got_data = FALSE; priv->got_data = FALSE;
ret = klass->handle_frame (enc, buf); ret = klass->handle_frame (enc, buf);
@ -734,7 +747,7 @@ gst_base_audio_encoder_set_base_gp (GstBaseAudioEncoder * enc)
enc->priv->base_ts); enc->priv->base_ts);
if (GST_CLOCK_TIME_IS_VALID (ts)) { if (GST_CLOCK_TIME_IS_VALID (ts)) {
enc->priv->base_gp = enc->priv->base_gp =
GST_CLOCK_TIME_TO_FRAMES (enc->priv->base_ts, enc->ctx->state.rate); GST_CLOCK_TIME_TO_FRAMES (enc->priv->base_ts, enc->priv->ctx.info.rate);
GST_DEBUG_OBJECT (enc, "new base gp %" G_GINT64_FORMAT, enc->priv->base_gp); GST_DEBUG_OBJECT (enc, "new base gp %" G_GINT64_FORMAT, enc->priv->base_gp);
} else { } else {
/* should reasonably have a valid base, /* should reasonably have a valid base,
@ -761,10 +774,10 @@ gst_base_audio_encoder_chain (GstPad * pad, GstBuffer * buffer)
bclass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc); bclass = GST_BASE_AUDIO_ENCODER_GET_CLASS (enc);
priv = enc->priv; priv = enc->priv;
ctx = enc->ctx; ctx = &enc->priv->ctx;
/* should know what is coming by now */ /* should know what is coming by now */
if (!ctx->state.bpf) if (!ctx->info.bpf)
goto not_negotiated; goto not_negotiated;
GST_LOG_OBJECT (enc, GST_LOG_OBJECT (enc,
@ -774,7 +787,7 @@ gst_base_audio_encoder_chain (GstPad * pad, GstBuffer * buffer)
GST_TIME_ARGS (GST_BUFFER_DURATION (buffer))); GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
/* input shoud be whole number of sample frames */ /* input shoud be whole number of sample frames */
if (GST_BUFFER_SIZE (buffer) % ctx->state.bpf) if (GST_BUFFER_SIZE (buffer) % ctx->info.bpf)
goto wrong_buffer; goto wrong_buffer;
#ifndef GST_DISABLE_GST_DEBUG #ifndef GST_DISABLE_GST_DEBUG
@ -784,11 +797,11 @@ gst_base_audio_encoder_chain (GstPad * pad, GstBuffer * buffer)
/* verify buffer duration */ /* verify buffer duration */
duration = gst_util_uint64_scale (GST_BUFFER_SIZE (buffer), GST_SECOND, duration = gst_util_uint64_scale (GST_BUFFER_SIZE (buffer), GST_SECOND,
ctx->state.rate * ctx->state.bpf); ctx->info.rate * ctx->info.bpf);
diff = GST_CLOCK_DIFF (duration, GST_BUFFER_DURATION (buffer)); diff = GST_CLOCK_DIFF (duration, GST_BUFFER_DURATION (buffer));
if (GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE && if (GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE &&
(diff > GST_SECOND / ctx->state.rate / 2 || (diff > GST_SECOND / ctx->info.rate / 2 ||
diff < -GST_SECOND / ctx->state.rate / 2)) { diff < -GST_SECOND / ctx->info.rate / 2)) {
GST_DEBUG_OBJECT (enc, "incoming buffer had incorrect duration %" GST_DEBUG_OBJECT (enc, "incoming buffer had incorrect duration %"
GST_TIME_FORMAT ", expected duration %" GST_TIME_FORMAT, GST_TIME_FORMAT ", expected duration %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
@ -805,8 +818,8 @@ gst_base_audio_encoder_chain (GstPad * pad, GstBuffer * buffer)
/* clip to segment */ /* clip to segment */
/* NOTE: slightly painful linking -laudio only for this one ... */ /* NOTE: slightly painful linking -laudio only for this one ... */
buffer = gst_audio_buffer_clip (buffer, &enc->segment, ctx->state.rate, buffer = gst_audio_buffer_clip (buffer, &enc->segment, ctx->info.rate,
ctx->state.bpf); ctx->info.bpf);
if (G_UNLIKELY (!buffer)) { if (G_UNLIKELY (!buffer)) {
GST_DEBUG_OBJECT (buffer, "no data after clipping to segment"); GST_DEBUG_OBJECT (buffer, "no data after clipping to segment");
goto done; goto done;
@ -836,9 +849,9 @@ gst_base_audio_encoder_chain (GstPad * pad, GstBuffer * buffer)
guint64 samples; guint64 samples;
samples = priv->samples + samples = priv->samples +
gst_adapter_available (priv->adapter) / ctx->state.bpf; gst_adapter_available (priv->adapter) / ctx->info.bpf;
next_ts = priv->base_ts + next_ts = priv->base_ts +
gst_util_uint64_scale (samples, GST_SECOND, ctx->state.rate); gst_util_uint64_scale (samples, GST_SECOND, ctx->info.rate);
GST_LOG_OBJECT (enc, "buffer is %" G_GUINT64_FORMAT GST_LOG_OBJECT (enc, "buffer is %" G_GUINT64_FORMAT
" samples past base_ts %" GST_TIME_FORMAT " samples past base_ts %" GST_TIME_FORMAT
", expected ts %" GST_TIME_FORMAT, samples, ", expected ts %" GST_TIME_FORMAT, samples,
@ -863,7 +876,7 @@ gst_base_audio_encoder_chain (GstPad * pad, GstBuffer * buffer)
GST_TIME_FORMAT ". Clipping buffer", GST_TIME_ARGS (next_ts)); GST_TIME_FORMAT ". Clipping buffer", GST_TIME_ARGS (next_ts));
diff_bytes = diff_bytes =
GST_CLOCK_TIME_TO_FRAMES (-diff, ctx->state.rate) * ctx->state.bpf; GST_CLOCK_TIME_TO_FRAMES (-diff, ctx->info.rate) * ctx->info.bpf;
if (diff_bytes >= GST_BUFFER_SIZE (buffer)) { if (diff_bytes >= GST_BUFFER_SIZE (buffer)) {
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
goto done; goto done;
@ -907,7 +920,7 @@ wrong_buffer:
{ {
GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
("buffer size %d not a multiple of %d", GST_BUFFER_SIZE (buffer), ("buffer size %d not a multiple of %d", GST_BUFFER_SIZE (buffer),
ctx->state.bpf)); ctx->info.bpf));
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
@ -928,8 +941,8 @@ gst_base_audio_encoder_sink_setcaps (GstPad * pad, GstCaps * caps)
/* subclass must do something here ... */ /* subclass must do something here ... */
g_return_val_if_fail (klass->set_format != NULL, FALSE); g_return_val_if_fail (klass->set_format != NULL, FALSE);
ctx = enc->ctx; ctx = &enc->priv->ctx;
state = &ctx->state; state = &ctx->info;
GST_DEBUG_OBJECT (enc, "caps: %" GST_PTR_FORMAT, caps); GST_DEBUG_OBJECT (enc, "caps: %" GST_PTR_FORMAT, caps);
@ -954,9 +967,9 @@ gst_base_audio_encoder_sink_setcaps (GstPad * pad, GstCaps * caps)
gst_base_audio_encoder_drain (enc); gst_base_audio_encoder_drain (enc);
/* context defaults */ /* context defaults */
enc->ctx->frame_samples = 0; enc->priv->ctx.frame_samples = 0;
enc->ctx->frame_max = 0; enc->priv->ctx.frame_max = 0;
enc->ctx->lookahead = 0; enc->priv->ctx.lookahead = 0;
/* element might report latency */ /* element might report latency */
GST_OBJECT_LOCK (enc); GST_OBJECT_LOCK (enc);
@ -996,7 +1009,7 @@ refuse_caps:
/** /**
* gst_base_audio_encoder_proxy_getcaps: * gst_base_audio_encoder_proxy_getcaps:
* @enc: a #GstBaseAudioEncoder * @enc: a #GstBaseAudioEncoder
* @caps: initial * @caps: initial caps
* *
* Returns caps that express @caps (or sink template caps if @caps == NULL) * Returns caps that express @caps (or sink template caps if @caps == NULL)
* restricted to channel/rate combinations supported by downstream elements * restricted to channel/rate combinations supported by downstream elements
@ -1199,7 +1212,7 @@ gst_base_audio_encoder_sink_query (GstPad * pad, GstQuery * query)
gint64 src_val, dest_val; gint64 src_val, dest_val;
gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
if (!(res = gst_base_audio_raw_audio_convert (&enc->ctx->state, if (!(res = gst_base_audio_raw_audio_convert (&enc->priv->ctx.info,
src_fmt, src_val, &dest_fmt, &dest_val))) src_fmt, src_val, &dest_fmt, &dest_val)))
goto error; goto error;
gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
@ -1308,7 +1321,7 @@ gst_base_audio_encoder_src_query (GstPad * pad, GstQuery * query)
gint64 src_val, dest_val; gint64 src_val, dest_val;
gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
if (!(res = gst_base_audio_encoded_audio_convert (&enc->ctx->state, if (!(res = gst_base_audio_encoded_audio_convert (&enc->priv->ctx.info,
enc->priv->bytes_out, enc->priv->samples_in, src_fmt, src_val, enc->priv->bytes_out, enc->priv->samples_in, src_fmt, src_val,
&dest_fmt, &dest_val))) &dest_fmt, &dest_val)))
break; break;
@ -1329,9 +1342,9 @@ gst_base_audio_encoder_src_query (GstPad * pad, GstQuery * query)
GST_OBJECT_LOCK (enc); GST_OBJECT_LOCK (enc);
/* add our latency */ /* add our latency */
if (min_latency != -1) if (min_latency != -1)
min_latency += enc->ctx->min_latency; min_latency += enc->priv->ctx.min_latency;
if (max_latency != -1) if (max_latency != -1)
max_latency += enc->ctx->max_latency; max_latency += enc->priv->ctx.max_latency;
GST_OBJECT_UNLOCK (enc); GST_OBJECT_UNLOCK (enc);
gst_query_set_latency (query, live, min_latency, max_latency); gst_query_set_latency (query, live, min_latency, max_latency);
@ -1453,3 +1466,147 @@ gst_base_audio_encoder_sink_activate_push (GstPad * pad, gboolean active)
gst_object_unref (enc); gst_object_unref (enc);
return result; return result;
} }
/**
* gst_base_audio_encoder_get_info:
* @enc: a #GstBaseAudioEncoder
*
* Returns: a #AudioFormatInfo describing input audio format
*/
GstAudioFormatInfo *
gst_base_audio_encoder_get_info (GstBaseAudioEncoder * enc)
{
g_return_val_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc), NULL);
return &enc->priv->ctx.info;
}
/**
* gst_base_audio_encoder_set_frame_samples:
* @enc: a #GstBaseAudioEncoder
* @num: number of samples per frame
*
* Sets number of samples (per channel) subclass needs to be handed,
* or will be handed all available if 0.
*/
void
gst_base_audio_encoder_set_frame_samples (GstBaseAudioEncoder * enc, gint num)
{
g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
enc->priv->ctx.frame_samples = num;
}
/**
* gst_base_audio_encoder_get_frame_samples:
* @enc: a #GstBaseAudioEncoder
*
* Returns: currently requested samples per frame
*/
gint
gst_base_audio_encoder_get_frame_samples (GstBaseAudioEncoder * enc)
{
g_return_val_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc), 0);
return enc->priv->ctx.frame_samples;
}
/**
* gst_base_audio_encoder_set_frame_max:
* @enc: a #GstBaseAudioEncoder
* @num: number of frames
*
* Sets max number of frames accepted at once (assumed minimally 1)
*/
void
gst_base_audio_encoder_set_frame_max (GstBaseAudioEncoder * enc, gint num)
{
g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
enc->priv->ctx.frame_max = num;
}
/**
* gst_base_audio_encoder_get_frame_max:
* @enc: a #GstBaseAudioEncoder
*
* Returns: currently configured maximum handled frames
*/
gint
gst_base_audio_encoder_get_frame_max (GstBaseAudioEncoder * enc)
{
g_return_val_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc), 0);
return enc->priv->ctx.frame_max;
}
/**
* gst_base_audio_encoder_set_lookahead:
* @enc: a #GstBaseAudioEncoder
* @num: lookahead
*
* Sets encoder lookahead (in units of input rate samples)
*/
void
gst_base_audio_encoder_set_lookahead (GstBaseAudioEncoder * enc, gint num)
{
g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
enc->priv->ctx.lookahead = num;
}
/**
* gst_base_audio_encoder_get_lookahead:
* @enc: a #GstBaseAudioEncoder
*
* Returns: currently configured encoder lookahead
*/
gint
gst_base_audio_encoder_get_lookahead (GstBaseAudioEncoder * enc)
{
g_return_val_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc), 0);
return enc->priv->ctx.lookahead;
}
/**
* gst_base_audio_encoder_set_latency:
* @enc: a #GstBaseAudioEncoder
* @min: minimum latency
* @max: maximum latency
*
* Sets encoder latency.
*/
void
gst_base_audio_encoder_set_latency (GstBaseAudioEncoder * enc,
GstClockTime min, GstClockTime max)
{
g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
GST_OBJECT_LOCK (enc);
enc->priv->ctx.min_latency = min;
enc->priv->ctx.max_latency = max;
GST_OBJECT_UNLOCK (enc);
}
/**
* gst_base_audio_encoder_get_latency:
* @enc: a #GstBaseAudioEncoder
* @min: a pointer to storage to hold minimum latency
* @max: a pointer to storage to hold maximum latency
*
* Returns currently configured latency.
*/
void
gst_base_audio_encoder_get_latency (GstBaseAudioEncoder * enc,
GstClockTime * min, GstClockTime * max)
{
g_return_if_fail (GST_IS_BASE_AUDIO_ENCODER (enc));
GST_OBJECT_LOCK (enc);
if (min)
*min = enc->priv->ctx.min_latency;
if (max)
*max = enc->priv->ctx.max_latency;
GST_OBJECT_UNLOCK (enc);
}

View file

@ -88,33 +88,6 @@ typedef struct _GstBaseAudioEncoder GstBaseAudioEncoder;
typedef struct _GstBaseAudioEncoderClass GstBaseAudioEncoderClass; typedef struct _GstBaseAudioEncoderClass GstBaseAudioEncoderClass;
typedef struct _GstBaseAudioEncoderPrivate GstBaseAudioEncoderPrivate; typedef struct _GstBaseAudioEncoderPrivate GstBaseAudioEncoderPrivate;
typedef struct _GstBaseAudioEncoderContext GstBaseAudioEncoderContext;
/**
* GstBaseAudioEncoderContext:
* @state: a #GstAudioState describing input audio format
* @frame_samples: number of samples (per channel) subclass needs to be handed,
* or will be handed all available if 0.
* @frame_max: max number of frames of size @frame_bytes accepted at once
* (assumed minimally 1)
* @min_latency: min latency of element
* @max_latency: max latency of element
* @lookahead: encoder lookahead (in units of input rate samples)
*
* Transparent #GstBaseAudioEncoderContext data structure.
*/
struct _GstBaseAudioEncoderContext {
/* input */
GstAudioFormatInfo state;
/* output */
gint frame_samples;
gint frame_max;
gint lookahead;
/* MT-protected (with LOCK) */
GstClockTime min_latency;
GstClockTime max_latency;
};
/** /**
* GstBaseAudioEncoder: * GstBaseAudioEncoder:
@ -132,7 +105,6 @@ struct _GstBaseAudioEncoder {
/* MT-protected (with STREAM_LOCK) */ /* MT-protected (with STREAM_LOCK) */
GstSegment segment; GstSegment segment;
GstBaseAudioEncoderContext *ctx;
/* properties */ /* properties */
gint64 tolerance; gint64 tolerance;
@ -219,6 +191,26 @@ GstFlowReturn gst_base_audio_encoder_finish_frame (GstBaseAudioEncoder * enc,
GstCaps * gst_base_audio_encoder_proxy_getcaps (GstBaseAudioEncoder * enc, GstCaps * gst_base_audio_encoder_proxy_getcaps (GstBaseAudioEncoder * enc,
GstCaps * caps); GstCaps * caps);
GstAudioFormatInfo * gst_base_audio_encoder_get_info (GstBaseAudioEncoder * enc);
gint gst_base_audio_encoder_get_frame_samples (GstBaseAudioEncoder * enc);
void gst_base_audio_encoder_set_frame_samples (GstBaseAudioEncoder * enc,
gint num);
gint gst_base_audio_encoder_get_frame_max (GstBaseAudioEncoder * enc);
void gst_base_audio_encoder_set_frame_max (GstBaseAudioEncoder * enc,
gint num);
gint gst_base_audio_encoder_get_lookahead (GstBaseAudioEncoder * enc);
void gst_base_audio_encoder_set_lookahead (GstBaseAudioEncoder * enc,
gint num);
void gst_base_audio_encoder_get_latency (GstBaseAudioEncoder * enc,
GstClockTime * min, GstClockTime * max);
void gst_base_audio_encoder_set_latency (GstBaseAudioEncoder * enc,
GstClockTime min, GstClockTime max);
G_END_DECLS G_END_DECLS
#endif /* __GST_BASE_AUDIO_ENCODER_H__ */ #endif /* __GST_BASE_AUDIO_ENCODER_H__ */