From dae848818da8685c3b74d94db115b8d7f7c9fb28 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 18 Aug 2011 19:15:03 +0200 Subject: [PATCH] audio: rework audio caps. Rework the audio caps similar to the video caps. Remove width/depth/endianness/signed fields and replace with a simple string format and media type audio/x-raw. Create a GstAudioInfo and some helper methods to parse caps. Remove duplicate code from the ringbuffer and replace with audio info. Use AudioInfo in the base audio filter class. Port elements to new API. --- ext/alsa/gstalsasink.c | 149 +++--- ext/alsa/gstalsasink.h | 2 +- ext/alsa/gstalsasrc.c | 142 ++++-- ext/alsa/gstalsasrc.h | 2 +- ext/vorbis/gstvorbisdec.c | 88 ++-- ext/vorbis/gstvorbisdec.h | 2 +- ext/vorbis/gstvorbisdeclib.c | 96 +--- ext/vorbis/gstvorbisdeclib.h | 45 +- gst-libs/gst/audio/Makefile.am | 1 + gst-libs/gst/audio/audio.c | 336 ++++++++++++++ gst-libs/gst/audio/audio.h | 390 ++++++++++++---- gst-libs/gst/audio/gstaudiofilter.c | 27 +- gst-libs/gst/audio/gstaudiofilter.h | 6 +- gst-libs/gst/audio/gstaudioiec61937.c | 12 +- gst-libs/gst/audio/gstbaseaudiosink.c | 50 +- gst-libs/gst/audio/gstbaseaudiosrc.c | 73 ++- gst-libs/gst/audio/gstringbuffer.c | 393 ++++------------ gst-libs/gst/audio/gstringbuffer.h | 122 +---- gst-libs/gst/audio/multichannel.c | 4 - gst-libs/gst/audio/multichannel.h | 2 +- gst-libs/gst/video/video.h | 7 +- gst/adder/gstadder.c | 27 +- gst/audioconvert/audioconvert.c | 100 ++-- gst/audioconvert/audioconvert.h | 12 +- gst/audioconvert/gstaudioconvert.c | 640 ++++---------------------- gst/audioconvert/gstaudioconvert.h | 2 +- gst/audioconvert/gstaudioquantize.c | 6 +- gst/audioconvert/gstchannelmix.c | 51 +- gst/audiorate/Makefile.am | 4 +- gst/audiorate/gstaudiorate.c | 88 ++-- gst/audiorate/gstaudiorate.h | 3 +- gst/audioresample/Makefile.am | 1 + gst/audioresample/gstaudioresample.c | 192 +++----- gst/audioresample/gstaudioresample.h | 15 +- gst/audiotestsrc/Makefile.am | 6 +- gst/audiotestsrc/gstaudiotestsrc.c | 295 ++++++------ gst/audiotestsrc/gstaudiotestsrc.h | 15 +- gst/playback/gstrawcaps.h | 3 +- gst/volume/gstvolume.c | 153 +++--- 39 files changed, 1574 insertions(+), 1988 deletions(-) diff --git a/ext/alsa/gstalsasink.c b/ext/alsa/gstalsasink.c index 9dc5b53e9c..298e5a85fe 100644 --- a/ext/alsa/gstalsasink.c +++ b/ext/alsa/gstalsasink.c @@ -95,46 +95,13 @@ static gint output_ref; /* 0 */ static snd_output_t *output; /* NULL */ static GStaticMutex output_mutex = G_STATIC_MUTEX_INIT; - -#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) -# define ALSA_SINK_FACTORY_ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN" -#else -# define ALSA_SINK_FACTORY_ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN" -#endif - static GstStaticPadTemplate alsasink_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 32, " - "depth = (int) 32, " + GST_STATIC_CAPS ("audio/x-raw, " + "formats = (string) " GST_AUDIO_FORMATS_ALL ", " "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 24, " - "depth = (int) 24, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 32, " - "depth = (int) 24, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 16, " - "depth = (int) 16, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 8, " - "depth = (int) 8, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ];" "audio/x-iec958") ); @@ -627,26 +594,96 @@ alsasink_parse_spec (GstAlsaSink * alsa, GstRingBufferSpec * spec) alsa->iec958 = FALSE; switch (spec->type) { - case GST_BUFTYPE_LINEAR: - GST_DEBUG_OBJECT (alsa, - "Linear format : depth=%d, width=%d, sign=%d, bigend=%d", spec->depth, - spec->width, spec->sign, spec->bigend); - - alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width, - spec->sign ? 0 : 1, spec->bigend ? 1 : 0); - break; - case GST_BUFTYPE_FLOAT: - switch (spec->format) { - case GST_FLOAT32_LE: + case GST_BUFTYPE_RAW: + switch (GST_AUDIO_INFO_FORMAT (&spec->info)) { + case GST_AUDIO_FORMAT_U8: + alsa->format = SND_PCM_FORMAT_U8; + break; + case GST_AUDIO_FORMAT_S8: + alsa->format = SND_PCM_FORMAT_S8; + break; + case GST_AUDIO_FORMAT_S16_LE: + alsa->format = SND_PCM_FORMAT_S16_LE; + break; + case GST_AUDIO_FORMAT_S16_BE: + alsa->format = SND_PCM_FORMAT_S16_BE; + break; + case GST_AUDIO_FORMAT_U16_LE: + alsa->format = SND_PCM_FORMAT_U16_LE; + break; + case GST_AUDIO_FORMAT_U16_BE: + alsa->format = SND_PCM_FORMAT_U16_BE; + break; + case GST_AUDIO_FORMAT_S24_LE: + alsa->format = SND_PCM_FORMAT_S24_LE; + break; + case GST_AUDIO_FORMAT_S24_BE: + alsa->format = SND_PCM_FORMAT_S24_BE; + break; + case GST_AUDIO_FORMAT_U24_LE: + alsa->format = SND_PCM_FORMAT_U24_LE; + break; + case GST_AUDIO_FORMAT_U24_BE: + alsa->format = SND_PCM_FORMAT_U24_BE; + break; + case GST_AUDIO_FORMAT_S32_LE: + alsa->format = SND_PCM_FORMAT_S32_LE; + break; + case GST_AUDIO_FORMAT_S32_BE: + alsa->format = SND_PCM_FORMAT_S32_BE; + break; + case GST_AUDIO_FORMAT_U32_LE: + alsa->format = SND_PCM_FORMAT_U32_LE; + break; + case GST_AUDIO_FORMAT_U32_BE: + alsa->format = SND_PCM_FORMAT_U32_BE; + break; + case GST_AUDIO_FORMAT_S24_3LE: + alsa->format = SND_PCM_FORMAT_S24_3LE; + break; + case GST_AUDIO_FORMAT_S24_3BE: + alsa->format = SND_PCM_FORMAT_S24_3BE; + break; + case GST_AUDIO_FORMAT_U24_3LE: + alsa->format = SND_PCM_FORMAT_U24_3LE; + break; + case GST_AUDIO_FORMAT_U24_3BE: + alsa->format = SND_PCM_FORMAT_U24_3BE; + break; + case GST_AUDIO_FORMAT_S20_3LE: + alsa->format = SND_PCM_FORMAT_S20_3LE; + break; + case GST_AUDIO_FORMAT_S20_3BE: + alsa->format = SND_PCM_FORMAT_S20_3BE; + break; + case GST_AUDIO_FORMAT_U20_3LE: + alsa->format = SND_PCM_FORMAT_U20_3LE; + break; + case GST_AUDIO_FORMAT_U20_3BE: + alsa->format = SND_PCM_FORMAT_U20_3BE; + break; + case GST_AUDIO_FORMAT_S18_3LE: + alsa->format = SND_PCM_FORMAT_S18_3LE; + break; + case GST_AUDIO_FORMAT_S18_3BE: + alsa->format = SND_PCM_FORMAT_S18_3BE; + break; + case GST_AUDIO_FORMAT_U18_3LE: + alsa->format = SND_PCM_FORMAT_U18_3LE; + break; + case GST_AUDIO_FORMAT_U18_3BE: + alsa->format = SND_PCM_FORMAT_U18_3BE; + break; + case GST_AUDIO_FORMAT_F32_LE: alsa->format = SND_PCM_FORMAT_FLOAT_LE; break; - case GST_FLOAT32_BE: + case GST_AUDIO_FORMAT_F32_BE: alsa->format = SND_PCM_FORMAT_FLOAT_BE; break; - case GST_FLOAT64_LE: + case GST_AUDIO_FORMAT_F64_LE: alsa->format = SND_PCM_FORMAT_FLOAT64_LE; break; - case GST_FLOAT64_BE: + case GST_AUDIO_FORMAT_F64_BE: alsa->format = SND_PCM_FORMAT_FLOAT64_BE; break; default: @@ -667,8 +704,8 @@ alsasink_parse_spec (GstAlsaSink * alsa, GstRingBufferSpec * spec) goto error; } - alsa->rate = spec->rate; - alsa->channels = spec->channels; + alsa->rate = GST_AUDIO_INFO_RATE (&spec->info); + alsa->channels = GST_AUDIO_INFO_CHANNELS (&spec->info); alsa->buffer_time = spec->buffer_time; alsa->period_time = spec->latency_time; alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED; @@ -724,7 +761,7 @@ gst_alsasink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) alsa = GST_ALSA_SINK (asink); - if (spec->format == GST_IEC958) { + if (spec->type == GST_BUFTYPE_IEC958) { snd_pcm_close (alsa->handle); alsa->handle = gst_alsa_open_iec958_pcm (GST_OBJECT (alsa)); if (G_UNLIKELY (!alsa->handle)) { @@ -738,8 +775,8 @@ gst_alsasink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) CHECK (set_hwparams (alsa), hw_params_failed); CHECK (set_swparams (alsa), sw_params_failed); - alsa->bytes_per_sample = spec->bytes_per_sample; - spec->segsize = alsa->period_size * spec->bytes_per_sample; + alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info); + spec->segsize = alsa->period_size * alsa->bpf; spec->segtotal = alsa->buffer_size / alsa->period_size; { @@ -867,7 +904,7 @@ gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length) GST_LOG_OBJECT (asink, "received audio samples buffer of %u bytes", length); - cptr = length / alsa->bytes_per_sample; + cptr = length / alsa->bpf; GST_ALSA_SINK_LOCK (asink); while (cptr > 0) { @@ -896,7 +933,7 @@ gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length) } GST_ALSA_SINK_UNLOCK (asink); - return length - (cptr * alsa->bytes_per_sample); + return length - (cptr * alsa->bpf); write_error: { diff --git a/ext/alsa/gstalsasink.h b/ext/alsa/gstalsasink.h index 902dbf77e5..a4bcdbe304 100644 --- a/ext/alsa/gstalsasink.h +++ b/ext/alsa/gstalsasink.h @@ -61,7 +61,7 @@ struct _GstAlsaSink { snd_pcm_format_t format; guint rate; guint channels; - gint bytes_per_sample; + gint bpf; gboolean iec958; gboolean need_swap; diff --git a/ext/alsa/gstalsasrc.c b/ext/alsa/gstalsasrc.c index 350c9a7248..425dc7f594 100644 --- a/ext/alsa/gstalsasrc.c +++ b/ext/alsa/gstalsasrc.c @@ -107,37 +107,11 @@ enum #endif static GstStaticPadTemplate alsasrc_src_factory = - GST_STATIC_PAD_TEMPLATE ("src", +GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 32, " - "depth = (int) 32, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 32, " - "depth = (int) 24, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 24, " - "depth = (int) 24, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 16, " - "depth = (int) 16, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 8, " - "depth = (int) 8, " + GST_STATIC_CAPS ("audio/x-raw, " + "format = (string) " GST_AUDIO_FORMATS_ALL ", " "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]") ); @@ -655,22 +629,96 @@ static gboolean alsasrc_parse_spec (GstAlsaSrc * alsa, GstRingBufferSpec * spec) { switch (spec->type) { - case GST_BUFTYPE_LINEAR: - alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width, - spec->sign ? 0 : 1, spec->bigend ? 1 : 0); - break; - case GST_BUFTYPE_FLOAT: - switch (spec->format) { - case GST_FLOAT32_LE: + case GST_BUFTYPE_RAW: + switch (GST_AUDIO_INFO_FORMAT (&spec->info)) { + case GST_AUDIO_FORMAT_U8: + alsa->format = SND_PCM_FORMAT_U8; + break; + case GST_AUDIO_FORMAT_S8: + alsa->format = SND_PCM_FORMAT_S8; + break; + case GST_AUDIO_FORMAT_S16_LE: + alsa->format = SND_PCM_FORMAT_S16_LE; + break; + case GST_AUDIO_FORMAT_S16_BE: + alsa->format = SND_PCM_FORMAT_S16_BE; + break; + case GST_AUDIO_FORMAT_U16_LE: + alsa->format = SND_PCM_FORMAT_U16_LE; + break; + case GST_AUDIO_FORMAT_U16_BE: + alsa->format = SND_PCM_FORMAT_U16_BE; + break; + case GST_AUDIO_FORMAT_S24_LE: + alsa->format = SND_PCM_FORMAT_S24_LE; + break; + case GST_AUDIO_FORMAT_S24_BE: + alsa->format = SND_PCM_FORMAT_S24_BE; + break; + case GST_AUDIO_FORMAT_U24_LE: + alsa->format = SND_PCM_FORMAT_U24_LE; + break; + case GST_AUDIO_FORMAT_U24_BE: + alsa->format = SND_PCM_FORMAT_U24_BE; + break; + case GST_AUDIO_FORMAT_S32_LE: + alsa->format = SND_PCM_FORMAT_S32_LE; + break; + case GST_AUDIO_FORMAT_S32_BE: + alsa->format = SND_PCM_FORMAT_S32_BE; + break; + case GST_AUDIO_FORMAT_U32_LE: + alsa->format = SND_PCM_FORMAT_U32_LE; + break; + case GST_AUDIO_FORMAT_U32_BE: + alsa->format = SND_PCM_FORMAT_U32_BE; + break; + case GST_AUDIO_FORMAT_S24_3LE: + alsa->format = SND_PCM_FORMAT_S24_3LE; + break; + case GST_AUDIO_FORMAT_S24_3BE: + alsa->format = SND_PCM_FORMAT_S24_3BE; + break; + case GST_AUDIO_FORMAT_U24_3LE: + alsa->format = SND_PCM_FORMAT_U24_3LE; + break; + case GST_AUDIO_FORMAT_U24_3BE: + alsa->format = SND_PCM_FORMAT_U24_3BE; + break; + case GST_AUDIO_FORMAT_S20_3LE: + alsa->format = SND_PCM_FORMAT_S20_3LE; + break; + case GST_AUDIO_FORMAT_S20_3BE: + alsa->format = SND_PCM_FORMAT_S20_3BE; + break; + case GST_AUDIO_FORMAT_U20_3LE: + alsa->format = SND_PCM_FORMAT_U20_3LE; + break; + case GST_AUDIO_FORMAT_U20_3BE: + alsa->format = SND_PCM_FORMAT_U20_3BE; + break; + case GST_AUDIO_FORMAT_S18_3LE: + alsa->format = SND_PCM_FORMAT_S18_3LE; + break; + case GST_AUDIO_FORMAT_S18_3BE: + alsa->format = SND_PCM_FORMAT_S18_3BE; + break; + case GST_AUDIO_FORMAT_U18_3LE: + alsa->format = SND_PCM_FORMAT_U18_3LE; + break; + case GST_AUDIO_FORMAT_U18_3BE: + alsa->format = SND_PCM_FORMAT_U18_3BE; + break; + case GST_AUDIO_FORMAT_F32_LE: alsa->format = SND_PCM_FORMAT_FLOAT_LE; break; - case GST_FLOAT32_BE: + case GST_AUDIO_FORMAT_F32_BE: alsa->format = SND_PCM_FORMAT_FLOAT_BE; break; - case GST_FLOAT64_LE: + case GST_AUDIO_FORMAT_F64_LE: alsa->format = SND_PCM_FORMAT_FLOAT64_LE; break; - case GST_FLOAT64_BE: + case GST_AUDIO_FORMAT_F64_BE: alsa->format = SND_PCM_FORMAT_FLOAT64_BE; break; default: @@ -687,8 +735,8 @@ alsasrc_parse_spec (GstAlsaSrc * alsa, GstRingBufferSpec * spec) goto error; } - alsa->rate = spec->rate; - alsa->channels = spec->channels; + alsa->rate = GST_AUDIO_INFO_RATE (&spec->info); + alsa->channels = GST_AUDIO_INFO_CHANNELS (&spec->info); alsa->buffer_time = spec->buffer_time; alsa->period_time = spec->latency_time; alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED; @@ -753,13 +801,9 @@ gst_alsasrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec) CHECK (set_swparams (alsa), sw_params_failed); CHECK (snd_pcm_prepare (alsa->handle), prepare_failed); - alsa->bytes_per_sample = spec->bytes_per_sample; - spec->segsize = alsa->period_size * spec->bytes_per_sample; + alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info); + spec->segsize = alsa->period_size * alsa->bpf; spec->segtotal = alsa->buffer_size / alsa->period_size; - spec->silence_sample[0] = 0; - spec->silence_sample[1] = 0; - spec->silence_sample[2] = 0; - spec->silence_sample[3] = 0; return TRUE; @@ -869,7 +913,7 @@ gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length) alsa = GST_ALSA_SRC (asrc); - cptr = length / alsa->bytes_per_sample; + cptr = length / alsa->bpf; ptr = data; GST_ALSA_SRC_LOCK (asrc); @@ -889,7 +933,7 @@ gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length) } GST_ALSA_SRC_UNLOCK (asrc); - return length - (cptr * alsa->bytes_per_sample); + return length - (cptr * alsa->bpf); read_error: { diff --git a/ext/alsa/gstalsasrc.h b/ext/alsa/gstalsasrc.h index 7072ab784d..de3383346a 100644 --- a/ext/alsa/gstalsasrc.h +++ b/ext/alsa/gstalsasrc.h @@ -63,7 +63,7 @@ struct _GstAlsaSrc { snd_pcm_format_t format; guint rate; guint channels; - gint bytes_per_sample; + gint bpf; gboolean driver_timestamps; guint buffer_time; diff --git a/ext/vorbis/gstvorbisdec.c b/ext/vorbis/gstvorbisdec.c index df58a44f6f..db8b8c7f13 100644 --- a/ext/vorbis/gstvorbisdec.c +++ b/ext/vorbis/gstvorbisdec.c @@ -224,7 +224,7 @@ vorbis_dec_convert (GstPad * pad, case GST_FORMAT_TIME: switch (*dest_format) { case GST_FORMAT_BYTES: - scale = dec->width * dec->vi.channels; + scale = dec->info.bpf; case GST_FORMAT_DEFAULT: *dest_value = scale * gst_util_uint64_scale_int (src_value, dec->vi.rate, @@ -237,7 +237,7 @@ vorbis_dec_convert (GstPad * pad, case GST_FORMAT_DEFAULT: switch (*dest_format) { case GST_FORMAT_BYTES: - *dest_value = src_value * dec->width * dec->vi.channels; + *dest_value = src_value * dec->info.bpf; break; case GST_FORMAT_TIME: *dest_value = @@ -250,11 +250,11 @@ vorbis_dec_convert (GstPad * pad, case GST_FORMAT_BYTES: switch (*dest_format) { case GST_FORMAT_DEFAULT: - *dest_value = src_value / (dec->width * dec->vi.channels); + *dest_value = src_value / dec->info.bpf; break; case GST_FORMAT_TIME: *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND, - dec->vi.rate * dec->width * dec->vi.channels); + dec->vi.rate * dec->info.bpf); break; default: res = FALSE; @@ -545,10 +545,13 @@ static GstFlowReturn vorbis_handle_identification_packet (GstVorbisDec * vd) { GstCaps *caps; + GstAudioInfo info; const GstAudioChannelPosition *pos = NULL; - gint width = GST_VORBIS_DEC_DEFAULT_SAMPLE_WIDTH; - switch (vd->vi.channels) { + gst_audio_info_set_format (&info, GST_VORBIS_AUDIO_FORMAT, vd->vi.rate, + vd->vi.channels); + + switch (info.channels) { case 1: case 2: /* nothing */ @@ -559,60 +562,28 @@ vorbis_handle_identification_packet (GstVorbisDec * vd) case 6: case 7: case 8: - pos = gst_vorbis_channel_positions[vd->vi.channels - 1]; + pos = gst_vorbis_channel_positions[info.channels - 1]; break; - default:{ - gint i; - GstAudioChannelPosition *posn = - g_new (GstAudioChannelPosition, vd->vi.channels); + default: + { + gint i, max_pos = MAX (info.channels, 64); - GST_ELEMENT_WARNING (GST_ELEMENT (vd), STREAM, DECODE, + GST_ELEMENT_WARNING (vd, STREAM, DECODE, (NULL), ("Using NONE channel layout for more than 8 channels")); - - for (i = 0; i < vd->vi.channels; i++) - posn[i] = GST_AUDIO_CHANNEL_POSITION_NONE; - - pos = posn; + for (i = 0; i < max_pos; i++) + info.position[i] = GST_AUDIO_CHANNEL_POSITION_NONE; } } - /* negotiate width with downstream */ - caps = gst_pad_get_allowed_caps (vd->srcpad); - if (caps) { - if (!gst_caps_is_empty (caps)) { - GstStructure *s; - - s = gst_caps_get_structure (caps, 0); - /* template ensures 16 or 32 */ - gst_structure_get_int (s, "width", &width); - - GST_INFO_OBJECT (vd, "using %s with %d channels and %d bit audio depth", - gst_structure_get_name (s), vd->vi.channels, width); - } - gst_caps_unref (caps); - } - vd->width = width >> 3; - - /* select a copy_samples function, this way we can have specialized versions - * for mono/stereo and avoid the depth switch in tremor case */ - vd->copy_samples = get_copy_sample_func (vd->vi.channels, vd->width); - - caps = gst_caps_make_writable (gst_pad_get_pad_template_caps (vd->srcpad)); - gst_caps_set_simple (caps, "rate", G_TYPE_INT, vd->vi.rate, - "channels", G_TYPE_INT, vd->vi.channels, - "width", G_TYPE_INT, width, NULL); - - if (pos) { - gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos); - } - - if (vd->vi.channels > 8) { - g_free ((GstAudioChannelPosition *) pos); - } - + caps = gst_audio_info_to_caps (&info); gst_pad_set_caps (vd->srcpad, caps); gst_caps_unref (caps); + vd->info = info; + /* select a copy_samples function, this way we can have specialized versions + * for mono/stereo and avoid the depth switch in tremor case */ + vd->copy_samples = get_copy_sample_func (info.channels); + return GST_FLOW_OK; } @@ -792,7 +763,7 @@ vorbis_dec_push_forward (GstVorbisDec * dec, GstBuffer * buf) /* clip */ if (!(buf = gst_audio_buffer_clip (buf, &dec->segment, dec->vi.rate, - dec->vi.channels * dec->width))) { + dec->info.bpf))) { GST_LOG_OBJECT (dec, "clipped buffer"); return GST_FLOW_OK; } @@ -856,9 +827,7 @@ static GstFlowReturn vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet, GstClockTime timestamp, GstClockTime duration) { -#ifdef USE_TREMOLO - vorbis_sample_t *pcm; -#else +#ifndef USE_TREMOLO vorbis_sample_t **pcm; #endif guint sample_count; @@ -899,17 +868,17 @@ vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet, #endif goto done; - size = sample_count * vd->vi.channels * vd->width; + size = sample_count * vd->info.bpf; GST_LOG_OBJECT (vd, "%d samples ready for reading, size %" G_GSIZE_FORMAT, sample_count, size); /* alloc buffer for it */ out = gst_buffer_new_and_alloc (size); + data = gst_buffer_map (out, NULL, NULL, GST_MAP_WRITE); /* get samples ready for reading now, should be sample_count */ #ifdef USE_TREMOLO - pcm = GST_BUFFER_DATA (out); - if (G_UNLIKELY ((vorbis_dsp_pcmout (&vd->vd, pcm, + if (G_UNLIKELY ((vorbis_dsp_pcmout (&vd->vd, data, sample_count)) != sample_count)) #else if (G_UNLIKELY ((vorbis_synthesis_pcmout (&vd->vd, &pcm)) != sample_count)) @@ -918,9 +887,8 @@ vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet, #ifndef USE_TREMOLO /* copy samples in buffer */ - data = gst_buffer_map (out, NULL, NULL, GST_MAP_WRITE); vd->copy_samples ((vorbis_sample_t *) data, pcm, - sample_count, vd->vi.channels, vd->width); + sample_count, vd->info.channels); #endif GST_LOG_OBJECT (vd, "setting output size to %" G_GSIZE_FORMAT, size); diff --git a/ext/vorbis/gstvorbisdec.h b/ext/vorbis/gstvorbisdec.h index 04e4677410..d122a0e02d 100644 --- a/ext/vorbis/gstvorbisdec.h +++ b/ext/vorbis/gstvorbisdec.h @@ -65,7 +65,7 @@ struct _GstVorbisDec { #endif gboolean initialized; - guint width; + GstAudioInfo info; /* list of buffers that need timestamps */ GList *queued; diff --git a/ext/vorbis/gstvorbisdeclib.c b/ext/vorbis/gstvorbisdeclib.c index 1ddce38772..66a2ee39fc 100644 --- a/ext/vorbis/gstvorbisdeclib.c +++ b/ext/vorbis/gstvorbisdeclib.c @@ -34,14 +34,14 @@ * is allowed, downstream elements are supposed to clip */ static void copy_samples_m (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples, - gint channels, gint width) + gint channels) { memcpy (out, in[0], samples * sizeof (float)); } static void copy_samples_s (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples, - gint channels, gint width) + gint channels) { #ifdef GST_VORBIS_DEC_SEQUENTIAL memcpy (out, in[0], samples * sizeof (float)); @@ -59,7 +59,7 @@ copy_samples_s (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples, static void copy_samples (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples, - gint channels, gint width) + gint channels) { #ifdef GST_VORBIS_DEC_SEQUENTIAL gint i; @@ -80,12 +80,10 @@ copy_samples (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples, } CopySampleFunc -get_copy_sample_func (gint channels, gint width) +get_copy_sample_func (gint channels) { CopySampleFunc f = NULL; - g_assert (width == 4); - switch (channels) { case 1: f = copy_samples_m; @@ -130,51 +128,9 @@ CLIP_TO_15 (ogg_int32_t x) } #endif -static void -copy_samples_32_m (vorbis_sample_t * _out, vorbis_sample_t ** _in, - guint samples, gint channels, gint width) -{ - gint32 *out = (gint32 *) _out; - ogg_int32_t **in = (ogg_int32_t **) _in; - gint j; - - for (j = 0; j < samples; j++) { - *out++ = CLIP_TO_15 (in[0][j] >> 9); - } -} - -static void -copy_samples_32_s (vorbis_sample_t * _out, vorbis_sample_t ** _in, - guint samples, gint channels, gint width) -{ - gint32 *out = (gint32 *) _out; - ogg_int32_t **in = (ogg_int32_t **) _in; - gint j; - - for (j = 0; j < samples; j++) { - *out++ = CLIP_TO_15 (in[0][j] >> 9); - *out++ = CLIP_TO_15 (in[1][j] >> 9); - } -} - -static void -copy_samples_32 (vorbis_sample_t * _out, vorbis_sample_t ** _in, guint samples, - gint channels, gint width) -{ - gint32 *out = (gint32 *) _out; - ogg_int32_t **in = (ogg_int32_t **) _in; - gint i, j; - - for (j = 0; j < samples; j++) { - for (i = 0; i < channels; i++) { - *out++ = CLIP_TO_15 (in[i][j] >> 9); - } - } -} - static void copy_samples_16_m (vorbis_sample_t * _out, vorbis_sample_t ** _in, - guint samples, gint channels, gint width) + guint samples, gint channels) { gint16 *out = (gint16 *) _out; ogg_int32_t **in = (ogg_int32_t **) _in; @@ -187,7 +143,7 @@ copy_samples_16_m (vorbis_sample_t * _out, vorbis_sample_t ** _in, static void copy_samples_16_s (vorbis_sample_t * _out, vorbis_sample_t ** _in, - guint samples, gint channels, gint width) + guint samples, gint channels) { gint16 *out = (gint16 *) _out; ogg_int32_t **in = (ogg_int32_t **) _in; @@ -201,7 +157,7 @@ copy_samples_16_s (vorbis_sample_t * _out, vorbis_sample_t ** _in, static void copy_samples_16 (vorbis_sample_t * _out, vorbis_sample_t ** _in, guint samples, - gint channels, gint width) + gint channels) { gint16 *out = (gint16 *) _out; ogg_int32_t **in = (ogg_int32_t **) _in; @@ -215,36 +171,20 @@ copy_samples_16 (vorbis_sample_t * _out, vorbis_sample_t ** _in, guint samples, } CopySampleFunc -get_copy_sample_func (gint channels, gint width) +get_copy_sample_func (gint channels) { CopySampleFunc f = NULL; - if (width == 4) { - switch (channels) { - case 1: - f = copy_samples_32_m; - break; - case 2: - f = copy_samples_32_s; - break; - default: - f = copy_samples_32; - break; - } - } else if (width == 2) { - switch (channels) { - case 1: - f = copy_samples_16_m; - break; - case 2: - f = copy_samples_16_s; - break; - default: - f = copy_samples_16; - break; - } - } else { - g_assert_not_reached (); + switch (channels) { + case 1: + f = copy_samples_16_m; + break; + case 2: + f = copy_samples_16_s; + break; + default: + f = copy_samples_16; + break; } return f; } diff --git a/ext/vorbis/gstvorbisdeclib.h b/ext/vorbis/gstvorbisdeclib.h index 2e3942267f..fd416432c1 100644 --- a/ext/vorbis/gstvorbisdeclib.h +++ b/ext/vorbis/gstvorbisdeclib.h @@ -26,6 +26,7 @@ #define __GST_VORBIS_DEC_LIB_H__ #include +#include #ifndef TREMOR @@ -36,12 +37,19 @@ typedef ogg_packet ogg_packet_wrapper; #define GST_VORBIS_DEC_DESCRIPTION "decode raw vorbis streams to float audio" -#define GST_VORBIS_DEC_SRC_CAPS \ - GST_STATIC_CAPS ("audio/x-raw-float, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 256 ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 32") +#define GST_VORBIS_AUDIO_FORMAT GST_AUDIO_FORMAT_F32 + +#if G_BYTE_ORDER == G_BIG_ENDIAN +#define GST_VORBIS_AUDIO_FORMAT_STR "F32_BE" +#else +#define GST_VORBIS_AUDIO_FORMAT_STR "F32_LE" +#endif + +#define GST_VORBIS_DEC_SRC_CAPS \ + GST_STATIC_CAPS ("audio/x-raw, " \ + "format = (string)" GST_VORBIS_AUDIO_FORMAT_STR ", " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, 256 ]") #define GST_VORBIS_DEC_DEFAULT_SAMPLE_WIDTH (32) @@ -101,16 +109,19 @@ struct _ogg_packet_wrapper { #define GST_VORBIS_DEC_DESCRIPTION "decode raw vorbis streams to integer audio" -#define GST_VORBIS_DEC_SRC_CAPS \ - GST_STATIC_CAPS ("audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 6 ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) { 16, 32 }, " \ - "depth = (int) 16, " \ - "signed = (boolean) true") +#define GST_VORBIS_AUDIO_FORMAT GST_AUDIO_FORMAT_S16 -#define GST_VORBIS_DEC_DEFAULT_SAMPLE_WIDTH (16) +#if G_BYTE_ORDER == G_BIG_ENDIAN +#define GST_VORBIS_AUDIO_FORMAT_STR "S16_BE" +#else +#define GST_VORBIS_AUDIO_FORMAT_STR "S16_LE" +#endif + +#define GST_VORBIS_DEC_SRC_CAPS \ + GST_STATIC_CAPS ("audio/x-raw, " \ + "format = (string) " GST_VORBIS_AUDIO_FORMAT_STR ", " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, 6 ]") /* we need a different type name here */ #define GST_VORBIS_DEC_GLIB_TYPE_NAME GstIVorbisDec @@ -176,8 +187,8 @@ gst_ogg_packet_from_wrapper (ogg_packet_wrapper * packet) #endif typedef void (*CopySampleFunc)(vorbis_sample_t *out, vorbis_sample_t **in, - guint samples, gint channels, gint width); + guint samples, gint channels); -CopySampleFunc get_copy_sample_func (gint channels, gint width); +CopySampleFunc get_copy_sample_func (gint channels); #endif /* __GST_VORBIS_DEC_LIB_H__ */ diff --git a/gst-libs/gst/audio/Makefile.am b/gst-libs/gst/audio/Makefile.am index f0c59fcc79..bf38ead07b 100644 --- a/gst-libs/gst/audio/Makefile.am +++ b/gst-libs/gst/audio/Makefile.am @@ -69,6 +69,7 @@ GstAudio-@GST_MAJORMINOR@.gir: $(INTROSPECTION_SCANNER) libgstaudio-@GST_MAJORMI GST_PLUGIN_SYSTEM_PATH="" GST_PLUGIN_PATH="" GST_REGISTRY_UPDATE=no \ $(INTROSPECTION_SCANNER) -v --namespace GstAudio \ --nsversion=@GST_MAJORMINOR@ \ + --warn-all \ --strip-prefix=Gst \ -DGST_USE_UNSTABLE_API \ -I$(top_srcdir)/gst-libs \ diff --git a/gst-libs/gst/audio/audio.c b/gst-libs/gst/audio/audio.c index 52ca63344d..ea415c3df0 100644 --- a/gst-libs/gst/audio/audio.c +++ b/gst-libs/gst/audio/audio.c @@ -27,11 +27,347 @@ # include "config.h" #endif +#include + #include "audio.h" #include "audio-enumtypes.h" #include +#define SINT (GST_AUDIO_FORMAT_FLAG_INT | GST_AUDIO_FORMAT_FLAG_SIGNED) +#define UINT (GST_AUDIO_FORMAT_FLAG_INT) + +#define MAKE_FORMAT(str,flags,end,width,depth,silent) \ + { GST_AUDIO_FORMAT_ ##str, G_STRINGIFY(str), flags, end, width, depth, silent } + +#define SILENT_0 { 0, 0, 0, 0, 0, 0, 0, 0 } +#define SILENT_U8 { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 } +#define SILENT_U16_LE { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80 } +#define SILENT_U16_BE { 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 } +#define SILENT_U24_LE { 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00 } +#define SILENT_U24_BE { 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00 } +#define SILENT_U32_LE { 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 } +#define SILENT_U32_BE { 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 } +#define SILENT_U24_3LE { 0x00, 0x00, 0x80, 0x00, 0x00, 0x80 } +#define SILENT_U24_3BE { 0x80, 0x00, 0x00, 0x80, 0x00, 0x00 } +#define SILENT_U20_3LE { 0x00, 0x00, 0x08, 0x00, 0x00, 0x08 } +#define SILENT_U20_3BE { 0x08, 0x00, 0x00, 0x08, 0x00, 0x00 } +#define SILENT_U18_3LE { 0x00, 0x00, 0x02, 0x00, 0x00, 0x02 } +#define SILENT_U18_3BE { 0x02, 0x00, 0x00, 0x02, 0x00, 0x00 } + +static GstAudioFormatInfo formats[] = { + {GST_AUDIO_FORMAT_UNKNOWN, "UNKNOWN", 0, 0, 0, 0}, + /* 8 bit */ + MAKE_FORMAT (S8, SINT, 0, 8, 8, SILENT_0), + MAKE_FORMAT (U8, UINT, 0, 8, 8, SILENT_U8), + /* 16 bit */ + MAKE_FORMAT (S16_LE, SINT, G_LITTLE_ENDIAN, 16, 16, SILENT_0), + MAKE_FORMAT (S16_BE, SINT, G_BIG_ENDIAN, 16, 16, SILENT_0), + MAKE_FORMAT (U16_LE, UINT, G_LITTLE_ENDIAN, 16, 16, SILENT_U16_LE), + MAKE_FORMAT (U16_BE, UINT, G_BIG_ENDIAN, 16, 16, SILENT_U16_BE), + /* 24 bit in low 3 bytes of 32 bits */ + MAKE_FORMAT (S24_LE, SINT, G_LITTLE_ENDIAN, 32, 24, SILENT_0), + MAKE_FORMAT (S24_BE, SINT, G_BIG_ENDIAN, 32, 24, SILENT_0), + MAKE_FORMAT (U24_LE, UINT, G_LITTLE_ENDIAN, 32, 24, SILENT_U24_LE), + MAKE_FORMAT (U24_BE, UINT, G_BIG_ENDIAN, 32, 24, SILENT_U24_BE), + /* 32 bit */ + MAKE_FORMAT (S32_LE, SINT, G_LITTLE_ENDIAN, 32, 32, SILENT_0), + MAKE_FORMAT (S32_BE, SINT, G_BIG_ENDIAN, 32, 32, SILENT_0), + MAKE_FORMAT (U32_LE, UINT, G_LITTLE_ENDIAN, 32, 32, SILENT_U32_LE), + MAKE_FORMAT (U32_BE, UINT, G_BIG_ENDIAN, 32, 32, SILENT_U32_BE), + /* 24 bit in 3 bytes */ + MAKE_FORMAT (S24_3LE, SINT, G_LITTLE_ENDIAN, 24, 24, SILENT_0), + MAKE_FORMAT (S24_3BE, SINT, G_BIG_ENDIAN, 24, 24, SILENT_0), + MAKE_FORMAT (U24_3LE, UINT, G_LITTLE_ENDIAN, 24, 24, SILENT_U24_3LE), + MAKE_FORMAT (U24_3BE, UINT, G_BIG_ENDIAN, 24, 24, SILENT_U24_3BE), + /* 20 bit in 3 bytes */ + MAKE_FORMAT (S20_3LE, SINT, G_LITTLE_ENDIAN, 24, 20, SILENT_0), + MAKE_FORMAT (S20_3BE, SINT, G_BIG_ENDIAN, 24, 20, SILENT_0), + MAKE_FORMAT (U20_3LE, UINT, G_LITTLE_ENDIAN, 24, 20, SILENT_U20_3LE), + MAKE_FORMAT (U20_3BE, UINT, G_BIG_ENDIAN, 24, 20, SILENT_U20_3BE), + /* 18 bit in 3 bytes */ + MAKE_FORMAT (S18_3LE, SINT, G_LITTLE_ENDIAN, 24, 18, SILENT_0), + MAKE_FORMAT (S18_3BE, SINT, G_BIG_ENDIAN, 24, 18, SILENT_0), + MAKE_FORMAT (U18_3LE, UINT, G_LITTLE_ENDIAN, 24, 18, SILENT_U18_3LE), + MAKE_FORMAT (U18_3BE, UINT, G_BIG_ENDIAN, 24, 18, SILENT_U18_3BE), + /* float */ + MAKE_FORMAT (F32_LE, GST_AUDIO_FORMAT_FLAG_FLOAT, G_LITTLE_ENDIAN, 32, 32, + SILENT_0), + MAKE_FORMAT (F32_BE, GST_AUDIO_FORMAT_FLAG_FLOAT, G_BIG_ENDIAN, 32, 32, + SILENT_0), + MAKE_FORMAT (F64_LE, GST_AUDIO_FORMAT_FLAG_FLOAT, G_LITTLE_ENDIAN, 64, 64, + SILENT_0), + MAKE_FORMAT (F64_BE, GST_AUDIO_FORMAT_FLAG_FLOAT, G_BIG_ENDIAN, 64, 64, + SILENT_0) +}; + +/** + * gst_audio_format_from_string: + * @format: a format string + * + * Convert the @format string to its #GstAudioFormat. + * + * Returns: the #GstAudioFormat for @format or GST_AUDIO_FORMAT_UNKNOWN when the + * string is not a known format. + */ +GstAudioFormat +gst_audio_format_from_string (const gchar * format) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (formats); i++) { + if (strcmp (GST_AUDIO_FORMAT_INFO_NAME (&formats[i]), format) == 0) + return GST_AUDIO_FORMAT_INFO_FORMAT (&formats[i]); + } + return GST_AUDIO_FORMAT_UNKNOWN; +} + +const gchar * +gst_audio_format_to_string (GstAudioFormat format) +{ + g_return_val_if_fail (format != GST_AUDIO_FORMAT_UNKNOWN, NULL); + + if (format >= G_N_ELEMENTS (formats)) + return NULL; + + return GST_AUDIO_FORMAT_INFO_NAME (&formats[format]); +} + +/** + * gst_audio_format_get_info: + * @format: a #GstAudioFormat + * + * Get the #GstAudioFormatInfo for @format + * + * Returns: The #GstAudioFormatInfo for @format. + */ +const GstAudioFormatInfo * +gst_audio_format_get_info (GstAudioFormat format) +{ + g_return_val_if_fail (format != GST_AUDIO_FORMAT_UNKNOWN, NULL); + g_return_val_if_fail (format < G_N_ELEMENTS (formats), NULL); + + return &formats[format]; +} + +/** + * gst_audio_format_fill_silence: + * @info: a #GstAudioFormatInfo + * @dest: a destination to fill + * @lenfth: the length to fill + * + * Fill @length bytes in @dest with silence samples for @info. + */ +void +gst_audio_format_fill_silence (const GstAudioFormatInfo * info, + gpointer dest, gsize length) +{ + guint8 *dptr = dest; + + g_return_if_fail (info != NULL); + g_return_if_fail (dest != NULL); + + if (info->flags & GST_AUDIO_FORMAT_FLAG_FLOAT || + info->flags & GST_AUDIO_FORMAT_FLAG_SIGNED) { + /* float or signed always 0 */ + memset (dest, 0, length); + } else { + gint i, j, bps = info->width >> 3; + + switch (bps) { + case 1: + memset (dest, info->silence[0], length); + break; + default: + for (i = 0; i < length; i += bps) { + for (j = 0; j < bps; j++) + *dptr++ = info->silence[j]; + } + break; + } + } +} + + +/** + * gst_audio_info_init: + * @info: a #GstAudioInfo + * + * Initialize @info with default values. + */ +void +gst_audio_info_init (GstAudioInfo * info) +{ + g_return_if_fail (info != NULL); + + memset (info, 0, sizeof (GstAudioInfo)); +} + +/** + * gst_audio_info_set_format: + * @info: a #GstAudioInfo + * @format: the format + * @rate: the samplerate + * @channels: the number of channels + * + * Set the default info for the audio info of @format and @rate and @channels. + */ +void +gst_audio_info_set_format (GstAudioInfo * info, GstAudioFormat format, + gint rate, gint channels) +{ + const GstAudioFormatInfo *finfo; + + g_return_if_fail (info != NULL); + g_return_if_fail (format != GST_AUDIO_FORMAT_UNKNOWN); + + finfo = &formats[format]; + + info->flags = 0; + info->finfo = finfo; + info->rate = rate; + info->channels = channels; + info->bpf = (finfo->width * channels) / 8; +} + +/** + * gst_audio_info_from_caps: + * @info: a #GstAudioInfo + * @caps: a #GstCaps + * + * Parse @caps and update @info. + * + * Returns: TRUE if @caps could be parsed + */ +gboolean +gst_audio_info_from_caps (GstAudioInfo * info, const GstCaps * caps) +{ + GstStructure *str; + const gchar *s; + GstAudioFormat format; + gint rate, channels; + const GValue *pos_val_arr, *pos_val_entry; + gint i; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (caps != NULL, FALSE); + g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE); + + GST_DEBUG ("parsing caps %" GST_PTR_FORMAT, caps); + + str = gst_caps_get_structure (caps, 0); + + if (!gst_structure_has_name (str, "audio/x-raw")) + goto wrong_name; + + if (!(s = gst_structure_get_string (str, "format"))) + goto no_format; + + format = gst_audio_format_from_string (s); + if (format == GST_AUDIO_FORMAT_UNKNOWN) + goto unknown_format; + + if (!gst_structure_get_int (str, "rate", &rate)) + goto no_rate; + if (!gst_structure_get_int (str, "channels", &channels)) + goto no_channels; + + gst_audio_info_set_format (info, format, rate, channels); + + pos_val_arr = gst_structure_get_value (str, "channel-positions"); + if (pos_val_arr) { + guint max_pos = MAX (channels, 64); + for (i = 0; i < max_pos; i++) { + pos_val_entry = gst_value_array_get_value (pos_val_arr, i); + info->position[i] = g_value_get_enum (pos_val_entry); + } + } else { + info->flags |= GST_AUDIO_FLAG_UNPOSITIONED; + } + + return TRUE; + + /* ERROR */ +wrong_name: + { + GST_ERROR ("wrong name, expected audio/x-raw"); + return FALSE; + } +no_format: + { + GST_ERROR ("no format given"); + return FALSE; + } +unknown_format: + { + GST_ERROR ("unknown format given"); + return FALSE; + } +no_rate: + { + GST_ERROR ("no rate property given"); + return FALSE; + } +no_channels: + { + GST_ERROR ("no channels property given"); + return FALSE; + } +} + +/** + * gst_audio_info_to_caps: + * @info: a #GstAudioInfo + * + * Convert the values of @info into a #GstCaps. + * + * Returns: a new #GstCaps containing the info of @info. + */ +GstCaps * +gst_audio_info_to_caps (GstAudioInfo * info) +{ + GstCaps *caps; + const gchar *format; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (info->finfo != NULL, NULL); + g_return_val_if_fail (info->finfo->format != GST_AUDIO_FORMAT_UNKNOWN, NULL); + + format = gst_audio_format_to_string (info->finfo->format); + g_return_val_if_fail (format != NULL, NULL); + + caps = gst_caps_new_simple ("audio/x-raw", + "format", G_TYPE_STRING, format, + "rate", G_TYPE_INT, info->rate, + "channels", G_TYPE_INT, info->channels, NULL); + + if (info->channels > 2) { + GValue pos_val_arr = { 0 } + , pos_val_entry = { + 0}; + gint i, max_pos; + GstStructure *str; + + /* build gvaluearray from positions */ + g_value_init (&pos_val_arr, GST_TYPE_ARRAY); + g_value_init (&pos_val_entry, GST_TYPE_AUDIO_CHANNEL_POSITION); + max_pos = MAX (info->channels, 64); + for (i = 0; i < max_pos; i++) { + g_value_set_enum (&pos_val_entry, info->position[i]); + gst_value_array_append_value (&pos_val_arr, &pos_val_entry); + } + g_value_unset (&pos_val_entry); + + /* add to structure */ + str = gst_caps_get_structure (caps, 0); + gst_structure_set_value (str, "channel-positions", &pos_val_arr); + g_value_unset (&pos_val_arr); + } + + return caps; +} + + /** * gst_audio_frame_byte_size: * @pad: the #GstPad to get the caps from diff --git a/gst-libs/gst/audio/audio.h b/gst-libs/gst/audio/audio.h index 65b3cce868..24a3ca14b6 100644 --- a/gst-libs/gst/audio/audio.h +++ b/gst-libs/gst/audio/audio.h @@ -1,6 +1,7 @@ /* GStreamer * Copyright (C) <1999> Erik Walthinsen * Library <2001> Thomas Vander Stichele + * <2011> Wim Taymans * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,38 +24,322 @@ #ifndef __GST_AUDIO_AUDIO_H__ #define __GST_AUDIO_AUDIO_H__ +#include + G_BEGIN_DECLS -/* For people that are looking at this source: the purpose of these defines is - * to make GstCaps a bit easier, in that you don't have to know all of the - * properties that need to be defined. you can just use these macros. currently - * (8/01) the only plugins that use these are the passthrough, speed, volume, - * adder, and [de]interleave plugins. These are for convenience only, and do not - * specify the 'limits' of GStreamer. you might also use these definitions as a - * base for making your own caps, if need be. +/** + * GstAudioFormat: + * @GST_AUDIO_FORMAT_UNKNOWN: unknown audio format + * @GST_AUDIO_FORMAT_S8: sample + * @GST_AUDIO_FORMAT_U8: sample + * @GST_AUDIO_FORMAT_S16_LE: sample + * @GST_AUDIO_FORMAT_S16_BE: sample + * @GST_AUDIO_FORMAT_U16_LE: sample + * @GST_AUDIO_FORMAT_U16_BE: sample + * @GST_AUDIO_FORMAT_S24_LE: sample + * @GST_AUDIO_FORMAT_S24_BE: sample + * @GST_AUDIO_FORMAT_U24_LE: sample + * @GST_AUDIO_FORMAT_U24_BE: sample + * @GST_AUDIO_FORMAT_S32_LE: sample + * @GST_AUDIO_FORMAT_S32_BE: sample + * @GST_AUDIO_FORMAT_U32_LE: sample + * @GST_AUDIO_FORMAT_U32_BE: sample + * @GST_AUDIO_FORMAT_S24_3LE: sample + * @GST_AUDIO_FORMAT_S24_3BE: sample + * @GST_AUDIO_FORMAT_U24_3LE: sample + * @GST_AUDIO_FORMAT_U24_3BE: sample + * @GST_AUDIO_FORMAT_S20_3LE: sample + * @GST_AUDIO_FORMAT_S20_3BE: sample + * @GST_AUDIO_FORMAT_U20_3LE: sample + * @GST_AUDIO_FORMAT_U20_3BE: sample + * @GST_AUDIO_FORMAT_S18_3LE: sample + * @GST_AUDIO_FORMAT_S18_3BE: sample + * @GST_AUDIO_FORMAT_U18_3LE: sample + * @GST_AUDIO_FORMAT_U18_3BE: sample + * @GST_AUDIO_FORMAT_F32_LE: sample + * @GST_AUDIO_FORMAT_F32_BE: sample + * @GST_AUDIO_FORMAT_F64_LE: sample + * @GST_AUDIO_FORMAT_F64_BE: sample * - * For example, to make a source pad that can output streams of either mono - * float or any channel int: + * Enum value describing the most common audio formats. + */ +typedef enum { + GST_AUDIO_FORMAT_UNKNOWN, + /* 8 bit */ + GST_AUDIO_FORMAT_S8, + GST_AUDIO_FORMAT_U8, + /* 16 bit */ + GST_AUDIO_FORMAT_S16_LE, + GST_AUDIO_FORMAT_S16_BE, + GST_AUDIO_FORMAT_U16_LE, + GST_AUDIO_FORMAT_U16_BE, + /* 24 bit in low 3 bytes of 32 bits*/ + GST_AUDIO_FORMAT_S24_LE, + GST_AUDIO_FORMAT_S24_BE, + GST_AUDIO_FORMAT_U24_LE, + GST_AUDIO_FORMAT_U24_BE, + /* 32 bit */ + GST_AUDIO_FORMAT_S32_LE, + GST_AUDIO_FORMAT_S32_BE, + GST_AUDIO_FORMAT_U32_LE, + GST_AUDIO_FORMAT_U32_BE, + /* 24 bit in 3 bytes*/ + GST_AUDIO_FORMAT_S24_3LE, + GST_AUDIO_FORMAT_S24_3BE, + GST_AUDIO_FORMAT_U24_3LE, + GST_AUDIO_FORMAT_U24_3BE, + /* 20 bit in 3 bytes*/ + GST_AUDIO_FORMAT_S20_3LE, + GST_AUDIO_FORMAT_S20_3BE, + GST_AUDIO_FORMAT_U20_3LE, + GST_AUDIO_FORMAT_U20_3BE, + /* 18 bit in 3 bytes*/ + GST_AUDIO_FORMAT_S18_3LE, + GST_AUDIO_FORMAT_S18_3BE, + GST_AUDIO_FORMAT_U18_3LE, + GST_AUDIO_FORMAT_U18_3BE, + /* float */ + GST_AUDIO_FORMAT_F32_LE, + GST_AUDIO_FORMAT_F32_BE, + GST_AUDIO_FORMAT_F64_LE, + GST_AUDIO_FORMAT_F64_BE, +#if G_BYTE_ORDER == G_BIG_ENDIAN + GST_AUDIO_FORMAT_S16 = GST_AUDIO_FORMAT_S16_BE, + GST_AUDIO_FORMAT_U16 = GST_AUDIO_FORMAT_U16_BE, + GST_AUDIO_FORMAT_S24 = GST_AUDIO_FORMAT_S24_BE, + GST_AUDIO_FORMAT_U24 = GST_AUDIO_FORMAT_U24_BE, + GST_AUDIO_FORMAT_S32 = GST_AUDIO_FORMAT_S32_BE, + GST_AUDIO_FORMAT_U32 = GST_AUDIO_FORMAT_U32_BE, + GST_AUDIO_FORMAT_S24_3 = GST_AUDIO_FORMAT_S24_3BE, + GST_AUDIO_FORMAT_U24_3 = GST_AUDIO_FORMAT_U24_3BE, + GST_AUDIO_FORMAT_S20_3 = GST_AUDIO_FORMAT_S20_3BE, + GST_AUDIO_FORMAT_U20_3 = GST_AUDIO_FORMAT_U20_3BE, + GST_AUDIO_FORMAT_S18_3 = GST_AUDIO_FORMAT_S18_3BE, + GST_AUDIO_FORMAT_U18_3 = GST_AUDIO_FORMAT_U18_3BE, + GST_AUDIO_FORMAT_F32 = GST_AUDIO_FORMAT_F32_BE, + GST_AUDIO_FORMAT_F64 = GST_AUDIO_FORMAT_F64_BE +#elif G_BYTE_ORDER == G_LITTLE_ENDIAN + GST_AUDIO_FORMAT_S16 = GST_AUDIO_FORMAT_S16_LE, + GST_AUDIO_FORMAT_U16 = GST_AUDIO_FORMAT_U16_LE, + GST_AUDIO_FORMAT_S24 = GST_AUDIO_FORMAT_S24_LE, + GST_AUDIO_FORMAT_U24 = GST_AUDIO_FORMAT_U24_LE, + GST_AUDIO_FORMAT_S32 = GST_AUDIO_FORMAT_S32_LE, + GST_AUDIO_FORMAT_U32 = GST_AUDIO_FORMAT_U32_LE, + GST_AUDIO_FORMAT_S24_3 = GST_AUDIO_FORMAT_S24_3LE, + GST_AUDIO_FORMAT_U24_3 = GST_AUDIO_FORMAT_U24_3LE, + GST_AUDIO_FORMAT_S20_3 = GST_AUDIO_FORMAT_S20_3LE, + GST_AUDIO_FORMAT_U20_3 = GST_AUDIO_FORMAT_U20_3LE, + GST_AUDIO_FORMAT_S18_3 = GST_AUDIO_FORMAT_S18_3LE, + GST_AUDIO_FORMAT_U18_3 = GST_AUDIO_FORMAT_U18_3LE, + GST_AUDIO_FORMAT_F32 = GST_AUDIO_FORMAT_F32_LE, + GST_AUDIO_FORMAT_F64 = GST_AUDIO_FORMAT_F64_LE +#endif +} GstAudioFormat; + +typedef struct _GstAudioFormatInfo GstAudioFormatInfo; +typedef struct _GstAudioInfo GstAudioInfo; + +/** + * GstAudioFormatFlags: + * @GST_AUDIO_FORMAT_FLAG_INT: int samples + * @GST_AUDIO_FORMAT_FLAG_FLOAT: float samples + * @GST_AUDIO_FORMAT_FLAG_SIGNED: signed samples + * @GST_AUDIO_FORMAT_FLAG_COMPLEX: complex layout * - * template = gst_pad_template_new - * ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - * gst_caps_append(gst_caps_new ("sink_int", "audio/x-raw-int", - * GST_AUDIO_INT_PAD_TEMPLATE_PROPS), - * gst_caps_new ("sink_float", "audio/x-raw-float", - * GST_AUDIO_FLOAT_PAD_TEMPLATE_PROPS)), - * NULL); + * The different audio flags that a format info can have. + */ +typedef enum +{ + GST_AUDIO_FORMAT_FLAG_INT = (1 << 0), + GST_AUDIO_FORMAT_FLAG_FLOAT = (1 << 1), + GST_AUDIO_FORMAT_FLAG_SIGNED = (1 << 2), + GST_AUDIO_FORMAT_FLAG_COMPLEX = (1 << 4) +} GstAudioFormatFlags; + +/** + * GstAudioFormatUnpack: + * @info: a #GstAudioFormatInfo + * @dest: a destination array + * @data: pointer to the audio data + * @length: the amount of samples to unpack. * - * sinkpad = gst_pad_new_from_template(template, "sink"); + * Unpacks @length samples from the given data of format @info. + * The samples will be unpacked into @dest which each channel + * interleaved. @dest should at least be big enough to hold @length * + * channels * unpack_size bytes. + */ +typedef void (*GstAudioFormatUnpack) (GstAudioFormatInfo *info, gpointer dest, + const gpointer data, gint length); +/** + * GstAudioFormatPack: + * @info: a #GstAudioFormatInfo + * @src: a source array + * @data: pointer to the destination data + * @length: the amount of samples to pack. * - * Andy Wingo, 18 August 2001 - * Thomas, 6 September 2002 */ + * Packs @length samples from @src to the data array in format @info. + * The samples from source have each channel interleaved + * and will be packed into @data. + */ +typedef void (*GstAudioFormatPack) (GstAudioFormatInfo *info, const gpointer src, + gpointer data, gint length); + +/** + * GstAudioFormatInfo: + * @format: #GstAudioFormat + * @name: string representation of the format + * @flags: #GstAudioFormatFlags + * @endianness: the endianness + * @width: amount of bits used for one sample + * @depth: amount of valid bits in @width + * @silence: @width/8 bytes with 1 silent sample + * @unpack_size: number of bytes for the unpack functions + * @unpack_func: function to unpack samples + * @pack_func: function to pack samples + * + * Information for an audio format. + */ +struct _GstAudioFormatInfo { + GstAudioFormat format; + const gchar *name; + GstAudioFormatFlags flags; + gint endianness; + gint width; + gint depth; + guint8 silence[8]; + guint unpack_size; + GstAudioFormatUnpack unpack_func; + GstAudioFormatPack pack_func; +}; + +#define GST_AUDIO_FORMAT_INFO_FORMAT(info) ((info)->format) +#define GST_AUDIO_FORMAT_INFO_NAME(info) ((info)->name) +#define GST_AUDIO_FORMAT_INFO_FLAGS(info) ((info)->flags) + +#define GST_AUDIO_FORMAT_INFO_IS_INT(info) ((info)->flags & GST_AUDIO_FORMAT_FLAG_INT) +#define GST_AUDIO_FORMAT_INFO_IS_FLOAT(info) ((info)->flags & GST_AUDIO_FORMAT_FLAG_FLOAT) +#define GST_AUDIO_FORMAT_INFO_IS_SIGNED(info) ((info)->flags & GST_AUDIO_FORMAT_FLAG_SIGNED) + +#define GST_AUDIO_FORMAT_INFO_ENDIANNESS(info) ((info)->endianness) +#define GST_AUDIO_FORMAT_INFO_IS_LE(info) ((info)->endianness == G_LITTLE_ENDIAN) +#define GST_AUDIO_FORMAT_INFO_IS_BE(info) ((info)->endianness == G_BIG_ENDIAN) +#define GST_AUDIO_FORMAT_INFO_WIDTH(info) ((info)->width) +#define GST_AUDIO_FORMAT_INFO_DEPTH(info) ((info)->depth) + +GstAudioFormat gst_audio_format_from_string (const gchar *format) G_GNUC_CONST; +const gchar * gst_audio_format_to_string (GstAudioFormat format) G_GNUC_CONST; +const GstAudioFormatInfo * + gst_audio_format_get_info (GstAudioFormat format) G_GNUC_CONST; + +void gst_audio_format_fill_silence (const GstAudioFormatInfo *info, + gpointer dest, gsize length); +/** + * GstAudioFlags: + * @GST_AUDIO_FLAG_NONE: no valid flag + * @GST_AUDIO_FLAG_UNPOSITIONED: unpositioned audio layout, position array + * contains the default layout. + * + * Extra audio flags + */ +typedef enum { + GST_AUDIO_FLAG_NONE = 0, + GST_AUDIO_FLAG_UNPOSITIONED = (1 << 0) +} GstAudioFlags; + +/** + * GstAudioInfo: + * @finfo: the format info of the audio + * @flags: additional audio flags + * @rate: the audio sample rate + * @channels: the number of channels + * @bpf: the number of bytes for one frame, this is the size of one + * sample * @channels + * @positions: the positions for each channel + * + * Information describing audio properties. This information can be filled + * in from GstCaps with gst_audio_info_from_caps(). + * + * Use the provided macros to access the info in this structure. + */ +struct _GstAudioInfo { + const GstAudioFormatInfo *finfo; + GstAudioFlags flags; + gint rate; + gint channels; + gint bpf; + GstAudioChannelPosition position[64]; +}; + +#define GST_AUDIO_INFO_FORMAT(i) (GST_AUDIO_FORMAT_INFO_FORMAT((i)->finfo)) +#define GST_AUDIO_INFO_NAME(i) (GST_AUDIO_FORMAT_INFO_NAME((i)->finfo)) + +#define GST_AUDIO_INFO_FLAGS(info) ((info)->flags) +#define GST_AUDIO_INFO_IS_UNPOSITIONED(info) ((info)->flags & GST_AUDIO_FLAG_UNPOSITIONED) + +#define GST_AUDIO_INFO_RATE(info) ((info)->rate) +#define GST_AUDIO_INFO_CHANNELS(info) ((info)->channels) +#define GST_AUDIO_INFO_BPF(info) ((info)->bpf) +#define GST_AUDIO_INFO_POSITION(info,c) ((info)->position[c]) + +void gst_audio_info_init (GstAudioInfo *info); +void gst_audio_info_set_format (GstAudioInfo *info, GstAudioFormat format, + gint rate, gint channels); + +gboolean gst_audio_info_from_caps (GstAudioInfo *info, const GstCaps *caps); +GstCaps * gst_audio_info_to_caps (GstAudioInfo *info); + + +#define GST_AUDIO_RATE_RANGE "(int) [ 1, max ]" +#define GST_AUDIO_CHANNELS_RANGE "(int) [ 1, max ]" + +#define GST_AUDIO_FORMATS_ALL " { S8, U8, " \ + "S16_LE, S16_BE, U16_LE, U16_BE, " \ + "S24_LE, S24_BE, U24_LE, U24_BE, " \ + "S32_LE, S32_BE, U32_LE, U32_BE, " \ + "S24_3LE, S24_3BE, U24_3LE, U24_3BE, " \ + "S20_3LE, S20_3BE, U20_3LE, U20_3BE, " \ + "S18_3LE, S18_3BE, U18_3LE, U18_3BE, " \ + "F32_LE, F32_BE, F64_LE, F64_BE }" + +/** + * GST_AUDIO_CAPS_MAKE: + * @format: string format that describes the pixel layout, as string + * (e.g. "S16_LE", "S8", etc.) + * + * Generic caps string for audio, for use in pad templates. + */ +#define GST_AUDIO_CAPS_MAKE(format) \ + "audio/x-raw, " \ + "format = (string) " format ", " \ + "rate = " GST_AUDIO_RATE_RANGE ", " \ + "channels = " GST_AUDIO_CHANNELS_RANGE + +/** + * GST_AUDIO_DEF_RATE: + * + * Standard sampling rate used in consumer audio. + */ +#define GST_AUDIO_DEF_RATE 44100 +/** + * GST_AUDIO_DEF_CHANNELS: + * + * Standard number of channels used in consumer audio. + */ +#define GST_AUDIO_DEF_CHANNELS 2 +/** + * GST_AUDIO_DEF_FORMAT: + * + * Standard format used in consumer audio. + */ +#define GST_AUDIO_DEF_FORMAT "S16_LE" /* conversion macros */ /** * GST_FRAMES_TO_CLOCK_TIME: * @frames: sample frames * @rate: sampling rate - * + * * Calculate clocktime from sample @frames and @rate. */ #define GST_FRAMES_TO_CLOCK_TIME(frames, rate) \ @@ -64,75 +349,12 @@ G_BEGIN_DECLS * GST_CLOCK_TIME_TO_FRAMES: * @clocktime: clock time * @rate: sampling rate - * + * * Calculate frames from @clocktime and sample @rate. */ #define GST_CLOCK_TIME_TO_FRAMES(clocktime, rate) \ gst_util_uint64_scale_round (clocktime, rate, GST_SECOND) -/** - * GST_AUDIO_DEF_RATE: - * - * Standard sampling rate used in consumer audio. - */ -#define GST_AUDIO_DEF_RATE 44100 - -/** - * GST_AUDIO_INT_PAD_TEMPLATE_CAPS: - * - * Template caps for integer audio. Can be used when defining a - * #GstStaticPadTemplate - */ -#define GST_AUDIO_INT_PAD_TEMPLATE_CAPS \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ - "width = (int) { 8, 16, 24, 32 }, " \ - "depth = (int) [ 1, 32 ], " \ - "signed = (boolean) { true, false }" - -/** - * GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS: - * - * Template caps for 16bit integer stereo audio in native byte-order. - * Can be used when defining a #GstStaticPadTemplate - */ -#define GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) 2, " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 16, " \ - "depth = (int) 16, " \ - "signed = (boolean) true" - -/** - * GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS: - * - * Template caps for float audio. Can be used when defining a - * #GstStaticPadTemplate - */ -#define GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS \ - "audio/x-raw-float, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, " \ - "width = (int) { 32, 64 }" - -/** - * GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS: - * - * Template caps for 32bit float mono audio in native byte-order. - * Can be used when defining a #GstStaticPadTemplate - */ -#define GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS \ - "audio/x-raw-float, " \ - "width = (int) 32, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) 1, " \ - "endianness = (int) BYTE_ORDER" - /* * this library defines and implements some helper functions for audio * handling diff --git a/gst-libs/gst/audio/gstaudiofilter.c b/gst-libs/gst/audio/gstaudiofilter.c index fe6ad8a8f0..52d7eeecbf 100644 --- a/gst-libs/gst/audio/gstaudiofilter.c +++ b/gst-libs/gst/audio/gstaudiofilter.c @@ -78,12 +78,6 @@ gst_audio_filter_class_init (GstAudioFilterClass * klass) basetrans_class->set_caps = GST_DEBUG_FUNCPTR (gst_audio_filter_set_caps); basetrans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_audio_filter_get_unit_size); - - /* FIXME: Ref the GstRingerBuffer class to get it's debug category - * initialized. gst_ring_buffer_parse_caps () which we use later - * uses this debug category. - */ - g_type_class_ref (GST_TYPE_RING_BUFFER); } static void @@ -103,9 +97,7 @@ gst_audio_filter_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: - memset (&filter->format, 0, sizeof (GstRingBufferSpec)); - /* to make gst_buffer_spec_parse_caps() happy */ - filter->format.latency_time = GST_SECOND; + gst_audio_info_init (&filter->info); break; default: break; @@ -120,7 +112,7 @@ gst_audio_filter_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_READY_TO_NULL: - gst_caps_replace (&filter->format.caps, NULL); + gst_audio_info_init (&filter->info); break; default: break; @@ -139,17 +131,22 @@ gst_audio_filter_set_caps (GstBaseTransform * btrans, GstCaps * incaps, GST_LOG_OBJECT (filter, "caps: %" GST_PTR_FORMAT, incaps); - if (!gst_ring_buffer_parse_caps (&filter->format, incaps)) { - GST_WARNING_OBJECT (filter, "couldn't parse %" GST_PTR_FORMAT, incaps); - return FALSE; - } + if (!gst_audio_info_from_caps (&filter->info, incaps)) + goto invalid_format; klass = GST_AUDIO_FILTER_CLASS_CAST (G_OBJECT_GET_CLASS (filter)); if (klass->setup) - ret = klass->setup (filter, &filter->format); + ret = klass->setup (filter, &filter->info); return ret; + + /* ERROR */ +invalid_format: + { + GST_WARNING_OBJECT (filter, "couldn't parse %" GST_PTR_FORMAT, incaps); + return FALSE; + } } static gboolean diff --git a/gst-libs/gst/audio/gstaudiofilter.h b/gst-libs/gst/audio/gstaudiofilter.h index ed50317b35..5f4b6568c1 100644 --- a/gst-libs/gst/audio/gstaudiofilter.h +++ b/gst-libs/gst/audio/gstaudiofilter.h @@ -23,7 +23,7 @@ #include #include -#include +#include G_BEGIN_DECLS @@ -56,7 +56,7 @@ struct _GstAudioFilter { GstBaseTransform basetransform; /*< protected >*/ - GstRingBufferSpec format; /* currently configured format */ + GstAudioInfo info; /* currently configured format */ /*< private >*/ gpointer _gst_reserved[GST_PADDING]; @@ -78,7 +78,7 @@ struct _GstAudioFilterClass { GstBaseTransformClass basetransformclass; /* virtual function, called whenever the format changes */ - gboolean (*setup) (GstAudioFilter * filter, GstRingBufferSpec * format); + gboolean (*setup) (GstAudioFilter * filter, GstAudioInfo * info); /*< private >*/ gpointer _gst_reserved[GST_PADDING]; diff --git a/gst-libs/gst/audio/gstaudioiec61937.c b/gst-libs/gst/audio/gstaudioiec61937.c index 9ad787b3d9..5742d282b7 100644 --- a/gst-libs/gst/audio/gstaudioiec61937.c +++ b/gst-libs/gst/audio/gstaudioiec61937.c @@ -114,9 +114,9 @@ gst_audio_iec61937_frame_size (const GstRingBufferSpec * spec) if (version == 1 && layer == 1) frames = 384; - else if (version == 2 && layer == 1 && spec->rate < 32000) + else if (version == 2 && layer == 1 && spec->info.rate < 32000) frames = 768; - else if (version == 2 && layer == 1 && spec->rate < 32000) + else if (version == 2 && layer == 1 && spec->info.rate < 32000) frames = 2304; else frames = 1152; @@ -271,13 +271,13 @@ gst_audio_iec61937_payload (const guint8 * src, guint src_n, guint8 * dst, if (version == 1 && layer == 1) dst[five] = 0x04; else if ((version == 1 && (layer == 2 || layer == 3)) || - (version == 2 && spec->rate >= 32000)) + (version == 2 && spec->info.rate >= 32000)) dst[five] = 0x05; - else if (version == 2 && layer == 1 && spec->rate < 32000) + else if (version == 2 && layer == 1 && spec->info.rate < 32000) dst[five] = 0x08; - else if (version == 2 && layer == 2 && spec->rate < 32000) + else if (version == 2 && layer == 2 && spec->info.rate < 32000) dst[five] = 0x09; - else if (version == 2 && layer == 3 && spec->rate < 32000) + else if (version == 2 && layer == 3 && spec->info.rate < 32000) dst[five] = 0x0A; else g_return_val_if_reached (FALSE); diff --git a/gst-libs/gst/audio/gstbaseaudiosink.c b/gst-libs/gst/audio/gstbaseaudiosink.c index 262a97bfd1..45b66a602b 100644 --- a/gst-libs/gst/audio/gstbaseaudiosink.c +++ b/gst-libs/gst/audio/gstbaseaudiosink.c @@ -395,7 +395,7 @@ gst_base_audio_sink_query (GstElement * element, GstQuery * query) GstRingBufferSpec *spec; GST_OBJECT_LOCK (basesink); - if (!basesink->ringbuffer || !basesink->ringbuffer->spec.rate) { + if (!basesink->ringbuffer || !basesink->ringbuffer->spec.info.rate) { GST_OBJECT_UNLOCK (basesink); GST_DEBUG_OBJECT (basesink, @@ -409,7 +409,7 @@ gst_base_audio_sink_query (GstElement * element, GstQuery * query) base_latency = gst_util_uint64_scale_int (spec->seglatency * spec->segsize, - GST_SECOND, spec->rate * spec->bytes_per_sample); + GST_SECOND, spec->info.rate * spec->info.bpf); GST_OBJECT_UNLOCK (basesink); /* we cannot go lower than the buffer size and the min peer latency */ @@ -470,7 +470,7 @@ gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink) guint delay; GstClockTime result; - if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0) + if (sink->ringbuffer == NULL || sink->ringbuffer->spec.info.rate == 0) return GST_CLOCK_TIME_NONE; /* our processed samples are always increasing */ @@ -486,7 +486,7 @@ gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink) samples = 0; result = gst_util_uint64_scale_int (samples, GST_SECOND, - sink->ringbuffer->spec.rate); + sink->ringbuffer->spec.info.rate); GST_DEBUG_OBJECT (sink, "processed samples: raw %" G_GUINT64_FORMAT ", delay %u, real %" @@ -756,7 +756,7 @@ gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) /* calculate actual latency and buffer times. * FIXME: In 0.11, store the latency_time internally in ns */ spec->latency_time = gst_util_uint64_scale (spec->segsize, - (GST_SECOND / GST_USECOND), spec->rate * spec->bytes_per_sample); + (GST_SECOND / GST_USECOND), spec->info.rate * spec->info.bpf); spec->buffer_time = spec->segtotal * spec->latency_time; @@ -821,7 +821,7 @@ gst_base_audio_sink_drain (GstBaseAudioSink * sink) { if (!sink->ringbuffer) return TRUE; - if (!sink->ringbuffer->spec.rate) + if (!sink->ringbuffer->spec.info.rate) return TRUE; /* if PLAYING is interrupted, @@ -1066,7 +1066,7 @@ gst_base_audio_sink_skew_slaving (GstBaseAudioSink * sink, cexternal = cexternal > mdrift ? cexternal - mdrift : 0; sink->priv->avg_skew -= mdrift; - driftsamples = (sink->ringbuffer->spec.rate * mdrift) / GST_SECOND; + driftsamples = (sink->ringbuffer->spec.info.rate * mdrift) / GST_SECOND; last_align = sink->priv->last_align; /* if we were aligning in the wrong direction or we aligned more than what we @@ -1088,7 +1088,7 @@ gst_base_audio_sink_skew_slaving (GstBaseAudioSink * sink, cexternal += mdrift; sink->priv->avg_skew += mdrift; - driftsamples = (sink->ringbuffer->spec.rate * mdrift) / GST_SECOND; + driftsamples = (sink->ringbuffer->spec.info.rate * mdrift) / GST_SECOND; last_align = sink->priv->last_align; /* if we were aligning in the wrong direction or we aligned more than what we @@ -1308,6 +1308,7 @@ gst_base_audio_sink_get_alignment (GstBaseAudioSink * sink, gint64 samples_done = segdone * ringbuf->samples_per_seg; gint64 headroom = sample_offset - samples_done; gboolean allow_align = TRUE; + gint rate; /* now try to align the sample to the previous one, first see how big the * difference is. */ @@ -1316,9 +1317,11 @@ gst_base_audio_sink_get_alignment (GstBaseAudioSink * sink, else diff = sink->next_sample - sample_offset; + rate = GST_AUDIO_INFO_RATE (&ringbuf->spec.info); + /* calculate the max allowed drift in units of samples. By default this is * 20ms and should be anough to compensate for timestamp rounding errors. */ - maxdrift = (ringbuf->spec.rate * sink->priv->drift_tolerance) / GST_MSECOND; + maxdrift = (rate * sink->priv->drift_tolerance) / GST_MSECOND; /* calc align with previous sample */ align = sink->next_sample - sample_offset; @@ -1333,8 +1336,7 @@ gst_base_audio_sink_get_alignment (GstBaseAudioSink * sink, G_GINT64_FORMAT, align, maxdrift); } else { /* calculate sample diff in seconds for error message */ - gint64 diff_s = - gst_util_uint64_scale_int (diff, GST_SECOND, ringbuf->spec.rate); + gint64 diff_s = gst_util_uint64_scale_int (diff, GST_SECOND, rate); /* timestamps drifted apart from previous samples too much, we need to * resync. We log this as an element warning. */ GST_WARNING_OBJECT (sink, @@ -1362,7 +1364,7 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf) guint8 *data; gsize size; guint samples, written; - gint bps; + gint bpf, rate; gint accum; gint out_samples; GstClockTime base_time, render_delay, latency; @@ -1409,13 +1411,14 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf) buf = out; } - bps = ringbuf->spec.bytes_per_sample; + bpf = GST_AUDIO_INFO_BPF (&ringbuf->spec.info); + rate = GST_AUDIO_INFO_RATE (&ringbuf->spec.info); size = gst_buffer_get_size (buf); - if (G_UNLIKELY (size % bps) != 0) + if (G_UNLIKELY (size % bpf) != 0) goto wrong_size; - samples = size / bps; + samples = size / bpf; out_samples = samples; in_offset = GST_BUFFER_OFFSET (buf); @@ -1442,8 +1445,7 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf) /* let's calc stop based on the number of samples in the buffer instead * of trusting the DURATION */ - stop = time + gst_util_uint64_scale_int (samples, GST_SECOND, - ringbuf->spec.rate); + stop = time + gst_util_uint64_scale_int (samples, GST_SECOND, rate); /* prepare the clipping segment. Since we will be subtracting ts-offset and * device-delay later we scale the start and stop with those values so that we @@ -1484,17 +1486,17 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf) diff = ctime - time; if (diff > 0) { /* bring clipped time to samples */ - diff = gst_util_uint64_scale_int (diff, ringbuf->spec.rate, GST_SECOND); + diff = gst_util_uint64_scale_int (diff, rate, GST_SECOND); GST_DEBUG_OBJECT (sink, "clipping start to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT " samples", GST_TIME_ARGS (ctime), diff); samples -= diff; - offset += diff * bps; + offset += diff * bpf; time = ctime; } diff = stop - cstop; if (diff > 0) { /* bring clipped time to samples */ - diff = gst_util_uint64_scale_int (diff, ringbuf->spec.rate, GST_SECOND); + diff = gst_util_uint64_scale_int (diff, rate, GST_SECOND); GST_DEBUG_OBJECT (sink, "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT " samples", GST_TIME_ARGS (cstop), diff); samples -= diff; @@ -1588,10 +1590,8 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf) goto too_late; /* and bring the time to the rate corrected offset in the buffer */ - render_start = gst_util_uint64_scale_int (render_start, - ringbuf->spec.rate, GST_SECOND); - render_stop = gst_util_uint64_scale_int (render_stop, - ringbuf->spec.rate, GST_SECOND); + render_start = gst_util_uint64_scale_int (render_start, rate, GST_SECOND); + render_stop = gst_util_uint64_scale_int (render_stop, rate, GST_SECOND); /* positive playback rate, first sample is render_start, negative rate, first * sample is render_stop. When no rate conversion is active, render exactly @@ -1677,7 +1677,7 @@ no_sync: break; samples -= written; - offset += written * bps; + offset += written * bpf; } while (TRUE); gst_buffer_unmap (buf, data, size); diff --git a/gst-libs/gst/audio/gstbaseaudiosrc.c b/gst-libs/gst/audio/gstbaseaudiosrc.c index 7a1df7b2f9..23c89878e5 100644 --- a/gst-libs/gst/audio/gstbaseaudiosrc.c +++ b/gst-libs/gst/audio/gstbaseaudiosrc.c @@ -323,7 +323,8 @@ gst_base_audio_src_get_time (GstClock * clock, GstBaseAudioSrc * src) guint delay; GstClockTime result; - if (G_UNLIKELY (src->ringbuffer == NULL || src->ringbuffer->spec.rate == 0)) + if (G_UNLIKELY (src->ringbuffer == NULL + || src->ringbuffer->spec.info.rate == 0)) return GST_CLOCK_TIME_NONE; raw = samples = gst_ring_buffer_samples_done (src->ringbuffer); @@ -335,7 +336,7 @@ gst_base_audio_src_get_time (GstClock * clock, GstBaseAudioSrc * src) samples += delay; result = gst_util_uint64_scale_int (samples, GST_SECOND, - src->ringbuffer->spec.rate); + src->ringbuffer->spec.info.rate); GST_DEBUG_OBJECT (src, "processed samples: raw %" G_GUINT64_FORMAT ", delay %u, real %" @@ -509,26 +510,14 @@ static void gst_base_audio_src_fixate (GstBaseSrc * bsrc, GstCaps * caps) { GstStructure *s; - gint width, depth; s = gst_caps_get_structure (caps, 0); /* fields for all formats */ - gst_structure_fixate_field_nearest_int (s, "rate", 44100); - gst_structure_fixate_field_nearest_int (s, "channels", 2); - gst_structure_fixate_field_nearest_int (s, "width", 16); - - /* fields for int */ - if (gst_structure_has_field (s, "depth")) { - gst_structure_get_int (s, "width", &width); - /* round width to nearest multiple of 8 for the depth */ - depth = GST_ROUND_UP_8 (width); - gst_structure_fixate_field_nearest_int (s, "depth", depth); - } - if (gst_structure_has_field (s, "signed")) - gst_structure_fixate_field_boolean (s, "signed", TRUE); - if (gst_structure_has_field (s, "endianness")) - gst_structure_fixate_field_nearest_int (s, "endianness", G_BYTE_ORDER); + gst_structure_fixate_field_nearest_int (s, "rate", GST_AUDIO_DEF_RATE); + gst_structure_fixate_field_nearest_int (s, "channels", + GST_AUDIO_DEF_CHANNELS); + gst_structure_fixate_field_string (s, "format", GST_AUDIO_DEF_FORMAT); GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps); } @@ -538,6 +527,7 @@ gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps) { GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc); GstRingBufferSpec *spec; + gint bpf, rate; spec = &src->ringbuffer->spec; @@ -550,9 +540,11 @@ gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps) goto parse_error; } + bpf = GST_AUDIO_INFO_BPF (&spec->info); + rate = GST_AUDIO_INFO_RATE (&spec->info); + /* calculate suggested segsize and segtotal */ - spec->segsize = - spec->rate * spec->bytes_per_sample * spec->latency_time / GST_MSECOND; + spec->segsize = rate * bpf * spec->latency_time / GST_MSECOND; spec->segtotal = spec->buffer_time / spec->latency_time; GST_OBJECT_UNLOCK (src); @@ -569,11 +561,9 @@ gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps) goto acquire_error; /* calculate actual latency and buffer times */ - spec->latency_time = - spec->segsize * GST_MSECOND / (spec->rate * spec->bytes_per_sample); + spec->latency_time = spec->segsize * GST_MSECOND / (rate * bpf); spec->buffer_time = - spec->segtotal * spec->segsize * GST_MSECOND / (spec->rate * - spec->bytes_per_sample); + spec->segtotal * spec->segsize * GST_MSECOND / (rate * bpf); gst_ring_buffer_debug_spec_buff (spec); @@ -616,24 +606,26 @@ gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query) { GstClockTime min_latency, max_latency; GstRingBufferSpec *spec; + gint bpf, rate; GST_OBJECT_LOCK (src); if (G_UNLIKELY (src->ringbuffer == NULL - || src->ringbuffer->spec.rate == 0)) { + || src->ringbuffer->spec.info.rate == 0)) { GST_OBJECT_UNLOCK (src); goto done; } spec = &src->ringbuffer->spec; + rate = GST_AUDIO_INFO_RATE (&spec->info); + bpf = GST_AUDIO_INFO_BPF (&spec->info); /* we have at least 1 segment of latency */ min_latency = - gst_util_uint64_scale_int (spec->segsize, GST_SECOND, - spec->rate * spec->bytes_per_sample); + gst_util_uint64_scale_int (spec->segsize, GST_SECOND, rate * bpf); /* we cannot delay more than the buffersize else we lose data */ max_latency = gst_util_uint64_scale_int (spec->segtotal * spec->segsize, GST_SECOND, - spec->rate * spec->bytes_per_sample); + rate * bpf); GST_OBJECT_UNLOCK (src); GST_DEBUG_OBJECT (src, @@ -757,7 +749,7 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length, guchar *data, *ptr; guint samples, total_samples; guint64 sample; - gint bps; + gint bpf, rate; GstRingBuffer *ringbuffer; GstRingBufferSpec *spec; guint read; @@ -770,18 +762,19 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length, if (G_UNLIKELY (!gst_ring_buffer_is_acquired (ringbuffer))) goto wrong_state; - bps = spec->bytes_per_sample; + bpf = GST_AUDIO_INFO_BPF (&spec->info); + rate = GST_AUDIO_INFO_RATE (&spec->info); if ((length == 0 && bsrc->blocksize == 0) || length == -1) /* no length given, use the default segment size */ length = spec->segsize; else /* make sure we round down to an integral number of samples */ - length -= length % bps; + length -= length % bpf; /* figure out the offset in the ringbuffer */ if (G_UNLIKELY (offset != -1)) { - sample = offset / bps; + sample = offset / bpf; /* if a specific offset was given it must be the next sequential * offset we expect or we fail for now. */ if (src->next_sample != -1 && sample != src->next_sample) @@ -796,7 +789,7 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length, sample, length); /* get the number of samples to read */ - total_samples = samples = length / bps; + total_samples = samples = length / bpf; /* use the basesrc allocation code to use bufferpools or custom allocators */ ret = GST_BASE_SRC_CLASS (parent_class)->alloc (bsrc, offset, length, &buf); @@ -821,7 +814,7 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length, /* read next samples */ sample += read; samples -= read; - ptr += read * bps; + ptr += read * bpf; } while (TRUE); gst_buffer_unmap (buf, data, length); @@ -841,9 +834,9 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length, src->next_sample = sample + samples; /* get the normal timestamp to get the duration. */ - timestamp = gst_util_uint64_scale_int (sample, GST_SECOND, spec->rate); + timestamp = gst_util_uint64_scale_int (sample, GST_SECOND, rate); duration = gst_util_uint64_scale_int (src->next_sample, GST_SECOND, - spec->rate) - timestamp; + rate) - timestamp; GST_OBJECT_LOCK (src); if (!(clock = GST_ELEMENT_CLOCK (src))) @@ -890,7 +883,7 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length, /* the running_time converted to a sample (relative to the ringbuffer) */ running_time_sample = - gst_util_uint64_scale_int (running_time, spec->rate, GST_SECOND); + gst_util_uint64_scale_int (running_time, rate, GST_SECOND); /* the segmentnr corrensponding to running_time, round down */ running_time_segment = running_time_sample / sps; @@ -944,8 +937,7 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length, new_sample = ((guint64) new_read_segment) * sps; /* and get the relative time to this -> our new timestamp */ - timestamp = - gst_util_uint64_scale_int (new_sample, GST_SECOND, spec->rate); + timestamp = gst_util_uint64_scale_int (new_sample, GST_SECOND, rate); /* we update the next sample accordingly */ src->next_sample = new_sample + samples; @@ -974,8 +966,7 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length, timestamp = 0; /* subtract latency */ - latency = - gst_util_uint64_scale_int (total_samples, GST_SECOND, spec->rate); + latency = gst_util_uint64_scale_int (total_samples, GST_SECOND, rate); if (timestamp > latency) timestamp -= latency; else diff --git a/gst-libs/gst/audio/gstringbuffer.c b/gst-libs/gst/audio/gstringbuffer.c index 7528a78212..cb18f764ef 100644 --- a/gst-libs/gst/audio/gstringbuffer.c +++ b/gst-libs/gst/audio/gstringbuffer.c @@ -111,95 +111,9 @@ gst_ring_buffer_finalize (GObject * object) (ringbuffer)); } -typedef struct -{ - const GstBufferFormat format; - const guint8 silence[4]; -} FormatDef; - -static const FormatDef linear_defs[4 * 2 * 2] = { - {GST_S8, {0x00, 0x00, 0x00, 0x00}}, - {GST_S8, {0x00, 0x00, 0x00, 0x00}}, - {GST_U8, {0x80, 0x80, 0x80, 0x80}}, - {GST_U8, {0x80, 0x80, 0x80, 0x80}}, - {GST_S16_LE, {0x00, 0x00, 0x00, 0x00}}, - {GST_S16_BE, {0x00, 0x00, 0x00, 0x00}}, - {GST_U16_LE, {0x00, 0x80, 0x00, 0x80}}, - {GST_U16_BE, {0x80, 0x00, 0x80, 0x00}}, - {GST_S24_LE, {0x00, 0x00, 0x00, 0x00}}, - {GST_S24_BE, {0x00, 0x00, 0x00, 0x00}}, - {GST_U24_LE, {0x00, 0x00, 0x80, 0x00}}, - {GST_U24_BE, {0x80, 0x00, 0x00, 0x00}}, - {GST_S32_LE, {0x00, 0x00, 0x00, 0x00}}, - {GST_S32_BE, {0x00, 0x00, 0x00, 0x00}}, - {GST_U32_LE, {0x00, 0x00, 0x00, 0x80}}, - {GST_U32_BE, {0x80, 0x00, 0x00, 0x00}} -}; - -static const FormatDef linear24_defs[3 * 2 * 2] = { - {GST_S24_3LE, {0x00, 0x00, 0x00, 0x00}}, - {GST_S24_3BE, {0x00, 0x00, 0x00, 0x00}}, - {GST_U24_3LE, {0x00, 0x00, 0x80, 0x00}}, - {GST_U24_3BE, {0x80, 0x00, 0x00, 0x00}}, - {GST_S20_3LE, {0x00, 0x00, 0x00, 0x00}}, - {GST_S20_3BE, {0x00, 0x00, 0x00, 0x00}}, - {GST_U20_3LE, {0x00, 0x00, 0x08, 0x00}}, - {GST_U20_3BE, {0x08, 0x00, 0x00, 0x00}}, - {GST_S18_3LE, {0x00, 0x00, 0x00, 0x00}}, - {GST_S18_3BE, {0x00, 0x00, 0x00, 0x00}}, - {GST_U18_3LE, {0x00, 0x00, 0x02, 0x00}}, - {GST_U18_3BE, {0x02, 0x00, 0x00, 0x00}} -}; - -static const FormatDef * -build_linear_format (int depth, int width, int unsignd, int big_endian) -{ - const FormatDef *formats; - - if (width == 24) { - switch (depth) { - case 24: - formats = &linear24_defs[0]; - break; - case 20: - formats = &linear24_defs[4]; - break; - case 18: - formats = &linear24_defs[8]; - break; - default: - return NULL; - } - } else { - switch (depth) { - case 8: - formats = &linear_defs[0]; - break; - case 16: - formats = &linear_defs[4]; - break; - case 24: - formats = &linear_defs[8]; - break; - case 32: - formats = &linear_defs[12]; - break; - default: - return NULL; - } - } - if (unsignd) - formats += 2; - if (big_endian) - formats += 1; - - return formats; -} - #ifndef GST_DISABLE_GST_DEBUG static const gchar *format_type_names[] = { - "linear", - "float", + "raw", "mu law", "a law", "ima adpcm", @@ -210,49 +124,6 @@ static const gchar *format_type_names[] = { "eac3", "dts" }; - -static const gchar *format_names[] = { - "unknown", - "s8", - "u8", - "s16_le", - "s16_be", - "u16_le", - "u16_be", - "s24_le", - "s24_be", - "u24_le", - "u24_be", - "s32_le", - "s32_be", - "u32_le", - "u32_be", - "s24_3le", - "s24_3be", - "u24_3le", - "u24_3be", - "s20_3le", - "s20_3be", - "u20_3le", - "u20_3be", - "s18_3le", - "s18_3be", - "u18_3le", - "u18_3be", - "float32_le", - "float32_be", - "float64_le", - "float64_be", - "mu_law", - "a_law", - "ima_adpcm", - "mpeg", - "gsm", - "iec958", - "ac3", - "eac3", - "dts" -}; #endif /** @@ -264,15 +135,15 @@ static const gchar *format_names[] = { void gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec) { +#if 0 gint i, bytes; +#endif GST_DEBUG ("spec caps: %p %" GST_PTR_FORMAT, spec->caps, spec->caps); GST_DEBUG ("parsed caps: type: %d, '%s'", spec->type, format_type_names[spec->type]); - GST_DEBUG ("parsed caps: format: %d, '%s'", spec->format, - format_names[spec->format]); +#if 0 GST_DEBUG ("parsed caps: width: %d", spec->width); - GST_DEBUG ("parsed caps: depth: %d", spec->depth); GST_DEBUG ("parsed caps: sign: %d", spec->sign); GST_DEBUG ("parsed caps: bigend: %d", spec->bigend); GST_DEBUG ("parsed caps: rate: %d", spec->rate); @@ -282,6 +153,7 @@ gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec) for (i = 0; i < bytes; i++) { GST_DEBUG ("silence byte %d: %02x", i, spec->silence_sample[i]); } +#endif } /** @@ -293,6 +165,8 @@ gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec) void gst_ring_buffer_debug_spec_buff (GstRingBufferSpec * spec) { + gint bpf = GST_AUDIO_INFO_BPF (&spec->info); + GST_DEBUG ("acquire ringbuffer: buffer time: %" G_GINT64_FORMAT " usec", spec->buffer_time); GST_DEBUG ("acquire ringbuffer: latency time: %" G_GINT64_FORMAT " usec", @@ -300,10 +174,9 @@ gst_ring_buffer_debug_spec_buff (GstRingBufferSpec * spec) GST_DEBUG ("acquire ringbuffer: total segments: %d", spec->segtotal); GST_DEBUG ("acquire ringbuffer: latency segments: %d", spec->seglatency); GST_DEBUG ("acquire ringbuffer: segment size: %d bytes = %d samples", - spec->segsize, spec->segsize / spec->bytes_per_sample); + spec->segsize, spec->segsize / bpf); GST_DEBUG ("acquire ringbuffer: buffer size: %d bytes = %d samples", - spec->segsize * spec->segtotal, - spec->segsize * spec->segtotal / spec->bytes_per_sample); + spec->segsize * spec->segtotal, spec->segsize * spec->segtotal / bpf); } /** @@ -321,160 +194,77 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps) const gchar *mimetype; GstStructure *structure; gint i; + GstAudioInfo info; structure = gst_caps_get_structure (caps, 0); + gst_audio_info_init (&info); /* we have to differentiate between int and float formats */ mimetype = gst_structure_get_name (structure); - if (g_str_equal (mimetype, "audio/x-raw-int")) { - gint endianness; - const FormatDef *def; - gint j, bytes; - - spec->type = GST_BUFTYPE_LINEAR; - - /* extract the needed information from the cap */ - if (!(gst_structure_get_int (structure, "rate", &spec->rate) && - gst_structure_get_int (structure, "channels", &spec->channels) && - gst_structure_get_int (structure, "width", &spec->width) && - gst_structure_get_int (structure, "depth", &spec->depth) && - gst_structure_get_boolean (structure, "signed", &spec->sign))) + if (g_str_equal (mimetype, "audio/x-raw")) { + if (!gst_audio_info_from_caps (&info, caps)) goto parse_error; - /* extract endianness if needed */ - if (spec->width > 8) { - if (!gst_structure_get_int (structure, "endianness", &endianness)) - goto parse_error; - } else { - endianness = G_BYTE_ORDER; - } - - spec->bigend = endianness == G_LITTLE_ENDIAN ? FALSE : TRUE; - - def = build_linear_format (spec->depth, spec->width, spec->sign ? 0 : 1, - spec->bigend ? 1 : 0); - - if (def == NULL) - goto parse_error; - - spec->format = def->format; - - bytes = spec->width >> 3; - - for (i = 0; i < spec->channels; i++) { - for (j = 0; j < bytes; j++) { - spec->silence_sample[i * bytes + j] = def->silence[j]; - } - } - } else if (g_str_equal (mimetype, "audio/x-raw-float")) { - - spec->type = GST_BUFTYPE_FLOAT; - - /* extract the needed information from the cap */ - if (!(gst_structure_get_int (structure, "rate", &spec->rate) && - gst_structure_get_int (structure, "channels", &spec->channels) && - gst_structure_get_int (structure, "width", &spec->width))) - goto parse_error; - - /* match layout to format wrt to endianness */ - switch (spec->width) { - case 32: - spec->format = - G_BYTE_ORDER == G_LITTLE_ENDIAN ? GST_FLOAT32_LE : GST_FLOAT32_BE; - break; - case 64: - spec->format = - G_BYTE_ORDER == G_LITTLE_ENDIAN ? GST_FLOAT64_LE : GST_FLOAT64_BE; - break; - default: - goto parse_error; - } - /* float silence is all zeros.. */ - memset (spec->silence_sample, 0, 32); + spec->type = GST_BUFTYPE_RAW; } else if (g_str_equal (mimetype, "audio/x-alaw")) { /* extract the needed information from the cap */ - if (!(gst_structure_get_int (structure, "rate", &spec->rate) && - gst_structure_get_int (structure, "channels", &spec->channels))) + if (!(gst_structure_get_int (structure, "rate", &info.rate) && + gst_structure_get_int (structure, "channels", &info.channels))) goto parse_error; spec->type = GST_BUFTYPE_A_LAW; - spec->format = GST_A_LAW; - spec->width = 8; - spec->depth = 8; - for (i = 0; i < spec->channels; i++) - spec->silence_sample[i] = 0xd5; + spec->info.bpf = info.channels; } else if (g_str_equal (mimetype, "audio/x-mulaw")) { /* extract the needed information from the cap */ - if (!(gst_structure_get_int (structure, "rate", &spec->rate) && - gst_structure_get_int (structure, "channels", &spec->channels))) + if (!(gst_structure_get_int (structure, "rate", &info.rate) && + gst_structure_get_int (structure, "channels", &info.channels))) goto parse_error; spec->type = GST_BUFTYPE_MU_LAW; - spec->format = GST_MU_LAW; - spec->width = 8; - spec->depth = 8; - for (i = 0; i < spec->channels; i++) - spec->silence_sample[i] = 0xff; + spec->info.bpf = info.channels; } else if (g_str_equal (mimetype, "audio/x-iec958")) { /* extract the needed information from the cap */ - if (!(gst_structure_get_int (structure, "rate", &spec->rate))) + if (!(gst_structure_get_int (structure, "rate", &info.rate))) goto parse_error; spec->type = GST_BUFTYPE_IEC958; - spec->format = GST_IEC958; - spec->width = 16; - spec->depth = 16; - spec->channels = 2; + spec->info.bpf = 4; } else if (g_str_equal (mimetype, "audio/x-ac3")) { /* extract the needed information from the cap */ - if (!(gst_structure_get_int (structure, "rate", &spec->rate))) + if (!(gst_structure_get_int (structure, "rate", &info.rate))) goto parse_error; spec->type = GST_BUFTYPE_AC3; - spec->format = GST_AC3; - spec->width = 16; - spec->depth = 16; - spec->channels = 2; + spec->info.bpf = 4; } else if (g_str_equal (mimetype, "audio/x-eac3")) { /* extract the needed information from the cap */ - if (!(gst_structure_get_int (structure, "rate", &spec->rate))) + if (!(gst_structure_get_int (structure, "rate", &info.rate))) goto parse_error; spec->type = GST_BUFTYPE_EAC3; - spec->format = GST_EAC3; - spec->width = 64; - spec->depth = 64; - spec->channels = 2; + spec->info.bpf = 16; } else if (g_str_equal (mimetype, "audio/x-dts")) { /* extract the needed information from the cap */ - if (!(gst_structure_get_int (structure, "rate", &spec->rate))) + if (!(gst_structure_get_int (structure, "rate", &info.rate))) goto parse_error; spec->type = GST_BUFTYPE_DTS; - spec->format = GST_DTS; - spec->width = 16; - spec->depth = 16; - spec->channels = 2; + spec->info.bpf = 4; } else if (g_str_equal (mimetype, "audio/mpeg") && gst_structure_get_int (structure, "mpegaudioversion", &i) && (i == 1 || i == 2)) { /* Now we know this is MPEG-1 or MPEG-2 (non AAC) */ /* extract the needed information from the cap */ - if (!(gst_structure_get_int (structure, "rate", &spec->rate))) + if (!(gst_structure_get_int (structure, "rate", &info.rate))) goto parse_error; spec->type = GST_BUFTYPE_MPEG; - spec->format = GST_MPEG; - spec->width = 16; - spec->depth = 16; - spec->channels = 2; + spec->info.bpf = 4; } else { goto parse_error; } - spec->bytes_per_sample = (spec->width >> 3) * spec->channels; - gst_caps_replace (&spec->caps, caps); g_return_val_if_fail (spec->latency_time != 0, FALSE); @@ -482,10 +272,10 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps) /* calculate suggested segsize and segtotal. segsize should be one unit * of 'latency_time' samples, scaling for the fact that latency_time is * currently stored in microseconds (FIXME: in 0.11) */ - spec->segsize = gst_util_uint64_scale (spec->rate * spec->bytes_per_sample, + spec->segsize = gst_util_uint64_scale (info.rate * info.bpf, spec->latency_time, GST_SECOND / GST_USECOND); /* Round to an integer number of samples */ - spec->segsize -= spec->segsize % spec->bytes_per_sample; + spec->segsize -= spec->segsize % info.bpf; spec->segtotal = spec->buffer_time / spec->latency_time; /* leave the latency undefined now, implementations can change it but if it's @@ -495,6 +285,8 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps) gst_ring_buffer_debug_spec_caps (spec); gst_ring_buffer_debug_spec_buff (spec); + spec->info = info; + return TRUE; /* ERRORS */ @@ -525,7 +317,7 @@ gst_ring_buffer_convert (GstRingBuffer * buf, GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val) { gboolean res = TRUE; - gint bps, rate; + gint bpf, rate; GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s (%d) to %s (%d)", src_val, gst_format_get_name (src_fmt), src_fmt, @@ -538,12 +330,12 @@ gst_ring_buffer_convert (GstRingBuffer * buf, /* get important info */ GST_OBJECT_LOCK (buf); - bps = buf->spec.bytes_per_sample; - rate = buf->spec.rate; + bpf = GST_AUDIO_INFO_BPF (&buf->spec.info); + rate = GST_AUDIO_INFO_RATE (&buf->spec.info); GST_OBJECT_UNLOCK (buf); - if (bps == 0 || rate == 0) { - GST_DEBUG ("no rate or bps configured"); + if (bpf == 0 || rate == 0) { + GST_DEBUG ("no rate or bpf configured"); res = FALSE; goto done; } @@ -552,11 +344,11 @@ gst_ring_buffer_convert (GstRingBuffer * buf, case GST_FORMAT_BYTES: switch (dest_fmt) { case GST_FORMAT_TIME: - *dest_val = gst_util_uint64_scale_int (src_val / bps, GST_SECOND, + *dest_val = gst_util_uint64_scale_int (src_val / bpf, GST_SECOND, rate); break; case GST_FORMAT_DEFAULT: - *dest_val = src_val / bps; + *dest_val = src_val / bpf; break; default: res = FALSE; @@ -569,7 +361,7 @@ gst_ring_buffer_convert (GstRingBuffer * buf, *dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, rate); break; case GST_FORMAT_BYTES: - *dest_val = src_val * bps; + *dest_val = src_val * bpf; break; default: res = FALSE; @@ -583,7 +375,7 @@ gst_ring_buffer_convert (GstRingBuffer * buf, break; case GST_FORMAT_BYTES: *dest_val = gst_util_uint64_scale_int (src_val, rate, GST_SECOND); - *dest_val *= bps; + *dest_val *= bpf; break; default: res = FALSE; @@ -794,8 +586,7 @@ gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) { gboolean res = FALSE; GstRingBufferClass *rclass; - gint i, j; - gint segsize, bps; + gint segsize, bpf; g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE); @@ -817,8 +608,8 @@ gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) if (G_UNLIKELY (!res)) goto acquire_failed; - if (G_UNLIKELY ((bps = buf->spec.bytes_per_sample) == 0)) - goto invalid_bps; + if (G_UNLIKELY ((bpf = buf->spec.info.bpf) == 0)) + goto invalid_bpf; /* if the seglatency was overwritten with something else than -1, use it, else * assume segtotal as the latency */ @@ -827,18 +618,18 @@ gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) segsize = buf->spec.segsize; - buf->samples_per_seg = segsize / bps; + buf->samples_per_seg = segsize / bpf; /* create an empty segment */ g_free (buf->empty_seg); buf->empty_seg = g_malloc (segsize); - /* FIXME, we only have 32 silence samples, which might not be enough to - * represent silence in all channels */ - bps = MIN (bps, 32); - for (i = 0, j = 0; i < segsize; i++) { - buf->empty_seg[i] = buf->spec.silence_sample[j]; - j = (j + 1) % bps; + if (buf->spec.type == GST_BUFTYPE_RAW) { + gst_audio_format_fill_silence (buf->spec.info.finfo, buf->empty_seg, + segsize); + } else { + /* FIXME, non-raw formats get 0 as the empty sample */ + memset (buf->empty_seg, 0, segsize); } GST_DEBUG_OBJECT (buf, "acquired device"); @@ -867,10 +658,10 @@ acquire_failed: GST_DEBUG_OBJECT (buf, "failed to acquire device"); goto done; } -invalid_bps: +invalid_bpf: { g_warning - ("invalid bytes_per_sample from acquire ringbuffer %p, fix the element", + ("invalid bytes_per_frame from acquire ringbuffer %p, fix the element", buf); buf->acquired = FALSE; res = FALSE; @@ -1547,12 +1338,12 @@ no_start: #define FWD_SAMPLES(s,se,d,de) \ G_STMT_START { \ /* no rate conversion */ \ - guint towrite = MIN (se + bps - s, de - d); \ + guint towrite = MIN (se + bpf - s, de - d); \ /* simple copy */ \ if (!skip) \ memcpy (d, s, towrite); \ - in_samples -= towrite / bps; \ - out_samples -= towrite / bps; \ + in_samples -= towrite / bpf; \ + out_samples -= towrite / bpf; \ s += towrite; \ GST_DEBUG ("copy %u bytes", towrite); \ } G_STMT_END @@ -1563,16 +1354,16 @@ G_STMT_START { \ guint8 *sb = s, *db = d; \ while (s <= se && d < de) { \ if (!skip) \ - memcpy (d, s, bps); \ - s += bps; \ + memcpy (d, s, bpf); \ + s += bpf; \ *accum += outr; \ if ((*accum << 1) >= inr) { \ *accum -= inr; \ - d += bps; \ + d += bpf; \ } \ } \ - in_samples -= (s - sb)/bps; \ - out_samples -= (d - db)/bps; \ + in_samples -= (s - sb)/bpf; \ + out_samples -= (d - db)/bpf; \ GST_DEBUG ("fwd_up end %d/%d",*accum,*toprocess); \ } G_STMT_END @@ -1582,16 +1373,16 @@ G_STMT_START { \ guint8 *sb = s, *db = d; \ while (s <= se && d < de) { \ if (!skip) \ - memcpy (d, s, bps); \ - d += bps; \ + memcpy (d, s, bpf); \ + d += bpf; \ *accum += inr; \ if ((*accum << 1) >= outr) { \ *accum -= outr; \ - s += bps; \ + s += bpf; \ } \ } \ - in_samples -= (s - sb)/bps; \ - out_samples -= (d - db)/bps; \ + in_samples -= (s - sb)/bpf; \ + out_samples -= (d - db)/bpf; \ GST_DEBUG ("fwd_down end %d/%d",*accum,*toprocess); \ } G_STMT_END @@ -1600,16 +1391,16 @@ G_STMT_START { \ guint8 *sb = se, *db = d; \ while (s <= se && d < de) { \ if (!skip) \ - memcpy (d, se, bps); \ - se -= bps; \ + memcpy (d, se, bpf); \ + se -= bpf; \ *accum += outr; \ while (d < de && (*accum << 1) >= inr) { \ *accum -= inr; \ - d += bps; \ + d += bpf; \ } \ } \ - in_samples -= (sb - se)/bps; \ - out_samples -= (d - db)/bps; \ + in_samples -= (sb - se)/bpf; \ + out_samples -= (d - db)/bpf; \ GST_DEBUG ("rev_up end %d/%d",*accum,*toprocess); \ } G_STMT_END @@ -1618,16 +1409,16 @@ G_STMT_START { \ guint8 *sb = se, *db = d; \ while (s <= se && d < de) { \ if (!skip) \ - memcpy (d, se, bps); \ - d += bps; \ + memcpy (d, se, bpf); \ + d += bpf; \ *accum += inr; \ while (s <= se && (*accum << 1) >= outr) { \ *accum -= outr; \ - se -= bps; \ + se -= bpf; \ } \ } \ - in_samples -= (sb - se)/bps; \ - out_samples -= (d - db)/bps; \ + in_samples -= (sb - se)/bpf; \ + out_samples -= (d - db)/bpf; \ GST_DEBUG ("rev_down end %d/%d",*accum,*toprocess); \ } G_STMT_END @@ -1636,7 +1427,7 @@ default_commit (GstRingBuffer * buf, guint64 * sample, guchar * data, gint in_samples, gint out_samples, gint * accum) { gint segdone; - gint segsize, segtotal, bps, sps; + gint segsize, segtotal, bpf, sps; guint8 *dest, *data_end; gint writeseg, sampleoff; gint *toprocess; @@ -1649,7 +1440,7 @@ default_commit (GstRingBuffer * buf, guint64 * sample, dest = buf->memory; segsize = buf->spec.segsize; segtotal = buf->spec.segtotal; - bps = buf->spec.bytes_per_sample; + bpf = buf->spec.info.bpf; sps = buf->samples_per_seg; reverse = out_samples < 0; @@ -1665,12 +1456,12 @@ default_commit (GstRingBuffer * buf, guint64 * sample, /* data_end points to the last sample we have to write, not past it. This is * needed to properly handle reverse playback: it points to the last sample. */ - data_end = data + (bps * inr); + data_end = data + (bpf * inr); /* figure out the segment and the offset inside the segment where * the first sample should be written. */ writeseg = *sample / sps; - sampleoff = (*sample % sps) * bps; + sampleoff = (*sample % sps) * bpf; /* write out all samples */ while (*toprocess > 0) { @@ -1714,11 +1505,11 @@ default_commit (GstRingBuffer * buf, guint64 * sample, /* we can write now */ ws = writeseg % segtotal; - avail = MIN (segsize - sampleoff, bps * out_samples); + avail = MIN (segsize - sampleoff, bpf * out_samples); d = dest + (ws * segsize) + sampleoff; d_end = d + avail; - *sample += avail / bps; + *sample += avail / bpf; GST_DEBUG_OBJECT (buf, "write @%p seg %d, sps %d, off %d, avail %d", dest + ws * segsize, ws, sps, sampleoff, avail); @@ -1747,10 +1538,10 @@ default_commit (GstRingBuffer * buf, guint64 * sample, sampleoff = 0; } /* we consumed all samples here */ - data = data_end + bps; + data = data_end + bpf; done: - return inr - ((data_end - data) / bps); + return inr - ((data_end - data) / bpf); /* ERRORS */ not_started: @@ -1867,7 +1658,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data, guint len) { gint segdone; - gint segsize, segtotal, bps, sps; + gint segsize, segtotal, bpf, sps; guint8 *dest; guint to_read; @@ -1878,7 +1669,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data, dest = buf->memory; segsize = buf->spec.segsize; segtotal = buf->spec.segtotal; - bps = buf->spec.bytes_per_sample; + bpf = buf->spec.info.bpf; sps = buf->samples_per_seg; to_read = len; @@ -1913,7 +1704,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data, if (G_UNLIKELY (diff >= segtotal)) { /* pretend we read an empty segment. */ sampleslen = MIN (sps, to_read); - memcpy (data, buf->empty_seg, sampleslen * bps); + memcpy (data, buf->empty_seg, sampleslen * bpf); goto next; } @@ -1934,13 +1725,13 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data, GST_DEBUG_OBJECT (buf, "read @%p seg %d, off %d, sampleslen %d", dest + readseg * segsize, readseg, sampleoff, sampleslen); - memcpy (data, dest + (readseg * segsize) + (sampleoff * bps), - (sampleslen * bps)); + memcpy (data, dest + (readseg * segsize) + (sampleoff * bpf), + (sampleslen * bpf)); next: to_read -= sampleslen; sample += sampleslen; - data += sampleslen * bps; + data += sampleslen * bpf; } return len - to_read; diff --git a/gst-libs/gst/audio/gstringbuffer.h b/gst-libs/gst/audio/gstringbuffer.h index 99a6966a8b..76e61c36a8 100644 --- a/gst-libs/gst/audio/gstringbuffer.h +++ b/gst-libs/gst/audio/gstringbuffer.h @@ -24,6 +24,7 @@ #define __GST_RING_BUFFER_H__ #include +#include G_BEGIN_DECLS @@ -83,8 +84,7 @@ typedef enum { /** * GstBufferFormatType: - * @GST_BUFTYPE_LINEAR: samples in linear PCM - * @GST_BUFTYPE_FLOAT: samples in float + * @GST_BUFTYPE_RAW: samples in linear or float * @GST_BUFTYPE_MU_LAW: samples in mulaw * @GST_BUFTYPE_A_LAW: samples in alaw * @GST_BUFTYPE_IMA_ADPCM: samples in ima adpcm @@ -101,8 +101,7 @@ typedef enum { */ typedef enum { - GST_BUFTYPE_LINEAR, - GST_BUFTYPE_FLOAT, + GST_BUFTYPE_RAW, GST_BUFTYPE_MU_LAW, GST_BUFTYPE_A_LAW, GST_BUFTYPE_IMA_ADPCM, @@ -116,107 +115,6 @@ typedef enum GST_BUFTYPE_MPEG4_AAC, } GstBufferFormatType; -/** - * GstBufferFormat: - * @GST_UNKNOWN: unspecified - * @GST_S8: integer signed 8 bit - * @GST_U8: integer unsigned 8 bit - * @GST_S16_LE: integer signed 16 bit little endian - * @GST_S16_BE: integer signed 16 bit big endian - * @GST_U16_LE: integer unsigned 16 bit little endian - * @GST_U16_BE: integer unsigned 16 bit big endian - * @GST_S24_LE: integer signed 24 bit little endian - * @GST_S24_BE: integer signed 24 bit big endian - * @GST_U24_LE: integer unsigned 24 bit little endian - * @GST_U24_BE: integer unsigned 24 bit big endian - * @GST_S32_LE: integer signed 32 bit little endian - * @GST_S32_BE: integer signed 32 bit big endian - * @GST_U32_LE: integer unsigned 32 bit little endian - * @GST_U32_BE: integer unsigned 32 bit big endian - * @GST_S24_3LE: integer signed 24 bit little endian packed in 3 bytes - * @GST_S24_3BE: integer signed 24 bit big endian packed in 3 bytes - * @GST_U24_3LE: integer unsigned 24 bit little endian packed in 3 bytes - * @GST_U24_3BE: integer unsigned 24 bit big endian packed in 3 bytes - * @GST_S20_3LE: integer signed 20 bit little endian packed in 3 bytes - * @GST_S20_3BE: integer signed 20 bit big endian packed in 3 bytes - * @GST_U20_3LE: integer unsigned 20 bit little endian packed in 3 bytes - * @GST_U20_3BE: integer unsigned 20 bit big endian packed in 3 bytes - * @GST_S18_3LE: integer signed 18 bit little endian packed in 3 bytes - * @GST_S18_3BE: integer signed 18 bit big endian packed in 3 bytes - * @GST_U18_3LE: integer unsigned 18 bit little endian packed in 3 bytes - * @GST_U18_3BE: integer unsigned 18 bit big endian packed in 3 bytes - * @GST_FLOAT32_LE: floating 32 bit little endian - * @GST_FLOAT32_BE: floating 32 bit big endian - * @GST_FLOAT64_LE: floating 64 bit little endian - * @GST_FLOAT64_BE: floating 64 bit big endian - * @GST_MU_LAW: mu-law - * @GST_A_LAW: a-law - * @GST_IMA_ADPCM: ima adpcm - * @GST_MPEG: mpeg audio (but not aac) - * @GST_GSM: gsm - * @GST_IEC958: IEC958 frames - * @GST_AC3: ac3 - * @GST_EAC3: eac3 - * @GST_DTS: dts - * @GST_MPEG2_AAC: mpeg-2 aac - * @GST_MPEG4_AAC: mpeg-4 aac - * - * The detailed format of the samples in the ringbuffer. - */ -typedef enum -{ - GST_UNKNOWN, - - GST_S8, - GST_U8, - - GST_S16_LE, - GST_S16_BE, - GST_U16_LE, - GST_U16_BE, - - GST_S24_LE, - GST_S24_BE, - GST_U24_LE, - GST_U24_BE, - - GST_S32_LE, - GST_S32_BE, - GST_U32_LE, - GST_U32_BE, - - GST_S24_3LE, - GST_S24_3BE, - GST_U24_3LE, - GST_U24_3BE, - GST_S20_3LE, - GST_S20_3BE, - GST_U20_3LE, - GST_U20_3BE, - GST_S18_3LE, - GST_S18_3BE, - GST_U18_3LE, - GST_U18_3BE, - - GST_FLOAT32_LE, - GST_FLOAT32_BE, - - GST_FLOAT64_LE, - GST_FLOAT64_BE, - - GST_MU_LAW, - GST_A_LAW, - GST_IMA_ADPCM, - GST_MPEG, - GST_GSM, - GST_IEC958, - GST_AC3, - GST_EAC3, - GST_DTS, - GST_MPEG2_AAC, - GST_MPEG4_AAC, -} GstBufferFormat; - /** * GstRingBufferSpec: * @caps: The caps that generated the Spec. @@ -246,14 +144,8 @@ struct _GstRingBufferSpec GstCaps *caps; /* the caps of the buffer */ /* in/out */ - GstBufferFormatType type; - GstBufferFormat format; - gboolean sign; - gboolean bigend; - gint width; - gint depth; - gint rate; - gint channels; + GstBufferFormatType type; + GstAudioInfo info; guint64 latency_time; /* the required/actual latency time, this is the * actual the size of one segment and the @@ -268,10 +160,6 @@ struct _GstRingBufferSpec * number of segments of @segsize and should be * chosen so that it matches buffer_time as * close as possible. */ - /* out */ - gint bytes_per_sample; /* number of bytes of one sample */ - guint8 silence_sample[32]; /* bytes representing silence */ - /* ABI added 0.10.20 */ gint seglatency; /* number of segments queued in the lower * level device, defaults to segtotal. */ diff --git a/gst-libs/gst/audio/multichannel.c b/gst-libs/gst/audio/multichannel.c index bd26f1c2b5..388adcd8d5 100644 --- a/gst-libs/gst/audio/multichannel.c +++ b/gst-libs/gst/audio/multichannel.c @@ -231,13 +231,9 @@ GstAudioChannelPosition * gst_audio_get_channel_positions (GstStructure * str) { GstAudioChannelPosition *pos; - gint channels, n; - const GValue *pos_val_arr, *pos_val_entry; - gboolean res; - GType t; /* get number of channels, general type checkups */ diff --git a/gst-libs/gst/audio/multichannel.h b/gst-libs/gst/audio/multichannel.h index 3a3efe3d79..6f28d37c31 100644 --- a/gst-libs/gst/audio/multichannel.h +++ b/gst-libs/gst/audio/multichannel.h @@ -20,7 +20,7 @@ #ifndef __GST_AUDIO_MULTICHANNEL_H__ #define __GST_AUDIO_MULTICHANNEL_H__ -#include +#include #include G_BEGIN_DECLS diff --git a/gst-libs/gst/video/video.h b/gst-libs/gst/video/video.h index a1ce234fb1..59a32ab755 100644 --- a/gst-libs/gst/video/video.h +++ b/gst-libs/gst/video/video.h @@ -1,6 +1,5 @@ /* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Library <2002> Ronald Bultje + * Copyright (C) <2011> Wim Taymans * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -196,7 +195,7 @@ typedef void (*GstVideoFormatUnpack) (GstVideoFormatInfo *info, gpointer * * Packs @width pixels from @src to the given planes and strides in the * format @info. The pixels from source have each component interleaved - * and will be packed into @src. + * and will be packed into the planes in @data. */ typedef void (*GstVideoFormatPack) (GstVideoFormatInfo *info, const gpointer src, gpointer data[GST_VIDEO_MAX_PLANES], @@ -529,7 +528,7 @@ gboolean gst_video_frame_copy (GstVideoFrame *dest, const GstVideoFr */ #define GST_VIDEO_BUFFER_PROGRESSIVE GST_BUFFER_FLAG_MEDIA4 -/* functions */ +/* some helper functions */ gboolean gst_video_calculate_display_ratio (guint * dar_n, guint * dar_d, guint video_width, diff --git a/gst/adder/gstadder.c b/gst/adder/gstadder.c index bf6465c2e2..4cf7f746b9 100644 --- a/gst/adder/gstadder.c +++ b/gst/adder/gstadder.c @@ -75,32 +75,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); /* elementfactory information */ #define CAPS \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 32, " \ - "depth = (int) 32, " \ - "signed = (boolean) { true, false } ;" \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 16, " \ - "depth = (int) 16, " \ - "signed = (boolean) { true, false } ;" \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 8, " \ - "depth = (int) 8, " \ - "signed = (boolean) { true, false } ;" \ - "audio/x-raw-float, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) { 32, 64 }" + GST_AUDIO_CAPS_MAKE ("{ S32, U32, S16, U16, S8, U8, F32, F64 }") static GstStaticPadTemplate gst_adder_src_template = GST_STATIC_PAD_TEMPLATE ("src", diff --git a/gst/audioconvert/audioconvert.c b/gst/audioconvert/audioconvert.c index 524098c2aa..65d13093e0 100644 --- a/gst/audioconvert/audioconvert.c +++ b/gst/audioconvert/audioconvert.c @@ -556,24 +556,27 @@ static AudioConvertPack pack_funcs[] = { (AudioConvertPack) MAKE_PACK_FUNC_NAME (s32_be_float), }; -#define DOUBLE_INTERMEDIATE_FORMAT(ctx) \ - ((!ctx->in.is_int && !ctx->out.is_int) || (ctx->ns != NOISE_SHAPING_NONE)) +#define DOUBLE_INTERMEDIATE_FORMAT(ctx) \ + ((!GST_AUDIO_FORMAT_INFO_IS_INT (ctx->in.finfo) && \ + !GST_AUDIO_FORMAT_INFO_IS_INT (ctx->out.finfo)) || \ + (ctx->ns != NOISE_SHAPING_NONE)) static gint -audio_convert_get_func_index (AudioConvertCtx * ctx, AudioConvertFmt * fmt) +audio_convert_get_func_index (AudioConvertCtx * ctx, + const GstAudioFormatInfo * fmt) { gint index = 0; - if (fmt->is_int) { - index += (fmt->width / 8 - 1) * 4; - index += fmt->endianness == G_LITTLE_ENDIAN ? 0 : 2; - index += fmt->sign ? 1 : 0; + if (GST_AUDIO_FORMAT_INFO_IS_INT (fmt)) { + index += (GST_AUDIO_FORMAT_INFO_WIDTH (fmt) / 8 - 1) * 4; + index += GST_AUDIO_FORMAT_INFO_IS_LE (fmt) ? 0 : 2; + index += GST_AUDIO_FORMAT_INFO_IS_SIGNED (fmt) ? 1 : 0; index += (ctx->ns == NOISE_SHAPING_NONE) ? 0 : 24; } else { /* this is float/double */ index = 16; - index += (fmt->width == 32) ? 0 : 2; - index += (fmt->endianness == G_LITTLE_ENDIAN) ? 0 : 1; + index += (GST_AUDIO_FORMAT_INFO_WIDTH (fmt) == 32) ? 0 : 2; + index += GST_AUDIO_FORMAT_INFO_IS_LE (fmt) ? 0 : 1; index += (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? 4 : 0; } @@ -581,34 +584,22 @@ audio_convert_get_func_index (AudioConvertCtx * ctx, AudioConvertFmt * fmt) } static inline gboolean -check_default (AudioConvertCtx * ctx, AudioConvertFmt * fmt) +check_default (AudioConvertCtx * ctx, const GstAudioFormatInfo * fmt) { if (!DOUBLE_INTERMEDIATE_FORMAT (ctx)) { - return (fmt->width == 32 && fmt->depth == 32 && - fmt->endianness == G_BYTE_ORDER && fmt->sign == TRUE); + return GST_AUDIO_FORMAT_INFO_FORMAT (fmt) == GST_AUDIO_FORMAT_S32; } else { - return (fmt->width == 64 && fmt->endianness == G_BYTE_ORDER); + return GST_AUDIO_FORMAT_INFO_FORMAT (fmt) == GST_AUDIO_FORMAT_F64; } } gboolean -audio_convert_clean_fmt (AudioConvertFmt * fmt) -{ - g_return_val_if_fail (fmt != NULL, FALSE); - - g_free (fmt->pos); - fmt->pos = NULL; - - return TRUE; -} - - -gboolean -audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in, - AudioConvertFmt * out, GstAudioConvertDithering dither, +audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, + GstAudioInfo * out, GstAudioConvertDithering dither, GstAudioConvertNoiseShaping ns) { gint idx_in, idx_out; + gint in_depth, out_depth; g_return_val_if_fail (ctx != NULL, FALSE); g_return_val_if_fail (in != NULL, FALSE); @@ -617,18 +608,21 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in, /* first clean the existing context */ audio_convert_clean_context (ctx); - g_return_val_if_fail (in->unpositioned_layout == out->unpositioned_layout, - FALSE); + g_return_val_if_fail (GST_AUDIO_INFO_IS_UNPOSITIONED (in) == + GST_AUDIO_INFO_IS_UNPOSITIONED (out), FALSE); ctx->in = *in; ctx->out = *out; + in_depth = GST_AUDIO_FORMAT_INFO_DEPTH (in->finfo); + out_depth = GST_AUDIO_FORMAT_INFO_DEPTH (out->finfo); + /* Don't dither or apply noise shaping if target depth is bigger than 20 bits * as DA converters only can do a SNR up to 20 bits in reality. * Also don't dither or apply noise shaping if target depth is larger than * source depth. */ - if (ctx->out.depth <= 20 && (!ctx->in.is_int - || ctx->in.depth >= ctx->out.depth)) { + if (out_depth <= 20 && (!GST_AUDIO_FORMAT_INFO_IS_INT (in->finfo) + || in_depth >= out_depth)) { ctx->dither = dither; ctx->ns = ns; } else { @@ -638,15 +632,15 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in, /* Use simple error feedback when output sample rate is smaller than * 32000 as the other methods might move the noise to audible ranges */ - if (ctx->ns > NOISE_SHAPING_ERROR_FEEDBACK && ctx->out.rate < 32000) + if (ctx->ns > NOISE_SHAPING_ERROR_FEEDBACK && out->rate < 32000) ctx->ns = NOISE_SHAPING_ERROR_FEEDBACK; gst_channel_mix_setup_matrix (ctx); - idx_in = audio_convert_get_func_index (ctx, in); + idx_in = audio_convert_get_func_index (ctx, in->finfo); ctx->unpack = unpack_funcs[idx_in]; - idx_out = audio_convert_get_func_index (ctx, out); + idx_out = audio_convert_get_func_index (ctx, out->finfo); ctx->pack = pack_funcs[idx_out]; /* if both formats are float/double or we use noise shaping use double as @@ -658,20 +652,22 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in, GST_INFO ("use float mixing"); ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_float; } - GST_INFO ("unitsizes: %d -> %d", in->unit_size, out->unit_size); + GST_INFO ("unitsizes: %d -> %d", in->bpf, out->bpf); /* check if input is in default format */ - ctx->in_default = check_default (ctx, in); + ctx->in_default = check_default (ctx, in->finfo); /* check if channel mixer is passthrough */ ctx->mix_passthrough = gst_channel_mix_passthrough (ctx); /* check if output is in default format */ - ctx->out_default = check_default (ctx, out); + ctx->out_default = check_default (ctx, out->finfo); GST_INFO ("in default %d, mix passthrough %d, out default %d", ctx->in_default, ctx->mix_passthrough, ctx->out_default); - ctx->in_scale = (in->is_int) ? (32 - in->depth) : 0; - ctx->out_scale = (out->is_int) ? (32 - out->depth) : 0; + ctx->in_scale = + GST_AUDIO_FORMAT_INFO_IS_INT (in->finfo) ? (32 - in_depth) : 0; + ctx->out_scale = + GST_AUDIO_FORMAT_INFO_IS_INT (out->finfo) ? (32 - out_depth) : 0; gst_audio_quantize_setup (ctx); @@ -684,8 +680,8 @@ audio_convert_clean_context (AudioConvertCtx * ctx) g_return_val_if_fail (ctx != NULL, FALSE); gst_audio_quantize_free (ctx); - audio_convert_clean_fmt (&ctx->in); - audio_convert_clean_fmt (&ctx->out); + gst_audio_info_init (&ctx->in); + gst_audio_info_init (&ctx->out); gst_channel_mix_unset_matrix (ctx); g_free (ctx->tmpbuf); @@ -702,9 +698,9 @@ audio_convert_get_sizes (AudioConvertCtx * ctx, gint samples, gint * srcsize, g_return_val_if_fail (ctx != NULL, FALSE); if (srcsize) - *srcsize = samples * ctx->in.unit_size; + *srcsize = samples * ctx->in.bpf; if (dstsize) - *dstsize = samples * ctx->out.unit_size; + *dstsize = samples * ctx->out.bpf; return TRUE; } @@ -716,6 +712,7 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src, guint insize, outsize, size; gpointer outbuf, tmpbuf; guint intemp = 0, outtemp = 0, biggest; + gint in_width, out_width; g_return_val_if_fail (ctx != NULL, FALSE); g_return_val_if_fail (src != NULL, FALSE); @@ -725,23 +722,26 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src, if (samples == 0) return TRUE; - insize = ctx->in.unit_size * samples; - outsize = ctx->out.unit_size * samples; + insize = ctx->in.bpf * samples; + outsize = ctx->out.bpf * samples; + + in_width = GST_AUDIO_FORMAT_INFO_WIDTH (ctx->in.finfo); + out_width = GST_AUDIO_FORMAT_INFO_WIDTH (ctx->out.finfo); /* find biggest temp buffer size */ size = (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? sizeof (gdouble) : sizeof (gint32); if (!ctx->in_default) - intemp = gst_util_uint64_scale (insize, size * 8, ctx->in.width); + intemp = gst_util_uint64_scale (insize, size * 8, in_width); if (!ctx->mix_passthrough || !ctx->out_default) - outtemp = gst_util_uint64_scale (outsize, size * 8, ctx->out.width); + outtemp = gst_util_uint64_scale (outsize, size * 8, out_width); biggest = MAX (intemp, outtemp); /* see if one of the buffers can be used as temp */ - if ((outsize >= biggest) && (ctx->out.unit_size <= size)) + if ((outsize >= biggest) && (ctx->out.bpf <= size)) tmpbuf = dst; - else if ((insize >= biggest) && src_writable && (ctx->in.unit_size >= size)) + else if ((insize >= biggest) && src_writable && (ctx->in.bpf >= size)) tmpbuf = src; else { if (biggest > ctx->tmpbufsize) { @@ -779,7 +779,7 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src, } /* we only need to quantize if output format is int */ - if (ctx->out.is_int) { + if (GST_AUDIO_FORMAT_INFO_IS_INT (ctx->out.finfo)) { if (ctx->out_default) outbuf = dst; else diff --git a/gst/audioconvert/audioconvert.h b/gst/audioconvert/audioconvert.h index ccc40146d5..638a42a815 100644 --- a/gst/audioconvert/audioconvert.h +++ b/gst/audioconvert/audioconvert.h @@ -23,7 +23,7 @@ #define __AUDIO_CONVERT_H__ #include -#include +#include GST_DEBUG_CATEGORY_EXTERN (audio_convert_debug); #define GST_CAT_DEFAULT (audio_convert_debug) @@ -65,6 +65,7 @@ typedef enum } GstAudioConvertNoiseShaping; typedef struct _AudioConvertCtx AudioConvertCtx; +#if 0 typedef struct _AudioConvertFmt AudioConvertFmt; struct _AudioConvertFmt @@ -84,6 +85,7 @@ struct _AudioConvertFmt gint unit_size; }; +#endif typedef void (*AudioConvertUnpack) (gpointer src, gpointer dst, gint scale, gint count); @@ -96,8 +98,8 @@ typedef void (*AudioConvertQuantize) (AudioConvertCtx * ctx, gpointer src, struct _AudioConvertCtx { - AudioConvertFmt in; - AudioConvertFmt out; + GstAudioInfo in; + GstAudioInfo out; AudioConvertUnpack unpack; AudioConvertPack pack; @@ -130,10 +132,8 @@ struct _AudioConvertCtx gdouble *error_buf; }; -gboolean audio_convert_clean_fmt (AudioConvertFmt * fmt); - gboolean audio_convert_prepare_context (AudioConvertCtx * ctx, - AudioConvertFmt * in, AudioConvertFmt * out, + GstAudioInfo * in, GstAudioInfo * out, GstAudioConvertDithering dither, GstAudioConvertNoiseShaping ns); gboolean audio_convert_get_sizes (AudioConvertCtx * ctx, gint samples, gint * srcsize, gint * dstsize); diff --git a/gst/audioconvert/gstaudioconvert.c b/gst/audioconvert/gstaudioconvert.c index 1562088612..6cf8775733 100644 --- a/gst/audioconvert/gstaudioconvert.c +++ b/gst/audioconvert/gstaudioconvert.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2003 Benjamin Otte * Copyright (C) 2005 Thomas Vander Stichele - * Copyright (C) 2005 Wim Taymans + * Copyright (C) 2011 Wim Taymans * * gstaudioconvert.c: Convert audio to different audio formats automatically * @@ -31,7 +31,7 @@ * * Example launch line * |[ - * gst-launch -v -m audiotestsrc ! audioconvert ! audio/x-raw-int,channels=2,width=8,depth=8 ! level ! fakesink silent=TRUE + * gst-launch -v -m audiotestsrc ! audioconvert ! audio/x-raw,format=S8,channels=2 ! level ! fakesink silent=TRUE * ]| This pipeline converts audio to 8-bit. The level element shows that * the output levels still match the one for a sine wave. * |[ @@ -91,8 +91,6 @@ static void gst_audio_convert_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_audio_convert_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean structure_has_fixed_channel_positions (GstStructure * s, - gboolean * unpositioned_layout); /* AudioConvert signals and args */ enum @@ -118,45 +116,7 @@ G_DEFINE_TYPE_WITH_CODE (GstAudioConvert, gst_audio_convert, /*** GSTREAMER PROTOTYPES *****************************************************/ #define STATIC_CAPS \ -GST_STATIC_CAPS ( \ - "audio/x-raw-float, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ - "width = (int) 64;" \ - "audio/x-raw-float, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ - "width = (int) 32;" \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ - "width = (int) 32, " \ - "depth = (int) [ 1, 32 ], " \ - "signed = (boolean) { true, false }; " \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ - "width = (int) 24, " \ - "depth = (int) [ 1, 24 ], " "signed = (boolean) { true, false }; " \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ - "width = (int) 16, " \ - "depth = (int) [ 1, 16 ], " \ - "signed = (boolean) { true, false }; " \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ - "width = (int) 8, " \ - "depth = (int) [ 1, 8 ], " \ - "signed = (boolean) { true, false } " \ -) +GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL)) static GstStaticPadTemplate gst_audio_convert_src_template = GST_STATIC_PAD_TEMPLATE ("src", @@ -284,90 +244,20 @@ gst_audio_convert_dispose (GObject * obj) /*** GSTREAMER FUNCTIONS ******************************************************/ -/* convert the given GstCaps to our format */ -static gboolean -gst_audio_convert_parse_caps (const GstCaps * caps, AudioConvertFmt * fmt) -{ - GstStructure *structure = gst_caps_get_structure (caps, 0); - - GST_DEBUG ("parse caps %p and %" GST_PTR_FORMAT, caps, caps); - - g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE); - g_return_val_if_fail (fmt != NULL, FALSE); - - /* cleanup old */ - audio_convert_clean_fmt (fmt); - - fmt->endianness = G_BYTE_ORDER; - fmt->is_int = - (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0); - - /* parse common fields */ - if (!gst_structure_get_int (structure, "channels", &fmt->channels)) - goto no_values; - if (!(fmt->pos = gst_audio_get_channel_positions (structure))) - goto no_values; - - fmt->unpositioned_layout = FALSE; - structure_has_fixed_channel_positions (structure, &fmt->unpositioned_layout); - - if (!gst_structure_get_int (structure, "width", &fmt->width)) - goto no_values; - if (!gst_structure_get_int (structure, "rate", &fmt->rate)) - goto no_values; - /* width != 8 needs an endianness field */ - if (fmt->width != 8) { - if (!gst_structure_get_int (structure, "endianness", &fmt->endianness)) - goto no_values; - } - - if (fmt->is_int) { - /* int specific fields */ - if (!gst_structure_get_boolean (structure, "signed", &fmt->sign)) - goto no_values; - if (!gst_structure_get_int (structure, "depth", &fmt->depth)) - goto no_values; - - /* depth cannot be bigger than the width */ - if (fmt->depth > fmt->width) - goto not_allowed; - } - - fmt->unit_size = (fmt->width * fmt->channels) / 8; - - return TRUE; - - /* ERRORS */ -no_values: - { - GST_DEBUG ("could not get some values from structure"); - audio_convert_clean_fmt (fmt); - return FALSE; - } -not_allowed: - { - GST_DEBUG ("width > depth, not allowed - make us advertise correct fmt"); - audio_convert_clean_fmt (fmt); - return FALSE; - } -} - /* BaseTransform vmethods */ static gboolean gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps, gsize * size) { - AudioConvertFmt fmt = { 0 }; + GstAudioInfo info; g_assert (size); - if (!gst_audio_convert_parse_caps (caps, &fmt)) + if (!gst_audio_info_from_caps (&info, caps)) goto parse_error; - GST_INFO_OBJECT (base, "unit_size = %u", fmt.unit_size); - *size = fmt.unit_size; - - audio_convert_clean_fmt (&fmt); + *size = info.bpf; + GST_INFO_OBJECT (base, "unit_size = %" G_GSIZE_FORMAT, *size); return TRUE; @@ -378,351 +268,61 @@ parse_error: } } -/* Set widths (a list); multiples of 8 between min and max */ -static void -set_structure_widths (GstStructure * s, int min, int max) -{ - GValue list = { 0 }; - GValue val = { 0 }; - int width; - - if (min == max) { - gst_structure_set (s, "width", G_TYPE_INT, min, NULL); - return; - } - - g_value_init (&list, GST_TYPE_LIST); - g_value_init (&val, G_TYPE_INT); - for (width = min; width <= max; width += 8) { - g_value_set_int (&val, width); - gst_value_list_append_value (&list, &val); - } - gst_structure_set_value (s, "width", &list); - g_value_unset (&val); - g_value_unset (&list); -} - -/* Set widths of 32 bits and 64 bits (as list) */ -static void -set_structure_widths_32_and_64 (GstStructure * s) -{ - GValue list = { 0 }; - GValue val = { 0 }; - - g_value_init (&list, GST_TYPE_LIST); - g_value_init (&val, G_TYPE_INT); - g_value_set_int (&val, 32); - gst_value_list_append_value (&list, &val); - g_value_set_int (&val, 64); - gst_value_list_append_value (&list, &val); - gst_structure_set_value (s, "width", &list); - g_value_unset (&val); - g_value_unset (&list); -} - -/* Modify the structure so that things that must always have a single - * value (for float), or can always be losslessly converted (for int), have - * appropriate values. - */ -static GstStructure * -make_lossless_changes (GstStructure * s, gboolean isfloat) -{ - GValue list = { 0 }; - GValue val = { 0 }; - int i; - const gint endian[] = { G_LITTLE_ENDIAN, G_BIG_ENDIAN }; - const gboolean booleans[] = { TRUE, FALSE }; - - g_value_init (&list, GST_TYPE_LIST); - g_value_init (&val, G_TYPE_INT); - for (i = 0; i < 2; i++) { - g_value_set_int (&val, endian[i]); - gst_value_list_append_value (&list, &val); - } - gst_structure_set_value (s, "endianness", &list); - g_value_unset (&val); - g_value_unset (&list); - - if (isfloat) { - /* float doesn't have a depth or signedness field and only supports - * widths of 32 and 64 bits */ - gst_structure_remove_field (s, "depth"); - gst_structure_remove_field (s, "signed"); - set_structure_widths_32_and_64 (s); - } else { - /* int supports signed and unsigned. GValues are a pain */ - g_value_init (&list, GST_TYPE_LIST); - g_value_init (&val, G_TYPE_BOOLEAN); - for (i = 0; i < 2; i++) { - g_value_set_boolean (&val, booleans[i]); - gst_value_list_append_value (&list, &val); - } - gst_structure_set_value (s, "signed", &list); - g_value_unset (&val); - g_value_unset (&list); - } - - return s; -} - -static void -strip_width_64 (GstStructure * s) -{ - const GValue *v = gst_structure_get_value (s, "width"); - GValue widths = { 0 }; - - if (GST_VALUE_HOLDS_LIST (v)) { - int i; - int len = gst_value_list_get_size (v); - - g_value_init (&widths, GST_TYPE_LIST); - - for (i = 0; i < len; i++) { - const GValue *width = gst_value_list_get_value (v, i); - - if (g_value_get_int (width) != 64) - gst_value_list_append_value (&widths, width); - } - gst_structure_set_value (s, "width", &widths); - g_value_unset (&widths); - } -} - -/* Little utility function to create a related structure for float/int */ -static void -append_with_other_format (GstCaps * caps, const GstStructure * s, - gboolean isfloat) -{ - GstStructure *s2; - - if (isfloat) { - s2 = gst_structure_copy (s); - gst_structure_set_name (s2, "audio/x-raw-int"); - make_lossless_changes (s2, FALSE); - /* If 64 bit float was allowed; remove width 64: we don't support it for - * integer*/ - strip_width_64 (s2); - gst_caps_merge_structure (caps, s2); - } else { - s2 = gst_structure_copy (s); - gst_structure_set_name (s2, "audio/x-raw-float"); - make_lossless_changes (s2, TRUE); - gst_caps_merge_structure (caps, s2); - } -} - -static gboolean -structure_has_fixed_channel_positions (GstStructure * s, - gboolean * unpositioned_layout) -{ - GstAudioChannelPosition *pos; - const GValue *val; - gint channels = 0; - - if (!gst_structure_get_int (s, "channels", &channels)) - return FALSE; /* probably a range */ - - val = gst_structure_get_value (s, "channel-positions"); - if ((val == NULL || !gst_value_is_fixed (val)) && channels <= 8) { - GST_LOG ("no or unfixed channel-positions in %" GST_PTR_FORMAT, s); - return FALSE; - } else if (val == NULL || !gst_value_is_fixed (val)) { - GST_LOG ("implicit undefined channel-positions"); - *unpositioned_layout = TRUE; - return TRUE; - } - - pos = gst_audio_get_channel_positions (s); - if (pos && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) { - GST_LOG ("fixed undefined channel-positions in %" GST_PTR_FORMAT, s); - *unpositioned_layout = TRUE; - } else { - GST_LOG ("fixed defined channel-positions in %" GST_PTR_FORMAT, s); - *unpositioned_layout = FALSE; - } - g_free (pos); - - return TRUE; -} - -/* Audioconvert can perform all conversions on audio except for resampling. - * However, there are some conversions we _prefer_ not to do. For example, it's - * better to convert format (float<->int, endianness, etc) than the number of - * channels, as the latter conversion is not lossless. - * - * So, we return, in order (assuming input caps have only one structure; - * which is enforced by basetransform): - * - input caps with a different format (lossless conversions). - * - input caps with a different format (slightly lossy conversions). - * - input caps with a different number of channels (very lossy!) - */ +/* copies the given caps */ static GstCaps * -gst_audio_convert_transform_caps (GstBaseTransform * base, - GstPadDirection direction, GstCaps * caps, GstCaps * filter) +gst_audio_convert_caps_remove_format_info (GstCaps * caps) { - GstCaps *ret; - GstStructure *s, *structure; - gboolean isfloat, allow_mixing; - gint width, depth, channels = 0; - const gchar *fields_used[] = { - "width", "depth", "rate", "channels", "endianness", "signed" - }; - const gchar *structure_name; - gint n, j; - int i; + GstStructure *st; + gint i, n; + GstCaps *res; + + res = gst_caps_new_empty (); n = gst_caps_get_size (caps); + for (i = 0; i < n; i++) { + st = gst_caps_get_structure (caps, i); - ret = gst_caps_new_empty (); + /* If this is already expressed by the existing caps + * skip this structure */ + if (i > 0 && gst_caps_is_subset_structure (res, st)) + continue; - for (j = 0; j < n; j++) { - structure = gst_caps_get_structure (caps, j); + st = gst_structure_copy (st); + gst_structure_remove_fields (st, "format", "channel-positions", NULL); - if (j > 0) { - /* If the new structure is a subset of the already existing transformed - * caps we can safely skip it because we would transform it to the - * same caps again. - */ - if (gst_caps_is_subset_structure (ret, structure)) - continue; - } - - structure_name = gst_structure_get_name (structure); - - isfloat = strcmp (structure_name, "audio/x-raw-float") == 0; - - /* We operate on a version of the original structure with any additional - * fields absent */ - s = gst_structure_empty_new (structure_name); - for (i = 0; i < sizeof (fields_used) / sizeof (*fields_used); i++) { - if (gst_structure_has_field (structure, fields_used[i])) - gst_structure_set_value (s, fields_used[i], - gst_structure_get_value (structure, fields_used[i])); - } - - if (!isfloat) { - /* Commonly, depth is left out: set it equal to width if we have a fixed - * width, if so */ - if (!gst_structure_has_field (s, "depth") && - gst_structure_get_int (s, "width", &width)) - gst_structure_set (s, "depth", G_TYPE_INT, width, NULL); - } - - /* All lossless conversions */ - s = make_lossless_changes (s, isfloat); - gst_caps_merge_structure (ret, gst_structure_copy (s)); - - /* Same, plus a float<->int conversion */ - append_with_other_format (ret, s, isfloat); - GST_DEBUG_OBJECT (base, " step1: (%d) %" GST_PTR_FORMAT, - gst_caps_get_size (ret), ret); - - /* We don't mind increasing width/depth/channels, but reducing them is - * Very Bad. Only available if width, depth, channels are already fixed. */ - if (!isfloat) { - if (gst_structure_get_int (structure, "width", &width)) - set_structure_widths (s, width, 32); - if (gst_structure_get_int (structure, "depth", &depth)) { - if (depth == 32) - gst_structure_set (s, "depth", G_TYPE_INT, 32, NULL); - else - gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, depth, 32, NULL); - } - } - - allow_mixing = TRUE; - if (gst_structure_get_int (structure, "channels", &channels)) { - gboolean unpositioned; - - /* we don't support mixing for channels without channel positions */ - if (structure_has_fixed_channel_positions (structure, &unpositioned)) - allow_mixing = (unpositioned == FALSE); - } - - if (!allow_mixing) { - gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL); - if (gst_structure_has_field (structure, "channel-positions")) - gst_structure_set_value (s, "channel-positions", - gst_structure_get_value (structure, "channel-positions")); - } else { - if (channels == 0) - gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 11, NULL); - else if (channels == 11) - gst_structure_set (s, "channels", G_TYPE_INT, 11, NULL); - else - gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, channels, 11, - NULL); - gst_structure_remove_field (s, "channel-positions"); - } - gst_caps_merge_structure (ret, gst_structure_copy (s)); - - /* Same, plus a float<->int conversion */ - append_with_other_format (ret, s, isfloat); - - /* We'll reduce depth if we must. We reduce as low as 16 bits (for integer); - * reducing to less than this is even worse than dropping channels. We only - * do this if we haven't already done the equivalent above. */ - if (!gst_structure_get_int (structure, "width", &width) || width > 16) { - if (isfloat) { - GstStructure *s2 = gst_structure_copy (s); - - set_structure_widths_32_and_64 (s2); - append_with_other_format (ret, s2, TRUE); - gst_structure_free (s2); - } else { - GstStructure *s2 = gst_structure_copy (s); - - set_structure_widths (s2, 16, 32); - gst_structure_set (s2, "depth", GST_TYPE_INT_RANGE, 16, 32, NULL); - gst_caps_merge_structure (ret, s2); - } - } - - /* Channel conversions to fewer channels is only done if needed - generally - * it's very bad to drop channels entirely. - */ - if (allow_mixing) { - gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 11, NULL); - gst_structure_remove_field (s, "channel-positions"); - } else { - /* allow_mixing can only be FALSE if we got a fixed number of channels */ - gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL); - if (gst_structure_has_field (structure, "channel-positions")) - gst_structure_set_value (s, "channel-positions", - gst_structure_get_value (structure, "channel-positions")); - } - gst_caps_merge_structure (ret, gst_structure_copy (s)); - - /* Same, plus a float<->int conversion */ - append_with_other_format (ret, s, isfloat); - - /* And, finally, for integer only, we allow conversion to any width/depth we - * support: this should be equivalent to our (non-float) template caps. (the - * floating point case should be being handled just above) */ - set_structure_widths (s, 8, 32); - gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, 1, 32, NULL); - - if (isfloat) { - append_with_other_format (ret, s, TRUE); - gst_structure_free (s); - } else - gst_caps_merge_structure (ret, s); + gst_caps_append_structure (res, st); } - GST_DEBUG_OBJECT (base, "Caps transformed to %" GST_PTR_FORMAT, ret); + return res; +} + +/* The caps can be transformed into any other caps with format info removed. + * However, we should prefer passthrough, so if passthrough is possible, + * put it first in the list. */ +static GstCaps * +gst_audio_convert_transform_caps (GstBaseTransform * btrans, + GstPadDirection direction, GstCaps * caps, GstCaps * filter) +{ + GstCaps *tmp, *tmp2; + GstCaps *result; + + result = gst_caps_copy (caps); + + /* Get all possible caps that we can transform to */ + tmp = gst_audio_convert_caps_remove_format_info (caps); if (filter) { - GstCaps *intersection; - - GST_DEBUG_OBJECT (base, "Using filter caps %" GST_PTR_FORMAT, filter); - intersection = - gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST); - gst_caps_unref (ret); - ret = intersection; - GST_DEBUG_OBJECT (base, "Intersection %" GST_PTR_FORMAT, ret); + tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (tmp); + tmp = tmp2; } - return ret; + result = tmp; + + GST_DEBUG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " into %" + GST_PTR_FORMAT, caps, result); + + return result; } static const GstAudioChannelPosition default_positions[8][8] = { @@ -924,8 +524,8 @@ gst_audio_convert_fixate_caps (GstBaseTransform * base, GstPadDirection direction, GstCaps * caps, GstCaps * othercaps) { GstStructure *ins, *outs; - gint rate, endianness, depth, width; - gboolean signedness; + gint rate; + const gchar *fmt; g_return_if_fail (gst_caps_is_fixed (caps)); @@ -937,41 +537,16 @@ gst_audio_convert_fixate_caps (GstBaseTransform * base, gst_audio_convert_fixate_channels (base, ins, outs); + if ((fmt = gst_structure_get_string (ins, "format"))) { + /* FIXME, find the best format */ + gst_structure_fixate_field_string (outs, "format", fmt); + } + if (gst_structure_get_int (ins, "rate", &rate)) { if (gst_structure_has_field (outs, "rate")) { gst_structure_fixate_field_nearest_int (outs, "rate", rate); } } - if (gst_structure_get_int (ins, "endianness", &endianness)) { - if (gst_structure_has_field (outs, "endianness")) { - gst_structure_fixate_field_nearest_int (outs, "endianness", endianness); - } - } - if (gst_structure_get_int (ins, "width", &width)) { - if (gst_structure_has_field (outs, "width")) { - gst_structure_fixate_field_nearest_int (outs, "width", width); - } - } else { - /* this is not allowed */ - } - - if (gst_structure_get_int (ins, "depth", &depth)) { - if (gst_structure_has_field (outs, "depth")) { - gst_structure_fixate_field_nearest_int (outs, "depth", depth); - } - } else { - /* set depth as width */ - if (gst_structure_has_field (outs, "depth")) { - gst_structure_fixate_field_nearest_int (outs, "depth", width); - } - } - - if (gst_structure_get_boolean (ins, "signed", &signedness)) { - if (gst_structure_has_field (outs, "signed")) { - gst_structure_fixate_field_boolean (outs, "signed", signedness); - } - } - GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps); } @@ -979,26 +554,38 @@ static gboolean gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps) { - AudioConvertFmt in_ac_caps = { 0 }; - AudioConvertFmt out_ac_caps = { 0 }; GstAudioConvert *this = GST_AUDIO_CONVERT (base); + GstAudioInfo in_info; + GstAudioInfo out_info; GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %" GST_PTR_FORMAT, incaps, outcaps); - if (!gst_audio_convert_parse_caps (incaps, &in_ac_caps)) - return FALSE; - if (!gst_audio_convert_parse_caps (outcaps, &out_ac_caps)) - return FALSE; + if (!gst_audio_info_from_caps (&in_info, incaps)) + goto invalid_in; + if (!gst_audio_info_from_caps (&out_info, outcaps)) + goto invalid_out; - if (!audio_convert_prepare_context (&this->ctx, &in_ac_caps, &out_ac_caps, + if (!audio_convert_prepare_context (&this->ctx, &in_info, &out_info, this->dither, this->ns)) goto no_converter; return TRUE; + /* ERRORS */ +invalid_in: + { + GST_ERROR_OBJECT (base, "invalid input caps"); + return FALSE; + } +invalid_out: + { + GST_ERROR_OBJECT (base, "invalid output caps"); + return FALSE; + } no_converter: { + GST_ERROR_OBJECT (base, "could not find converter"); return FALSE; } } @@ -1010,79 +597,6 @@ gst_audio_convert_transform_ip (GstBaseTransform * base, GstBuffer * buf) return GST_FLOW_OK; } -static void -gst_audio_convert_create_silence_buffer (GstAudioConvert * this, gpointer dst, - gint size) -{ - if (this->ctx.out.is_int && !this->ctx.out.sign) { - gint i; - - switch (this->ctx.out.width) { - case 8:{ - guint8 zero = 0x80 >> (8 - this->ctx.out.depth); - - memset (dst, zero, size); - break; - } - case 16:{ - guint16 *data = (guint16 *) dst; - guint16 zero = 0x8000 >> (16 - this->ctx.out.depth); - - if (this->ctx.out.endianness == G_LITTLE_ENDIAN) - zero = GUINT16_TO_LE (zero); - else - zero = GUINT16_TO_BE (zero); - - size /= 2; - - for (i = 0; i < size; i++) - data[i] = zero; - break; - } - case 24:{ - guint32 zero = 0x800000 >> (24 - this->ctx.out.depth); - guint8 *data = (guint8 *) dst; - - if (this->ctx.out.endianness == G_LITTLE_ENDIAN) { - for (i = 0; i < size; i += 3) { - data[i] = zero & 0xff; - data[i + 1] = (zero >> 8) & 0xff; - data[i + 2] = (zero >> 16) & 0xff; - } - } else { - for (i = 0; i < size; i += 3) { - data[i + 2] = zero & 0xff; - data[i + 1] = (zero >> 8) & 0xff; - data[i] = (zero >> 16) & 0xff; - } - } - break; - } - case 32:{ - guint32 *data = (guint32 *) dst; - guint32 zero = (0x80000000 >> (32 - this->ctx.out.depth)); - - if (this->ctx.out.endianness == G_LITTLE_ENDIAN) - zero = GUINT32_TO_LE (zero); - else - zero = GUINT32_TO_BE (zero); - - size /= 4; - - for (i = 0; i < size; i++) - data[i] = zero; - break; - } - default: - memset (dst, 0, size); - g_return_if_reached (); - break; - } - } else { - memset (dst, 0, size); - } -} - static GstFlowReturn gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf, GstBuffer * outbuf) @@ -1095,7 +609,7 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf, gpointer src, dst; /* get amount of samples to convert. */ - samples = gst_buffer_get_size (inbuf) / this->ctx.in.unit_size; + samples = gst_buffer_get_size (inbuf) / this->ctx.in.bpf; /* get in/output sizes, to see if the buffers we got are of correct * sizes */ @@ -1122,7 +636,7 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf, goto convert_error; } else { /* Create silence buffer */ - gst_audio_convert_create_silence_buffer (this, dst, outsize); + gst_audio_format_fill_silence (this->ctx.out.finfo, dst, outsize); } ret = GST_FLOW_OK; diff --git a/gst/audioconvert/gstaudioconvert.h b/gst/audioconvert/gstaudioconvert.h index 9370d38069..62f324f60a 100644 --- a/gst/audioconvert/gstaudioconvert.h +++ b/gst/audioconvert/gstaudioconvert.h @@ -24,7 +24,7 @@ #include #include -#include +#include #include "audioconvert.h" diff --git a/gst/audioconvert/gstaudioquantize.c b/gst/audioconvert/gstaudioquantize.c index 2155397cb4..aea2c92f60 100644 --- a/gst/audioconvert/gstaudioquantize.c +++ b/gst/audioconvert/gstaudioquantize.c @@ -439,7 +439,7 @@ gst_audio_quantize_setup_dither (AudioConvertCtx * ctx) { switch (ctx->dither) { case DITHER_TPDF_HF: - if (ctx->out.is_int) + if (GST_AUDIO_FORMAT_INFO_IS_INT (ctx->out.finfo)) ctx->last_random = g_new0 (gint32, ctx->out.channels); else ctx->last_random = g_new0 (gdouble, ctx->out.channels); @@ -469,14 +469,14 @@ gst_audio_quantize_setup_quantize_func (AudioConvertCtx * ctx) { gint index = 0; - if (!ctx->out.is_int) { + if (!GST_AUDIO_FORMAT_INFO_IS_INT (ctx->out.finfo)) { ctx->quantize = NULL; return; } if (ctx->ns == NOISE_SHAPING_NONE) { index += ctx->dither; - index += (ctx->out.sign) ? 0 : 4; + index += GST_AUDIO_FORMAT_INFO_IS_SIGNED (ctx->out.finfo) ? 0 : 4; } else { index += 8 + (4 * ctx->dither); index += ctx->ns - 1; diff --git a/gst/audioconvert/gstchannelmix.c b/gst/audioconvert/gstchannelmix.c index 055f28d7af..033068639a 100644 --- a/gst/audioconvert/gstchannelmix.c +++ b/gst/audioconvert/gstchannelmix.c @@ -70,7 +70,7 @@ gst_channel_mix_fill_identical (AudioConvertCtx * this) for (co = 0; co < this->out.channels; co++) { /* find a channel in input with same position */ for (ci = 0; ci < this->in.channels; ci++) { - if (this->in.pos[ci] == this->out.pos[co]) { + if (this->in.position[ci] == this->out.position[co]) { this->matrix[ci][co] = 1.0; } } @@ -118,19 +118,19 @@ gst_channel_mix_fill_compatible (AudioConvertCtx * this) gint n; for (n = 0; n < this->in.channels; n++) { - if (this->in.pos[n] == conv[c].pos1[0]) + if (this->in.position[n] == conv[c].pos1[0]) pos1_0 = n; - else if (this->in.pos[n] == conv[c].pos1[1]) + else if (this->in.position[n] == conv[c].pos1[1]) pos1_1 = n; - else if (this->in.pos[n] == conv[c].pos2[0]) + else if (this->in.position[n] == conv[c].pos2[0]) pos1_2 = n; } for (n = 0; n < this->out.channels; n++) { - if (this->out.pos[n] == conv[c].pos1[0]) + if (this->out.position[n] == conv[c].pos1[0]) pos2_0 = n; - else if (this->out.pos[n] == conv[c].pos1[1]) + else if (this->out.position[n] == conv[c].pos1[1]) pos2_1 = n; - else if (this->out.pos[n] == conv[c].pos2[0]) + else if (this->out.position[n] == conv[c].pos2[0]) pos2_2 = n; } @@ -182,15 +182,15 @@ gst_channel_mix_fill_compatible (AudioConvertCtx * this) */ static void -gst_channel_mix_detect_pos (AudioConvertFmt * caps, +gst_channel_mix_detect_pos (GstAudioInfo * info, gint * f, gboolean * has_f, gint * c, gboolean * has_c, gint * r, gboolean * has_r, gint * s, gboolean * has_s, gint * b, gboolean * has_b) { gint n; - for (n = 0; n < caps->channels; n++) { - switch (caps->pos[n]) { + for (n = 0; n < info->channels; n++) { + switch (info->position[n]) { case GST_AUDIO_CHANNEL_POSITION_FRONT_MONO: f[1] = n; *has_f = TRUE; @@ -247,8 +247,8 @@ gst_channel_mix_detect_pos (AudioConvertFmt * caps, static void gst_channel_mix_fill_one_other (gfloat ** matrix, - AudioConvertFmt * from_caps, gint * from_idx, - AudioConvertFmt * to_caps, gint * to_idx, gfloat ratio) + GstAudioInfo * from_info, gint * from_idx, + GstAudioInfo * to_info, gint * to_idx, gfloat ratio) { /* src & dst have center => passthrough */ @@ -542,26 +542,26 @@ gst_channel_mix_fill_normalize (AudioConvertCtx * this) static gboolean gst_channel_mix_fill_special (AudioConvertCtx * this) { - AudioConvertFmt *in = &this->in, *out = &this->out; + GstAudioInfo *in = &this->in, *out = &this->out; /* Special, standard conversions here */ /* Mono<->Stereo, just a fast-path */ if (in->channels == 2 && out->channels == 1 && - ((in->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT && - in->pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) || - (in->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT && - in->pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) && - out->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) { + ((in->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT && + in->position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) || + (in->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT && + in->position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) && + out->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) { this->matrix[0][0] = 0.5; this->matrix[1][0] = 0.5; return TRUE; } else if (in->channels == 1 && out->channels == 2 && - ((out->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT && - out->pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) || - (out->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT && - out->pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) && - in->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) { + ((out->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT && + out->position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) || + (out->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT && + out->position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) && + in->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) { this->matrix[0][0] = 1.0; this->matrix[0][1] = 1.0; return TRUE; @@ -584,7 +584,7 @@ gst_channel_mix_fill_matrix (AudioConvertCtx * this) gst_channel_mix_fill_identical (this); - if (!this->in.unpositioned_layout) { + if (!GST_AUDIO_INFO_IS_UNPOSITIONED (&this->in)) { gst_channel_mix_fill_compatible (this); gst_channel_mix_fill_others (this); gst_channel_mix_fill_normalize (this); @@ -601,7 +601,8 @@ gst_channel_mix_setup_matrix (AudioConvertCtx * this) gst_channel_mix_unset_matrix (this); /* temp storage */ - if (this->in.is_int || this->out.is_int) { + if (GST_AUDIO_FORMAT_INFO_IS_INT (this->in.finfo) || + GST_AUDIO_FORMAT_INFO_IS_INT (this->out.finfo)) { this->tmp = (gpointer) g_new (gint32, this->out.channels); } else { this->tmp = (gpointer) g_new (gdouble, this->out.channels); diff --git a/gst/audiorate/Makefile.am b/gst/audiorate/Makefile.am index 72c33558f7..bcb6625d8a 100644 --- a/gst/audiorate/Makefile.am +++ b/gst/audiorate/Makefile.am @@ -5,7 +5,9 @@ plugin_LTLIBRARIES = libgstaudiorate.la libgstaudiorate_la_SOURCES = gstaudiorate.c libgstaudiorate_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) libgstaudiorate_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstaudiorate_la_LIBADD = $(GST_LIBS) +libgstaudiorate_la_LIBADD = $(GST_LIBS) \ + $(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la + libgstaudiorate_la_LIBTOOLFLAGS = --tag=disable-static Android.mk: Makefile.am $(BUILT_SOURCES) diff --git a/gst/audiorate/gstaudiorate.c b/gst/audiorate/gstaudiorate.c index 7ba9ddda4b..8661c24ad3 100644 --- a/gst/audiorate/gstaudiorate.c +++ b/gst/audiorate/gstaudiorate.c @@ -93,19 +93,17 @@ enum }; static GstStaticPadTemplate gst_audio_rate_src_template = - GST_STATIC_PAD_TEMPLATE ("src", +GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS ";" - GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS) + GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL)) ); static GstStaticPadTemplate gst_audio_rate_sink_template = - GST_STATIC_PAD_TEMPLATE ("sink", +GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS ";" - GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS) + GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL)) ); static gboolean gst_audio_rate_sink_event (GstPad * pad, GstEvent * event); @@ -208,35 +206,19 @@ gst_audio_rate_reset (GstAudioRate * audiorate) static gboolean gst_audio_rate_setcaps (GstAudioRate * audiorate, GstCaps * caps) { - GstStructure *structure; - gint channels, width, rate; + GstAudioInfo info; - structure = gst_caps_get_structure (caps, 0); - - if (!gst_structure_get_int (structure, "channels", &channels)) - goto wrong_caps; - if (!gst_structure_get_int (structure, "width", &width)) - goto wrong_caps; - if (!gst_structure_get_int (structure, "rate", &rate)) + if (!gst_audio_info_from_caps (&info, caps)) goto wrong_caps; - audiorate->bytes_per_sample = channels * (width / 8); - if (audiorate->bytes_per_sample == 0) - goto wrong_format; - - audiorate->rate = rate; + audiorate->info = info; return TRUE; /* ERRORS */ wrong_caps: { - GST_DEBUG_OBJECT (audiorate, "could not get channels/width from caps"); - return FALSE; - } -wrong_format: - { - GST_DEBUG_OBJECT (audiorate, "bytes_per_samples gave 0"); + GST_DEBUG_OBJECT (audiorate, "could not parse caps"); return FALSE; } } @@ -386,20 +368,24 @@ static gboolean gst_audio_rate_convert (GstAudioRate * audiorate, GstFormat src_fmt, guint64 src_val, GstFormat dest_fmt, guint64 * dest_val) { + gint rate, bpf; + if (src_fmt == dest_fmt) { *dest_val = src_val; return TRUE; } + rate = GST_AUDIO_INFO_RATE (&audiorate->info); + bpf = GST_AUDIO_INFO_BPF (&audiorate->info); + switch (src_fmt) { case GST_FORMAT_DEFAULT: switch (dest_fmt) { case GST_FORMAT_BYTES: - *dest_val = src_val * audiorate->bytes_per_sample; + *dest_val = src_val * bpf; break; case GST_FORMAT_TIME: - *dest_val = - gst_util_uint64_scale_int (src_val, GST_SECOND, audiorate->rate); + *dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, rate); break; default: return FALSE;; @@ -408,11 +394,11 @@ gst_audio_rate_convert (GstAudioRate * audiorate, case GST_FORMAT_BYTES: switch (dest_fmt) { case GST_FORMAT_DEFAULT: - *dest_val = src_val / audiorate->bytes_per_sample; + *dest_val = src_val / bpf; break; case GST_FORMAT_TIME: *dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, - audiorate->rate * audiorate->bytes_per_sample); + rate * bpf); break; default: return FALSE;; @@ -422,14 +408,13 @@ gst_audio_rate_convert (GstAudioRate * audiorate, switch (dest_fmt) { case GST_FORMAT_BYTES: *dest_val = gst_util_uint64_scale_int (src_val, - audiorate->rate * audiorate->bytes_per_sample, GST_SECOND); + rate * bpf, GST_SECOND); break; case GST_FORMAT_DEFAULT: - *dest_val = - gst_util_uint64_scale_int (src_val, audiorate->rate, GST_SECOND); + *dest_val = gst_util_uint64_scale_int (src_val, rate, GST_SECOND); break; default: - return FALSE;; + return FALSE; } break; default: @@ -493,11 +478,15 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf) guint in_size; GstFlowReturn ret = GST_FLOW_OK; GstClockTimeDiff diff; + gint rate, bpf; audiorate = GST_AUDIO_RATE (gst_pad_get_parent (pad)); + rate = GST_AUDIO_INFO_RATE (&audiorate->info); + bpf = GST_AUDIO_INFO_BPF (&audiorate->info); + /* need to be negotiated now */ - if (audiorate->bytes_per_sample == 0) + if (bpf == 0) goto not_negotiated; /* we have a new pending segment */ @@ -514,7 +503,7 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf) */ /* convert first timestamp of segment to sample position */ pos = gst_util_uint64_scale_int (audiorate->src_segment.start, - audiorate->rate, GST_SECOND); + GST_AUDIO_INFO_RATE (&audiorate->info), GST_SECOND); GST_DEBUG_OBJECT (audiorate, "resync to offset %" G_GINT64_FORMAT, pos); @@ -523,12 +512,12 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf) audiorate->next_offset = pos; audiorate->next_ts = gst_util_uint64_scale_int (audiorate->next_offset, - GST_SECOND, audiorate->rate); + GST_SECOND, GST_AUDIO_INFO_RATE (&audiorate->info)); if (audiorate->skip_to_first && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { GST_DEBUG_OBJECT (audiorate, "but skipping to first buffer instead"); pos = gst_util_uint64_scale_int (GST_BUFFER_TIMESTAMP (buf), - audiorate->rate, GST_SECOND); + GST_AUDIO_INFO_RATE (&audiorate->info), GST_SECOND); GST_DEBUG_OBJECT (audiorate, "so resync to offset %" G_GINT64_FORMAT, pos); audiorate->next_offset = pos; @@ -545,11 +534,10 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf) } in_size = gst_buffer_get_size (buf); - in_samples = in_size / audiorate->bytes_per_sample; + in_samples = in_size / bpf; /* calculate the buffer offset */ - in_offset = gst_util_uint64_scale_int_round (in_time, audiorate->rate, - GST_SECOND); + in_offset = gst_util_uint64_scale_int_round (in_time, rate, GST_SECOND); in_offset_end = in_offset + in_samples; GST_LOG_OBJECT (audiorate, @@ -557,7 +545,7 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf) ", in_size:%u, in_offset:%" G_GUINT64_FORMAT ", in_offset_end:%" G_GUINT64_FORMAT ", ->next_offset:%" G_GUINT64_FORMAT ", ->next_ts:%" GST_TIME_FORMAT, GST_TIME_ARGS (in_time), - GST_TIME_ARGS (GST_FRAMES_TO_CLOCK_TIME (in_samples, audiorate->rate)), + GST_TIME_ARGS (GST_FRAMES_TO_CLOCK_TIME (in_samples, rate)), in_size, in_offset, in_offset_end, audiorate->next_offset, GST_TIME_ARGS (audiorate->next_ts)); @@ -587,11 +575,11 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf) fillsamples = in_offset - audiorate->next_offset; while (fillsamples > 0) { - guint64 cursamples = MIN (fillsamples, audiorate->rate); + guint64 cursamples = MIN (fillsamples, rate); guint8 *data; fillsamples -= cursamples; - fillsize = cursamples * audiorate->bytes_per_sample; + fillsize = cursamples * bpf; fill = gst_buffer_new_and_alloc (fillsize); @@ -612,7 +600,7 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf) * streams */ GST_BUFFER_TIMESTAMP (fill) = audiorate->next_ts; audiorate->next_ts = gst_util_uint64_scale_int (audiorate->next_offset, - GST_SECOND, audiorate->rate); + GST_SECOND, rate); GST_BUFFER_DURATION (fill) = audiorate->next_ts - GST_BUFFER_TIMESTAMP (fill); @@ -638,7 +626,7 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf) } else if (in_offset < audiorate->next_offset) { /* need to remove samples */ if (in_offset_end <= audiorate->next_offset) { - guint64 drop = in_size / audiorate->bytes_per_sample; + guint64 drop = in_size / bpf; audiorate->drop += drop; @@ -660,7 +648,7 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf) /* truncate buffer */ truncsamples = audiorate->next_offset - in_offset; - truncsize = truncsamples * audiorate->bytes_per_sample; + truncsize = truncsamples * bpf; leftsize = in_size - truncsize; trunc = @@ -690,7 +678,7 @@ send: GST_BUFFER_TIMESTAMP (buf) = audiorate->next_ts; audiorate->next_ts = gst_util_uint64_scale_int (in_offset_end, - GST_SECOND, audiorate->rate); + GST_SECOND, rate); GST_BUFFER_DURATION (buf) = audiorate->next_ts - GST_BUFFER_TIMESTAMP (buf); if (audiorate->discont) { @@ -804,8 +792,8 @@ gst_audio_rate_change_state (GstElement * element, GstStateChange transition) audiorate->in = 0; audiorate->out = 0; audiorate->drop = 0; - audiorate->bytes_per_sample = 0; audiorate->add = 0; + gst_audio_info_init (&audiorate->info); gst_audio_rate_reset (audiorate); break; default: diff --git a/gst/audiorate/gstaudiorate.h b/gst/audiorate/gstaudiorate.h index f2eafcfc9b..b0b191efd0 100644 --- a/gst/audiorate/gstaudiorate.h +++ b/gst/audiorate/gstaudiorate.h @@ -51,8 +51,7 @@ struct _GstAudioRate GstPad *sinkpad, *srcpad; /* audio format */ - gint bytes_per_sample; - gint rate; + GstAudioInfo info; /* stats */ guint64 in, out, add, drop; diff --git a/gst/audioresample/Makefile.am b/gst/audioresample/Makefile.am index f2be5c702a..9c2999c8dd 100644 --- a/gst/audioresample/Makefile.am +++ b/gst/audioresample/Makefile.am @@ -20,6 +20,7 @@ libgstaudioresample_la_CFLAGS = \ $(ORC_CFLAGS) libgstaudioresample_la_LIBADD = \ + $(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la \ $(GST_BASE_LIBS) \ $(GST_LIBS) \ $(ORC_LIBS) $(ORC_TEST_LIBS) \ diff --git a/gst/audioresample/gstaudioresample.c b/gst/audioresample/gstaudioresample.c index 5b9e162b0a..29464b0b3e 100644 --- a/gst/audioresample/gstaudioresample.c +++ b/gst/audioresample/gstaudioresample.c @@ -28,7 +28,7 @@ * * Example launch line * |[ - * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! audio/x-raw-int, rate=8000 ! alsasink + * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! audio/x-raw, rate=8000 ! alsasink * ]| Decode an Ogg/Vorbis downsample to 8Khz and play sound through alsa. * To create the Ogg/Vorbis file refer to the documentation of vorbisenc. * @@ -65,42 +65,13 @@ enum PROP_QUALITY }; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN #define SUPPORTED_CAPS \ -GST_STATIC_CAPS ( \ - "audio/x-raw-float, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) { 32, 64 }; " \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 32, " \ - "depth = (int) 32, " \ - "signed = (boolean) true; " \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 24, " \ - "depth = (int) 24, " \ - "signed = (boolean) true; " \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 16, " \ - "depth = (int) 16, " \ - "signed = (boolean) true; " \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 8, " \ - "depth = (int) 8, " \ - "signed = (boolean) true" \ -) + GST_AUDIO_CAPS_MAKE ("{ F32_LE, F64_LE, S32_LE, S24_3LE, S16_LE, S8 }") +#else +#define SUPPORTED_CAPS \ + GST_AUDIO_CAPS_MAKE ("{ F32_BE, F64_BE, S32_BE, S24_3BE, S16_BE, S8 }") +#endif /* If TRUE integer arithmetic resampling is faster and will be used if appropiate */ #if defined AUDIORESAMPLE_FORMAT_INT @@ -113,11 +84,15 @@ static gboolean gst_audio_resample_use_int = FALSE; static GstStaticPadTemplate gst_audio_resample_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS); + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SUPPORTED_CAPS)); static GstStaticPadTemplate gst_audio_resample_src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS); + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SUPPORTED_CAPS)); static void gst_audio_resample_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -252,9 +227,6 @@ gst_audio_resample_stop (GstBaseTransform * base) resample->tmp_out = NULL; resample->tmp_out_size = 0; - gst_caps_replace (&resample->sinkcaps, NULL); - gst_caps_replace (&resample->srccaps, NULL); - return TRUE; } @@ -262,23 +234,21 @@ static gboolean gst_audio_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps, gsize * size) { - gint width, channels; - GstStructure *structure; - gboolean ret; + GstAudioInfo info; - g_return_val_if_fail (size != NULL, FALSE); + if (!gst_audio_info_from_caps (&info, caps)) + goto invalid_caps; - /* this works for both float and int */ - structure = gst_caps_get_structure (caps, 0); - ret = gst_structure_get_int (structure, "width", &width); - ret &= gst_structure_get_int (structure, "channels", &channels); - - if (G_UNLIKELY (!ret)) - return FALSE; - - *size = (width / 8) * channels; + *size = GST_AUDIO_INFO_BPF (&info); return TRUE; + + /* ERRORS */ +invalid_caps: + { + GST_ERROR_OBJECT (base, "invalid caps"); + return FALSE; + } } static GstCaps * @@ -455,63 +425,6 @@ gst_audio_resample_reset_state (GstAudioResample * resample) resample->funcs->reset_mem (resample->state); } -static gboolean -gst_audio_resample_parse_caps (GstCaps * incaps, - GstCaps * outcaps, gint * width, gint * channels, gint * inrate, - gint * outrate, gboolean * fp) -{ - GstStructure *structure; - gboolean ret; - gint mywidth, myinrate, myoutrate, mychannels; - gboolean myfp; - - GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %" - GST_PTR_FORMAT, incaps, outcaps); - - structure = gst_caps_get_structure (incaps, 0); - - if (gst_structure_has_name (structure, "audio/x-raw-float")) - myfp = TRUE; - else - myfp = FALSE; - - ret = gst_structure_get_int (structure, "rate", &myinrate); - ret &= gst_structure_get_int (structure, "channels", &mychannels); - ret &= gst_structure_get_int (structure, "width", &mywidth); - if (G_UNLIKELY (!ret)) - goto no_in_rate_channels; - - structure = gst_caps_get_structure (outcaps, 0); - ret = gst_structure_get_int (structure, "rate", &myoutrate); - if (G_UNLIKELY (!ret)) - goto no_out_rate; - - if (channels) - *channels = mychannels; - if (inrate) - *inrate = myinrate; - if (outrate) - *outrate = myoutrate; - if (width) - *width = mywidth; - if (fp) - *fp = myfp; - - return TRUE; - - /* ERRORS */ -no_in_rate_channels: - { - GST_DEBUG ("could not get input rate and channels"); - return FALSE; - } -no_out_rate: - { - GST_DEBUG ("could not get output rate"); - return FALSE; - } -} - static gint _gcd (gint a, gint b) { @@ -531,26 +444,29 @@ gst_audio_resample_transform_size (GstBaseTransform * base, gsize * othersize) { gboolean ret = TRUE; + GstAudioInfo in, out; guint32 ratio_den, ratio_num; gint inrate, outrate, gcd; - gint bytes_per_samp, channels; + gint bpf; GST_LOG_OBJECT (base, "asked to transform size %" G_GSIZE_FORMAT " in direction %s", size, direction == GST_PAD_SINK ? "SINK" : "SRC"); /* Get sample width -> bytes_per_samp, channels, inrate, outrate */ - ret = - gst_audio_resample_parse_caps (caps, othercaps, &bytes_per_samp, - &channels, &inrate, &outrate, NULL); + ret = gst_audio_info_from_caps (&in, caps); + ret &= gst_audio_info_from_caps (&out, othercaps); if (G_UNLIKELY (!ret)) { GST_ERROR_OBJECT (base, "Wrong caps"); return FALSE; } /* Number of samples in either buffer is size / (width*channels) -> * calculate the factor */ - bytes_per_samp = bytes_per_samp * channels / 8; + bpf = GST_AUDIO_INFO_BPF (&in); + inrate = GST_AUDIO_INFO_RATE (&in); + outrate = GST_AUDIO_INFO_RATE (&out); + /* Convert source buffer size to samples */ - size /= bytes_per_samp; + size /= bpf; /* Simplify the conversion ratio factors */ gcd = _gcd (inrate, outrate); @@ -560,16 +476,16 @@ gst_audio_resample_transform_size (GstBaseTransform * base, if (direction == GST_PAD_SINK) { /* asked to convert size of an incoming buffer. Round up the output size */ *othersize = gst_util_uint64_scale_int_ceil (size, ratio_den, ratio_num); - *othersize *= bytes_per_samp; + *othersize *= bpf; } else { /* asked to convert size of an outgoing buffer. Round down the input size */ *othersize = gst_util_uint64_scale_int (size, ratio_num, ratio_den); - *othersize *= bytes_per_samp; + *othersize *= bpf; } GST_LOG_OBJECT (base, "transformed size %" G_GSIZE_FORMAT " to %" G_GSIZE_FORMAT, - size * bytes_per_samp, *othersize); + size * bpf, *othersize); return ret; } @@ -579,18 +495,27 @@ gst_audio_resample_set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps) { gboolean ret; - gint width = 0, inrate = 0, outrate = 0, channels = 0; + gint width, inrate, outrate, channels; gboolean fp; GstAudioResample *resample = GST_AUDIO_RESAMPLE (base); + GstAudioInfo in, out; GST_LOG ("incaps %" GST_PTR_FORMAT ", outcaps %" GST_PTR_FORMAT, incaps, outcaps); - ret = gst_audio_resample_parse_caps (incaps, outcaps, - &width, &channels, &inrate, &outrate, &fp); + if (!gst_audio_info_from_caps (&in, incaps)) + goto invalid_incaps; + if (!gst_audio_info_from_caps (&out, outcaps)) + goto invalid_outcaps; - if (G_UNLIKELY (!ret)) - return FALSE; + /* FIXME do some checks */ + + /* take new values */ + width = GST_AUDIO_FORMAT_INFO_WIDTH (in.finfo); + channels = GST_AUDIO_INFO_CHANNELS (&in); + inrate = GST_AUDIO_INFO_RATE (&in); + outrate = GST_AUDIO_INFO_RATE (&out); + fp = GST_AUDIO_FORMAT_INFO_IS_FLOAT (in.finfo); ret = gst_audio_resample_update_state (resample, width, channels, inrate, @@ -599,12 +524,19 @@ gst_audio_resample_set_caps (GstBaseTransform * base, GstCaps * incaps, if (G_UNLIKELY (!ret)) return FALSE; - /* save caps so we can short-circuit in the size_transform if the caps - * are the same */ - gst_caps_replace (&resample->sinkcaps, incaps); - gst_caps_replace (&resample->srccaps, outcaps); - return TRUE; + + /* ERROR */ +invalid_incaps: + { + GST_ERROR_OBJECT (base, "invalid incaps"); + return FALSE; + } +invalid_outcaps: + { + GST_ERROR_OBJECT (base, "invalid outcaps"); + return FALSE; + } } #define GST_MAXINT24 (8388607) diff --git a/gst/audioresample/gstaudioresample.h b/gst/audioresample/gstaudioresample.h index f5f746482d..da75b64581 100644 --- a/gst/audioresample/gstaudioresample.h +++ b/gst/audioresample/gstaudioresample.h @@ -53,9 +53,6 @@ struct _GstAudioResample { GstBaseTransform element; /* */ - - GstCaps *srccaps, *sinkcaps; - gboolean need_discont; GstClockTime t0; @@ -67,12 +64,18 @@ struct _GstAudioResample { guint64 num_gap_samples; guint64 num_nongap_samples; + GstAudioInfo in; + GstAudioInfo out; + + /* properties */ + gint quality; + + /* state */ + gboolean fp; + gint width; gint channels; gint inrate; gint outrate; - gint quality; - gint width; - gboolean fp; guint8 *tmp_in; guint tmp_in_size; diff --git a/gst/audiotestsrc/Makefile.am b/gst/audiotestsrc/Makefile.am index 67a2c0bbb2..c00f9ff1cc 100644 --- a/gst/audiotestsrc/Makefile.am +++ b/gst/audiotestsrc/Makefile.am @@ -1,9 +1,11 @@ plugin_LTLIBRARIES = libgstaudiotestsrc.la libgstaudiotestsrc_la_SOURCES = gstaudiotestsrc.c -libgstaudiotestsrc_la_CFLAGS = $(GST_CFLAGS) $(GST_CONTROLLER_CFLAGS) +libgstaudiotestsrc_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GST_CONTROLLER_CFLAGS) libgstaudiotestsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstaudiotestsrc_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(GST_CONTROLLER_LIBS) $(LIBM) +libgstaudiotestsrc_la_LIBADD = \ + $(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la \ + $(GST_BASE_LIBS) $(GST_LIBS) $(GST_CONTROLLER_LIBS) $(LIBM) libgstaudiotestsrc_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = gstaudiotestsrc.h diff --git a/gst/audiotestsrc/gstaudiotestsrc.c b/gst/audiotestsrc/gstaudiotestsrc.c index 84432695ad..b545787f2c 100644 --- a/gst/audiotestsrc/gstaudiotestsrc.c +++ b/gst/audiotestsrc/gstaudiotestsrc.c @@ -76,28 +76,20 @@ enum PROP_LAST }; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define FORMAT_STR "{ S16_LE, S32_LE, F32_LE, F64_LE }" +#define DEFAULT_FORMAT_STR "S16_LE" +#else +#define FORMAT_STR "{ S16_BE, S32_BE, F32_BE, F64_BE }" +#define DEFAULT_FORMAT_STR "S16_BE" +#endif static GstStaticPadTemplate gst_audio_test_src_src_template = - GST_STATIC_PAD_TEMPLATE ("src", +GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "endianness = (int) BYTE_ORDER, " - "signed = (boolean) true, " - "width = (int) 16, " - "depth = (int) 16, " - "rate = (int) [ 1, MAX ], " - "channels = (int) [ 1, 2 ]; " - "audio/x-raw-int, " - "endianness = (int) BYTE_ORDER, " - "signed = (boolean) true, " - "width = (int) 32, " - "depth = (int) 32," - "rate = (int) [ 1, MAX ], " - "channels = (int) [ 1, 2 ]; " - "audio/x-raw-float, " - "endianness = (int) BYTE_ORDER, " - "width = (int) { 32, 64 }, " + GST_STATIC_CAPS ("audio/x-raw, " + "format = (string) " FORMAT_STR ", " "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]") ); @@ -234,9 +226,6 @@ gst_audio_test_src_class_init (GstAudioTestSrcClass * klass) static void gst_audio_test_src_init (GstAudioTestSrc * src) { - src->samplerate = 44100; - src->format = GST_AUDIO_TEST_SRC_FORMAT_NONE; - src->volume = DEFAULT_VOLUME; src->freq = DEFAULT_FREQ; @@ -271,20 +260,16 @@ static void gst_audio_test_src_fixate (GstBaseSrc * bsrc, GstCaps * caps) { GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (bsrc); - const gchar *name; GstStructure *structure; structure = gst_caps_get_structure (caps, 0); - GST_DEBUG_OBJECT (src, "fixating samplerate to %d", src->samplerate); + GST_DEBUG_OBJECT (src, "fixating samplerate to %d", GST_AUDIO_DEF_RATE); - gst_structure_fixate_field_nearest_int (structure, "rate", src->samplerate); + gst_structure_fixate_field_nearest_int (structure, "rate", + GST_AUDIO_DEF_RATE); - name = gst_structure_get_name (structure); - if (strcmp (name, "audio/x-raw-int") == 0) - gst_structure_fixate_field_nearest_int (structure, "width", 32); - else if (strcmp (name, "audio/x-raw-float") == 0) - gst_structure_fixate_field_nearest_int (structure, "width", 64); + gst_structure_fixate_field_string (structure, "format", DEFAULT_FORMAT_STR); /* fixate to mono unless downstream requires stereo, for backwards compat */ gst_structure_fixate_field_nearest_int (structure, "channels", 1); @@ -296,53 +281,25 @@ static gboolean gst_audio_test_src_setcaps (GstBaseSrc * basesrc, GstCaps * caps) { GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (basesrc); - const GstStructure *structure; - const gchar *name; - gint width; - gboolean ret; + GstAudioInfo info; - structure = gst_caps_get_structure (caps, 0); - ret = gst_structure_get_int (structure, "rate", &src->samplerate); + if (!gst_audio_info_from_caps (&info, caps)) + goto invalid_caps; - GST_DEBUG_OBJECT (src, "negotiated to samplerate %d", src->samplerate); + GST_DEBUG_OBJECT (src, "negotiated to caps %" GST_PTR_FORMAT, caps); - name = gst_structure_get_name (structure); - if (strcmp (name, "audio/x-raw-int") == 0) { - ret &= gst_structure_get_int (structure, "width", &width); - src->format = (width == 32) ? GST_AUDIO_TEST_SRC_FORMAT_S32 : - GST_AUDIO_TEST_SRC_FORMAT_S16; - } else { - ret &= gst_structure_get_int (structure, "width", &width); - src->format = (width == 32) ? GST_AUDIO_TEST_SRC_FORMAT_F32 : - GST_AUDIO_TEST_SRC_FORMAT_F64; - } - - /* allocate a new buffer suitable for this pad */ - switch (src->format) { - case GST_AUDIO_TEST_SRC_FORMAT_S16: - src->sample_size = sizeof (gint16); - break; - case GST_AUDIO_TEST_SRC_FORMAT_S32: - src->sample_size = sizeof (gint32); - break; - case GST_AUDIO_TEST_SRC_FORMAT_F32: - src->sample_size = sizeof (gfloat); - break; - case GST_AUDIO_TEST_SRC_FORMAT_F64: - src->sample_size = sizeof (gdouble); - break; - default: - /* can't really happen */ - ret = FALSE; - break; - } - - ret &= gst_structure_get_int (structure, "channels", &src->channels); - GST_DEBUG_OBJECT (src, "negotiated to %d channels", src->channels); + src->info = info; gst_audio_test_src_change_wave (src); - return ret; + return TRUE; + + /* ERROR */ +invalid_caps: + { + GST_ERROR_OBJECT (basesrc, "received invalid caps"); + return FALSE; + } } static gboolean @@ -356,6 +313,7 @@ gst_audio_test_src_query (GstBaseSrc * basesrc, GstQuery * query) { GstFormat src_fmt, dest_fmt; gint64 src_val, dest_val; + gint rate; gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); if (src_fmt == dest_fmt) { @@ -363,14 +321,14 @@ gst_audio_test_src_query (GstBaseSrc * basesrc, GstQuery * query) goto done; } + rate = GST_AUDIO_INFO_RATE (&src->info); + switch (src_fmt) { case GST_FORMAT_DEFAULT: switch (dest_fmt) { case GST_FORMAT_TIME: /* samples to time */ - dest_val = - gst_util_uint64_scale_int (src_val, GST_SECOND, - src->samplerate); + dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, rate); break; default: goto error; @@ -380,9 +338,7 @@ gst_audio_test_src_query (GstBaseSrc * basesrc, GstQuery * query) switch (dest_fmt) { case GST_FORMAT_DEFAULT: /* time to samples */ - dest_val = - gst_util_uint64_scale_int (src_val, src->samplerate, - GST_SECOND); + dest_val = gst_util_uint64_scale_int (src_val, rate, GST_SECOND); break; default: goto error; @@ -422,19 +378,20 @@ error: static void \ gst_audio_test_src_create_sine_##type (GstAudioTestSrc * src, g##type * samples) \ { \ - gint i, c; \ + gint i, c, channels; \ gdouble step, amp; \ \ - step = M_PI_M2 * src->freq / src->samplerate; \ + channels = GST_AUDIO_INFO_CHANNELS (&src->info); \ + step = M_PI_M2 * src->freq / GST_AUDIO_INFO_RATE (&src->info); \ amp = src->volume * scale; \ \ i = 0; \ - while (i < (src->generate_samples_per_buffer * src->channels)) { \ + while (i < (src->generate_samples_per_buffer * channels)) { \ src->accumulator += step; \ if (src->accumulator >= M_PI_M2) \ src->accumulator -= M_PI_M2; \ \ - for (c = 0; c < src->channels; ++c) { \ + for (c = 0; c < channels; ++c) { \ samples[i++] = (g##type) (sin (src->accumulator) * amp); \ } \ } \ @@ -456,19 +413,20 @@ static const ProcessFunc sine_funcs[] = { static void \ gst_audio_test_src_create_square_##type (GstAudioTestSrc * src, g##type * samples) \ { \ - gint i, c; \ + gint i, c, channels; \ gdouble step, amp; \ \ - step = M_PI_M2 * src->freq / src->samplerate; \ + channels = GST_AUDIO_INFO_CHANNELS (&src->info); \ + step = M_PI_M2 * src->freq / GST_AUDIO_INFO_RATE (&src->info); \ amp = src->volume * scale; \ \ i = 0; \ - while (i < (src->generate_samples_per_buffer * src->channels)) { \ + while (i < (src->generate_samples_per_buffer * channels)) { \ src->accumulator += step; \ if (src->accumulator >= M_PI_M2) \ src->accumulator -= M_PI_M2; \ \ - for (c = 0; c < src->channels; ++c) { \ + for (c = 0; c < channels; ++c) { \ samples[i++] = (g##type) ((src->accumulator < G_PI) ? amp : -amp); \ } \ } \ @@ -490,23 +448,24 @@ static const ProcessFunc square_funcs[] = { static void \ gst_audio_test_src_create_saw_##type (GstAudioTestSrc * src, g##type * samples) \ { \ - gint i, c; \ + gint i, c, channels; \ gdouble step, amp; \ \ - step = M_PI_M2 * src->freq / src->samplerate; \ + channels = GST_AUDIO_INFO_CHANNELS (&src->info); \ + step = M_PI_M2 * src->freq / GST_AUDIO_INFO_RATE (&src->info); \ amp = (src->volume * scale) / G_PI; \ \ i = 0; \ - while (i < (src->generate_samples_per_buffer * src->channels)) { \ + while (i < (src->generate_samples_per_buffer * channels)) { \ src->accumulator += step; \ if (src->accumulator >= M_PI_M2) \ src->accumulator -= M_PI_M2; \ \ if (src->accumulator < G_PI) { \ - for (c = 0; c < src->channels; ++c) \ + for (c = 0; c < channels; ++c) \ samples[i++] = (g##type) (src->accumulator * amp); \ } else { \ - for (c = 0; c < src->channels; ++c) \ + for (c = 0; c < channels; ++c) \ samples[i++] = (g##type) ((M_PI_M2 - src->accumulator) * -amp); \ } \ } \ @@ -528,26 +487,27 @@ static const ProcessFunc saw_funcs[] = { static void \ gst_audio_test_src_create_triangle_##type (GstAudioTestSrc * src, g##type * samples) \ { \ - gint i, c; \ + gint i, c, channels; \ gdouble step, amp; \ \ - step = M_PI_M2 * src->freq / src->samplerate; \ + channels = GST_AUDIO_INFO_CHANNELS (&src->info); \ + step = M_PI_M2 * src->freq / GST_AUDIO_INFO_RATE (&src->info); \ amp = (src->volume * scale) / G_PI_2; \ \ i = 0; \ - while (i < (src->generate_samples_per_buffer * src->channels)) { \ + while (i < (src->generate_samples_per_buffer * channels)) { \ src->accumulator += step; \ if (src->accumulator >= M_PI_M2) \ src->accumulator -= M_PI_M2; \ \ if (src->accumulator < (G_PI_2)) { \ - for (c = 0; c < src->channels; ++c) \ + for (c = 0; c < channels; ++c) \ samples[i++] = (g##type) (src->accumulator * amp); \ } else if (src->accumulator < (G_PI * 1.5)) { \ - for (c = 0; c < src->channels; ++c) \ + for (c = 0; c < channels; ++c) \ samples[i++] = (g##type) ((src->accumulator - G_PI) * -amp); \ } else { \ - for (c = 0; c < src->channels; ++c) \ + for (c = 0; c < channels; ++c) \ samples[i++] = (g##type) ((M_PI_M2 - src->accumulator) * -amp); \ } \ } \ @@ -569,7 +529,7 @@ static const ProcessFunc triangle_funcs[] = { static void \ gst_audio_test_src_create_silence_##type (GstAudioTestSrc * src, g##type * samples) \ { \ - memset (samples, 0, src->generate_samples_per_buffer * sizeof (g##type) * src->channels); \ + memset (samples, 0, src->generate_samples_per_buffer * sizeof (g##type) * src->info.channels); \ } DEFINE_SILENCE (int16); @@ -590,10 +550,11 @@ gst_audio_test_src_create_white_noise_##type (GstAudioTestSrc * src, g##type * s { \ gint i, c; \ gdouble amp = (src->volume * scale); \ + gint channels = GST_AUDIO_INFO_CHANNELS (&src->info); \ \ i = 0; \ - while (i < (src->generate_samples_per_buffer * src->channels)) { \ - for (c = 0; c < src->channels; ++c) \ + while (i < (src->generate_samples_per_buffer * channels)) { \ + for (c = 0; c < channels; ++c) \ samples[i++] = (g##type) (amp * g_rand_double_range (src->gen, -1.0, 1.0)); \ } \ } @@ -681,14 +642,15 @@ gst_audio_test_src_generate_pink_noise_value (GstAudioTestSrc * src) static void \ gst_audio_test_src_create_pink_noise_##type (GstAudioTestSrc * src, g##type * samples) \ { \ - gint i, c; \ + gint i, c, channels; \ gdouble amp; \ \ amp = src->volume * scale; \ + channels = GST_AUDIO_INFO_CHANNELS (&src->info); \ \ i = 0; \ - while (i < (src->generate_samples_per_buffer * src->channels)) { \ - for (c = 0; c < src->channels; ++c) { \ + while (i < (src->generate_samples_per_buffer * channels)) { \ + for (c = 0; c < channels; ++c) { \ samples[i++] = \ (g##type) (gst_audio_test_src_generate_pink_noise_value (src) * \ amp); \ @@ -726,19 +688,20 @@ gst_audio_test_src_init_sine_table (GstAudioTestSrc * src) static void \ gst_audio_test_src_create_sine_table_##type (GstAudioTestSrc * src, g##type * samples) \ { \ - gint i, c; \ + gint i, c, channels; \ gdouble step, scl; \ \ - step = M_PI_M2 * src->freq / src->samplerate; \ + channels = GST_AUDIO_INFO_CHANNELS (&src->info); \ + step = M_PI_M2 * src->freq / GST_AUDIO_INFO_RATE (&src->info); \ scl = 1024.0 / M_PI_M2; \ \ i = 0; \ - while (i < (src->generate_samples_per_buffer * src->channels)) { \ + while (i < (src->generate_samples_per_buffer * channels)) { \ src->accumulator += step; \ if (src->accumulator >= M_PI_M2) \ src->accumulator -= M_PI_M2; \ \ - for (c = 0; c < src->channels; ++c) \ + for (c = 0; c < channels; ++c) \ samples[i++] = (g##type) scale * src->wave_table[(gint) (src->accumulator * scl)]; \ } \ } @@ -759,10 +722,12 @@ static const ProcessFunc sine_table_funcs[] = { static void \ gst_audio_test_src_create_tick_##type (GstAudioTestSrc * src, g##type * samples) \ { \ - gint i, c; \ + gint i, c, channels, samplerate; \ gdouble step, scl; \ \ - step = M_PI_M2 * src->freq / src->samplerate; \ + channels = GST_AUDIO_INFO_CHANNELS (&src->info); \ + samplerate = GST_AUDIO_INFO_RATE (&src->info); \ + step = M_PI_M2 * src->freq / samplerate; \ scl = 1024.0 / M_PI_M2; \ \ for (i = 0; i < src->generate_samples_per_buffer; i++) { \ @@ -770,12 +735,12 @@ gst_audio_test_src_create_tick_##type (GstAudioTestSrc * src, g##type * samples) if (src->accumulator >= M_PI_M2) \ src->accumulator -= M_PI_M2; \ \ - if ((src->next_sample + i)%src->samplerate < 1600) { \ - for (c = 0; c < src->channels; ++c) \ - samples[(i * src->channels) + c] = (g##type) scale * src->wave_table[(gint) (src->accumulator * scl)]; \ + if ((src->next_sample + i)%samplerate < 1600) { \ + for (c = 0; c < channels; ++c) \ + samples[(i * channels) + c] = (g##type) scale * src->wave_table[(gint) (src->accumulator * scl)]; \ } else { \ - for (c = 0; c < src->channels; ++c) \ - samples[(i * src->channels) + c] = 0; \ + for (c = 0; c < channels; ++c) \ + samples[(i * channels) + c] = 0; \ } \ } \ } @@ -804,14 +769,15 @@ gst_audio_test_src_create_gaussian_white_noise_##type (GstAudioTestSrc * src, g# { \ gint i, c; \ gdouble amp = (src->volume * scale); \ + gint channels = GST_AUDIO_INFO_CHANNELS (&src->info); \ \ - for (i = 0; i < src->generate_samples_per_buffer * src->channels; ) { \ - for (c = 0; c < src->channels; ++c) { \ + for (i = 0; i < src->generate_samples_per_buffer * channels; ) { \ + for (c = 0; c < channels; ++c) { \ gdouble mag = sqrt (-2 * log (1.0 - g_rand_double (src->gen))); \ gdouble phs = g_rand_double_range (src->gen, 0.0, M_PI_M2); \ \ samples[i++] = (g##type) (amp * mag * cos (phs)); \ - if (++c >= src->channels) \ + if (++c >= channels) \ break; \ samples[i++] = (g##type) (amp * mag * sin (phs)); \ } \ @@ -844,9 +810,10 @@ gst_audio_test_src_create_red_noise_##type (GstAudioTestSrc * src, g##type * sam gint i, c; \ gdouble amp = (src->volume * scale); \ gdouble state = src->red.state; \ + gint channels = GST_AUDIO_INFO_CHANNELS (&src->info); \ \ - for (i = 0; i < src->generate_samples_per_buffer * src->channels; ) { \ - for (c = 0; c < src->channels; ++c) { \ + for (i = 0; i < src->generate_samples_per_buffer * channels; ) { \ + for (c = 0; c < channels; ++c) { \ while (TRUE) { \ gdouble r = g_rand_double_range (src->gen, -1.0, 1.0); \ state += r; \ @@ -879,10 +846,11 @@ gst_audio_test_src_create_blue_noise_##type (GstAudioTestSrc * src, g##type * sa { \ gint i, c; \ static gdouble flip=1.0; \ + gint channels = GST_AUDIO_INFO_CHANNELS (&src->info); \ \ gst_audio_test_src_create_pink_noise_##type (src, samples); \ - for (i = 0; i < src->generate_samples_per_buffer * src->channels; ) { \ - for (c = 0; c < src->channels; ++c) { \ + for (i = 0; i < src->generate_samples_per_buffer * channels; ) { \ + for (c = 0; c < channels; ++c) { \ samples[i++] *= flip; \ } \ flip *= -1.0; \ @@ -910,10 +878,11 @@ gst_audio_test_src_create_violet_noise_##type (GstAudioTestSrc * src, g##type * { \ gint i, c; \ static gdouble flip=1.0; \ + gint channels = GST_AUDIO_INFO_CHANNELS (&src->info); \ \ gst_audio_test_src_create_red_noise_##type (src, samples); \ - for (i = 0; i < src->generate_samples_per_buffer * src->channels; ) { \ - for (c = 0; c < src->channels; ++c) { \ + for (i = 0; i < src->generate_samples_per_buffer * channels; ) { \ + for (c = 0; c < channels; ++c) { \ samples[i++] *= flip; \ } \ flip *= -1.0; \ @@ -940,68 +909,83 @@ static const ProcessFunc violet_noise_funcs[] = { static void gst_audio_test_src_change_wave (GstAudioTestSrc * src) { - if (src->format == -1) { - src->process = NULL; - return; + gint idx; + + switch (GST_AUDIO_FORMAT_INFO_FORMAT (src->info.finfo)) { + case GST_AUDIO_FORMAT_S16: + idx = 0; + break; + case GST_AUDIO_FORMAT_S32: + idx = 1; + break; + case GST_AUDIO_FORMAT_F32: + idx = 2; + break; + case GST_AUDIO_FORMAT_F64: + idx = 3; + break; + default: + src->process = NULL; + return; } switch (src->wave) { case GST_AUDIO_TEST_SRC_WAVE_SINE: - src->process = sine_funcs[src->format]; + src->process = sine_funcs[idx]; break; case GST_AUDIO_TEST_SRC_WAVE_SQUARE: - src->process = square_funcs[src->format]; + src->process = square_funcs[idx]; break; case GST_AUDIO_TEST_SRC_WAVE_SAW: - src->process = saw_funcs[src->format]; + src->process = saw_funcs[idx]; break; case GST_AUDIO_TEST_SRC_WAVE_TRIANGLE: - src->process = triangle_funcs[src->format]; + src->process = triangle_funcs[idx]; break; case GST_AUDIO_TEST_SRC_WAVE_SILENCE: - src->process = silence_funcs[src->format]; + src->process = silence_funcs[idx]; break; case GST_AUDIO_TEST_SRC_WAVE_WHITE_NOISE: if (!(src->gen)) src->gen = g_rand_new (); - src->process = white_noise_funcs[src->format]; + src->process = white_noise_funcs[idx]; break; case GST_AUDIO_TEST_SRC_WAVE_PINK_NOISE: if (!(src->gen)) src->gen = g_rand_new (); gst_audio_test_src_init_pink_noise (src); - src->process = pink_noise_funcs[src->format]; + src->process = pink_noise_funcs[idx]; break; case GST_AUDIO_TEST_SRC_WAVE_SINE_TAB: gst_audio_test_src_init_sine_table (src); - src->process = sine_table_funcs[src->format]; + src->process = sine_table_funcs[idx]; break; case GST_AUDIO_TEST_SRC_WAVE_TICKS: gst_audio_test_src_init_sine_table (src); - src->process = tick_funcs[src->format]; + src->process = tick_funcs[idx]; break; case GST_AUDIO_TEST_SRC_WAVE_GAUSSIAN_WHITE_NOISE: if (!(src->gen)) src->gen = g_rand_new (); - src->process = gaussian_white_noise_funcs[src->format]; + src->process = gaussian_white_noise_funcs[idx]; break; case GST_AUDIO_TEST_SRC_WAVE_RED_NOISE: if (!(src->gen)) src->gen = g_rand_new (); src->red.state = 0.0; - src->process = red_noise_funcs[src->format]; + src->process = red_noise_funcs[idx]; break; case GST_AUDIO_TEST_SRC_WAVE_BLUE_NOISE: if (!(src->gen)) src->gen = g_rand_new (); gst_audio_test_src_init_pink_noise (src); - src->process = blue_noise_funcs[src->format]; + src->process = blue_noise_funcs[idx]; break; case GST_AUDIO_TEST_SRC_WAVE_VIOLET_NOISE: if (!(src->gen)) src->gen = g_rand_new (); src->red.state = 0.0; - src->process = violet_noise_funcs[src->format]; + src->process = violet_noise_funcs[idx]; default: GST_ERROR ("invalid wave-form"); break; @@ -1076,18 +1060,24 @@ gst_audio_test_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment) { GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (basesrc); GstClockTime time; + gint samplerate, bpf; GST_DEBUG_OBJECT (src, "seeking %" GST_SEGMENT_FORMAT, segment); time = segment->position; src->reverse = (segment->rate < 0.0); + samplerate = GST_AUDIO_INFO_RATE (&src->info); + bpf = GST_AUDIO_INFO_BPF (&src->info); + /* now move to the time indicated */ - src->next_sample = - gst_util_uint64_scale_int (time, src->samplerate, GST_SECOND); - src->next_byte = src->next_sample * src->sample_size * src->channels; - src->next_time = - gst_util_uint64_scale_int (src->next_sample, GST_SECOND, src->samplerate); + src->next_sample = gst_util_uint64_scale_int (time, samplerate, GST_SECOND); + src->next_byte = src->next_sample * bpf; + if (samplerate == 0) + src->next_time = 0; + else + src->next_time = + gst_util_uint64_scale_int (src->next_sample, GST_SECOND, samplerate); GST_DEBUG_OBJECT (src, "seeking next_sample=%" G_GINT64_FORMAT " next_time=%" GST_TIME_FORMAT, src->next_sample, @@ -1107,8 +1097,7 @@ gst_audio_test_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment) if (GST_CLOCK_TIME_IS_VALID (segment->stop)) { time = segment->stop; - src->sample_stop = gst_util_uint64_scale_int (time, src->samplerate, - GST_SECOND); + src->sample_stop = gst_util_uint64_scale_int (time, samplerate, GST_SECOND); src->check_seek_stop = TRUE; } else { src->check_seek_stop = FALSE; @@ -1136,6 +1125,7 @@ gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset, gint bytes, samples; GstElementClass *eclass; guint8 *data; + gint samplerate, bpf; src = GST_AUDIO_TEST_SRC (basesrc); @@ -1160,12 +1150,15 @@ gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset, return GST_FLOW_UNEXPECTED; } + samplerate = GST_AUDIO_INFO_RATE (&src->info); + bpf = GST_AUDIO_INFO_BPF (&src->info); + /* if no length was given, use our default length in samples otherwise convert * the length in bytes to samples. */ if (length == -1) samples = src->samples_per_buffer; else - samples = length / (src->sample_size * src->channels); + samples = length / bpf; /* if no offset was given, use our next logical byte */ if (offset == -1) @@ -1175,10 +1168,9 @@ gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset, if (offset != src->next_byte) { GST_DEBUG_OBJECT (src, "seek to new offset %" G_GUINT64_FORMAT, offset); /* we have a discont in the expected sample offset, do a 'seek' */ - src->next_sample = offset / (src->sample_size * src->channels); + src->next_sample = offset / bpf; src->next_time = - gst_util_uint64_scale_int (src->next_sample, GST_SECOND, - src->samplerate); + gst_util_uint64_scale_int (src->next_sample, GST_SECOND, samplerate); src->next_byte = offset; } @@ -1197,15 +1189,14 @@ gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset, next_sample = src->next_sample + (src->reverse ? (-samples) : samples); } - bytes = src->generate_samples_per_buffer * src->sample_size * src->channels; + bytes = src->generate_samples_per_buffer * bpf; buf = gst_buffer_new_and_alloc (bytes); next_byte = src->next_byte + (src->reverse ? (-bytes) : bytes); - next_time = gst_util_uint64_scale_int (next_sample, GST_SECOND, - src->samplerate); + next_time = gst_util_uint64_scale_int (next_sample, GST_SECOND, samplerate); - GST_LOG_OBJECT (src, "samplerate %d", src->samplerate); + GST_LOG_OBJECT (src, "samplerate %d", samplerate); GST_LOG_OBJECT (src, "next_sample %" G_GINT64_FORMAT ", ts %" GST_TIME_FORMAT, next_sample, GST_TIME_ARGS (next_time)); diff --git a/gst/audiotestsrc/gstaudiotestsrc.h b/gst/audiotestsrc/gstaudiotestsrc.h index 529ad63c3e..29c4285331 100644 --- a/gst/audiotestsrc/gstaudiotestsrc.h +++ b/gst/audiotestsrc/gstaudiotestsrc.h @@ -24,6 +24,8 @@ #include #include +#include + G_BEGIN_DECLS @@ -86,14 +88,6 @@ typedef struct { gdouble state; /* noise state */ } GstRedNoise; -typedef enum { - GST_AUDIO_TEST_SRC_FORMAT_NONE = -1, - GST_AUDIO_TEST_SRC_FORMAT_S16 = 0, - GST_AUDIO_TEST_SRC_FORMAT_S32, - GST_AUDIO_TEST_SRC_FORMAT_F32, - GST_AUDIO_TEST_SRC_FORMAT_F64 -} GstAudioTestSrcFormat; - typedef struct _GstAudioTestSrc GstAudioTestSrc; typedef struct _GstAudioTestSrcClass GstAudioTestSrcClass; @@ -115,11 +109,8 @@ struct _GstAudioTestSrc { gdouble freq; /* audio parameters */ - gint channels; - gint samplerate; + GstAudioInfo info; gint samples_per_buffer; - gint sample_size; - GstAudioTestSrcFormat format; /*< private >*/ gboolean tags_pushed; /* send tags just once ? */ diff --git a/gst/playback/gstrawcaps.h b/gst/playback/gstrawcaps.h index 5fb156e518..7f9ef35b52 100644 --- a/gst/playback/gstrawcaps.h +++ b/gst/playback/gstrawcaps.h @@ -27,8 +27,7 @@ G_BEGIN_DECLS #define DEFAULT_RAW_CAPS \ "video/x-raw; " \ - "audio/x-raw-int; " \ - "audio/x-raw-float; " \ + "audio/x-raw; " \ "text/plain; " \ "text/x-pango-markup; " \ "video/x-dvd-subpicture; " \ diff --git a/gst/volume/gstvolume.c b/gst/volume/gstvolume.c index 1dc37e52a3..bf76863a1e 100644 --- a/gst/volume/gstvolume.c +++ b/gst/volume/gstvolume.c @@ -104,40 +104,13 @@ enum PROP_VOLUME }; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN #define ALLOWED_CAPS \ - "audio/x-raw-float, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) {32, 64}; " \ - "audio/x-raw-int, " \ - "channels = (int) [ 1, MAX ], " \ - "rate = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 8, " \ - "depth = (int) 8, " \ - "signed = (bool) TRUE; " \ - "audio/x-raw-int, " \ - "channels = (int) [ 1, MAX ], " \ - "rate = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 16, " \ - "depth = (int) 16, " \ - "signed = (bool) TRUE; " \ - "audio/x-raw-int, " \ - "channels = (int) [ 1, MAX ], " \ - "rate = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 24, " \ - "depth = (int) 24, " \ - "signed = (bool) TRUE; " \ - "audio/x-raw-int, " \ - "channels = (int) [ 1, MAX ], " \ - "rate = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 32, " \ - "depth = (int) 32, " \ - "signed = (bool) TRUE" + GST_AUDIO_CAPS_MAKE ("{ F32_LE, F64_LE, S8, S16_LE, S24_3LE, S32_LE }") +#else +#define ALLOWED_CAPS \ + GST_AUDIO_CAPS_MAKE ("{ F32_BE, F64_BE, S8, S16_BE, S24_3BE, S32_BE }") +#endif static void gst_volume_mixer_init (GstMixerClass * iface); @@ -157,8 +130,7 @@ static void volume_before_transform (GstBaseTransform * base, static GstFlowReturn volume_transform_ip (GstBaseTransform * base, GstBuffer * outbuf); static gboolean volume_stop (GstBaseTransform * base); -static gboolean volume_setup (GstAudioFilter * filter, - GstRingBufferSpec * format); +static gboolean volume_setup (GstAudioFilter * filter, GstAudioInfo * info); static void volume_process_double (GstVolume * self, gpointer bytes, guint n_bytes); @@ -199,68 +171,61 @@ static void volume_process_controlled_int8_clamp (GstVolume * self, static gboolean volume_choose_func (GstVolume * self) { + GstAudioFilter *filter = GST_AUDIO_FILTER (self); + GstAudioFormat format; + self->process = NULL; self->process_controlled = NULL; - if (GST_AUDIO_FILTER (self)->format.caps == NULL) + format = GST_AUDIO_FORMAT_INFO_FORMAT (filter->info.finfo); + + if (format == GST_AUDIO_FORMAT_UNKNOWN) return FALSE; - switch (GST_AUDIO_FILTER (self)->format.type) { - case GST_BUFTYPE_LINEAR: - switch (GST_AUDIO_FILTER (self)->format.width) { - case 32: - /* only clamp if the gain is greater than 1.0 - */ - if (self->current_vol_i32 > VOLUME_UNITY_INT32) { - self->process = volume_process_int32_clamp; - } else { - self->process = volume_process_int32; - } - self->process_controlled = volume_process_controlled_int32_clamp; - break; - case 24: - /* only clamp if the gain is greater than 1.0 - */ - if (self->current_vol_i24 > VOLUME_UNITY_INT24) { - self->process = volume_process_int24_clamp; - } else { - self->process = volume_process_int24; - } - self->process_controlled = volume_process_controlled_int24_clamp; - break; - case 16: - /* only clamp if the gain is greater than 1.0 - */ - if (self->current_vol_i16 > VOLUME_UNITY_INT16) { - self->process = volume_process_int16_clamp; - } else { - self->process = volume_process_int16; - } - self->process_controlled = volume_process_controlled_int16_clamp; - break; - case 8: - /* only clamp if the gain is greater than 1.0 - */ - if (self->current_vol_i8 > VOLUME_UNITY_INT8) { - self->process = volume_process_int8_clamp; - } else { - self->process = volume_process_int8; - } - self->process_controlled = volume_process_controlled_int8_clamp; - break; + switch (format) { + case GST_AUDIO_FORMAT_S32: + /* only clamp if the gain is greater than 1.0 */ + if (self->current_vol_i32 > VOLUME_UNITY_INT32) { + self->process = volume_process_int32_clamp; + } else { + self->process = volume_process_int32; } + self->process_controlled = volume_process_controlled_int32_clamp; break; - case GST_BUFTYPE_FLOAT: - switch (GST_AUDIO_FILTER (self)->format.width) { - case 32: - self->process = volume_process_float; - self->process_controlled = volume_process_controlled_float; - break; - case 64: - self->process = volume_process_double; - self->process_controlled = volume_process_controlled_double; - break; + case GST_AUDIO_FORMAT_S24_3: + /* only clamp if the gain is greater than 1.0 */ + if (self->current_vol_i24 > VOLUME_UNITY_INT24) { + self->process = volume_process_int24_clamp; + } else { + self->process = volume_process_int24; } + self->process_controlled = volume_process_controlled_int24_clamp; + break; + case GST_AUDIO_FORMAT_S16: + /* only clamp if the gain is greater than 1.0 */ + if (self->current_vol_i16 > VOLUME_UNITY_INT16) { + self->process = volume_process_int16_clamp; + } else { + self->process = volume_process_int16; + } + self->process_controlled = volume_process_controlled_int16_clamp; + break; + case GST_AUDIO_FORMAT_S8: + /* only clamp if the gain is greater than 1.0 */ + if (self->current_vol_i8 > VOLUME_UNITY_INT8) { + self->process = volume_process_int8_clamp; + } else { + self->process = volume_process_int8; + } + self->process_controlled = volume_process_controlled_int8_clamp; + break; + case GST_AUDIO_FORMAT_F32: + self->process = volume_process_float; + self->process_controlled = volume_process_controlled_float; + break; + case GST_AUDIO_FORMAT_F64: + self->process = volume_process_double; + self->process_controlled = volume_process_controlled_double; break; default: break; @@ -756,7 +721,7 @@ volume_process_controlled_int8_clamp (GstVolume * self, gpointer bytes, /* get notified of caps and plug in the correct process function */ static gboolean -volume_setup (GstAudioFilter * filter, GstRingBufferSpec * format) +volume_setup (GstAudioFilter * filter, GstAudioInfo * info) { gboolean res; GstVolume *self = GST_VOLUME (filter); @@ -833,6 +798,7 @@ volume_before_transform (GstBaseTransform * base, GstBuffer * buffer) static GstFlowReturn volume_transform_ip (GstBaseTransform * base, GstBuffer * outbuf) { + GstAudioFilter *filter = GST_AUDIO_FILTER_CAST (base); GstVolume *self = GST_VOLUME (base); guint8 *data; gsize size; @@ -850,10 +816,11 @@ volume_transform_ip (GstBaseTransform * base, GstBuffer * outbuf) mute_csource = gst_object_get_control_source (G_OBJECT (self), "mute"); volume_csource = gst_object_get_control_source (G_OBJECT (self), "volume"); + if (mute_csource || (volume_csource && !self->current_mute)) { - gint rate = GST_AUDIO_FILTER_CAST (self)->format.rate; - gint width = GST_AUDIO_FILTER_CAST (self)->format.width / 8; - gint channels = GST_AUDIO_FILTER_CAST (self)->format.channels; + gint rate = GST_AUDIO_INFO_RATE (&filter->info); + gint width = GST_AUDIO_FORMAT_INFO_WIDTH (filter->info.finfo) / 8; + gint channels = GST_AUDIO_INFO_CHANNELS (&filter->info); guint nsamples = size / (width * channels); GstClockTime interval = gst_util_uint64_scale_int (1, GST_SECOND, rate); GstClockTime ts = GST_BUFFER_TIMESTAMP (outbuf);