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.
This commit is contained in:
Wim Taymans 2011-08-18 19:15:03 +02:00
parent d1a83d7a41
commit dae848818d
39 changed files with 1574 additions and 1988 deletions

View file

@ -95,46 +95,13 @@ static gint output_ref; /* 0 */
static snd_output_t *output; /* NULL */ static snd_output_t *output; /* NULL */
static GStaticMutex output_mutex = G_STATIC_MUTEX_INIT; 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 = static GstStaticPadTemplate alsasink_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, " GST_STATIC_CAPS ("audio/x-raw, "
"endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, " "formats = (string) " GST_AUDIO_FORMATS_ALL ", "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 32, "
"depth = (int) 32, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " "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") "audio/x-iec958")
); );
@ -627,26 +594,96 @@ alsasink_parse_spec (GstAlsaSink * alsa, GstRingBufferSpec * spec)
alsa->iec958 = FALSE; alsa->iec958 = FALSE;
switch (spec->type) { switch (spec->type) {
case GST_BUFTYPE_LINEAR: case GST_BUFTYPE_RAW:
GST_DEBUG_OBJECT (alsa, switch (GST_AUDIO_INFO_FORMAT (&spec->info)) {
"Linear format : depth=%d, width=%d, sign=%d, bigend=%d", spec->depth, case GST_AUDIO_FORMAT_U8:
spec->width, spec->sign, spec->bigend); alsa->format = SND_PCM_FORMAT_U8;
alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width,
spec->sign ? 0 : 1, spec->bigend ? 1 : 0);
break; break;
case GST_BUFTYPE_FLOAT: case GST_AUDIO_FORMAT_S8:
switch (spec->format) { alsa->format = SND_PCM_FORMAT_S8;
case GST_FLOAT32_LE: 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; alsa->format = SND_PCM_FORMAT_FLOAT_LE;
break; break;
case GST_FLOAT32_BE: case GST_AUDIO_FORMAT_F32_BE:
alsa->format = SND_PCM_FORMAT_FLOAT_BE; alsa->format = SND_PCM_FORMAT_FLOAT_BE;
break; break;
case GST_FLOAT64_LE: case GST_AUDIO_FORMAT_F64_LE:
alsa->format = SND_PCM_FORMAT_FLOAT64_LE; alsa->format = SND_PCM_FORMAT_FLOAT64_LE;
break; break;
case GST_FLOAT64_BE: case GST_AUDIO_FORMAT_F64_BE:
alsa->format = SND_PCM_FORMAT_FLOAT64_BE; alsa->format = SND_PCM_FORMAT_FLOAT64_BE;
break; break;
default: default:
@ -667,8 +704,8 @@ alsasink_parse_spec (GstAlsaSink * alsa, GstRingBufferSpec * spec)
goto error; goto error;
} }
alsa->rate = spec->rate; alsa->rate = GST_AUDIO_INFO_RATE (&spec->info);
alsa->channels = spec->channels; alsa->channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
alsa->buffer_time = spec->buffer_time; alsa->buffer_time = spec->buffer_time;
alsa->period_time = spec->latency_time; alsa->period_time = spec->latency_time;
alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED; alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED;
@ -724,7 +761,7 @@ gst_alsasink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
alsa = GST_ALSA_SINK (asink); alsa = GST_ALSA_SINK (asink);
if (spec->format == GST_IEC958) { if (spec->type == GST_BUFTYPE_IEC958) {
snd_pcm_close (alsa->handle); snd_pcm_close (alsa->handle);
alsa->handle = gst_alsa_open_iec958_pcm (GST_OBJECT (alsa)); alsa->handle = gst_alsa_open_iec958_pcm (GST_OBJECT (alsa));
if (G_UNLIKELY (!alsa->handle)) { 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_hwparams (alsa), hw_params_failed);
CHECK (set_swparams (alsa), sw_params_failed); CHECK (set_swparams (alsa), sw_params_failed);
alsa->bytes_per_sample = spec->bytes_per_sample; alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info);
spec->segsize = alsa->period_size * spec->bytes_per_sample; spec->segsize = alsa->period_size * alsa->bpf;
spec->segtotal = alsa->buffer_size / alsa->period_size; 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); 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); GST_ALSA_SINK_LOCK (asink);
while (cptr > 0) { while (cptr > 0) {
@ -896,7 +933,7 @@ gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length)
} }
GST_ALSA_SINK_UNLOCK (asink); GST_ALSA_SINK_UNLOCK (asink);
return length - (cptr * alsa->bytes_per_sample); return length - (cptr * alsa->bpf);
write_error: write_error:
{ {

View file

@ -61,7 +61,7 @@ struct _GstAlsaSink {
snd_pcm_format_t format; snd_pcm_format_t format;
guint rate; guint rate;
guint channels; guint channels;
gint bytes_per_sample; gint bpf;
gboolean iec958; gboolean iec958;
gboolean need_swap; gboolean need_swap;

View file

@ -107,37 +107,11 @@ enum
#endif #endif
static GstStaticPadTemplate alsasrc_src_factory = static GstStaticPadTemplate alsasrc_src_factory =
GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_SRC,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, " GST_STATIC_CAPS ("audio/x-raw, "
"endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, " "format = (string) " GST_AUDIO_FORMATS_ALL ", "
"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, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]") "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
); );
@ -655,22 +629,96 @@ static gboolean
alsasrc_parse_spec (GstAlsaSrc * alsa, GstRingBufferSpec * spec) alsasrc_parse_spec (GstAlsaSrc * alsa, GstRingBufferSpec * spec)
{ {
switch (spec->type) { switch (spec->type) {
case GST_BUFTYPE_LINEAR: case GST_BUFTYPE_RAW:
alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width, switch (GST_AUDIO_INFO_FORMAT (&spec->info)) {
spec->sign ? 0 : 1, spec->bigend ? 1 : 0); case GST_AUDIO_FORMAT_U8:
alsa->format = SND_PCM_FORMAT_U8;
break; break;
case GST_BUFTYPE_FLOAT: case GST_AUDIO_FORMAT_S8:
switch (spec->format) { alsa->format = SND_PCM_FORMAT_S8;
case GST_FLOAT32_LE: 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; alsa->format = SND_PCM_FORMAT_FLOAT_LE;
break; break;
case GST_FLOAT32_BE: case GST_AUDIO_FORMAT_F32_BE:
alsa->format = SND_PCM_FORMAT_FLOAT_BE; alsa->format = SND_PCM_FORMAT_FLOAT_BE;
break; break;
case GST_FLOAT64_LE: case GST_AUDIO_FORMAT_F64_LE:
alsa->format = SND_PCM_FORMAT_FLOAT64_LE; alsa->format = SND_PCM_FORMAT_FLOAT64_LE;
break; break;
case GST_FLOAT64_BE: case GST_AUDIO_FORMAT_F64_BE:
alsa->format = SND_PCM_FORMAT_FLOAT64_BE; alsa->format = SND_PCM_FORMAT_FLOAT64_BE;
break; break;
default: default:
@ -687,8 +735,8 @@ alsasrc_parse_spec (GstAlsaSrc * alsa, GstRingBufferSpec * spec)
goto error; goto error;
} }
alsa->rate = spec->rate; alsa->rate = GST_AUDIO_INFO_RATE (&spec->info);
alsa->channels = spec->channels; alsa->channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
alsa->buffer_time = spec->buffer_time; alsa->buffer_time = spec->buffer_time;
alsa->period_time = spec->latency_time; alsa->period_time = spec->latency_time;
alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED; 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 (set_swparams (alsa), sw_params_failed);
CHECK (snd_pcm_prepare (alsa->handle), prepare_failed); CHECK (snd_pcm_prepare (alsa->handle), prepare_failed);
alsa->bytes_per_sample = spec->bytes_per_sample; alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info);
spec->segsize = alsa->period_size * spec->bytes_per_sample; spec->segsize = alsa->period_size * alsa->bpf;
spec->segtotal = alsa->buffer_size / alsa->period_size; 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; return TRUE;
@ -869,7 +913,7 @@ gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length)
alsa = GST_ALSA_SRC (asrc); alsa = GST_ALSA_SRC (asrc);
cptr = length / alsa->bytes_per_sample; cptr = length / alsa->bpf;
ptr = data; ptr = data;
GST_ALSA_SRC_LOCK (asrc); GST_ALSA_SRC_LOCK (asrc);
@ -889,7 +933,7 @@ gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length)
} }
GST_ALSA_SRC_UNLOCK (asrc); GST_ALSA_SRC_UNLOCK (asrc);
return length - (cptr * alsa->bytes_per_sample); return length - (cptr * alsa->bpf);
read_error: read_error:
{ {

View file

@ -63,7 +63,7 @@ struct _GstAlsaSrc {
snd_pcm_format_t format; snd_pcm_format_t format;
guint rate; guint rate;
guint channels; guint channels;
gint bytes_per_sample; gint bpf;
gboolean driver_timestamps; gboolean driver_timestamps;
guint buffer_time; guint buffer_time;

View file

@ -224,7 +224,7 @@ vorbis_dec_convert (GstPad * pad,
case GST_FORMAT_TIME: case GST_FORMAT_TIME:
switch (*dest_format) { switch (*dest_format) {
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
scale = dec->width * dec->vi.channels; scale = dec->info.bpf;
case GST_FORMAT_DEFAULT: case GST_FORMAT_DEFAULT:
*dest_value = *dest_value =
scale * gst_util_uint64_scale_int (src_value, dec->vi.rate, scale * gst_util_uint64_scale_int (src_value, dec->vi.rate,
@ -237,7 +237,7 @@ vorbis_dec_convert (GstPad * pad,
case GST_FORMAT_DEFAULT: case GST_FORMAT_DEFAULT:
switch (*dest_format) { switch (*dest_format) {
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
*dest_value = src_value * dec->width * dec->vi.channels; *dest_value = src_value * dec->info.bpf;
break; break;
case GST_FORMAT_TIME: case GST_FORMAT_TIME:
*dest_value = *dest_value =
@ -250,11 +250,11 @@ vorbis_dec_convert (GstPad * pad,
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
switch (*dest_format) { switch (*dest_format) {
case GST_FORMAT_DEFAULT: case GST_FORMAT_DEFAULT:
*dest_value = src_value / (dec->width * dec->vi.channels); *dest_value = src_value / dec->info.bpf;
break; break;
case GST_FORMAT_TIME: case GST_FORMAT_TIME:
*dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND, *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; break;
default: default:
res = FALSE; res = FALSE;
@ -545,10 +545,13 @@ static GstFlowReturn
vorbis_handle_identification_packet (GstVorbisDec * vd) vorbis_handle_identification_packet (GstVorbisDec * vd)
{ {
GstCaps *caps; GstCaps *caps;
GstAudioInfo info;
const GstAudioChannelPosition *pos = NULL; 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 1:
case 2: case 2:
/* nothing */ /* nothing */
@ -559,60 +562,28 @@ vorbis_handle_identification_packet (GstVorbisDec * vd)
case 6: case 6:
case 7: case 7:
case 8: case 8:
pos = gst_vorbis_channel_positions[vd->vi.channels - 1]; pos = gst_vorbis_channel_positions[info.channels - 1];
break; break;
default:{ default:
gint i; {
GstAudioChannelPosition *posn = gint i, max_pos = MAX (info.channels, 64);
g_new (GstAudioChannelPosition, vd->vi.channels);
GST_ELEMENT_WARNING (GST_ELEMENT (vd), STREAM, DECODE, GST_ELEMENT_WARNING (vd, STREAM, DECODE,
(NULL), ("Using NONE channel layout for more than 8 channels")); (NULL), ("Using NONE channel layout for more than 8 channels"));
for (i = 0; i < max_pos; i++)
for (i = 0; i < vd->vi.channels; i++) info.position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
posn[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
pos = posn;
} }
} }
/* negotiate width with downstream */ caps = gst_audio_info_to_caps (&info);
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);
}
gst_pad_set_caps (vd->srcpad, caps); gst_pad_set_caps (vd->srcpad, caps);
gst_caps_unref (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; return GST_FLOW_OK;
} }
@ -792,7 +763,7 @@ vorbis_dec_push_forward (GstVorbisDec * dec, GstBuffer * buf)
/* clip */ /* clip */
if (!(buf = gst_audio_buffer_clip (buf, &dec->segment, dec->vi.rate, 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"); GST_LOG_OBJECT (dec, "clipped buffer");
return GST_FLOW_OK; return GST_FLOW_OK;
} }
@ -856,9 +827,7 @@ static GstFlowReturn
vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet, vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet,
GstClockTime timestamp, GstClockTime duration) GstClockTime timestamp, GstClockTime duration)
{ {
#ifdef USE_TREMOLO #ifndef USE_TREMOLO
vorbis_sample_t *pcm;
#else
vorbis_sample_t **pcm; vorbis_sample_t **pcm;
#endif #endif
guint sample_count; guint sample_count;
@ -899,17 +868,17 @@ vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet,
#endif #endif
goto done; 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, GST_LOG_OBJECT (vd, "%d samples ready for reading, size %" G_GSIZE_FORMAT,
sample_count, size); sample_count, size);
/* alloc buffer for it */ /* alloc buffer for it */
out = gst_buffer_new_and_alloc (size); 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 */ /* get samples ready for reading now, should be sample_count */
#ifdef USE_TREMOLO #ifdef USE_TREMOLO
pcm = GST_BUFFER_DATA (out); if (G_UNLIKELY ((vorbis_dsp_pcmout (&vd->vd, data,
if (G_UNLIKELY ((vorbis_dsp_pcmout (&vd->vd, pcm,
sample_count)) != sample_count)) sample_count)) != sample_count))
#else #else
if (G_UNLIKELY ((vorbis_synthesis_pcmout (&vd->vd, &pcm)) != sample_count)) 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 #ifndef USE_TREMOLO
/* copy samples in buffer */ /* copy samples in buffer */
data = gst_buffer_map (out, NULL, NULL, GST_MAP_WRITE);
vd->copy_samples ((vorbis_sample_t *) data, pcm, vd->copy_samples ((vorbis_sample_t *) data, pcm,
sample_count, vd->vi.channels, vd->width); sample_count, vd->info.channels);
#endif #endif
GST_LOG_OBJECT (vd, "setting output size to %" G_GSIZE_FORMAT, size); GST_LOG_OBJECT (vd, "setting output size to %" G_GSIZE_FORMAT, size);

View file

@ -65,7 +65,7 @@ struct _GstVorbisDec {
#endif #endif
gboolean initialized; gboolean initialized;
guint width; GstAudioInfo info;
/* list of buffers that need timestamps */ /* list of buffers that need timestamps */
GList *queued; GList *queued;

View file

@ -34,14 +34,14 @@
* is allowed, downstream elements are supposed to clip */ * is allowed, downstream elements are supposed to clip */
static void static void
copy_samples_m (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples, 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)); memcpy (out, in[0], samples * sizeof (float));
} }
static void static void
copy_samples_s (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples, copy_samples_s (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
gint channels, gint width) gint channels)
{ {
#ifdef GST_VORBIS_DEC_SEQUENTIAL #ifdef GST_VORBIS_DEC_SEQUENTIAL
memcpy (out, in[0], samples * sizeof (float)); 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 static void
copy_samples (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples, copy_samples (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
gint channels, gint width) gint channels)
{ {
#ifdef GST_VORBIS_DEC_SEQUENTIAL #ifdef GST_VORBIS_DEC_SEQUENTIAL
gint i; gint i;
@ -80,12 +80,10 @@ copy_samples (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
} }
CopySampleFunc CopySampleFunc
get_copy_sample_func (gint channels, gint width) get_copy_sample_func (gint channels)
{ {
CopySampleFunc f = NULL; CopySampleFunc f = NULL;
g_assert (width == 4);
switch (channels) { switch (channels) {
case 1: case 1:
f = copy_samples_m; f = copy_samples_m;
@ -130,51 +128,9 @@ CLIP_TO_15 (ogg_int32_t x)
} }
#endif #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 static void
copy_samples_16_m (vorbis_sample_t * _out, vorbis_sample_t ** _in, 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; gint16 *out = (gint16 *) _out;
ogg_int32_t **in = (ogg_int32_t **) _in; 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 static void
copy_samples_16_s (vorbis_sample_t * _out, vorbis_sample_t ** _in, 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; gint16 *out = (gint16 *) _out;
ogg_int32_t **in = (ogg_int32_t **) _in; 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 static void
copy_samples_16 (vorbis_sample_t * _out, vorbis_sample_t ** _in, guint samples, copy_samples_16 (vorbis_sample_t * _out, vorbis_sample_t ** _in, guint samples,
gint channels, gint width) gint channels)
{ {
gint16 *out = (gint16 *) _out; gint16 *out = (gint16 *) _out;
ogg_int32_t **in = (ogg_int32_t **) _in; ogg_int32_t **in = (ogg_int32_t **) _in;
@ -215,23 +171,10 @@ copy_samples_16 (vorbis_sample_t * _out, vorbis_sample_t ** _in, guint samples,
} }
CopySampleFunc CopySampleFunc
get_copy_sample_func (gint channels, gint width) get_copy_sample_func (gint channels)
{ {
CopySampleFunc f = NULL; 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) { switch (channels) {
case 1: case 1:
f = copy_samples_16_m; f = copy_samples_16_m;
@ -243,9 +186,6 @@ get_copy_sample_func (gint channels, gint width)
f = copy_samples_16; f = copy_samples_16;
break; break;
} }
} else {
g_assert_not_reached ();
}
return f; return f;
} }

View file

@ -26,6 +26,7 @@
#define __GST_VORBIS_DEC_LIB_H__ #define __GST_VORBIS_DEC_LIB_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/audio/audio.h>
#ifndef TREMOR #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_DESCRIPTION "decode raw vorbis streams to float audio"
#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 \ #define GST_VORBIS_DEC_SRC_CAPS \
GST_STATIC_CAPS ("audio/x-raw-float, " \ GST_STATIC_CAPS ("audio/x-raw, " \
"format = (string)" GST_VORBIS_AUDIO_FORMAT_STR ", " \
"rate = (int) [ 1, MAX ], " \ "rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, 256 ], " \ "channels = (int) [ 1, 256 ]")
"endianness = (int) BYTE_ORDER, " \
"width = (int) 32")
#define GST_VORBIS_DEC_DEFAULT_SAMPLE_WIDTH (32) #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_DESCRIPTION "decode raw vorbis streams to integer audio"
#define GST_VORBIS_DEC_SRC_CAPS \ #define GST_VORBIS_AUDIO_FORMAT GST_AUDIO_FORMAT_S16
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_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 */ /* we need a different type name here */
#define GST_VORBIS_DEC_GLIB_TYPE_NAME GstIVorbisDec #define GST_VORBIS_DEC_GLIB_TYPE_NAME GstIVorbisDec
@ -176,8 +187,8 @@ gst_ogg_packet_from_wrapper (ogg_packet_wrapper * packet)
#endif #endif
typedef void (*CopySampleFunc)(vorbis_sample_t *out, vorbis_sample_t **in, 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__ */ #endif /* __GST_VORBIS_DEC_LIB_H__ */

View file

@ -69,6 +69,7 @@ GstAudio-@GST_MAJORMINOR@.gir: $(INTROSPECTION_SCANNER) libgstaudio-@GST_MAJORMI
GST_PLUGIN_SYSTEM_PATH="" GST_PLUGIN_PATH="" GST_REGISTRY_UPDATE=no \ GST_PLUGIN_SYSTEM_PATH="" GST_PLUGIN_PATH="" GST_REGISTRY_UPDATE=no \
$(INTROSPECTION_SCANNER) -v --namespace GstAudio \ $(INTROSPECTION_SCANNER) -v --namespace GstAudio \
--nsversion=@GST_MAJORMINOR@ \ --nsversion=@GST_MAJORMINOR@ \
--warn-all \
--strip-prefix=Gst \ --strip-prefix=Gst \
-DGST_USE_UNSTABLE_API \ -DGST_USE_UNSTABLE_API \
-I$(top_srcdir)/gst-libs \ -I$(top_srcdir)/gst-libs \

View file

@ -27,11 +27,347 @@
# include "config.h" # include "config.h"
#endif #endif
#include <string.h>
#include "audio.h" #include "audio.h"
#include "audio-enumtypes.h" #include "audio-enumtypes.h"
#include <gst/gststructure.h> #include <gst/gststructure.h>
#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: * gst_audio_frame_byte_size:
* @pad: the #GstPad to get the caps from * @pad: the #GstPad to get the caps from

View file

@ -1,6 +1,7 @@
/* GStreamer /* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Library <2001> Thomas Vander Stichele <thomas@apestaart.org> * Library <2001> Thomas Vander Stichele <thomas@apestaart.org>
* <2011> Wim Taymans <wim.taymans@gmail.com>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -23,31 +24,315 @@
#ifndef __GST_AUDIO_AUDIO_H__ #ifndef __GST_AUDIO_AUDIO_H__
#define __GST_AUDIO_AUDIO_H__ #define __GST_AUDIO_AUDIO_H__
#include <gst/audio/multichannel.h>
G_BEGIN_DECLS 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 * GstAudioFormat:
* properties that need to be defined. you can just use these macros. currently * @GST_AUDIO_FORMAT_UNKNOWN: unknown audio format
* (8/01) the only plugins that use these are the passthrough, speed, volume, * @GST_AUDIO_FORMAT_S8: sample
* adder, and [de]interleave plugins. These are for convenience only, and do not * @GST_AUDIO_FORMAT_U8: sample
* specify the 'limits' of GStreamer. you might also use these definitions as a * @GST_AUDIO_FORMAT_S16_LE: sample
* base for making your own caps, if need be. * @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 * Enum value describing the most common audio formats.
* float or any channel int: */
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 * The different audio flags that a format info can have.
* ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, */
* gst_caps_append(gst_caps_new ("sink_int", "audio/x-raw-int", typedef enum
* GST_AUDIO_INT_PAD_TEMPLATE_PROPS), {
* gst_caps_new ("sink_float", "audio/x-raw-float", GST_AUDIO_FORMAT_FLAG_INT = (1 << 0),
* GST_AUDIO_FLOAT_PAD_TEMPLATE_PROPS)), GST_AUDIO_FORMAT_FLAG_FLOAT = (1 << 1),
* NULL); 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 * Packs @length samples from @src to the data array in format @info.
* Thomas, 6 September 2002 */ * 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 */ /* conversion macros */
/** /**
@ -70,69 +355,6 @@ G_BEGIN_DECLS
#define GST_CLOCK_TIME_TO_FRAMES(clocktime, rate) \ #define GST_CLOCK_TIME_TO_FRAMES(clocktime, rate) \
gst_util_uint64_scale_round (clocktime, rate, GST_SECOND) 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 * this library defines and implements some helper functions for audio
* handling * handling

View file

@ -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->set_caps = GST_DEBUG_FUNCPTR (gst_audio_filter_set_caps);
basetrans_class->get_unit_size = basetrans_class->get_unit_size =
GST_DEBUG_FUNCPTR (gst_audio_filter_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 static void
@ -103,9 +97,7 @@ gst_audio_filter_change_state (GstElement * element, GstStateChange transition)
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY: case GST_STATE_CHANGE_NULL_TO_READY:
memset (&filter->format, 0, sizeof (GstRingBufferSpec)); gst_audio_info_init (&filter->info);
/* to make gst_buffer_spec_parse_caps() happy */
filter->format.latency_time = GST_SECOND;
break; break;
default: default:
break; break;
@ -120,7 +112,7 @@ gst_audio_filter_change_state (GstElement * element, GstStateChange transition)
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_PAUSED_TO_READY:
case GST_STATE_CHANGE_READY_TO_NULL: case GST_STATE_CHANGE_READY_TO_NULL:
gst_caps_replace (&filter->format.caps, NULL); gst_audio_info_init (&filter->info);
break; break;
default: default:
break; break;
@ -139,17 +131,22 @@ gst_audio_filter_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
GST_LOG_OBJECT (filter, "caps: %" GST_PTR_FORMAT, incaps); GST_LOG_OBJECT (filter, "caps: %" GST_PTR_FORMAT, incaps);
if (!gst_ring_buffer_parse_caps (&filter->format, incaps)) { if (!gst_audio_info_from_caps (&filter->info, incaps))
GST_WARNING_OBJECT (filter, "couldn't parse %" GST_PTR_FORMAT, incaps); goto invalid_format;
return FALSE;
}
klass = GST_AUDIO_FILTER_CLASS_CAST (G_OBJECT_GET_CLASS (filter)); klass = GST_AUDIO_FILTER_CLASS_CAST (G_OBJECT_GET_CLASS (filter));
if (klass->setup) if (klass->setup)
ret = klass->setup (filter, &filter->format); ret = klass->setup (filter, &filter->info);
return ret; return ret;
/* ERROR */
invalid_format:
{
GST_WARNING_OBJECT (filter, "couldn't parse %" GST_PTR_FORMAT, incaps);
return FALSE;
}
} }
static gboolean static gboolean

View file

@ -23,7 +23,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstbasetransform.h> #include <gst/base/gstbasetransform.h>
#include <gst/audio/gstringbuffer.h> #include <gst/audio/audio.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -56,7 +56,7 @@ struct _GstAudioFilter {
GstBaseTransform basetransform; GstBaseTransform basetransform;
/*< protected >*/ /*< protected >*/
GstRingBufferSpec format; /* currently configured format */ GstAudioInfo info; /* currently configured format */
/*< private >*/ /*< private >*/
gpointer _gst_reserved[GST_PADDING]; gpointer _gst_reserved[GST_PADDING];
@ -78,7 +78,7 @@ struct _GstAudioFilterClass {
GstBaseTransformClass basetransformclass; GstBaseTransformClass basetransformclass;
/* virtual function, called whenever the format changes */ /* virtual function, called whenever the format changes */
gboolean (*setup) (GstAudioFilter * filter, GstRingBufferSpec * format); gboolean (*setup) (GstAudioFilter * filter, GstAudioInfo * info);
/*< private >*/ /*< private >*/
gpointer _gst_reserved[GST_PADDING]; gpointer _gst_reserved[GST_PADDING];

View file

@ -114,9 +114,9 @@ gst_audio_iec61937_frame_size (const GstRingBufferSpec * spec)
if (version == 1 && layer == 1) if (version == 1 && layer == 1)
frames = 384; frames = 384;
else if (version == 2 && layer == 1 && spec->rate < 32000) else if (version == 2 && layer == 1 && spec->info.rate < 32000)
frames = 768; frames = 768;
else if (version == 2 && layer == 1 && spec->rate < 32000) else if (version == 2 && layer == 1 && spec->info.rate < 32000)
frames = 2304; frames = 2304;
else else
frames = 1152; frames = 1152;
@ -271,13 +271,13 @@ gst_audio_iec61937_payload (const guint8 * src, guint src_n, guint8 * dst,
if (version == 1 && layer == 1) if (version == 1 && layer == 1)
dst[five] = 0x04; dst[five] = 0x04;
else if ((version == 1 && (layer == 2 || layer == 3)) || else if ((version == 1 && (layer == 2 || layer == 3)) ||
(version == 2 && spec->rate >= 32000)) (version == 2 && spec->info.rate >= 32000))
dst[five] = 0x05; 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; 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; 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; dst[five] = 0x0A;
else else
g_return_val_if_reached (FALSE); g_return_val_if_reached (FALSE);

View file

@ -395,7 +395,7 @@ gst_base_audio_sink_query (GstElement * element, GstQuery * query)
GstRingBufferSpec *spec; GstRingBufferSpec *spec;
GST_OBJECT_LOCK (basesink); GST_OBJECT_LOCK (basesink);
if (!basesink->ringbuffer || !basesink->ringbuffer->spec.rate) { if (!basesink->ringbuffer || !basesink->ringbuffer->spec.info.rate) {
GST_OBJECT_UNLOCK (basesink); GST_OBJECT_UNLOCK (basesink);
GST_DEBUG_OBJECT (basesink, GST_DEBUG_OBJECT (basesink,
@ -409,7 +409,7 @@ gst_base_audio_sink_query (GstElement * element, GstQuery * query)
base_latency = base_latency =
gst_util_uint64_scale_int (spec->seglatency * spec->segsize, 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); GST_OBJECT_UNLOCK (basesink);
/* we cannot go lower than the buffer size and the min peer latency */ /* 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; guint delay;
GstClockTime result; 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; return GST_CLOCK_TIME_NONE;
/* our processed samples are always increasing */ /* our processed samples are always increasing */
@ -486,7 +486,7 @@ gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
samples = 0; samples = 0;
result = gst_util_uint64_scale_int (samples, GST_SECOND, result = gst_util_uint64_scale_int (samples, GST_SECOND,
sink->ringbuffer->spec.rate); sink->ringbuffer->spec.info.rate);
GST_DEBUG_OBJECT (sink, GST_DEBUG_OBJECT (sink,
"processed samples: raw %" G_GUINT64_FORMAT ", delay %u, real %" "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. /* calculate actual latency and buffer times.
* FIXME: In 0.11, store the latency_time internally in ns */ * FIXME: In 0.11, store the latency_time internally in ns */
spec->latency_time = gst_util_uint64_scale (spec->segsize, 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; spec->buffer_time = spec->segtotal * spec->latency_time;
@ -821,7 +821,7 @@ gst_base_audio_sink_drain (GstBaseAudioSink * sink)
{ {
if (!sink->ringbuffer) if (!sink->ringbuffer)
return TRUE; return TRUE;
if (!sink->ringbuffer->spec.rate) if (!sink->ringbuffer->spec.info.rate)
return TRUE; return TRUE;
/* if PLAYING is interrupted, /* if PLAYING is interrupted,
@ -1066,7 +1066,7 @@ gst_base_audio_sink_skew_slaving (GstBaseAudioSink * sink,
cexternal = cexternal > mdrift ? cexternal - mdrift : 0; cexternal = cexternal > mdrift ? cexternal - mdrift : 0;
sink->priv->avg_skew -= 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; last_align = sink->priv->last_align;
/* if we were aligning in the wrong direction or we aligned more than what we /* 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; cexternal += mdrift;
sink->priv->avg_skew += 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; last_align = sink->priv->last_align;
/* if we were aligning in the wrong direction or we aligned more than what we /* 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 samples_done = segdone * ringbuf->samples_per_seg;
gint64 headroom = sample_offset - samples_done; gint64 headroom = sample_offset - samples_done;
gboolean allow_align = TRUE; gboolean allow_align = TRUE;
gint rate;
/* now try to align the sample to the previous one, first see how big the /* now try to align the sample to the previous one, first see how big the
* difference is. */ * difference is. */
@ -1316,9 +1317,11 @@ gst_base_audio_sink_get_alignment (GstBaseAudioSink * sink,
else else
diff = sink->next_sample - sample_offset; 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 /* calculate the max allowed drift in units of samples. By default this is
* 20ms and should be anough to compensate for timestamp rounding errors. */ * 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 */ /* calc align with previous sample */
align = sink->next_sample - sample_offset; align = sink->next_sample - sample_offset;
@ -1333,8 +1336,7 @@ gst_base_audio_sink_get_alignment (GstBaseAudioSink * sink,
G_GINT64_FORMAT, align, maxdrift); G_GINT64_FORMAT, align, maxdrift);
} else { } else {
/* calculate sample diff in seconds for error message */ /* calculate sample diff in seconds for error message */
gint64 diff_s = gint64 diff_s = gst_util_uint64_scale_int (diff, GST_SECOND, rate);
gst_util_uint64_scale_int (diff, GST_SECOND, ringbuf->spec.rate);
/* timestamps drifted apart from previous samples too much, we need to /* timestamps drifted apart from previous samples too much, we need to
* resync. We log this as an element warning. */ * resync. We log this as an element warning. */
GST_WARNING_OBJECT (sink, GST_WARNING_OBJECT (sink,
@ -1362,7 +1364,7 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
guint8 *data; guint8 *data;
gsize size; gsize size;
guint samples, written; guint samples, written;
gint bps; gint bpf, rate;
gint accum; gint accum;
gint out_samples; gint out_samples;
GstClockTime base_time, render_delay, latency; GstClockTime base_time, render_delay, latency;
@ -1409,13 +1411,14 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
buf = out; 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); size = gst_buffer_get_size (buf);
if (G_UNLIKELY (size % bps) != 0) if (G_UNLIKELY (size % bpf) != 0)
goto wrong_size; goto wrong_size;
samples = size / bps; samples = size / bpf;
out_samples = samples; out_samples = samples;
in_offset = GST_BUFFER_OFFSET (buf); 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 /* let's calc stop based on the number of samples in the buffer instead
* of trusting the DURATION */ * of trusting the DURATION */
stop = time + gst_util_uint64_scale_int (samples, GST_SECOND, stop = time + gst_util_uint64_scale_int (samples, GST_SECOND, rate);
ringbuf->spec.rate);
/* prepare the clipping segment. Since we will be subtracting ts-offset and /* 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 * 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; diff = ctime - time;
if (diff > 0) { if (diff > 0) {
/* bring clipped time to samples */ /* 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 " %" GST_DEBUG_OBJECT (sink, "clipping start to %" GST_TIME_FORMAT " %"
G_GUINT64_FORMAT " samples", GST_TIME_ARGS (ctime), diff); G_GUINT64_FORMAT " samples", GST_TIME_ARGS (ctime), diff);
samples -= diff; samples -= diff;
offset += diff * bps; offset += diff * bpf;
time = ctime; time = ctime;
} }
diff = stop - cstop; diff = stop - cstop;
if (diff > 0) { if (diff > 0) {
/* bring clipped time to samples */ /* 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 " %" GST_DEBUG_OBJECT (sink, "clipping stop to %" GST_TIME_FORMAT " %"
G_GUINT64_FORMAT " samples", GST_TIME_ARGS (cstop), diff); G_GUINT64_FORMAT " samples", GST_TIME_ARGS (cstop), diff);
samples -= diff; samples -= diff;
@ -1588,10 +1590,8 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
goto too_late; goto too_late;
/* and bring the time to the rate corrected offset in the buffer */ /* and bring the time to the rate corrected offset in the buffer */
render_start = gst_util_uint64_scale_int (render_start, render_start = gst_util_uint64_scale_int (render_start, rate, GST_SECOND);
ringbuf->spec.rate, GST_SECOND); render_stop = gst_util_uint64_scale_int (render_stop, rate, GST_SECOND);
render_stop = gst_util_uint64_scale_int (render_stop,
ringbuf->spec.rate, GST_SECOND);
/* positive playback rate, first sample is render_start, negative rate, first /* positive playback rate, first sample is render_start, negative rate, first
* sample is render_stop. When no rate conversion is active, render exactly * sample is render_stop. When no rate conversion is active, render exactly
@ -1677,7 +1677,7 @@ no_sync:
break; break;
samples -= written; samples -= written;
offset += written * bps; offset += written * bpf;
} while (TRUE); } while (TRUE);
gst_buffer_unmap (buf, data, size); gst_buffer_unmap (buf, data, size);

View file

@ -323,7 +323,8 @@ gst_base_audio_src_get_time (GstClock * clock, GstBaseAudioSrc * src)
guint delay; guint delay;
GstClockTime result; 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; return GST_CLOCK_TIME_NONE;
raw = samples = gst_ring_buffer_samples_done (src->ringbuffer); 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; samples += delay;
result = gst_util_uint64_scale_int (samples, GST_SECOND, result = gst_util_uint64_scale_int (samples, GST_SECOND,
src->ringbuffer->spec.rate); src->ringbuffer->spec.info.rate);
GST_DEBUG_OBJECT (src, GST_DEBUG_OBJECT (src,
"processed samples: raw %" G_GUINT64_FORMAT ", delay %u, real %" "processed samples: raw %" G_GUINT64_FORMAT ", delay %u, real %"
@ -509,26 +510,14 @@ static void
gst_base_audio_src_fixate (GstBaseSrc * bsrc, GstCaps * caps) gst_base_audio_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
{ {
GstStructure *s; GstStructure *s;
gint width, depth;
s = gst_caps_get_structure (caps, 0); s = gst_caps_get_structure (caps, 0);
/* fields for all formats */ /* fields for all formats */
gst_structure_fixate_field_nearest_int (s, "rate", 44100); gst_structure_fixate_field_nearest_int (s, "rate", GST_AUDIO_DEF_RATE);
gst_structure_fixate_field_nearest_int (s, "channels", 2); gst_structure_fixate_field_nearest_int (s, "channels",
gst_structure_fixate_field_nearest_int (s, "width", 16); GST_AUDIO_DEF_CHANNELS);
gst_structure_fixate_field_string (s, "format", GST_AUDIO_DEF_FORMAT);
/* 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_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps); 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); GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
GstRingBufferSpec *spec; GstRingBufferSpec *spec;
gint bpf, rate;
spec = &src->ringbuffer->spec; spec = &src->ringbuffer->spec;
@ -550,9 +540,11 @@ gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
goto parse_error; goto parse_error;
} }
bpf = GST_AUDIO_INFO_BPF (&spec->info);
rate = GST_AUDIO_INFO_RATE (&spec->info);
/* calculate suggested segsize and segtotal */ /* calculate suggested segsize and segtotal */
spec->segsize = spec->segsize = rate * bpf * spec->latency_time / GST_MSECOND;
spec->rate * spec->bytes_per_sample * spec->latency_time / GST_MSECOND;
spec->segtotal = spec->buffer_time / spec->latency_time; spec->segtotal = spec->buffer_time / spec->latency_time;
GST_OBJECT_UNLOCK (src); GST_OBJECT_UNLOCK (src);
@ -569,11 +561,9 @@ gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
goto acquire_error; goto acquire_error;
/* calculate actual latency and buffer times */ /* calculate actual latency and buffer times */
spec->latency_time = spec->latency_time = spec->segsize * GST_MSECOND / (rate * bpf);
spec->segsize * GST_MSECOND / (spec->rate * spec->bytes_per_sample);
spec->buffer_time = spec->buffer_time =
spec->segtotal * spec->segsize * GST_MSECOND / (spec->rate * spec->segtotal * spec->segsize * GST_MSECOND / (rate * bpf);
spec->bytes_per_sample);
gst_ring_buffer_debug_spec_buff (spec); 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; GstClockTime min_latency, max_latency;
GstRingBufferSpec *spec; GstRingBufferSpec *spec;
gint bpf, rate;
GST_OBJECT_LOCK (src); GST_OBJECT_LOCK (src);
if (G_UNLIKELY (src->ringbuffer == NULL if (G_UNLIKELY (src->ringbuffer == NULL
|| src->ringbuffer->spec.rate == 0)) { || src->ringbuffer->spec.info.rate == 0)) {
GST_OBJECT_UNLOCK (src); GST_OBJECT_UNLOCK (src);
goto done; goto done;
} }
spec = &src->ringbuffer->spec; 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 */ /* we have at least 1 segment of latency */
min_latency = min_latency =
gst_util_uint64_scale_int (spec->segsize, GST_SECOND, gst_util_uint64_scale_int (spec->segsize, GST_SECOND, rate * bpf);
spec->rate * spec->bytes_per_sample);
/* we cannot delay more than the buffersize else we lose data */ /* we cannot delay more than the buffersize else we lose data */
max_latency = max_latency =
gst_util_uint64_scale_int (spec->segtotal * spec->segsize, GST_SECOND, gst_util_uint64_scale_int (spec->segtotal * spec->segsize, GST_SECOND,
spec->rate * spec->bytes_per_sample); rate * bpf);
GST_OBJECT_UNLOCK (src); GST_OBJECT_UNLOCK (src);
GST_DEBUG_OBJECT (src, GST_DEBUG_OBJECT (src,
@ -757,7 +749,7 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
guchar *data, *ptr; guchar *data, *ptr;
guint samples, total_samples; guint samples, total_samples;
guint64 sample; guint64 sample;
gint bps; gint bpf, rate;
GstRingBuffer *ringbuffer; GstRingBuffer *ringbuffer;
GstRingBufferSpec *spec; GstRingBufferSpec *spec;
guint read; 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))) if (G_UNLIKELY (!gst_ring_buffer_is_acquired (ringbuffer)))
goto wrong_state; 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) if ((length == 0 && bsrc->blocksize == 0) || length == -1)
/* no length given, use the default segment size */ /* no length given, use the default segment size */
length = spec->segsize; length = spec->segsize;
else else
/* make sure we round down to an integral number of samples */ /* make sure we round down to an integral number of samples */
length -= length % bps; length -= length % bpf;
/* figure out the offset in the ringbuffer */ /* figure out the offset in the ringbuffer */
if (G_UNLIKELY (offset != -1)) { if (G_UNLIKELY (offset != -1)) {
sample = offset / bps; sample = offset / bpf;
/* if a specific offset was given it must be the next sequential /* if a specific offset was given it must be the next sequential
* offset we expect or we fail for now. */ * offset we expect or we fail for now. */
if (src->next_sample != -1 && sample != src->next_sample) 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); sample, length);
/* get the number of samples to read */ /* 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 */ /* use the basesrc allocation code to use bufferpools or custom allocators */
ret = GST_BASE_SRC_CLASS (parent_class)->alloc (bsrc, offset, length, &buf); 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 */ /* read next samples */
sample += read; sample += read;
samples -= read; samples -= read;
ptr += read * bps; ptr += read * bpf;
} while (TRUE); } while (TRUE);
gst_buffer_unmap (buf, data, length); 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; src->next_sample = sample + samples;
/* get the normal timestamp to get the duration. */ /* 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, duration = gst_util_uint64_scale_int (src->next_sample, GST_SECOND,
spec->rate) - timestamp; rate) - timestamp;
GST_OBJECT_LOCK (src); GST_OBJECT_LOCK (src);
if (!(clock = GST_ELEMENT_CLOCK (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) */ /* the running_time converted to a sample (relative to the ringbuffer) */
running_time_sample = 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 */ /* the segmentnr corrensponding to running_time, round down */
running_time_segment = running_time_sample / sps; 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; new_sample = ((guint64) new_read_segment) * sps;
/* and get the relative time to this -> our new timestamp */ /* and get the relative time to this -> our new timestamp */
timestamp = timestamp = gst_util_uint64_scale_int (new_sample, GST_SECOND, rate);
gst_util_uint64_scale_int (new_sample, GST_SECOND, spec->rate);
/* we update the next sample accordingly */ /* we update the next sample accordingly */
src->next_sample = new_sample + samples; src->next_sample = new_sample + samples;
@ -974,8 +966,7 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
timestamp = 0; timestamp = 0;
/* subtract latency */ /* subtract latency */
latency = latency = gst_util_uint64_scale_int (total_samples, GST_SECOND, rate);
gst_util_uint64_scale_int (total_samples, GST_SECOND, spec->rate);
if (timestamp > latency) if (timestamp > latency)
timestamp -= latency; timestamp -= latency;
else else

View file

@ -111,95 +111,9 @@ gst_ring_buffer_finalize (GObject * object)
(ringbuffer)); (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 #ifndef GST_DISABLE_GST_DEBUG
static const gchar *format_type_names[] = { static const gchar *format_type_names[] = {
"linear", "raw",
"float",
"mu law", "mu law",
"a law", "a law",
"ima adpcm", "ima adpcm",
@ -210,49 +124,6 @@ static const gchar *format_type_names[] = {
"eac3", "eac3",
"dts" "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 #endif
/** /**
@ -264,15 +135,15 @@ static const gchar *format_names[] = {
void void
gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec) gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec)
{ {
#if 0
gint i, bytes; gint i, bytes;
#endif
GST_DEBUG ("spec caps: %p %" GST_PTR_FORMAT, spec->caps, spec->caps); GST_DEBUG ("spec caps: %p %" GST_PTR_FORMAT, spec->caps, spec->caps);
GST_DEBUG ("parsed caps: type: %d, '%s'", spec->type, GST_DEBUG ("parsed caps: type: %d, '%s'", spec->type,
format_type_names[spec->type]); format_type_names[spec->type]);
GST_DEBUG ("parsed caps: format: %d, '%s'", spec->format, #if 0
format_names[spec->format]);
GST_DEBUG ("parsed caps: width: %d", spec->width); 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: sign: %d", spec->sign);
GST_DEBUG ("parsed caps: bigend: %d", spec->bigend); GST_DEBUG ("parsed caps: bigend: %d", spec->bigend);
GST_DEBUG ("parsed caps: rate: %d", spec->rate); 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++) { for (i = 0; i < bytes; i++) {
GST_DEBUG ("silence byte %d: %02x", i, spec->silence_sample[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 void
gst_ring_buffer_debug_spec_buff (GstRingBufferSpec * spec) 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", GST_DEBUG ("acquire ringbuffer: buffer time: %" G_GINT64_FORMAT " usec",
spec->buffer_time); spec->buffer_time);
GST_DEBUG ("acquire ringbuffer: latency time: %" G_GINT64_FORMAT " usec", 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: total segments: %d", spec->segtotal);
GST_DEBUG ("acquire ringbuffer: latency segments: %d", spec->seglatency); GST_DEBUG ("acquire ringbuffer: latency segments: %d", spec->seglatency);
GST_DEBUG ("acquire ringbuffer: segment size: %d bytes = %d samples", 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", GST_DEBUG ("acquire ringbuffer: buffer size: %d bytes = %d samples",
spec->segsize * spec->segtotal, spec->segsize * spec->segtotal, spec->segsize * spec->segtotal / bpf);
spec->segsize * spec->segtotal / spec->bytes_per_sample);
} }
/** /**
@ -321,160 +194,77 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
const gchar *mimetype; const gchar *mimetype;
GstStructure *structure; GstStructure *structure;
gint i; gint i;
GstAudioInfo info;
structure = gst_caps_get_structure (caps, 0); structure = gst_caps_get_structure (caps, 0);
gst_audio_info_init (&info);
/* we have to differentiate between int and float formats */ /* we have to differentiate between int and float formats */
mimetype = gst_structure_get_name (structure); mimetype = gst_structure_get_name (structure);
if (g_str_equal (mimetype, "audio/x-raw-int")) { if (g_str_equal (mimetype, "audio/x-raw")) {
gint endianness; if (!gst_audio_info_from_caps (&info, caps))
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)))
goto parse_error; goto parse_error;
/* extract endianness if needed */ spec->type = GST_BUFTYPE_RAW;
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);
} else if (g_str_equal (mimetype, "audio/x-alaw")) { } else if (g_str_equal (mimetype, "audio/x-alaw")) {
/* extract the needed information from the cap */ /* 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) &&
gst_structure_get_int (structure, "channels", &spec->channels))) gst_structure_get_int (structure, "channels", &info.channels)))
goto parse_error; goto parse_error;
spec->type = GST_BUFTYPE_A_LAW; spec->type = GST_BUFTYPE_A_LAW;
spec->format = GST_A_LAW; spec->info.bpf = info.channels;
spec->width = 8;
spec->depth = 8;
for (i = 0; i < spec->channels; i++)
spec->silence_sample[i] = 0xd5;
} else if (g_str_equal (mimetype, "audio/x-mulaw")) { } else if (g_str_equal (mimetype, "audio/x-mulaw")) {
/* extract the needed information from the cap */ /* 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) &&
gst_structure_get_int (structure, "channels", &spec->channels))) gst_structure_get_int (structure, "channels", &info.channels)))
goto parse_error; goto parse_error;
spec->type = GST_BUFTYPE_MU_LAW; spec->type = GST_BUFTYPE_MU_LAW;
spec->format = GST_MU_LAW; spec->info.bpf = info.channels;
spec->width = 8;
spec->depth = 8;
for (i = 0; i < spec->channels; i++)
spec->silence_sample[i] = 0xff;
} else if (g_str_equal (mimetype, "audio/x-iec958")) { } else if (g_str_equal (mimetype, "audio/x-iec958")) {
/* extract the needed information from the cap */ /* 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; goto parse_error;
spec->type = GST_BUFTYPE_IEC958; spec->type = GST_BUFTYPE_IEC958;
spec->format = GST_IEC958; spec->info.bpf = 4;
spec->width = 16;
spec->depth = 16;
spec->channels = 2;
} else if (g_str_equal (mimetype, "audio/x-ac3")) { } else if (g_str_equal (mimetype, "audio/x-ac3")) {
/* extract the needed information from the cap */ /* 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; goto parse_error;
spec->type = GST_BUFTYPE_AC3; spec->type = GST_BUFTYPE_AC3;
spec->format = GST_AC3; spec->info.bpf = 4;
spec->width = 16;
spec->depth = 16;
spec->channels = 2;
} else if (g_str_equal (mimetype, "audio/x-eac3")) { } else if (g_str_equal (mimetype, "audio/x-eac3")) {
/* extract the needed information from the cap */ /* 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; goto parse_error;
spec->type = GST_BUFTYPE_EAC3; spec->type = GST_BUFTYPE_EAC3;
spec->format = GST_EAC3; spec->info.bpf = 16;
spec->width = 64;
spec->depth = 64;
spec->channels = 2;
} else if (g_str_equal (mimetype, "audio/x-dts")) { } else if (g_str_equal (mimetype, "audio/x-dts")) {
/* extract the needed information from the cap */ /* 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; goto parse_error;
spec->type = GST_BUFTYPE_DTS; spec->type = GST_BUFTYPE_DTS;
spec->format = GST_DTS; spec->info.bpf = 4;
spec->width = 16;
spec->depth = 16;
spec->channels = 2;
} else if (g_str_equal (mimetype, "audio/mpeg") && } else if (g_str_equal (mimetype, "audio/mpeg") &&
gst_structure_get_int (structure, "mpegaudioversion", &i) && gst_structure_get_int (structure, "mpegaudioversion", &i) &&
(i == 1 || i == 2)) { (i == 1 || i == 2)) {
/* Now we know this is MPEG-1 or MPEG-2 (non AAC) */ /* Now we know this is MPEG-1 or MPEG-2 (non AAC) */
/* extract the needed information from the cap */ /* 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; goto parse_error;
spec->type = GST_BUFTYPE_MPEG; spec->type = GST_BUFTYPE_MPEG;
spec->format = GST_MPEG; spec->info.bpf = 4;
spec->width = 16;
spec->depth = 16;
spec->channels = 2;
} else { } else {
goto parse_error; goto parse_error;
} }
spec->bytes_per_sample = (spec->width >> 3) * spec->channels;
gst_caps_replace (&spec->caps, caps); gst_caps_replace (&spec->caps, caps);
g_return_val_if_fail (spec->latency_time != 0, FALSE); 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 /* calculate suggested segsize and segtotal. segsize should be one unit
* of 'latency_time' samples, scaling for the fact that latency_time is * of 'latency_time' samples, scaling for the fact that latency_time is
* currently stored in microseconds (FIXME: in 0.11) */ * 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); spec->latency_time, GST_SECOND / GST_USECOND);
/* Round to an integer number of samples */ /* 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; spec->segtotal = spec->buffer_time / spec->latency_time;
/* leave the latency undefined now, implementations can change it but if it's /* 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_caps (spec);
gst_ring_buffer_debug_spec_buff (spec); gst_ring_buffer_debug_spec_buff (spec);
spec->info = info;
return TRUE; return TRUE;
/* ERRORS */ /* ERRORS */
@ -525,7 +317,7 @@ gst_ring_buffer_convert (GstRingBuffer * buf,
GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val) GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val)
{ {
gboolean res = TRUE; gboolean res = TRUE;
gint bps, rate; gint bpf, rate;
GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s (%d) to %s (%d)", GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s (%d) to %s (%d)",
src_val, gst_format_get_name (src_fmt), src_fmt, src_val, gst_format_get_name (src_fmt), src_fmt,
@ -538,12 +330,12 @@ gst_ring_buffer_convert (GstRingBuffer * buf,
/* get important info */ /* get important info */
GST_OBJECT_LOCK (buf); GST_OBJECT_LOCK (buf);
bps = buf->spec.bytes_per_sample; bpf = GST_AUDIO_INFO_BPF (&buf->spec.info);
rate = buf->spec.rate; rate = GST_AUDIO_INFO_RATE (&buf->spec.info);
GST_OBJECT_UNLOCK (buf); GST_OBJECT_UNLOCK (buf);
if (bps == 0 || rate == 0) { if (bpf == 0 || rate == 0) {
GST_DEBUG ("no rate or bps configured"); GST_DEBUG ("no rate or bpf configured");
res = FALSE; res = FALSE;
goto done; goto done;
} }
@ -552,11 +344,11 @@ gst_ring_buffer_convert (GstRingBuffer * buf,
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
switch (dest_fmt) { switch (dest_fmt) {
case GST_FORMAT_TIME: 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); rate);
break; break;
case GST_FORMAT_DEFAULT: case GST_FORMAT_DEFAULT:
*dest_val = src_val / bps; *dest_val = src_val / bpf;
break; break;
default: default:
res = FALSE; res = FALSE;
@ -569,7 +361,7 @@ gst_ring_buffer_convert (GstRingBuffer * buf,
*dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, rate); *dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, rate);
break; break;
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
*dest_val = src_val * bps; *dest_val = src_val * bpf;
break; break;
default: default:
res = FALSE; res = FALSE;
@ -583,7 +375,7 @@ gst_ring_buffer_convert (GstRingBuffer * buf,
break; break;
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
*dest_val = gst_util_uint64_scale_int (src_val, rate, GST_SECOND); *dest_val = gst_util_uint64_scale_int (src_val, rate, GST_SECOND);
*dest_val *= bps; *dest_val *= bpf;
break; break;
default: default:
res = FALSE; res = FALSE;
@ -794,8 +586,7 @@ gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
{ {
gboolean res = FALSE; gboolean res = FALSE;
GstRingBufferClass *rclass; GstRingBufferClass *rclass;
gint i, j; gint segsize, bpf;
gint segsize, bps;
g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE); 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)) if (G_UNLIKELY (!res))
goto acquire_failed; goto acquire_failed;
if (G_UNLIKELY ((bps = buf->spec.bytes_per_sample) == 0)) if (G_UNLIKELY ((bpf = buf->spec.info.bpf) == 0))
goto invalid_bps; goto invalid_bpf;
/* if the seglatency was overwritten with something else than -1, use it, else /* if the seglatency was overwritten with something else than -1, use it, else
* assume segtotal as the latency */ * assume segtotal as the latency */
@ -827,18 +618,18 @@ gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
segsize = buf->spec.segsize; segsize = buf->spec.segsize;
buf->samples_per_seg = segsize / bps; buf->samples_per_seg = segsize / bpf;
/* create an empty segment */ /* create an empty segment */
g_free (buf->empty_seg); g_free (buf->empty_seg);
buf->empty_seg = g_malloc (segsize); buf->empty_seg = g_malloc (segsize);
/* FIXME, we only have 32 silence samples, which might not be enough to if (buf->spec.type == GST_BUFTYPE_RAW) {
* represent silence in all channels */ gst_audio_format_fill_silence (buf->spec.info.finfo, buf->empty_seg,
bps = MIN (bps, 32); segsize);
for (i = 0, j = 0; i < segsize; i++) { } else {
buf->empty_seg[i] = buf->spec.silence_sample[j]; /* FIXME, non-raw formats get 0 as the empty sample */
j = (j + 1) % bps; memset (buf->empty_seg, 0, segsize);
} }
GST_DEBUG_OBJECT (buf, "acquired device"); GST_DEBUG_OBJECT (buf, "acquired device");
@ -867,10 +658,10 @@ acquire_failed:
GST_DEBUG_OBJECT (buf, "failed to acquire device"); GST_DEBUG_OBJECT (buf, "failed to acquire device");
goto done; goto done;
} }
invalid_bps: invalid_bpf:
{ {
g_warning 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);
buf->acquired = FALSE; buf->acquired = FALSE;
res = FALSE; res = FALSE;
@ -1547,12 +1338,12 @@ no_start:
#define FWD_SAMPLES(s,se,d,de) \ #define FWD_SAMPLES(s,se,d,de) \
G_STMT_START { \ G_STMT_START { \
/* no rate conversion */ \ /* no rate conversion */ \
guint towrite = MIN (se + bps - s, de - d); \ guint towrite = MIN (se + bpf - s, de - d); \
/* simple copy */ \ /* simple copy */ \
if (!skip) \ if (!skip) \
memcpy (d, s, towrite); \ memcpy (d, s, towrite); \
in_samples -= towrite / bps; \ in_samples -= towrite / bpf; \
out_samples -= towrite / bps; \ out_samples -= towrite / bpf; \
s += towrite; \ s += towrite; \
GST_DEBUG ("copy %u bytes", towrite); \ GST_DEBUG ("copy %u bytes", towrite); \
} G_STMT_END } G_STMT_END
@ -1563,16 +1354,16 @@ G_STMT_START { \
guint8 *sb = s, *db = d; \ guint8 *sb = s, *db = d; \
while (s <= se && d < de) { \ while (s <= se && d < de) { \
if (!skip) \ if (!skip) \
memcpy (d, s, bps); \ memcpy (d, s, bpf); \
s += bps; \ s += bpf; \
*accum += outr; \ *accum += outr; \
if ((*accum << 1) >= inr) { \ if ((*accum << 1) >= inr) { \
*accum -= inr; \ *accum -= inr; \
d += bps; \ d += bpf; \
} \ } \
} \ } \
in_samples -= (s - sb)/bps; \ in_samples -= (s - sb)/bpf; \
out_samples -= (d - db)/bps; \ out_samples -= (d - db)/bpf; \
GST_DEBUG ("fwd_up end %d/%d",*accum,*toprocess); \ GST_DEBUG ("fwd_up end %d/%d",*accum,*toprocess); \
} G_STMT_END } G_STMT_END
@ -1582,16 +1373,16 @@ G_STMT_START { \
guint8 *sb = s, *db = d; \ guint8 *sb = s, *db = d; \
while (s <= se && d < de) { \ while (s <= se && d < de) { \
if (!skip) \ if (!skip) \
memcpy (d, s, bps); \ memcpy (d, s, bpf); \
d += bps; \ d += bpf; \
*accum += inr; \ *accum += inr; \
if ((*accum << 1) >= outr) { \ if ((*accum << 1) >= outr) { \
*accum -= outr; \ *accum -= outr; \
s += bps; \ s += bpf; \
} \ } \
} \ } \
in_samples -= (s - sb)/bps; \ in_samples -= (s - sb)/bpf; \
out_samples -= (d - db)/bps; \ out_samples -= (d - db)/bpf; \
GST_DEBUG ("fwd_down end %d/%d",*accum,*toprocess); \ GST_DEBUG ("fwd_down end %d/%d",*accum,*toprocess); \
} G_STMT_END } G_STMT_END
@ -1600,16 +1391,16 @@ G_STMT_START { \
guint8 *sb = se, *db = d; \ guint8 *sb = se, *db = d; \
while (s <= se && d < de) { \ while (s <= se && d < de) { \
if (!skip) \ if (!skip) \
memcpy (d, se, bps); \ memcpy (d, se, bpf); \
se -= bps; \ se -= bpf; \
*accum += outr; \ *accum += outr; \
while (d < de && (*accum << 1) >= inr) { \ while (d < de && (*accum << 1) >= inr) { \
*accum -= inr; \ *accum -= inr; \
d += bps; \ d += bpf; \
} \ } \
} \ } \
in_samples -= (sb - se)/bps; \ in_samples -= (sb - se)/bpf; \
out_samples -= (d - db)/bps; \ out_samples -= (d - db)/bpf; \
GST_DEBUG ("rev_up end %d/%d",*accum,*toprocess); \ GST_DEBUG ("rev_up end %d/%d",*accum,*toprocess); \
} G_STMT_END } G_STMT_END
@ -1618,16 +1409,16 @@ G_STMT_START { \
guint8 *sb = se, *db = d; \ guint8 *sb = se, *db = d; \
while (s <= se && d < de) { \ while (s <= se && d < de) { \
if (!skip) \ if (!skip) \
memcpy (d, se, bps); \ memcpy (d, se, bpf); \
d += bps; \ d += bpf; \
*accum += inr; \ *accum += inr; \
while (s <= se && (*accum << 1) >= outr) { \ while (s <= se && (*accum << 1) >= outr) { \
*accum -= outr; \ *accum -= outr; \
se -= bps; \ se -= bpf; \
} \ } \
} \ } \
in_samples -= (sb - se)/bps; \ in_samples -= (sb - se)/bpf; \
out_samples -= (d - db)/bps; \ out_samples -= (d - db)/bpf; \
GST_DEBUG ("rev_down end %d/%d",*accum,*toprocess); \ GST_DEBUG ("rev_down end %d/%d",*accum,*toprocess); \
} G_STMT_END } G_STMT_END
@ -1636,7 +1427,7 @@ default_commit (GstRingBuffer * buf, guint64 * sample,
guchar * data, gint in_samples, gint out_samples, gint * accum) guchar * data, gint in_samples, gint out_samples, gint * accum)
{ {
gint segdone; gint segdone;
gint segsize, segtotal, bps, sps; gint segsize, segtotal, bpf, sps;
guint8 *dest, *data_end; guint8 *dest, *data_end;
gint writeseg, sampleoff; gint writeseg, sampleoff;
gint *toprocess; gint *toprocess;
@ -1649,7 +1440,7 @@ default_commit (GstRingBuffer * buf, guint64 * sample,
dest = buf->memory; dest = buf->memory;
segsize = buf->spec.segsize; segsize = buf->spec.segsize;
segtotal = buf->spec.segtotal; segtotal = buf->spec.segtotal;
bps = buf->spec.bytes_per_sample; bpf = buf->spec.info.bpf;
sps = buf->samples_per_seg; sps = buf->samples_per_seg;
reverse = out_samples < 0; 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 /* 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. */ * 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 /* figure out the segment and the offset inside the segment where
* the first sample should be written. */ * the first sample should be written. */
writeseg = *sample / sps; writeseg = *sample / sps;
sampleoff = (*sample % sps) * bps; sampleoff = (*sample % sps) * bpf;
/* write out all samples */ /* write out all samples */
while (*toprocess > 0) { while (*toprocess > 0) {
@ -1714,11 +1505,11 @@ default_commit (GstRingBuffer * buf, guint64 * sample,
/* we can write now */ /* we can write now */
ws = writeseg % segtotal; ws = writeseg % segtotal;
avail = MIN (segsize - sampleoff, bps * out_samples); avail = MIN (segsize - sampleoff, bpf * out_samples);
d = dest + (ws * segsize) + sampleoff; d = dest + (ws * segsize) + sampleoff;
d_end = d + avail; d_end = d + avail;
*sample += avail / bps; *sample += avail / bpf;
GST_DEBUG_OBJECT (buf, "write @%p seg %d, sps %d, off %d, avail %d", GST_DEBUG_OBJECT (buf, "write @%p seg %d, sps %d, off %d, avail %d",
dest + ws * segsize, ws, sps, sampleoff, avail); dest + ws * segsize, ws, sps, sampleoff, avail);
@ -1747,10 +1538,10 @@ default_commit (GstRingBuffer * buf, guint64 * sample,
sampleoff = 0; sampleoff = 0;
} }
/* we consumed all samples here */ /* we consumed all samples here */
data = data_end + bps; data = data_end + bpf;
done: done:
return inr - ((data_end - data) / bps); return inr - ((data_end - data) / bpf);
/* ERRORS */ /* ERRORS */
not_started: not_started:
@ -1867,7 +1658,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
guint len) guint len)
{ {
gint segdone; gint segdone;
gint segsize, segtotal, bps, sps; gint segsize, segtotal, bpf, sps;
guint8 *dest; guint8 *dest;
guint to_read; guint to_read;
@ -1878,7 +1669,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
dest = buf->memory; dest = buf->memory;
segsize = buf->spec.segsize; segsize = buf->spec.segsize;
segtotal = buf->spec.segtotal; segtotal = buf->spec.segtotal;
bps = buf->spec.bytes_per_sample; bpf = buf->spec.info.bpf;
sps = buf->samples_per_seg; sps = buf->samples_per_seg;
to_read = len; to_read = len;
@ -1913,7 +1704,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
if (G_UNLIKELY (diff >= segtotal)) { if (G_UNLIKELY (diff >= segtotal)) {
/* pretend we read an empty segment. */ /* pretend we read an empty segment. */
sampleslen = MIN (sps, to_read); sampleslen = MIN (sps, to_read);
memcpy (data, buf->empty_seg, sampleslen * bps); memcpy (data, buf->empty_seg, sampleslen * bpf);
goto next; 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", GST_DEBUG_OBJECT (buf, "read @%p seg %d, off %d, sampleslen %d",
dest + readseg * segsize, readseg, sampleoff, sampleslen); dest + readseg * segsize, readseg, sampleoff, sampleslen);
memcpy (data, dest + (readseg * segsize) + (sampleoff * bps), memcpy (data, dest + (readseg * segsize) + (sampleoff * bpf),
(sampleslen * bps)); (sampleslen * bpf));
next: next:
to_read -= sampleslen; to_read -= sampleslen;
sample += sampleslen; sample += sampleslen;
data += sampleslen * bps; data += sampleslen * bpf;
} }
return len - to_read; return len - to_read;

View file

@ -24,6 +24,7 @@
#define __GST_RING_BUFFER_H__ #define __GST_RING_BUFFER_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/audio/audio.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -83,8 +84,7 @@ typedef enum {
/** /**
* GstBufferFormatType: * GstBufferFormatType:
* @GST_BUFTYPE_LINEAR: samples in linear PCM * @GST_BUFTYPE_RAW: samples in linear or float
* @GST_BUFTYPE_FLOAT: samples in float
* @GST_BUFTYPE_MU_LAW: samples in mulaw * @GST_BUFTYPE_MU_LAW: samples in mulaw
* @GST_BUFTYPE_A_LAW: samples in alaw * @GST_BUFTYPE_A_LAW: samples in alaw
* @GST_BUFTYPE_IMA_ADPCM: samples in ima adpcm * @GST_BUFTYPE_IMA_ADPCM: samples in ima adpcm
@ -101,8 +101,7 @@ typedef enum {
*/ */
typedef enum typedef enum
{ {
GST_BUFTYPE_LINEAR, GST_BUFTYPE_RAW,
GST_BUFTYPE_FLOAT,
GST_BUFTYPE_MU_LAW, GST_BUFTYPE_MU_LAW,
GST_BUFTYPE_A_LAW, GST_BUFTYPE_A_LAW,
GST_BUFTYPE_IMA_ADPCM, GST_BUFTYPE_IMA_ADPCM,
@ -116,107 +115,6 @@ typedef enum
GST_BUFTYPE_MPEG4_AAC, GST_BUFTYPE_MPEG4_AAC,
} GstBufferFormatType; } 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: * GstRingBufferSpec:
* @caps: The caps that generated the Spec. * @caps: The caps that generated the Spec.
@ -247,13 +145,7 @@ struct _GstRingBufferSpec
/* in/out */ /* in/out */
GstBufferFormatType type; GstBufferFormatType type;
GstBufferFormat format; GstAudioInfo info;
gboolean sign;
gboolean bigend;
gint width;
gint depth;
gint rate;
gint channels;
guint64 latency_time; /* the required/actual latency time, this is the guint64 latency_time; /* the required/actual latency time, this is the
* actual the size of one segment and the * actual the size of one segment and the
@ -268,10 +160,6 @@ struct _GstRingBufferSpec
* number of segments of @segsize and should be * number of segments of @segsize and should be
* chosen so that it matches buffer_time as * chosen so that it matches buffer_time as
* close as possible. */ * 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 */ /* ABI added 0.10.20 */
gint seglatency; /* number of segments queued in the lower gint seglatency; /* number of segments queued in the lower
* level device, defaults to segtotal. */ * level device, defaults to segtotal. */

View file

@ -231,13 +231,9 @@ GstAudioChannelPosition *
gst_audio_get_channel_positions (GstStructure * str) gst_audio_get_channel_positions (GstStructure * str)
{ {
GstAudioChannelPosition *pos; GstAudioChannelPosition *pos;
gint channels, n; gint channels, n;
const GValue *pos_val_arr, *pos_val_entry; const GValue *pos_val_arr, *pos_val_entry;
gboolean res; gboolean res;
GType t; GType t;
/* get number of channels, general type checkups */ /* get number of channels, general type checkups */

View file

@ -20,7 +20,7 @@
#ifndef __GST_AUDIO_MULTICHANNEL_H__ #ifndef __GST_AUDIO_MULTICHANNEL_H__
#define __GST_AUDIO_MULTICHANNEL_H__ #define __GST_AUDIO_MULTICHANNEL_H__
#include <gst/audio/audio.h> #include <gst/gst.h>
#include <gst/audio/audio-enumtypes.h> #include <gst/audio/audio-enumtypes.h>
G_BEGIN_DECLS G_BEGIN_DECLS

View file

@ -1,6 +1,5 @@
/* GStreamer /* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> * Copyright (C) <2011> Wim Taymans <wim.taymans@gmail.com>
* Library <2002> Ronald Bultje <rbultje@ronald.bitfreak.net>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * 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 * Packs @width pixels from @src to the given planes and strides in the
* format @info. The pixels from source have each component interleaved * 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, typedef void (*GstVideoFormatPack) (GstVideoFormatInfo *info, const gpointer src,
gpointer data[GST_VIDEO_MAX_PLANES], 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 #define GST_VIDEO_BUFFER_PROGRESSIVE GST_BUFFER_FLAG_MEDIA4
/* functions */ /* some helper functions */
gboolean gst_video_calculate_display_ratio (guint * dar_n, gboolean gst_video_calculate_display_ratio (guint * dar_n,
guint * dar_d, guint * dar_d,
guint video_width, guint video_width,

View file

@ -75,32 +75,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
/* elementfactory information */ /* elementfactory information */
#define CAPS \ #define CAPS \
"audio/x-raw-int, " \ GST_AUDIO_CAPS_MAKE ("{ S32, U32, S16, U16, S8, U8, F32, F64 }")
"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 }"
static GstStaticPadTemplate gst_adder_src_template = static GstStaticPadTemplate gst_adder_src_template =
GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_PAD_TEMPLATE ("src",

View file

@ -557,23 +557,26 @@ static AudioConvertPack pack_funcs[] = {
}; };
#define DOUBLE_INTERMEDIATE_FORMAT(ctx) \ #define DOUBLE_INTERMEDIATE_FORMAT(ctx) \
((!ctx->in.is_int && !ctx->out.is_int) || (ctx->ns != NOISE_SHAPING_NONE)) ((!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 static gint
audio_convert_get_func_index (AudioConvertCtx * ctx, AudioConvertFmt * fmt) audio_convert_get_func_index (AudioConvertCtx * ctx,
const GstAudioFormatInfo * fmt)
{ {
gint index = 0; gint index = 0;
if (fmt->is_int) { if (GST_AUDIO_FORMAT_INFO_IS_INT (fmt)) {
index += (fmt->width / 8 - 1) * 4; index += (GST_AUDIO_FORMAT_INFO_WIDTH (fmt) / 8 - 1) * 4;
index += fmt->endianness == G_LITTLE_ENDIAN ? 0 : 2; index += GST_AUDIO_FORMAT_INFO_IS_LE (fmt) ? 0 : 2;
index += fmt->sign ? 1 : 0; index += GST_AUDIO_FORMAT_INFO_IS_SIGNED (fmt) ? 1 : 0;
index += (ctx->ns == NOISE_SHAPING_NONE) ? 0 : 24; index += (ctx->ns == NOISE_SHAPING_NONE) ? 0 : 24;
} else { } else {
/* this is float/double */ /* this is float/double */
index = 16; index = 16;
index += (fmt->width == 32) ? 0 : 2; index += (GST_AUDIO_FORMAT_INFO_WIDTH (fmt) == 32) ? 0 : 2;
index += (fmt->endianness == G_LITTLE_ENDIAN) ? 0 : 1; index += GST_AUDIO_FORMAT_INFO_IS_LE (fmt) ? 0 : 1;
index += (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? 4 : 0; index += (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? 4 : 0;
} }
@ -581,34 +584,22 @@ audio_convert_get_func_index (AudioConvertCtx * ctx, AudioConvertFmt * fmt)
} }
static inline gboolean static inline gboolean
check_default (AudioConvertCtx * ctx, AudioConvertFmt * fmt) check_default (AudioConvertCtx * ctx, const GstAudioFormatInfo * fmt)
{ {
if (!DOUBLE_INTERMEDIATE_FORMAT (ctx)) { if (!DOUBLE_INTERMEDIATE_FORMAT (ctx)) {
return (fmt->width == 32 && fmt->depth == 32 && return GST_AUDIO_FORMAT_INFO_FORMAT (fmt) == GST_AUDIO_FORMAT_S32;
fmt->endianness == G_BYTE_ORDER && fmt->sign == TRUE);
} else { } else {
return (fmt->width == 64 && fmt->endianness == G_BYTE_ORDER); return GST_AUDIO_FORMAT_INFO_FORMAT (fmt) == GST_AUDIO_FORMAT_F64;
} }
} }
gboolean gboolean
audio_convert_clean_fmt (AudioConvertFmt * fmt) audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in,
{ GstAudioInfo * out, GstAudioConvertDithering dither,
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,
GstAudioConvertNoiseShaping ns) GstAudioConvertNoiseShaping ns)
{ {
gint idx_in, idx_out; gint idx_in, idx_out;
gint in_depth, out_depth;
g_return_val_if_fail (ctx != NULL, FALSE); g_return_val_if_fail (ctx != NULL, FALSE);
g_return_val_if_fail (in != 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 */ /* first clean the existing context */
audio_convert_clean_context (ctx); audio_convert_clean_context (ctx);
g_return_val_if_fail (in->unpositioned_layout == out->unpositioned_layout, g_return_val_if_fail (GST_AUDIO_INFO_IS_UNPOSITIONED (in) ==
FALSE); GST_AUDIO_INFO_IS_UNPOSITIONED (out), FALSE);
ctx->in = *in; ctx->in = *in;
ctx->out = *out; 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 /* 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. * 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 * Also don't dither or apply noise shaping if target depth is larger than
* source depth. */ * source depth. */
if (ctx->out.depth <= 20 && (!ctx->in.is_int if (out_depth <= 20 && (!GST_AUDIO_FORMAT_INFO_IS_INT (in->finfo)
|| ctx->in.depth >= ctx->out.depth)) { || in_depth >= out_depth)) {
ctx->dither = dither; ctx->dither = dither;
ctx->ns = ns; ctx->ns = ns;
} else { } else {
@ -638,15 +632,15 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in,
/* Use simple error feedback when output sample rate is smaller than /* Use simple error feedback when output sample rate is smaller than
* 32000 as the other methods might move the noise to audible ranges */ * 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; ctx->ns = NOISE_SHAPING_ERROR_FEEDBACK;
gst_channel_mix_setup_matrix (ctx); 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]; 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]; ctx->pack = pack_funcs[idx_out];
/* if both formats are float/double or we use noise shaping use double as /* 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"); GST_INFO ("use float mixing");
ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_float; 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 */ /* 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 */ /* check if channel mixer is passthrough */
ctx->mix_passthrough = gst_channel_mix_passthrough (ctx); ctx->mix_passthrough = gst_channel_mix_passthrough (ctx);
/* check if output is in default format */ /* 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", GST_INFO ("in default %d, mix passthrough %d, out default %d",
ctx->in_default, ctx->mix_passthrough, ctx->out_default); ctx->in_default, ctx->mix_passthrough, ctx->out_default);
ctx->in_scale = (in->is_int) ? (32 - in->depth) : 0; ctx->in_scale =
ctx->out_scale = (out->is_int) ? (32 - out->depth) : 0; 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); gst_audio_quantize_setup (ctx);
@ -684,8 +680,8 @@ audio_convert_clean_context (AudioConvertCtx * ctx)
g_return_val_if_fail (ctx != NULL, FALSE); g_return_val_if_fail (ctx != NULL, FALSE);
gst_audio_quantize_free (ctx); gst_audio_quantize_free (ctx);
audio_convert_clean_fmt (&ctx->in); gst_audio_info_init (&ctx->in);
audio_convert_clean_fmt (&ctx->out); gst_audio_info_init (&ctx->out);
gst_channel_mix_unset_matrix (ctx); gst_channel_mix_unset_matrix (ctx);
g_free (ctx->tmpbuf); 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); g_return_val_if_fail (ctx != NULL, FALSE);
if (srcsize) if (srcsize)
*srcsize = samples * ctx->in.unit_size; *srcsize = samples * ctx->in.bpf;
if (dstsize) if (dstsize)
*dstsize = samples * ctx->out.unit_size; *dstsize = samples * ctx->out.bpf;
return TRUE; return TRUE;
} }
@ -716,6 +712,7 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src,
guint insize, outsize, size; guint insize, outsize, size;
gpointer outbuf, tmpbuf; gpointer outbuf, tmpbuf;
guint intemp = 0, outtemp = 0, biggest; guint intemp = 0, outtemp = 0, biggest;
gint in_width, out_width;
g_return_val_if_fail (ctx != NULL, FALSE); g_return_val_if_fail (ctx != NULL, FALSE);
g_return_val_if_fail (src != NULL, FALSE); g_return_val_if_fail (src != NULL, FALSE);
@ -725,23 +722,26 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src,
if (samples == 0) if (samples == 0)
return TRUE; return TRUE;
insize = ctx->in.unit_size * samples; insize = ctx->in.bpf * samples;
outsize = ctx->out.unit_size * 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 */ /* find biggest temp buffer size */
size = (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? sizeof (gdouble) size = (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? sizeof (gdouble)
: sizeof (gint32); : sizeof (gint32);
if (!ctx->in_default) 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) 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); biggest = MAX (intemp, outtemp);
/* see if one of the buffers can be used as temp */ /* 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; 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; tmpbuf = src;
else { else {
if (biggest > ctx->tmpbufsize) { 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 */ /* 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) if (ctx->out_default)
outbuf = dst; outbuf = dst;
else else

View file

@ -23,7 +23,7 @@
#define __AUDIO_CONVERT_H__ #define __AUDIO_CONVERT_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/audio/multichannel.h> #include <gst/audio/audio.h>
GST_DEBUG_CATEGORY_EXTERN (audio_convert_debug); GST_DEBUG_CATEGORY_EXTERN (audio_convert_debug);
#define GST_CAT_DEFAULT (audio_convert_debug) #define GST_CAT_DEFAULT (audio_convert_debug)
@ -65,6 +65,7 @@ typedef enum
} GstAudioConvertNoiseShaping; } GstAudioConvertNoiseShaping;
typedef struct _AudioConvertCtx AudioConvertCtx; typedef struct _AudioConvertCtx AudioConvertCtx;
#if 0
typedef struct _AudioConvertFmt AudioConvertFmt; typedef struct _AudioConvertFmt AudioConvertFmt;
struct _AudioConvertFmt struct _AudioConvertFmt
@ -84,6 +85,7 @@ struct _AudioConvertFmt
gint unit_size; gint unit_size;
}; };
#endif
typedef void (*AudioConvertUnpack) (gpointer src, gpointer dst, gint scale, typedef void (*AudioConvertUnpack) (gpointer src, gpointer dst, gint scale,
gint count); gint count);
@ -96,8 +98,8 @@ typedef void (*AudioConvertQuantize) (AudioConvertCtx * ctx, gpointer src,
struct _AudioConvertCtx struct _AudioConvertCtx
{ {
AudioConvertFmt in; GstAudioInfo in;
AudioConvertFmt out; GstAudioInfo out;
AudioConvertUnpack unpack; AudioConvertUnpack unpack;
AudioConvertPack pack; AudioConvertPack pack;
@ -130,10 +132,8 @@ struct _AudioConvertCtx
gdouble *error_buf; gdouble *error_buf;
}; };
gboolean audio_convert_clean_fmt (AudioConvertFmt * fmt);
gboolean audio_convert_prepare_context (AudioConvertCtx * ctx, gboolean audio_convert_prepare_context (AudioConvertCtx * ctx,
AudioConvertFmt * in, AudioConvertFmt * out, GstAudioInfo * in, GstAudioInfo * out,
GstAudioConvertDithering dither, GstAudioConvertNoiseShaping ns); GstAudioConvertDithering dither, GstAudioConvertNoiseShaping ns);
gboolean audio_convert_get_sizes (AudioConvertCtx * ctx, gint samples, gboolean audio_convert_get_sizes (AudioConvertCtx * ctx, gint samples,
gint * srcsize, gint * dstsize); gint * srcsize, gint * dstsize);

View file

@ -1,7 +1,7 @@
/* GStreamer /* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de> * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
* Copyright (C) 2005 Thomas Vander Stichele <thomas at apestaart dot org> * Copyright (C) 2005 Thomas Vander Stichele <thomas at apestaart dot org>
* Copyright (C) 2005 Wim Taymans <wim at fluendo dot com> * Copyright (C) 2011 Wim Taymans <wim.taymans at gmail dot com>
* *
* gstaudioconvert.c: Convert audio to different audio formats automatically * gstaudioconvert.c: Convert audio to different audio formats automatically
* *
@ -31,7 +31,7 @@
* <refsect2> * <refsect2>
* <title>Example launch line</title> * <title>Example launch line</title>
* |[ * |[
* 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 * ]| This pipeline converts audio to 8-bit. The level element shows that
* the output levels still match the one for a sine wave. * 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); const GValue * value, GParamSpec * pspec);
static void gst_audio_convert_get_property (GObject * object, guint prop_id, static void gst_audio_convert_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static gboolean structure_has_fixed_channel_positions (GstStructure * s,
gboolean * unpositioned_layout);
/* AudioConvert signals and args */ /* AudioConvert signals and args */
enum enum
@ -118,45 +116,7 @@ G_DEFINE_TYPE_WITH_CODE (GstAudioConvert, gst_audio_convert,
/*** GSTREAMER PROTOTYPES *****************************************************/ /*** GSTREAMER PROTOTYPES *****************************************************/
#define STATIC_CAPS \ #define STATIC_CAPS \
GST_STATIC_CAPS ( \ GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL))
"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 } " \
)
static GstStaticPadTemplate gst_audio_convert_src_template = static GstStaticPadTemplate gst_audio_convert_src_template =
GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_PAD_TEMPLATE ("src",
@ -284,90 +244,20 @@ gst_audio_convert_dispose (GObject * obj)
/*** GSTREAMER FUNCTIONS ******************************************************/ /*** 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 */ /* BaseTransform vmethods */
static gboolean static gboolean
gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps, gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
gsize * size) gsize * size)
{ {
AudioConvertFmt fmt = { 0 }; GstAudioInfo info;
g_assert (size); g_assert (size);
if (!gst_audio_convert_parse_caps (caps, &fmt)) if (!gst_audio_info_from_caps (&info, caps))
goto parse_error; goto parse_error;
GST_INFO_OBJECT (base, "unit_size = %u", fmt.unit_size); *size = info.bpf;
*size = fmt.unit_size; GST_INFO_OBJECT (base, "unit_size = %" G_GSIZE_FORMAT, *size);
audio_convert_clean_fmt (&fmt);
return TRUE; return TRUE;
@ -378,351 +268,61 @@ parse_error:
} }
} }
/* Set widths (a list); multiples of 8 between min and max */ /* copies the given caps */
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!)
*/
static GstCaps * static GstCaps *
gst_audio_convert_transform_caps (GstBaseTransform * base, gst_audio_convert_caps_remove_format_info (GstCaps * caps)
GstPadDirection direction, GstCaps * caps, GstCaps * filter)
{ {
GstCaps *ret; GstStructure *st;
GstStructure *s, *structure; gint i, n;
gboolean isfloat, allow_mixing; GstCaps *res;
gint width, depth, channels = 0;
const gchar *fields_used[] = { res = gst_caps_new_empty ();
"width", "depth", "rate", "channels", "endianness", "signed"
};
const gchar *structure_name;
gint n, j;
int i;
n = gst_caps_get_size (caps); 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 */
for (j = 0; j < n; j++) { if (i > 0 && gst_caps_is_subset_structure (res, st))
structure = gst_caps_get_structure (caps, j);
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; continue;
st = gst_structure_copy (st);
gst_structure_remove_fields (st, "format", "channel-positions", NULL);
gst_caps_append_structure (res, st);
} }
structure_name = gst_structure_get_name (structure); return res;
}
isfloat = strcmp (structure_name, "audio/x-raw-float") == 0; /* 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;
/* We operate on a version of the original structure with any additional result = gst_caps_copy (caps);
* 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) { /* Get all possible caps that we can transform to */
/* Commonly, depth is left out: set it equal to width if we have a fixed tmp = gst_audio_convert_caps_remove_format_info (caps);
* 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_DEBUG_OBJECT (base, "Caps transformed to %" GST_PTR_FORMAT, ret);
if (filter) { if (filter) {
GstCaps *intersection; tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (tmp);
GST_DEBUG_OBJECT (base, "Using filter caps %" GST_PTR_FORMAT, filter); tmp = tmp2;
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);
} }
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] = { static const GstAudioChannelPosition default_positions[8][8] = {
@ -924,8 +524,8 @@ gst_audio_convert_fixate_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps, GstCaps * othercaps) GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
{ {
GstStructure *ins, *outs; GstStructure *ins, *outs;
gint rate, endianness, depth, width; gint rate;
gboolean signedness; const gchar *fmt;
g_return_if_fail (gst_caps_is_fixed (caps)); 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); 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_get_int (ins, "rate", &rate)) {
if (gst_structure_has_field (outs, "rate")) { if (gst_structure_has_field (outs, "rate")) {
gst_structure_fixate_field_nearest_int (outs, "rate", 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); 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, gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
GstCaps * outcaps) GstCaps * outcaps)
{ {
AudioConvertFmt in_ac_caps = { 0 };
AudioConvertFmt out_ac_caps = { 0 };
GstAudioConvert *this = GST_AUDIO_CONVERT (base); GstAudioConvert *this = GST_AUDIO_CONVERT (base);
GstAudioInfo in_info;
GstAudioInfo out_info;
GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %" GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
GST_PTR_FORMAT, incaps, outcaps); GST_PTR_FORMAT, incaps, outcaps);
if (!gst_audio_convert_parse_caps (incaps, &in_ac_caps)) if (!gst_audio_info_from_caps (&in_info, incaps))
return FALSE; goto invalid_in;
if (!gst_audio_convert_parse_caps (outcaps, &out_ac_caps)) if (!gst_audio_info_from_caps (&out_info, outcaps))
return FALSE; 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)) this->dither, this->ns))
goto no_converter; goto no_converter;
return TRUE; 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: no_converter:
{ {
GST_ERROR_OBJECT (base, "could not find converter");
return FALSE; return FALSE;
} }
} }
@ -1010,79 +597,6 @@ gst_audio_convert_transform_ip (GstBaseTransform * base, GstBuffer * buf)
return GST_FLOW_OK; 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 static GstFlowReturn
gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf, gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
GstBuffer * outbuf) GstBuffer * outbuf)
@ -1095,7 +609,7 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
gpointer src, dst; gpointer src, dst;
/* get amount of samples to convert. */ /* 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 /* get in/output sizes, to see if the buffers we got are of correct
* sizes */ * sizes */
@ -1122,7 +636,7 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
goto convert_error; goto convert_error;
} else { } else {
/* Create silence buffer */ /* 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; ret = GST_FLOW_OK;

View file

@ -24,7 +24,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstbasetransform.h> #include <gst/base/gstbasetransform.h>
#include <gst/audio/multichannel.h> #include <gst/audio/audio.h>
#include "audioconvert.h" #include "audioconvert.h"

View file

@ -439,7 +439,7 @@ gst_audio_quantize_setup_dither (AudioConvertCtx * ctx)
{ {
switch (ctx->dither) { switch (ctx->dither) {
case DITHER_TPDF_HF: 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); ctx->last_random = g_new0 (gint32, ctx->out.channels);
else else
ctx->last_random = g_new0 (gdouble, ctx->out.channels); ctx->last_random = g_new0 (gdouble, ctx->out.channels);
@ -469,14 +469,14 @@ gst_audio_quantize_setup_quantize_func (AudioConvertCtx * ctx)
{ {
gint index = 0; gint index = 0;
if (!ctx->out.is_int) { if (!GST_AUDIO_FORMAT_INFO_IS_INT (ctx->out.finfo)) {
ctx->quantize = NULL; ctx->quantize = NULL;
return; return;
} }
if (ctx->ns == NOISE_SHAPING_NONE) { if (ctx->ns == NOISE_SHAPING_NONE) {
index += ctx->dither; index += ctx->dither;
index += (ctx->out.sign) ? 0 : 4; index += GST_AUDIO_FORMAT_INFO_IS_SIGNED (ctx->out.finfo) ? 0 : 4;
} else { } else {
index += 8 + (4 * ctx->dither); index += 8 + (4 * ctx->dither);
index += ctx->ns - 1; index += ctx->ns - 1;

View file

@ -70,7 +70,7 @@ gst_channel_mix_fill_identical (AudioConvertCtx * this)
for (co = 0; co < this->out.channels; co++) { for (co = 0; co < this->out.channels; co++) {
/* find a channel in input with same position */ /* find a channel in input with same position */
for (ci = 0; ci < this->in.channels; ci++) { 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; this->matrix[ci][co] = 1.0;
} }
} }
@ -118,19 +118,19 @@ gst_channel_mix_fill_compatible (AudioConvertCtx * this)
gint n; gint n;
for (n = 0; n < this->in.channels; 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; 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; 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; pos1_2 = n;
} }
for (n = 0; n < this->out.channels; 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; 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; 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; pos2_2 = n;
} }
@ -182,15 +182,15 @@ gst_channel_mix_fill_compatible (AudioConvertCtx * this)
*/ */
static void static void
gst_channel_mix_detect_pos (AudioConvertFmt * caps, gst_channel_mix_detect_pos (GstAudioInfo * info,
gint * f, gboolean * has_f, gint * f, gboolean * has_f,
gint * c, gboolean * has_c, gint * r, gboolean * has_r, gint * c, gboolean * has_c, gint * r, gboolean * has_r,
gint * s, gboolean * has_s, gint * b, gboolean * has_b) gint * s, gboolean * has_s, gint * b, gboolean * has_b)
{ {
gint n; gint n;
for (n = 0; n < caps->channels; n++) { for (n = 0; n < info->channels; n++) {
switch (caps->pos[n]) { switch (info->position[n]) {
case GST_AUDIO_CHANNEL_POSITION_FRONT_MONO: case GST_AUDIO_CHANNEL_POSITION_FRONT_MONO:
f[1] = n; f[1] = n;
*has_f = TRUE; *has_f = TRUE;
@ -247,8 +247,8 @@ gst_channel_mix_detect_pos (AudioConvertFmt * caps,
static void static void
gst_channel_mix_fill_one_other (gfloat ** matrix, gst_channel_mix_fill_one_other (gfloat ** matrix,
AudioConvertFmt * from_caps, gint * from_idx, GstAudioInfo * from_info, gint * from_idx,
AudioConvertFmt * to_caps, gint * to_idx, gfloat ratio) GstAudioInfo * to_info, gint * to_idx, gfloat ratio)
{ {
/* src & dst have center => passthrough */ /* src & dst have center => passthrough */
@ -542,26 +542,26 @@ gst_channel_mix_fill_normalize (AudioConvertCtx * this)
static gboolean static gboolean
gst_channel_mix_fill_special (AudioConvertCtx * this) 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 */ /* Special, standard conversions here */
/* Mono<->Stereo, just a fast-path */ /* Mono<->Stereo, just a fast-path */
if (in->channels == 2 && out->channels == 1 && if (in->channels == 2 && out->channels == 1 &&
((in->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT && ((in->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT &&
in->pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) || in->position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) ||
(in->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT && (in->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT &&
in->pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) && in->position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) &&
out->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) { out->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) {
this->matrix[0][0] = 0.5; this->matrix[0][0] = 0.5;
this->matrix[1][0] = 0.5; this->matrix[1][0] = 0.5;
return TRUE; return TRUE;
} else if (in->channels == 1 && out->channels == 2 && } else if (in->channels == 1 && out->channels == 2 &&
((out->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT && ((out->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT &&
out->pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) || out->position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) ||
(out->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT && (out->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT &&
out->pos[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) && out->position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) &&
in->pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) { in->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) {
this->matrix[0][0] = 1.0; this->matrix[0][0] = 1.0;
this->matrix[0][1] = 1.0; this->matrix[0][1] = 1.0;
return TRUE; return TRUE;
@ -584,7 +584,7 @@ gst_channel_mix_fill_matrix (AudioConvertCtx * this)
gst_channel_mix_fill_identical (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_compatible (this);
gst_channel_mix_fill_others (this); gst_channel_mix_fill_others (this);
gst_channel_mix_fill_normalize (this); gst_channel_mix_fill_normalize (this);
@ -601,7 +601,8 @@ gst_channel_mix_setup_matrix (AudioConvertCtx * this)
gst_channel_mix_unset_matrix (this); gst_channel_mix_unset_matrix (this);
/* temp storage */ /* 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); this->tmp = (gpointer) g_new (gint32, this->out.channels);
} else { } else {
this->tmp = (gpointer) g_new (gdouble, this->out.channels); this->tmp = (gpointer) g_new (gdouble, this->out.channels);

View file

@ -5,7 +5,9 @@ plugin_LTLIBRARIES = libgstaudiorate.la
libgstaudiorate_la_SOURCES = gstaudiorate.c libgstaudiorate_la_SOURCES = gstaudiorate.c
libgstaudiorate_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) libgstaudiorate_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
libgstaudiorate_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) 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 libgstaudiorate_la_LIBTOOLFLAGS = --tag=disable-static
Android.mk: Makefile.am $(BUILT_SOURCES) Android.mk: Makefile.am $(BUILT_SOURCES)

View file

@ -93,19 +93,17 @@ enum
}; };
static GstStaticPadTemplate gst_audio_rate_src_template = static GstStaticPadTemplate gst_audio_rate_src_template =
GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_SRC,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS ";" GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL))
GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
); );
static GstStaticPadTemplate gst_audio_rate_sink_template = static GstStaticPadTemplate gst_audio_rate_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS ";" GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL))
GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
); );
static gboolean gst_audio_rate_sink_event (GstPad * pad, GstEvent * event); static gboolean gst_audio_rate_sink_event (GstPad * pad, GstEvent * event);
@ -208,35 +206,19 @@ gst_audio_rate_reset (GstAudioRate * audiorate)
static gboolean static gboolean
gst_audio_rate_setcaps (GstAudioRate * audiorate, GstCaps * caps) gst_audio_rate_setcaps (GstAudioRate * audiorate, GstCaps * caps)
{ {
GstStructure *structure; GstAudioInfo info;
gint channels, width, rate;
structure = gst_caps_get_structure (caps, 0); if (!gst_audio_info_from_caps (&info, caps))
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))
goto wrong_caps; goto wrong_caps;
audiorate->bytes_per_sample = channels * (width / 8); audiorate->info = info;
if (audiorate->bytes_per_sample == 0)
goto wrong_format;
audiorate->rate = rate;
return TRUE; return TRUE;
/* ERRORS */ /* ERRORS */
wrong_caps: wrong_caps:
{ {
GST_DEBUG_OBJECT (audiorate, "could not get channels/width from caps"); GST_DEBUG_OBJECT (audiorate, "could not parse caps");
return FALSE;
}
wrong_format:
{
GST_DEBUG_OBJECT (audiorate, "bytes_per_samples gave 0");
return FALSE; return FALSE;
} }
} }
@ -386,20 +368,24 @@ static gboolean
gst_audio_rate_convert (GstAudioRate * audiorate, gst_audio_rate_convert (GstAudioRate * audiorate,
GstFormat src_fmt, guint64 src_val, GstFormat dest_fmt, guint64 * dest_val) GstFormat src_fmt, guint64 src_val, GstFormat dest_fmt, guint64 * dest_val)
{ {
gint rate, bpf;
if (src_fmt == dest_fmt) { if (src_fmt == dest_fmt) {
*dest_val = src_val; *dest_val = src_val;
return TRUE; return TRUE;
} }
rate = GST_AUDIO_INFO_RATE (&audiorate->info);
bpf = GST_AUDIO_INFO_BPF (&audiorate->info);
switch (src_fmt) { switch (src_fmt) {
case GST_FORMAT_DEFAULT: case GST_FORMAT_DEFAULT:
switch (dest_fmt) { switch (dest_fmt) {
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
*dest_val = src_val * audiorate->bytes_per_sample; *dest_val = src_val * bpf;
break; break;
case GST_FORMAT_TIME: case GST_FORMAT_TIME:
*dest_val = *dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, rate);
gst_util_uint64_scale_int (src_val, GST_SECOND, audiorate->rate);
break; break;
default: default:
return FALSE;; return FALSE;;
@ -408,11 +394,11 @@ gst_audio_rate_convert (GstAudioRate * audiorate,
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
switch (dest_fmt) { switch (dest_fmt) {
case GST_FORMAT_DEFAULT: case GST_FORMAT_DEFAULT:
*dest_val = src_val / audiorate->bytes_per_sample; *dest_val = src_val / bpf;
break; break;
case GST_FORMAT_TIME: case GST_FORMAT_TIME:
*dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, *dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND,
audiorate->rate * audiorate->bytes_per_sample); rate * bpf);
break; break;
default: default:
return FALSE;; return FALSE;;
@ -422,14 +408,13 @@ gst_audio_rate_convert (GstAudioRate * audiorate,
switch (dest_fmt) { switch (dest_fmt) {
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
*dest_val = gst_util_uint64_scale_int (src_val, *dest_val = gst_util_uint64_scale_int (src_val,
audiorate->rate * audiorate->bytes_per_sample, GST_SECOND); rate * bpf, GST_SECOND);
break; break;
case GST_FORMAT_DEFAULT: case GST_FORMAT_DEFAULT:
*dest_val = *dest_val = gst_util_uint64_scale_int (src_val, rate, GST_SECOND);
gst_util_uint64_scale_int (src_val, audiorate->rate, GST_SECOND);
break; break;
default: default:
return FALSE;; return FALSE;
} }
break; break;
default: default:
@ -493,11 +478,15 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
guint in_size; guint in_size;
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
GstClockTimeDiff diff; GstClockTimeDiff diff;
gint rate, bpf;
audiorate = GST_AUDIO_RATE (gst_pad_get_parent (pad)); 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 */ /* need to be negotiated now */
if (audiorate->bytes_per_sample == 0) if (bpf == 0)
goto not_negotiated; goto not_negotiated;
/* we have a new pending segment */ /* 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 */ /* convert first timestamp of segment to sample position */
pos = gst_util_uint64_scale_int (audiorate->src_segment.start, 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); 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_offset = pos;
audiorate->next_ts = gst_util_uint64_scale_int (audiorate->next_offset, 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)) { if (audiorate->skip_to_first && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
GST_DEBUG_OBJECT (audiorate, "but skipping to first buffer instead"); GST_DEBUG_OBJECT (audiorate, "but skipping to first buffer instead");
pos = gst_util_uint64_scale_int (GST_BUFFER_TIMESTAMP (buf), 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, GST_DEBUG_OBJECT (audiorate, "so resync to offset %" G_GINT64_FORMAT,
pos); pos);
audiorate->next_offset = 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_size = gst_buffer_get_size (buf);
in_samples = in_size / audiorate->bytes_per_sample; in_samples = in_size / bpf;
/* calculate the buffer offset */ /* calculate the buffer offset */
in_offset = gst_util_uint64_scale_int_round (in_time, audiorate->rate, in_offset = gst_util_uint64_scale_int_round (in_time, rate, GST_SECOND);
GST_SECOND);
in_offset_end = in_offset + in_samples; in_offset_end = in_offset + in_samples;
GST_LOG_OBJECT (audiorate, 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:%" ", in_size:%u, in_offset:%" G_GUINT64_FORMAT ", in_offset_end:%"
G_GUINT64_FORMAT ", ->next_offset:%" G_GUINT64_FORMAT ", ->next_ts:%" G_GUINT64_FORMAT ", ->next_offset:%" G_GUINT64_FORMAT ", ->next_ts:%"
GST_TIME_FORMAT, GST_TIME_ARGS (in_time), 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, in_size, in_offset, in_offset_end, audiorate->next_offset,
GST_TIME_ARGS (audiorate->next_ts)); GST_TIME_ARGS (audiorate->next_ts));
@ -587,11 +575,11 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
fillsamples = in_offset - audiorate->next_offset; fillsamples = in_offset - audiorate->next_offset;
while (fillsamples > 0) { while (fillsamples > 0) {
guint64 cursamples = MIN (fillsamples, audiorate->rate); guint64 cursamples = MIN (fillsamples, rate);
guint8 *data; guint8 *data;
fillsamples -= cursamples; fillsamples -= cursamples;
fillsize = cursamples * audiorate->bytes_per_sample; fillsize = cursamples * bpf;
fill = gst_buffer_new_and_alloc (fillsize); fill = gst_buffer_new_and_alloc (fillsize);
@ -612,7 +600,7 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
* streams */ * streams */
GST_BUFFER_TIMESTAMP (fill) = audiorate->next_ts; GST_BUFFER_TIMESTAMP (fill) = audiorate->next_ts;
audiorate->next_ts = gst_util_uint64_scale_int (audiorate->next_offset, 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_DURATION (fill) = audiorate->next_ts -
GST_BUFFER_TIMESTAMP (fill); GST_BUFFER_TIMESTAMP (fill);
@ -638,7 +626,7 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
} else if (in_offset < audiorate->next_offset) { } else if (in_offset < audiorate->next_offset) {
/* need to remove samples */ /* need to remove samples */
if (in_offset_end <= audiorate->next_offset) { if (in_offset_end <= audiorate->next_offset) {
guint64 drop = in_size / audiorate->bytes_per_sample; guint64 drop = in_size / bpf;
audiorate->drop += drop; audiorate->drop += drop;
@ -660,7 +648,7 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
/* truncate buffer */ /* truncate buffer */
truncsamples = audiorate->next_offset - in_offset; truncsamples = audiorate->next_offset - in_offset;
truncsize = truncsamples * audiorate->bytes_per_sample; truncsize = truncsamples * bpf;
leftsize = in_size - truncsize; leftsize = in_size - truncsize;
trunc = trunc =
@ -690,7 +678,7 @@ send:
GST_BUFFER_TIMESTAMP (buf) = audiorate->next_ts; GST_BUFFER_TIMESTAMP (buf) = audiorate->next_ts;
audiorate->next_ts = gst_util_uint64_scale_int (in_offset_end, 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); GST_BUFFER_DURATION (buf) = audiorate->next_ts - GST_BUFFER_TIMESTAMP (buf);
if (audiorate->discont) { if (audiorate->discont) {
@ -804,8 +792,8 @@ gst_audio_rate_change_state (GstElement * element, GstStateChange transition)
audiorate->in = 0; audiorate->in = 0;
audiorate->out = 0; audiorate->out = 0;
audiorate->drop = 0; audiorate->drop = 0;
audiorate->bytes_per_sample = 0;
audiorate->add = 0; audiorate->add = 0;
gst_audio_info_init (&audiorate->info);
gst_audio_rate_reset (audiorate); gst_audio_rate_reset (audiorate);
break; break;
default: default:

View file

@ -51,8 +51,7 @@ struct _GstAudioRate
GstPad *sinkpad, *srcpad; GstPad *sinkpad, *srcpad;
/* audio format */ /* audio format */
gint bytes_per_sample; GstAudioInfo info;
gint rate;
/* stats */ /* stats */
guint64 in, out, add, drop; guint64 in, out, add, drop;

View file

@ -20,6 +20,7 @@ libgstaudioresample_la_CFLAGS = \
$(ORC_CFLAGS) $(ORC_CFLAGS)
libgstaudioresample_la_LIBADD = \ libgstaudioresample_la_LIBADD = \
$(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la \
$(GST_BASE_LIBS) \ $(GST_BASE_LIBS) \
$(GST_LIBS) \ $(GST_LIBS) \
$(ORC_LIBS) $(ORC_TEST_LIBS) \ $(ORC_LIBS) $(ORC_TEST_LIBS) \

View file

@ -28,7 +28,7 @@
* <refsect2> * <refsect2>
* <title>Example launch line</title> * <title>Example launch line</title>
* |[ * |[
* 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. * ]| Decode an Ogg/Vorbis downsample to 8Khz and play sound through alsa.
* To create the Ogg/Vorbis file refer to the documentation of vorbisenc. * To create the Ogg/Vorbis file refer to the documentation of vorbisenc.
* </refsect2> * </refsect2>
@ -65,42 +65,13 @@ enum
PROP_QUALITY PROP_QUALITY
}; };
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define SUPPORTED_CAPS \ #define SUPPORTED_CAPS \
GST_STATIC_CAPS ( \ GST_AUDIO_CAPS_MAKE ("{ F32_LE, F64_LE, S32_LE, S24_3LE, S16_LE, S8 }")
"audio/x-raw-float, " \ #else
"rate = (int) [ 1, MAX ], " \ #define SUPPORTED_CAPS \
"channels = (int) [ 1, MAX ], " \ GST_AUDIO_CAPS_MAKE ("{ F32_BE, F64_BE, S32_BE, S24_3BE, S16_BE, S8 }")
"endianness = (int) BYTE_ORDER, " \ #endif
"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" \
)
/* If TRUE integer arithmetic resampling is faster and will be used if appropiate */ /* If TRUE integer arithmetic resampling is faster and will be used if appropiate */
#if defined AUDIORESAMPLE_FORMAT_INT #if defined AUDIORESAMPLE_FORMAT_INT
@ -113,11 +84,15 @@ static gboolean gst_audio_resample_use_int = FALSE;
static GstStaticPadTemplate gst_audio_resample_sink_template = static GstStaticPadTemplate gst_audio_resample_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink", 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 = static GstStaticPadTemplate gst_audio_resample_src_template =
GST_STATIC_PAD_TEMPLATE ("src", 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, static void gst_audio_resample_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec); 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 = NULL;
resample->tmp_out_size = 0; resample->tmp_out_size = 0;
gst_caps_replace (&resample->sinkcaps, NULL);
gst_caps_replace (&resample->srccaps, NULL);
return TRUE; return TRUE;
} }
@ -262,23 +234,21 @@ static gboolean
gst_audio_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps, gst_audio_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
gsize * size) gsize * size)
{ {
gint width, channels; GstAudioInfo info;
GstStructure *structure;
gboolean ret;
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 */ *size = GST_AUDIO_INFO_BPF (&info);
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;
return TRUE; return TRUE;
/* ERRORS */
invalid_caps:
{
GST_ERROR_OBJECT (base, "invalid caps");
return FALSE;
}
} }
static GstCaps * static GstCaps *
@ -455,63 +425,6 @@ gst_audio_resample_reset_state (GstAudioResample * resample)
resample->funcs->reset_mem (resample->state); 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 static gint
_gcd (gint a, gint b) _gcd (gint a, gint b)
{ {
@ -531,26 +444,29 @@ gst_audio_resample_transform_size (GstBaseTransform * base,
gsize * othersize) gsize * othersize)
{ {
gboolean ret = TRUE; gboolean ret = TRUE;
GstAudioInfo in, out;
guint32 ratio_den, ratio_num; guint32 ratio_den, ratio_num;
gint inrate, outrate, gcd; gint inrate, outrate, gcd;
gint bytes_per_samp, channels; gint bpf;
GST_LOG_OBJECT (base, "asked to transform size %" G_GSIZE_FORMAT GST_LOG_OBJECT (base, "asked to transform size %" G_GSIZE_FORMAT
" in direction %s", size, direction == GST_PAD_SINK ? "SINK" : "SRC"); " in direction %s", size, direction == GST_PAD_SINK ? "SINK" : "SRC");
/* Get sample width -> bytes_per_samp, channels, inrate, outrate */ /* Get sample width -> bytes_per_samp, channels, inrate, outrate */
ret = ret = gst_audio_info_from_caps (&in, caps);
gst_audio_resample_parse_caps (caps, othercaps, &bytes_per_samp, ret &= gst_audio_info_from_caps (&out, othercaps);
&channels, &inrate, &outrate, NULL);
if (G_UNLIKELY (!ret)) { if (G_UNLIKELY (!ret)) {
GST_ERROR_OBJECT (base, "Wrong caps"); GST_ERROR_OBJECT (base, "Wrong caps");
return FALSE; return FALSE;
} }
/* Number of samples in either buffer is size / (width*channels) -> /* Number of samples in either buffer is size / (width*channels) ->
* calculate the factor */ * 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 */ /* Convert source buffer size to samples */
size /= bytes_per_samp; size /= bpf;
/* Simplify the conversion ratio factors */ /* Simplify the conversion ratio factors */
gcd = _gcd (inrate, outrate); gcd = _gcd (inrate, outrate);
@ -560,16 +476,16 @@ gst_audio_resample_transform_size (GstBaseTransform * base,
if (direction == GST_PAD_SINK) { if (direction == GST_PAD_SINK) {
/* asked to convert size of an incoming buffer. Round up the output size */ /* 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 = gst_util_uint64_scale_int_ceil (size, ratio_den, ratio_num);
*othersize *= bytes_per_samp; *othersize *= bpf;
} else { } else {
/* asked to convert size of an outgoing buffer. Round down the input size */ /* 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 = gst_util_uint64_scale_int (size, ratio_num, ratio_den);
*othersize *= bytes_per_samp; *othersize *= bpf;
} }
GST_LOG_OBJECT (base, GST_LOG_OBJECT (base,
"transformed size %" G_GSIZE_FORMAT " to %" G_GSIZE_FORMAT, "transformed size %" G_GSIZE_FORMAT " to %" G_GSIZE_FORMAT,
size * bytes_per_samp, *othersize); size * bpf, *othersize);
return ret; return ret;
} }
@ -579,18 +495,27 @@ gst_audio_resample_set_caps (GstBaseTransform * base, GstCaps * incaps,
GstCaps * outcaps) GstCaps * outcaps)
{ {
gboolean ret; gboolean ret;
gint width = 0, inrate = 0, outrate = 0, channels = 0; gint width, inrate, outrate, channels;
gboolean fp; gboolean fp;
GstAudioResample *resample = GST_AUDIO_RESAMPLE (base); GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
GstAudioInfo in, out;
GST_LOG ("incaps %" GST_PTR_FORMAT ", outcaps %" GST_LOG ("incaps %" GST_PTR_FORMAT ", outcaps %"
GST_PTR_FORMAT, incaps, outcaps); GST_PTR_FORMAT, incaps, outcaps);
ret = gst_audio_resample_parse_caps (incaps, outcaps, if (!gst_audio_info_from_caps (&in, incaps))
&width, &channels, &inrate, &outrate, &fp); goto invalid_incaps;
if (!gst_audio_info_from_caps (&out, outcaps))
goto invalid_outcaps;
if (G_UNLIKELY (!ret)) /* FIXME do some checks */
return FALSE;
/* 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 = ret =
gst_audio_resample_update_state (resample, width, channels, inrate, 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)) if (G_UNLIKELY (!ret))
return FALSE; 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; 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) #define GST_MAXINT24 (8388607)

View file

@ -53,9 +53,6 @@ struct _GstAudioResample {
GstBaseTransform element; GstBaseTransform element;
/* <private> */ /* <private> */
GstCaps *srccaps, *sinkcaps;
gboolean need_discont; gboolean need_discont;
GstClockTime t0; GstClockTime t0;
@ -67,12 +64,18 @@ struct _GstAudioResample {
guint64 num_gap_samples; guint64 num_gap_samples;
guint64 num_nongap_samples; guint64 num_nongap_samples;
GstAudioInfo in;
GstAudioInfo out;
/* properties */
gint quality;
/* state */
gboolean fp;
gint width;
gint channels; gint channels;
gint inrate; gint inrate;
gint outrate; gint outrate;
gint quality;
gint width;
gboolean fp;
guint8 *tmp_in; guint8 *tmp_in;
guint tmp_in_size; guint tmp_in_size;

View file

@ -1,9 +1,11 @@
plugin_LTLIBRARIES = libgstaudiotestsrc.la plugin_LTLIBRARIES = libgstaudiotestsrc.la
libgstaudiotestsrc_la_SOURCES = gstaudiotestsrc.c 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_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 libgstaudiotestsrc_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstaudiotestsrc.h noinst_HEADERS = gstaudiotestsrc.h

View file

@ -76,28 +76,20 @@ enum
PROP_LAST 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 = static GstStaticPadTemplate gst_audio_test_src_src_template =
GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_SRC,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, " GST_STATIC_CAPS ("audio/x-raw, "
"endianness = (int) BYTE_ORDER, " "format = (string) " FORMAT_STR ", "
"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 }, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]") "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
); );
@ -234,9 +226,6 @@ gst_audio_test_src_class_init (GstAudioTestSrcClass * klass)
static void static void
gst_audio_test_src_init (GstAudioTestSrc * src) gst_audio_test_src_init (GstAudioTestSrc * src)
{ {
src->samplerate = 44100;
src->format = GST_AUDIO_TEST_SRC_FORMAT_NONE;
src->volume = DEFAULT_VOLUME; src->volume = DEFAULT_VOLUME;
src->freq = DEFAULT_FREQ; src->freq = DEFAULT_FREQ;
@ -271,20 +260,16 @@ static void
gst_audio_test_src_fixate (GstBaseSrc * bsrc, GstCaps * caps) gst_audio_test_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
{ {
GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (bsrc); GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (bsrc);
const gchar *name;
GstStructure *structure; GstStructure *structure;
structure = gst_caps_get_structure (caps, 0); 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); gst_structure_fixate_field_string (structure, "format", DEFAULT_FORMAT_STR);
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);
/* fixate to mono unless downstream requires stereo, for backwards compat */ /* fixate to mono unless downstream requires stereo, for backwards compat */
gst_structure_fixate_field_nearest_int (structure, "channels", 1); gst_structure_fixate_field_nearest_int (structure, "channels", 1);
@ -296,53 +281,25 @@ static gboolean
gst_audio_test_src_setcaps (GstBaseSrc * basesrc, GstCaps * caps) gst_audio_test_src_setcaps (GstBaseSrc * basesrc, GstCaps * caps)
{ {
GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (basesrc); GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (basesrc);
const GstStructure *structure; GstAudioInfo info;
const gchar *name;
gint width;
gboolean ret;
structure = gst_caps_get_structure (caps, 0); if (!gst_audio_info_from_caps (&info, caps))
ret = gst_structure_get_int (structure, "rate", &src->samplerate); 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); src->info = info;
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);
gst_audio_test_src_change_wave (src); 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 static gboolean
@ -356,6 +313,7 @@ gst_audio_test_src_query (GstBaseSrc * basesrc, GstQuery * query)
{ {
GstFormat src_fmt, dest_fmt; GstFormat src_fmt, dest_fmt;
gint64 src_val, dest_val; gint64 src_val, dest_val;
gint rate;
gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
if (src_fmt == dest_fmt) { if (src_fmt == dest_fmt) {
@ -363,14 +321,14 @@ gst_audio_test_src_query (GstBaseSrc * basesrc, GstQuery * query)
goto done; goto done;
} }
rate = GST_AUDIO_INFO_RATE (&src->info);
switch (src_fmt) { switch (src_fmt) {
case GST_FORMAT_DEFAULT: case GST_FORMAT_DEFAULT:
switch (dest_fmt) { switch (dest_fmt) {
case GST_FORMAT_TIME: case GST_FORMAT_TIME:
/* samples to time */ /* samples to time */
dest_val = dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, rate);
gst_util_uint64_scale_int (src_val, GST_SECOND,
src->samplerate);
break; break;
default: default:
goto error; goto error;
@ -380,9 +338,7 @@ gst_audio_test_src_query (GstBaseSrc * basesrc, GstQuery * query)
switch (dest_fmt) { switch (dest_fmt) {
case GST_FORMAT_DEFAULT: case GST_FORMAT_DEFAULT:
/* time to samples */ /* time to samples */
dest_val = dest_val = gst_util_uint64_scale_int (src_val, rate, GST_SECOND);
gst_util_uint64_scale_int (src_val, src->samplerate,
GST_SECOND);
break; break;
default: default:
goto error; goto error;
@ -422,19 +378,20 @@ error:
static void \ static void \
gst_audio_test_src_create_sine_##type (GstAudioTestSrc * src, g##type * samples) \ gst_audio_test_src_create_sine_##type (GstAudioTestSrc * src, g##type * samples) \
{ \ { \
gint i, c; \ gint i, c, channels; \
gdouble step, amp; \ 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; \ amp = src->volume * scale; \
\ \
i = 0; \ i = 0; \
while (i < (src->generate_samples_per_buffer * src->channels)) { \ while (i < (src->generate_samples_per_buffer * channels)) { \
src->accumulator += step; \ src->accumulator += step; \
if (src->accumulator >= M_PI_M2) \ if (src->accumulator >= M_PI_M2) \
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); \ samples[i++] = (g##type) (sin (src->accumulator) * amp); \
} \ } \
} \ } \
@ -456,19 +413,20 @@ static const ProcessFunc sine_funcs[] = {
static void \ static void \
gst_audio_test_src_create_square_##type (GstAudioTestSrc * src, g##type * samples) \ gst_audio_test_src_create_square_##type (GstAudioTestSrc * src, g##type * samples) \
{ \ { \
gint i, c; \ gint i, c, channels; \
gdouble step, amp; \ 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; \ amp = src->volume * scale; \
\ \
i = 0; \ i = 0; \
while (i < (src->generate_samples_per_buffer * src->channels)) { \ while (i < (src->generate_samples_per_buffer * channels)) { \
src->accumulator += step; \ src->accumulator += step; \
if (src->accumulator >= M_PI_M2) \ if (src->accumulator >= M_PI_M2) \
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); \ samples[i++] = (g##type) ((src->accumulator < G_PI) ? amp : -amp); \
} \ } \
} \ } \
@ -490,23 +448,24 @@ static const ProcessFunc square_funcs[] = {
static void \ static void \
gst_audio_test_src_create_saw_##type (GstAudioTestSrc * src, g##type * samples) \ gst_audio_test_src_create_saw_##type (GstAudioTestSrc * src, g##type * samples) \
{ \ { \
gint i, c; \ gint i, c, channels; \
gdouble step, amp; \ 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; \ amp = (src->volume * scale) / G_PI; \
\ \
i = 0; \ i = 0; \
while (i < (src->generate_samples_per_buffer * src->channels)) { \ while (i < (src->generate_samples_per_buffer * channels)) { \
src->accumulator += step; \ src->accumulator += step; \
if (src->accumulator >= M_PI_M2) \ if (src->accumulator >= M_PI_M2) \
src->accumulator -= M_PI_M2; \ src->accumulator -= M_PI_M2; \
\ \
if (src->accumulator < G_PI) { \ 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); \ samples[i++] = (g##type) (src->accumulator * amp); \
} else { \ } else { \
for (c = 0; c < src->channels; ++c) \ for (c = 0; c < channels; ++c) \
samples[i++] = (g##type) ((M_PI_M2 - src->accumulator) * -amp); \ samples[i++] = (g##type) ((M_PI_M2 - src->accumulator) * -amp); \
} \ } \
} \ } \
@ -528,26 +487,27 @@ static const ProcessFunc saw_funcs[] = {
static void \ static void \
gst_audio_test_src_create_triangle_##type (GstAudioTestSrc * src, g##type * samples) \ gst_audio_test_src_create_triangle_##type (GstAudioTestSrc * src, g##type * samples) \
{ \ { \
gint i, c; \ gint i, c, channels; \
gdouble step, amp; \ 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; \ amp = (src->volume * scale) / G_PI_2; \
\ \
i = 0; \ i = 0; \
while (i < (src->generate_samples_per_buffer * src->channels)) { \ while (i < (src->generate_samples_per_buffer * channels)) { \
src->accumulator += step; \ src->accumulator += step; \
if (src->accumulator >= M_PI_M2) \ if (src->accumulator >= M_PI_M2) \
src->accumulator -= M_PI_M2; \ src->accumulator -= M_PI_M2; \
\ \
if (src->accumulator < (G_PI_2)) { \ 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); \ samples[i++] = (g##type) (src->accumulator * amp); \
} else if (src->accumulator < (G_PI * 1.5)) { \ } 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); \ samples[i++] = (g##type) ((src->accumulator - G_PI) * -amp); \
} else { \ } else { \
for (c = 0; c < src->channels; ++c) \ for (c = 0; c < channels; ++c) \
samples[i++] = (g##type) ((M_PI_M2 - src->accumulator) * -amp); \ samples[i++] = (g##type) ((M_PI_M2 - src->accumulator) * -amp); \
} \ } \
} \ } \
@ -569,7 +529,7 @@ static const ProcessFunc triangle_funcs[] = {
static void \ static void \
gst_audio_test_src_create_silence_##type (GstAudioTestSrc * src, g##type * samples) \ 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); DEFINE_SILENCE (int16);
@ -590,10 +550,11 @@ gst_audio_test_src_create_white_noise_##type (GstAudioTestSrc * src, g##type * s
{ \ { \
gint i, c; \ gint i, c; \
gdouble amp = (src->volume * scale); \ gdouble amp = (src->volume * scale); \
gint channels = GST_AUDIO_INFO_CHANNELS (&src->info); \
\ \
i = 0; \ i = 0; \
while (i < (src->generate_samples_per_buffer * src->channels)) { \ while (i < (src->generate_samples_per_buffer * channels)) { \
for (c = 0; c < src->channels; ++c) \ for (c = 0; c < channels; ++c) \
samples[i++] = (g##type) (amp * g_rand_double_range (src->gen, -1.0, 1.0)); \ 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 \ static void \
gst_audio_test_src_create_pink_noise_##type (GstAudioTestSrc * src, g##type * samples) \ gst_audio_test_src_create_pink_noise_##type (GstAudioTestSrc * src, g##type * samples) \
{ \ { \
gint i, c; \ gint i, c, channels; \
gdouble amp; \ gdouble amp; \
\ \
amp = src->volume * scale; \ amp = src->volume * scale; \
channels = GST_AUDIO_INFO_CHANNELS (&src->info); \
\ \
i = 0; \ i = 0; \
while (i < (src->generate_samples_per_buffer * src->channels)) { \ while (i < (src->generate_samples_per_buffer * channels)) { \
for (c = 0; c < src->channels; ++c) { \ for (c = 0; c < channels; ++c) { \
samples[i++] = \ samples[i++] = \
(g##type) (gst_audio_test_src_generate_pink_noise_value (src) * \ (g##type) (gst_audio_test_src_generate_pink_noise_value (src) * \
amp); \ amp); \
@ -726,19 +688,20 @@ gst_audio_test_src_init_sine_table (GstAudioTestSrc * src)
static void \ static void \
gst_audio_test_src_create_sine_table_##type (GstAudioTestSrc * src, g##type * samples) \ gst_audio_test_src_create_sine_table_##type (GstAudioTestSrc * src, g##type * samples) \
{ \ { \
gint i, c; \ gint i, c, channels; \
gdouble step, scl; \ 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; \ scl = 1024.0 / M_PI_M2; \
\ \
i = 0; \ i = 0; \
while (i < (src->generate_samples_per_buffer * src->channels)) { \ while (i < (src->generate_samples_per_buffer * channels)) { \
src->accumulator += step; \ src->accumulator += step; \
if (src->accumulator >= M_PI_M2) \ if (src->accumulator >= M_PI_M2) \
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)]; \ samples[i++] = (g##type) scale * src->wave_table[(gint) (src->accumulator * scl)]; \
} \ } \
} }
@ -759,10 +722,12 @@ static const ProcessFunc sine_table_funcs[] = {
static void \ static void \
gst_audio_test_src_create_tick_##type (GstAudioTestSrc * src, g##type * samples) \ gst_audio_test_src_create_tick_##type (GstAudioTestSrc * src, g##type * samples) \
{ \ { \
gint i, c; \ gint i, c, channels, samplerate; \
gdouble step, scl; \ 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; \ scl = 1024.0 / M_PI_M2; \
\ \
for (i = 0; i < src->generate_samples_per_buffer; i++) { \ 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) \ if (src->accumulator >= M_PI_M2) \
src->accumulator -= M_PI_M2; \ src->accumulator -= M_PI_M2; \
\ \
if ((src->next_sample + i)%src->samplerate < 1600) { \ if ((src->next_sample + i)%samplerate < 1600) { \
for (c = 0; c < src->channels; ++c) \ for (c = 0; c < channels; ++c) \
samples[(i * src->channels) + c] = (g##type) scale * src->wave_table[(gint) (src->accumulator * scl)]; \ samples[(i * channels) + c] = (g##type) scale * src->wave_table[(gint) (src->accumulator * scl)]; \
} else { \ } else { \
for (c = 0; c < src->channels; ++c) \ for (c = 0; c < channels; ++c) \
samples[(i * src->channels) + c] = 0; \ samples[(i * channels) + c] = 0; \
} \ } \
} \ } \
} }
@ -804,14 +769,15 @@ gst_audio_test_src_create_gaussian_white_noise_##type (GstAudioTestSrc * src, g#
{ \ { \
gint i, c; \ gint i, c; \
gdouble amp = (src->volume * scale); \ 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 (i = 0; i < src->generate_samples_per_buffer * channels; ) { \
for (c = 0; c < src->channels; ++c) { \ for (c = 0; c < channels; ++c) { \
gdouble mag = sqrt (-2 * log (1.0 - g_rand_double (src->gen))); \ 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); \ gdouble phs = g_rand_double_range (src->gen, 0.0, M_PI_M2); \
\ \
samples[i++] = (g##type) (amp * mag * cos (phs)); \ samples[i++] = (g##type) (amp * mag * cos (phs)); \
if (++c >= src->channels) \ if (++c >= channels) \
break; \ break; \
samples[i++] = (g##type) (amp * mag * sin (phs)); \ 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; \ gint i, c; \
gdouble amp = (src->volume * scale); \ gdouble amp = (src->volume * scale); \
gdouble state = src->red.state; \ 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 (i = 0; i < src->generate_samples_per_buffer * channels; ) { \
for (c = 0; c < src->channels; ++c) { \ for (c = 0; c < channels; ++c) { \
while (TRUE) { \ while (TRUE) { \
gdouble r = g_rand_double_range (src->gen, -1.0, 1.0); \ gdouble r = g_rand_double_range (src->gen, -1.0, 1.0); \
state += r; \ state += r; \
@ -879,10 +846,11 @@ gst_audio_test_src_create_blue_noise_##type (GstAudioTestSrc * src, g##type * sa
{ \ { \
gint i, c; \ gint i, c; \
static gdouble flip=1.0; \ static gdouble flip=1.0; \
gint channels = GST_AUDIO_INFO_CHANNELS (&src->info); \
\ \
gst_audio_test_src_create_pink_noise_##type (src, samples); \ gst_audio_test_src_create_pink_noise_##type (src, samples); \
for (i = 0; i < src->generate_samples_per_buffer * src->channels; ) { \ for (i = 0; i < src->generate_samples_per_buffer * channels; ) { \
for (c = 0; c < src->channels; ++c) { \ for (c = 0; c < channels; ++c) { \
samples[i++] *= flip; \ samples[i++] *= flip; \
} \ } \
flip *= -1.0; \ flip *= -1.0; \
@ -910,10 +878,11 @@ gst_audio_test_src_create_violet_noise_##type (GstAudioTestSrc * src, g##type *
{ \ { \
gint i, c; \ gint i, c; \
static gdouble flip=1.0; \ static gdouble flip=1.0; \
gint channels = GST_AUDIO_INFO_CHANNELS (&src->info); \
\ \
gst_audio_test_src_create_red_noise_##type (src, samples); \ gst_audio_test_src_create_red_noise_##type (src, samples); \
for (i = 0; i < src->generate_samples_per_buffer * src->channels; ) { \ for (i = 0; i < src->generate_samples_per_buffer * channels; ) { \
for (c = 0; c < src->channels; ++c) { \ for (c = 0; c < channels; ++c) { \
samples[i++] *= flip; \ samples[i++] *= flip; \
} \ } \
flip *= -1.0; \ flip *= -1.0; \
@ -940,68 +909,83 @@ static const ProcessFunc violet_noise_funcs[] = {
static void static void
gst_audio_test_src_change_wave (GstAudioTestSrc * src) gst_audio_test_src_change_wave (GstAudioTestSrc * src)
{ {
if (src->format == -1) { 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; src->process = NULL;
return; return;
} }
switch (src->wave) { switch (src->wave) {
case GST_AUDIO_TEST_SRC_WAVE_SINE: case GST_AUDIO_TEST_SRC_WAVE_SINE:
src->process = sine_funcs[src->format]; src->process = sine_funcs[idx];
break; break;
case GST_AUDIO_TEST_SRC_WAVE_SQUARE: case GST_AUDIO_TEST_SRC_WAVE_SQUARE:
src->process = square_funcs[src->format]; src->process = square_funcs[idx];
break; break;
case GST_AUDIO_TEST_SRC_WAVE_SAW: case GST_AUDIO_TEST_SRC_WAVE_SAW:
src->process = saw_funcs[src->format]; src->process = saw_funcs[idx];
break; break;
case GST_AUDIO_TEST_SRC_WAVE_TRIANGLE: case GST_AUDIO_TEST_SRC_WAVE_TRIANGLE:
src->process = triangle_funcs[src->format]; src->process = triangle_funcs[idx];
break; break;
case GST_AUDIO_TEST_SRC_WAVE_SILENCE: case GST_AUDIO_TEST_SRC_WAVE_SILENCE:
src->process = silence_funcs[src->format]; src->process = silence_funcs[idx];
break; break;
case GST_AUDIO_TEST_SRC_WAVE_WHITE_NOISE: case GST_AUDIO_TEST_SRC_WAVE_WHITE_NOISE:
if (!(src->gen)) if (!(src->gen))
src->gen = g_rand_new (); src->gen = g_rand_new ();
src->process = white_noise_funcs[src->format]; src->process = white_noise_funcs[idx];
break; break;
case GST_AUDIO_TEST_SRC_WAVE_PINK_NOISE: case GST_AUDIO_TEST_SRC_WAVE_PINK_NOISE:
if (!(src->gen)) if (!(src->gen))
src->gen = g_rand_new (); src->gen = g_rand_new ();
gst_audio_test_src_init_pink_noise (src); gst_audio_test_src_init_pink_noise (src);
src->process = pink_noise_funcs[src->format]; src->process = pink_noise_funcs[idx];
break; break;
case GST_AUDIO_TEST_SRC_WAVE_SINE_TAB: case GST_AUDIO_TEST_SRC_WAVE_SINE_TAB:
gst_audio_test_src_init_sine_table (src); gst_audio_test_src_init_sine_table (src);
src->process = sine_table_funcs[src->format]; src->process = sine_table_funcs[idx];
break; break;
case GST_AUDIO_TEST_SRC_WAVE_TICKS: case GST_AUDIO_TEST_SRC_WAVE_TICKS:
gst_audio_test_src_init_sine_table (src); gst_audio_test_src_init_sine_table (src);
src->process = tick_funcs[src->format]; src->process = tick_funcs[idx];
break; break;
case GST_AUDIO_TEST_SRC_WAVE_GAUSSIAN_WHITE_NOISE: case GST_AUDIO_TEST_SRC_WAVE_GAUSSIAN_WHITE_NOISE:
if (!(src->gen)) if (!(src->gen))
src->gen = g_rand_new (); src->gen = g_rand_new ();
src->process = gaussian_white_noise_funcs[src->format]; src->process = gaussian_white_noise_funcs[idx];
break; break;
case GST_AUDIO_TEST_SRC_WAVE_RED_NOISE: case GST_AUDIO_TEST_SRC_WAVE_RED_NOISE:
if (!(src->gen)) if (!(src->gen))
src->gen = g_rand_new (); src->gen = g_rand_new ();
src->red.state = 0.0; src->red.state = 0.0;
src->process = red_noise_funcs[src->format]; src->process = red_noise_funcs[idx];
break; break;
case GST_AUDIO_TEST_SRC_WAVE_BLUE_NOISE: case GST_AUDIO_TEST_SRC_WAVE_BLUE_NOISE:
if (!(src->gen)) if (!(src->gen))
src->gen = g_rand_new (); src->gen = g_rand_new ();
gst_audio_test_src_init_pink_noise (src); gst_audio_test_src_init_pink_noise (src);
src->process = blue_noise_funcs[src->format]; src->process = blue_noise_funcs[idx];
break; break;
case GST_AUDIO_TEST_SRC_WAVE_VIOLET_NOISE: case GST_AUDIO_TEST_SRC_WAVE_VIOLET_NOISE:
if (!(src->gen)) if (!(src->gen))
src->gen = g_rand_new (); src->gen = g_rand_new ();
src->red.state = 0.0; src->red.state = 0.0;
src->process = violet_noise_funcs[src->format]; src->process = violet_noise_funcs[idx];
default: default:
GST_ERROR ("invalid wave-form"); GST_ERROR ("invalid wave-form");
break; break;
@ -1076,18 +1060,24 @@ gst_audio_test_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment)
{ {
GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (basesrc); GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (basesrc);
GstClockTime time; GstClockTime time;
gint samplerate, bpf;
GST_DEBUG_OBJECT (src, "seeking %" GST_SEGMENT_FORMAT, segment); GST_DEBUG_OBJECT (src, "seeking %" GST_SEGMENT_FORMAT, segment);
time = segment->position; time = segment->position;
src->reverse = (segment->rate < 0.0); 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 */ /* now move to the time indicated */
src->next_sample = src->next_sample = gst_util_uint64_scale_int (time, samplerate, GST_SECOND);
gst_util_uint64_scale_int (time, src->samplerate, GST_SECOND); src->next_byte = src->next_sample * bpf;
src->next_byte = src->next_sample * src->sample_size * src->channels; if (samplerate == 0)
src->next_time = 0;
else
src->next_time = 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);
GST_DEBUG_OBJECT (src, "seeking next_sample=%" G_GINT64_FORMAT GST_DEBUG_OBJECT (src, "seeking next_sample=%" G_GINT64_FORMAT
" next_time=%" GST_TIME_FORMAT, src->next_sample, " 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)) { if (GST_CLOCK_TIME_IS_VALID (segment->stop)) {
time = segment->stop; time = segment->stop;
src->sample_stop = gst_util_uint64_scale_int (time, src->samplerate, src->sample_stop = gst_util_uint64_scale_int (time, samplerate, GST_SECOND);
GST_SECOND);
src->check_seek_stop = TRUE; src->check_seek_stop = TRUE;
} else { } else {
src->check_seek_stop = FALSE; src->check_seek_stop = FALSE;
@ -1136,6 +1125,7 @@ gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset,
gint bytes, samples; gint bytes, samples;
GstElementClass *eclass; GstElementClass *eclass;
guint8 *data; guint8 *data;
gint samplerate, bpf;
src = GST_AUDIO_TEST_SRC (basesrc); src = GST_AUDIO_TEST_SRC (basesrc);
@ -1160,12 +1150,15 @@ gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset,
return GST_FLOW_UNEXPECTED; 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 /* if no length was given, use our default length in samples otherwise convert
* the length in bytes to samples. */ * the length in bytes to samples. */
if (length == -1) if (length == -1)
samples = src->samples_per_buffer; samples = src->samples_per_buffer;
else else
samples = length / (src->sample_size * src->channels); samples = length / bpf;
/* if no offset was given, use our next logical byte */ /* if no offset was given, use our next logical byte */
if (offset == -1) if (offset == -1)
@ -1175,10 +1168,9 @@ gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset,
if (offset != src->next_byte) { if (offset != src->next_byte) {
GST_DEBUG_OBJECT (src, "seek to new offset %" G_GUINT64_FORMAT, offset); GST_DEBUG_OBJECT (src, "seek to new offset %" G_GUINT64_FORMAT, offset);
/* we have a discont in the expected sample offset, do a 'seek' */ /* 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 = src->next_time =
gst_util_uint64_scale_int (src->next_sample, GST_SECOND, gst_util_uint64_scale_int (src->next_sample, GST_SECOND, samplerate);
src->samplerate);
src->next_byte = offset; 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); 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); buf = gst_buffer_new_and_alloc (bytes);
next_byte = src->next_byte + (src->reverse ? (-bytes) : bytes); next_byte = src->next_byte + (src->reverse ? (-bytes) : bytes);
next_time = gst_util_uint64_scale_int (next_sample, GST_SECOND, next_time = gst_util_uint64_scale_int (next_sample, GST_SECOND, samplerate);
src->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, GST_LOG_OBJECT (src, "next_sample %" G_GINT64_FORMAT ", ts %" GST_TIME_FORMAT,
next_sample, GST_TIME_ARGS (next_time)); next_sample, GST_TIME_ARGS (next_time));

View file

@ -24,6 +24,8 @@
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstbasesrc.h> #include <gst/base/gstbasesrc.h>
#include <gst/audio/audio.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -86,14 +88,6 @@ typedef struct {
gdouble state; /* noise state */ gdouble state; /* noise state */
} GstRedNoise; } 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 _GstAudioTestSrc GstAudioTestSrc;
typedef struct _GstAudioTestSrcClass GstAudioTestSrcClass; typedef struct _GstAudioTestSrcClass GstAudioTestSrcClass;
@ -115,11 +109,8 @@ struct _GstAudioTestSrc {
gdouble freq; gdouble freq;
/* audio parameters */ /* audio parameters */
gint channels; GstAudioInfo info;
gint samplerate;
gint samples_per_buffer; gint samples_per_buffer;
gint sample_size;
GstAudioTestSrcFormat format;
/*< private >*/ /*< private >*/
gboolean tags_pushed; /* send tags just once ? */ gboolean tags_pushed; /* send tags just once ? */

View file

@ -27,8 +27,7 @@ G_BEGIN_DECLS
#define DEFAULT_RAW_CAPS \ #define DEFAULT_RAW_CAPS \
"video/x-raw; " \ "video/x-raw; " \
"audio/x-raw-int; " \ "audio/x-raw; " \
"audio/x-raw-float; " \
"text/plain; " \ "text/plain; " \
"text/x-pango-markup; " \ "text/x-pango-markup; " \
"video/x-dvd-subpicture; " \ "video/x-dvd-subpicture; " \

View file

@ -104,40 +104,13 @@ enum
PROP_VOLUME PROP_VOLUME
}; };
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define ALLOWED_CAPS \ #define ALLOWED_CAPS \
"audio/x-raw-float, " \ GST_AUDIO_CAPS_MAKE ("{ F32_LE, F64_LE, S8, S16_LE, S24_3LE, S32_LE }")
"rate = (int) [ 1, MAX ], " \ #else
"channels = (int) [ 1, MAX ], " \ #define ALLOWED_CAPS \
"endianness = (int) BYTE_ORDER, " \ GST_AUDIO_CAPS_MAKE ("{ F32_BE, F64_BE, S8, S16_BE, S24_3BE, S32_BE }")
"width = (int) {32, 64}; " \ #endif
"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"
static void gst_volume_mixer_init (GstMixerClass * iface); 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, static GstFlowReturn volume_transform_ip (GstBaseTransform * base,
GstBuffer * outbuf); GstBuffer * outbuf);
static gboolean volume_stop (GstBaseTransform * base); static gboolean volume_stop (GstBaseTransform * base);
static gboolean volume_setup (GstAudioFilter * filter, static gboolean volume_setup (GstAudioFilter * filter, GstAudioInfo * info);
GstRingBufferSpec * format);
static void volume_process_double (GstVolume * self, gpointer bytes, static void volume_process_double (GstVolume * self, gpointer bytes,
guint n_bytes); guint n_bytes);
@ -199,18 +171,20 @@ static void volume_process_controlled_int8_clamp (GstVolume * self,
static gboolean static gboolean
volume_choose_func (GstVolume * self) volume_choose_func (GstVolume * self)
{ {
GstAudioFilter *filter = GST_AUDIO_FILTER (self);
GstAudioFormat format;
self->process = NULL; self->process = NULL;
self->process_controlled = 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; return FALSE;
switch (GST_AUDIO_FILTER (self)->format.type) { switch (format) {
case GST_BUFTYPE_LINEAR: case GST_AUDIO_FORMAT_S32:
switch (GST_AUDIO_FILTER (self)->format.width) { /* only clamp if the gain is greater than 1.0 */
case 32:
/* only clamp if the gain is greater than 1.0
*/
if (self->current_vol_i32 > VOLUME_UNITY_INT32) { if (self->current_vol_i32 > VOLUME_UNITY_INT32) {
self->process = volume_process_int32_clamp; self->process = volume_process_int32_clamp;
} else { } else {
@ -218,9 +192,8 @@ volume_choose_func (GstVolume * self)
} }
self->process_controlled = volume_process_controlled_int32_clamp; self->process_controlled = volume_process_controlled_int32_clamp;
break; break;
case 24: case GST_AUDIO_FORMAT_S24_3:
/* only clamp if the gain is greater than 1.0 /* only clamp if the gain is greater than 1.0 */
*/
if (self->current_vol_i24 > VOLUME_UNITY_INT24) { if (self->current_vol_i24 > VOLUME_UNITY_INT24) {
self->process = volume_process_int24_clamp; self->process = volume_process_int24_clamp;
} else { } else {
@ -228,9 +201,8 @@ volume_choose_func (GstVolume * self)
} }
self->process_controlled = volume_process_controlled_int24_clamp; self->process_controlled = volume_process_controlled_int24_clamp;
break; break;
case 16: case GST_AUDIO_FORMAT_S16:
/* only clamp if the gain is greater than 1.0 /* only clamp if the gain is greater than 1.0 */
*/
if (self->current_vol_i16 > VOLUME_UNITY_INT16) { if (self->current_vol_i16 > VOLUME_UNITY_INT16) {
self->process = volume_process_int16_clamp; self->process = volume_process_int16_clamp;
} else { } else {
@ -238,9 +210,8 @@ volume_choose_func (GstVolume * self)
} }
self->process_controlled = volume_process_controlled_int16_clamp; self->process_controlled = volume_process_controlled_int16_clamp;
break; break;
case 8: case GST_AUDIO_FORMAT_S8:
/* only clamp if the gain is greater than 1.0 /* only clamp if the gain is greater than 1.0 */
*/
if (self->current_vol_i8 > VOLUME_UNITY_INT8) { if (self->current_vol_i8 > VOLUME_UNITY_INT8) {
self->process = volume_process_int8_clamp; self->process = volume_process_int8_clamp;
} else { } else {
@ -248,20 +219,14 @@ volume_choose_func (GstVolume * self)
} }
self->process_controlled = volume_process_controlled_int8_clamp; self->process_controlled = volume_process_controlled_int8_clamp;
break; break;
} case GST_AUDIO_FORMAT_F32:
break;
case GST_BUFTYPE_FLOAT:
switch (GST_AUDIO_FILTER (self)->format.width) {
case 32:
self->process = volume_process_float; self->process = volume_process_float;
self->process_controlled = volume_process_controlled_float; self->process_controlled = volume_process_controlled_float;
break; break;
case 64: case GST_AUDIO_FORMAT_F64:
self->process = volume_process_double; self->process = volume_process_double;
self->process_controlled = volume_process_controlled_double; self->process_controlled = volume_process_controlled_double;
break; break;
}
break;
default: default:
break; 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 */ /* get notified of caps and plug in the correct process function */
static gboolean static gboolean
volume_setup (GstAudioFilter * filter, GstRingBufferSpec * format) volume_setup (GstAudioFilter * filter, GstAudioInfo * info)
{ {
gboolean res; gboolean res;
GstVolume *self = GST_VOLUME (filter); GstVolume *self = GST_VOLUME (filter);
@ -833,6 +798,7 @@ volume_before_transform (GstBaseTransform * base, GstBuffer * buffer)
static GstFlowReturn static GstFlowReturn
volume_transform_ip (GstBaseTransform * base, GstBuffer * outbuf) volume_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
{ {
GstAudioFilter *filter = GST_AUDIO_FILTER_CAST (base);
GstVolume *self = GST_VOLUME (base); GstVolume *self = GST_VOLUME (base);
guint8 *data; guint8 *data;
gsize size; gsize size;
@ -850,10 +816,11 @@ volume_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
mute_csource = gst_object_get_control_source (G_OBJECT (self), "mute"); mute_csource = gst_object_get_control_source (G_OBJECT (self), "mute");
volume_csource = gst_object_get_control_source (G_OBJECT (self), "volume"); volume_csource = gst_object_get_control_source (G_OBJECT (self), "volume");
if (mute_csource || (volume_csource && !self->current_mute)) { if (mute_csource || (volume_csource && !self->current_mute)) {
gint rate = GST_AUDIO_FILTER_CAST (self)->format.rate; gint rate = GST_AUDIO_INFO_RATE (&filter->info);
gint width = GST_AUDIO_FILTER_CAST (self)->format.width / 8; gint width = GST_AUDIO_FORMAT_INFO_WIDTH (filter->info.finfo) / 8;
gint channels = GST_AUDIO_FILTER_CAST (self)->format.channels; gint channels = GST_AUDIO_INFO_CHANNELS (&filter->info);
guint nsamples = size / (width * channels); guint nsamples = size / (width * channels);
GstClockTime interval = gst_util_uint64_scale_int (1, GST_SECOND, rate); GstClockTime interval = gst_util_uint64_scale_int (1, GST_SECOND, rate);
GstClockTime ts = GST_BUFFER_TIMESTAMP (outbuf); GstClockTime ts = GST_BUFFER_TIMESTAMP (outbuf);