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 GStaticMutex output_mutex = G_STATIC_MUTEX_INIT;
#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
# define ALSA_SINK_FACTORY_ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN"
#else
# define ALSA_SINK_FACTORY_ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN"
#endif
static GstStaticPadTemplate alsasink_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, "
"endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 32, "
"depth = (int) 32, "
GST_STATIC_CAPS ("audio/x-raw, "
"formats = (string) " GST_AUDIO_FORMATS_ALL ", "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
"audio/x-raw-int, "
"endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 24, "
"depth = (int) 24, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
"audio/x-raw-int, "
"endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 32, "
"depth = (int) 24, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
"audio/x-raw-int, "
"endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 16, "
"depth = (int) 16, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
"audio/x-raw-int, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 8, "
"depth = (int) 8, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ];"
"audio/x-iec958")
);
@ -627,26 +594,96 @@ alsasink_parse_spec (GstAlsaSink * alsa, GstRingBufferSpec * spec)
alsa->iec958 = FALSE;
switch (spec->type) {
case GST_BUFTYPE_LINEAR:
GST_DEBUG_OBJECT (alsa,
"Linear format : depth=%d, width=%d, sign=%d, bigend=%d", spec->depth,
spec->width, spec->sign, spec->bigend);
alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width,
spec->sign ? 0 : 1, spec->bigend ? 1 : 0);
break;
case GST_BUFTYPE_FLOAT:
switch (spec->format) {
case GST_FLOAT32_LE:
case GST_BUFTYPE_RAW:
switch (GST_AUDIO_INFO_FORMAT (&spec->info)) {
case GST_AUDIO_FORMAT_U8:
alsa->format = SND_PCM_FORMAT_U8;
break;
case GST_AUDIO_FORMAT_S8:
alsa->format = SND_PCM_FORMAT_S8;
break;
case GST_AUDIO_FORMAT_S16_LE:
alsa->format = SND_PCM_FORMAT_S16_LE;
break;
case GST_AUDIO_FORMAT_S16_BE:
alsa->format = SND_PCM_FORMAT_S16_BE;
break;
case GST_AUDIO_FORMAT_U16_LE:
alsa->format = SND_PCM_FORMAT_U16_LE;
break;
case GST_AUDIO_FORMAT_U16_BE:
alsa->format = SND_PCM_FORMAT_U16_BE;
break;
case GST_AUDIO_FORMAT_S24_LE:
alsa->format = SND_PCM_FORMAT_S24_LE;
break;
case GST_AUDIO_FORMAT_S24_BE:
alsa->format = SND_PCM_FORMAT_S24_BE;
break;
case GST_AUDIO_FORMAT_U24_LE:
alsa->format = SND_PCM_FORMAT_U24_LE;
break;
case GST_AUDIO_FORMAT_U24_BE:
alsa->format = SND_PCM_FORMAT_U24_BE;
break;
case GST_AUDIO_FORMAT_S32_LE:
alsa->format = SND_PCM_FORMAT_S32_LE;
break;
case GST_AUDIO_FORMAT_S32_BE:
alsa->format = SND_PCM_FORMAT_S32_BE;
break;
case GST_AUDIO_FORMAT_U32_LE:
alsa->format = SND_PCM_FORMAT_U32_LE;
break;
case GST_AUDIO_FORMAT_U32_BE:
alsa->format = SND_PCM_FORMAT_U32_BE;
break;
case GST_AUDIO_FORMAT_S24_3LE:
alsa->format = SND_PCM_FORMAT_S24_3LE;
break;
case GST_AUDIO_FORMAT_S24_3BE:
alsa->format = SND_PCM_FORMAT_S24_3BE;
break;
case GST_AUDIO_FORMAT_U24_3LE:
alsa->format = SND_PCM_FORMAT_U24_3LE;
break;
case GST_AUDIO_FORMAT_U24_3BE:
alsa->format = SND_PCM_FORMAT_U24_3BE;
break;
case GST_AUDIO_FORMAT_S20_3LE:
alsa->format = SND_PCM_FORMAT_S20_3LE;
break;
case GST_AUDIO_FORMAT_S20_3BE:
alsa->format = SND_PCM_FORMAT_S20_3BE;
break;
case GST_AUDIO_FORMAT_U20_3LE:
alsa->format = SND_PCM_FORMAT_U20_3LE;
break;
case GST_AUDIO_FORMAT_U20_3BE:
alsa->format = SND_PCM_FORMAT_U20_3BE;
break;
case GST_AUDIO_FORMAT_S18_3LE:
alsa->format = SND_PCM_FORMAT_S18_3LE;
break;
case GST_AUDIO_FORMAT_S18_3BE:
alsa->format = SND_PCM_FORMAT_S18_3BE;
break;
case GST_AUDIO_FORMAT_U18_3LE:
alsa->format = SND_PCM_FORMAT_U18_3LE;
break;
case GST_AUDIO_FORMAT_U18_3BE:
alsa->format = SND_PCM_FORMAT_U18_3BE;
break;
case GST_AUDIO_FORMAT_F32_LE:
alsa->format = SND_PCM_FORMAT_FLOAT_LE;
break;
case GST_FLOAT32_BE:
case GST_AUDIO_FORMAT_F32_BE:
alsa->format = SND_PCM_FORMAT_FLOAT_BE;
break;
case GST_FLOAT64_LE:
case GST_AUDIO_FORMAT_F64_LE:
alsa->format = SND_PCM_FORMAT_FLOAT64_LE;
break;
case GST_FLOAT64_BE:
case GST_AUDIO_FORMAT_F64_BE:
alsa->format = SND_PCM_FORMAT_FLOAT64_BE;
break;
default:
@ -667,8 +704,8 @@ alsasink_parse_spec (GstAlsaSink * alsa, GstRingBufferSpec * spec)
goto error;
}
alsa->rate = spec->rate;
alsa->channels = spec->channels;
alsa->rate = GST_AUDIO_INFO_RATE (&spec->info);
alsa->channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
alsa->buffer_time = spec->buffer_time;
alsa->period_time = spec->latency_time;
alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED;
@ -724,7 +761,7 @@ gst_alsasink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
alsa = GST_ALSA_SINK (asink);
if (spec->format == GST_IEC958) {
if (spec->type == GST_BUFTYPE_IEC958) {
snd_pcm_close (alsa->handle);
alsa->handle = gst_alsa_open_iec958_pcm (GST_OBJECT (alsa));
if (G_UNLIKELY (!alsa->handle)) {
@ -738,8 +775,8 @@ gst_alsasink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
CHECK (set_hwparams (alsa), hw_params_failed);
CHECK (set_swparams (alsa), sw_params_failed);
alsa->bytes_per_sample = spec->bytes_per_sample;
spec->segsize = alsa->period_size * spec->bytes_per_sample;
alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info);
spec->segsize = alsa->period_size * alsa->bpf;
spec->segtotal = alsa->buffer_size / alsa->period_size;
{
@ -867,7 +904,7 @@ gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length)
GST_LOG_OBJECT (asink, "received audio samples buffer of %u bytes", length);
cptr = length / alsa->bytes_per_sample;
cptr = length / alsa->bpf;
GST_ALSA_SINK_LOCK (asink);
while (cptr > 0) {
@ -896,7 +933,7 @@ gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length)
}
GST_ALSA_SINK_UNLOCK (asink);
return length - (cptr * alsa->bytes_per_sample);
return length - (cptr * alsa->bpf);
write_error:
{

View file

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

View file

@ -107,37 +107,11 @@ enum
#endif
static GstStaticPadTemplate alsasrc_src_factory =
GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, "
"endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 32, "
"depth = (int) 32, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
"audio/x-raw-int, "
"endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 32, "
"depth = (int) 24, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
"audio/x-raw-int, "
"endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 24, "
"depth = (int) 24, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
"audio/x-raw-int, "
"endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 16, "
"depth = (int) 16, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
"audio/x-raw-int, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 8, "
"depth = (int) 8, "
GST_STATIC_CAPS ("audio/x-raw, "
"format = (string) " GST_AUDIO_FORMATS_ALL ", "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
);
@ -655,22 +629,96 @@ static gboolean
alsasrc_parse_spec (GstAlsaSrc * alsa, GstRingBufferSpec * spec)
{
switch (spec->type) {
case GST_BUFTYPE_LINEAR:
alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width,
spec->sign ? 0 : 1, spec->bigend ? 1 : 0);
break;
case GST_BUFTYPE_FLOAT:
switch (spec->format) {
case GST_FLOAT32_LE:
case GST_BUFTYPE_RAW:
switch (GST_AUDIO_INFO_FORMAT (&spec->info)) {
case GST_AUDIO_FORMAT_U8:
alsa->format = SND_PCM_FORMAT_U8;
break;
case GST_AUDIO_FORMAT_S8:
alsa->format = SND_PCM_FORMAT_S8;
break;
case GST_AUDIO_FORMAT_S16_LE:
alsa->format = SND_PCM_FORMAT_S16_LE;
break;
case GST_AUDIO_FORMAT_S16_BE:
alsa->format = SND_PCM_FORMAT_S16_BE;
break;
case GST_AUDIO_FORMAT_U16_LE:
alsa->format = SND_PCM_FORMAT_U16_LE;
break;
case GST_AUDIO_FORMAT_U16_BE:
alsa->format = SND_PCM_FORMAT_U16_BE;
break;
case GST_AUDIO_FORMAT_S24_LE:
alsa->format = SND_PCM_FORMAT_S24_LE;
break;
case GST_AUDIO_FORMAT_S24_BE:
alsa->format = SND_PCM_FORMAT_S24_BE;
break;
case GST_AUDIO_FORMAT_U24_LE:
alsa->format = SND_PCM_FORMAT_U24_LE;
break;
case GST_AUDIO_FORMAT_U24_BE:
alsa->format = SND_PCM_FORMAT_U24_BE;
break;
case GST_AUDIO_FORMAT_S32_LE:
alsa->format = SND_PCM_FORMAT_S32_LE;
break;
case GST_AUDIO_FORMAT_S32_BE:
alsa->format = SND_PCM_FORMAT_S32_BE;
break;
case GST_AUDIO_FORMAT_U32_LE:
alsa->format = SND_PCM_FORMAT_U32_LE;
break;
case GST_AUDIO_FORMAT_U32_BE:
alsa->format = SND_PCM_FORMAT_U32_BE;
break;
case GST_AUDIO_FORMAT_S24_3LE:
alsa->format = SND_PCM_FORMAT_S24_3LE;
break;
case GST_AUDIO_FORMAT_S24_3BE:
alsa->format = SND_PCM_FORMAT_S24_3BE;
break;
case GST_AUDIO_FORMAT_U24_3LE:
alsa->format = SND_PCM_FORMAT_U24_3LE;
break;
case GST_AUDIO_FORMAT_U24_3BE:
alsa->format = SND_PCM_FORMAT_U24_3BE;
break;
case GST_AUDIO_FORMAT_S20_3LE:
alsa->format = SND_PCM_FORMAT_S20_3LE;
break;
case GST_AUDIO_FORMAT_S20_3BE:
alsa->format = SND_PCM_FORMAT_S20_3BE;
break;
case GST_AUDIO_FORMAT_U20_3LE:
alsa->format = SND_PCM_FORMAT_U20_3LE;
break;
case GST_AUDIO_FORMAT_U20_3BE:
alsa->format = SND_PCM_FORMAT_U20_3BE;
break;
case GST_AUDIO_FORMAT_S18_3LE:
alsa->format = SND_PCM_FORMAT_S18_3LE;
break;
case GST_AUDIO_FORMAT_S18_3BE:
alsa->format = SND_PCM_FORMAT_S18_3BE;
break;
case GST_AUDIO_FORMAT_U18_3LE:
alsa->format = SND_PCM_FORMAT_U18_3LE;
break;
case GST_AUDIO_FORMAT_U18_3BE:
alsa->format = SND_PCM_FORMAT_U18_3BE;
break;
case GST_AUDIO_FORMAT_F32_LE:
alsa->format = SND_PCM_FORMAT_FLOAT_LE;
break;
case GST_FLOAT32_BE:
case GST_AUDIO_FORMAT_F32_BE:
alsa->format = SND_PCM_FORMAT_FLOAT_BE;
break;
case GST_FLOAT64_LE:
case GST_AUDIO_FORMAT_F64_LE:
alsa->format = SND_PCM_FORMAT_FLOAT64_LE;
break;
case GST_FLOAT64_BE:
case GST_AUDIO_FORMAT_F64_BE:
alsa->format = SND_PCM_FORMAT_FLOAT64_BE;
break;
default:
@ -687,8 +735,8 @@ alsasrc_parse_spec (GstAlsaSrc * alsa, GstRingBufferSpec * spec)
goto error;
}
alsa->rate = spec->rate;
alsa->channels = spec->channels;
alsa->rate = GST_AUDIO_INFO_RATE (&spec->info);
alsa->channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
alsa->buffer_time = spec->buffer_time;
alsa->period_time = spec->latency_time;
alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED;
@ -753,13 +801,9 @@ gst_alsasrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
CHECK (set_swparams (alsa), sw_params_failed);
CHECK (snd_pcm_prepare (alsa->handle), prepare_failed);
alsa->bytes_per_sample = spec->bytes_per_sample;
spec->segsize = alsa->period_size * spec->bytes_per_sample;
alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info);
spec->segsize = alsa->period_size * alsa->bpf;
spec->segtotal = alsa->buffer_size / alsa->period_size;
spec->silence_sample[0] = 0;
spec->silence_sample[1] = 0;
spec->silence_sample[2] = 0;
spec->silence_sample[3] = 0;
return TRUE;
@ -869,7 +913,7 @@ gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length)
alsa = GST_ALSA_SRC (asrc);
cptr = length / alsa->bytes_per_sample;
cptr = length / alsa->bpf;
ptr = data;
GST_ALSA_SRC_LOCK (asrc);
@ -889,7 +933,7 @@ gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length)
}
GST_ALSA_SRC_UNLOCK (asrc);
return length - (cptr * alsa->bytes_per_sample);
return length - (cptr * alsa->bpf);
read_error:
{

View file

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

View file

@ -224,7 +224,7 @@ vorbis_dec_convert (GstPad * pad,
case GST_FORMAT_TIME:
switch (*dest_format) {
case GST_FORMAT_BYTES:
scale = dec->width * dec->vi.channels;
scale = dec->info.bpf;
case GST_FORMAT_DEFAULT:
*dest_value =
scale * gst_util_uint64_scale_int (src_value, dec->vi.rate,
@ -237,7 +237,7 @@ vorbis_dec_convert (GstPad * pad,
case GST_FORMAT_DEFAULT:
switch (*dest_format) {
case GST_FORMAT_BYTES:
*dest_value = src_value * dec->width * dec->vi.channels;
*dest_value = src_value * dec->info.bpf;
break;
case GST_FORMAT_TIME:
*dest_value =
@ -250,11 +250,11 @@ vorbis_dec_convert (GstPad * pad,
case GST_FORMAT_BYTES:
switch (*dest_format) {
case GST_FORMAT_DEFAULT:
*dest_value = src_value / (dec->width * dec->vi.channels);
*dest_value = src_value / dec->info.bpf;
break;
case GST_FORMAT_TIME:
*dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
dec->vi.rate * dec->width * dec->vi.channels);
dec->vi.rate * dec->info.bpf);
break;
default:
res = FALSE;
@ -545,10 +545,13 @@ static GstFlowReturn
vorbis_handle_identification_packet (GstVorbisDec * vd)
{
GstCaps *caps;
GstAudioInfo info;
const GstAudioChannelPosition *pos = NULL;
gint width = GST_VORBIS_DEC_DEFAULT_SAMPLE_WIDTH;
switch (vd->vi.channels) {
gst_audio_info_set_format (&info, GST_VORBIS_AUDIO_FORMAT, vd->vi.rate,
vd->vi.channels);
switch (info.channels) {
case 1:
case 2:
/* nothing */
@ -559,60 +562,28 @@ vorbis_handle_identification_packet (GstVorbisDec * vd)
case 6:
case 7:
case 8:
pos = gst_vorbis_channel_positions[vd->vi.channels - 1];
pos = gst_vorbis_channel_positions[info.channels - 1];
break;
default:{
gint i;
GstAudioChannelPosition *posn =
g_new (GstAudioChannelPosition, vd->vi.channels);
default:
{
gint i, max_pos = MAX (info.channels, 64);
GST_ELEMENT_WARNING (GST_ELEMENT (vd), STREAM, DECODE,
GST_ELEMENT_WARNING (vd, STREAM, DECODE,
(NULL), ("Using NONE channel layout for more than 8 channels"));
for (i = 0; i < vd->vi.channels; i++)
posn[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
pos = posn;
for (i = 0; i < max_pos; i++)
info.position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
}
}
/* negotiate width with downstream */
caps = gst_pad_get_allowed_caps (vd->srcpad);
if (caps) {
if (!gst_caps_is_empty (caps)) {
GstStructure *s;
s = gst_caps_get_structure (caps, 0);
/* template ensures 16 or 32 */
gst_structure_get_int (s, "width", &width);
GST_INFO_OBJECT (vd, "using %s with %d channels and %d bit audio depth",
gst_structure_get_name (s), vd->vi.channels, width);
}
gst_caps_unref (caps);
}
vd->width = width >> 3;
/* select a copy_samples function, this way we can have specialized versions
* for mono/stereo and avoid the depth switch in tremor case */
vd->copy_samples = get_copy_sample_func (vd->vi.channels, vd->width);
caps = gst_caps_make_writable (gst_pad_get_pad_template_caps (vd->srcpad));
gst_caps_set_simple (caps, "rate", G_TYPE_INT, vd->vi.rate,
"channels", G_TYPE_INT, vd->vi.channels,
"width", G_TYPE_INT, width, NULL);
if (pos) {
gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos);
}
if (vd->vi.channels > 8) {
g_free ((GstAudioChannelPosition *) pos);
}
caps = gst_audio_info_to_caps (&info);
gst_pad_set_caps (vd->srcpad, caps);
gst_caps_unref (caps);
vd->info = info;
/* select a copy_samples function, this way we can have specialized versions
* for mono/stereo and avoid the depth switch in tremor case */
vd->copy_samples = get_copy_sample_func (info.channels);
return GST_FLOW_OK;
}
@ -792,7 +763,7 @@ vorbis_dec_push_forward (GstVorbisDec * dec, GstBuffer * buf)
/* clip */
if (!(buf = gst_audio_buffer_clip (buf, &dec->segment, dec->vi.rate,
dec->vi.channels * dec->width))) {
dec->info.bpf))) {
GST_LOG_OBJECT (dec, "clipped buffer");
return GST_FLOW_OK;
}
@ -856,9 +827,7 @@ static GstFlowReturn
vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet,
GstClockTime timestamp, GstClockTime duration)
{
#ifdef USE_TREMOLO
vorbis_sample_t *pcm;
#else
#ifndef USE_TREMOLO
vorbis_sample_t **pcm;
#endif
guint sample_count;
@ -899,17 +868,17 @@ vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet,
#endif
goto done;
size = sample_count * vd->vi.channels * vd->width;
size = sample_count * vd->info.bpf;
GST_LOG_OBJECT (vd, "%d samples ready for reading, size %" G_GSIZE_FORMAT,
sample_count, size);
/* alloc buffer for it */
out = gst_buffer_new_and_alloc (size);
data = gst_buffer_map (out, NULL, NULL, GST_MAP_WRITE);
/* get samples ready for reading now, should be sample_count */
#ifdef USE_TREMOLO
pcm = GST_BUFFER_DATA (out);
if (G_UNLIKELY ((vorbis_dsp_pcmout (&vd->vd, pcm,
if (G_UNLIKELY ((vorbis_dsp_pcmout (&vd->vd, data,
sample_count)) != sample_count))
#else
if (G_UNLIKELY ((vorbis_synthesis_pcmout (&vd->vd, &pcm)) != sample_count))
@ -918,9 +887,8 @@ vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet,
#ifndef USE_TREMOLO
/* copy samples in buffer */
data = gst_buffer_map (out, NULL, NULL, GST_MAP_WRITE);
vd->copy_samples ((vorbis_sample_t *) data, pcm,
sample_count, vd->vi.channels, vd->width);
sample_count, vd->info.channels);
#endif
GST_LOG_OBJECT (vd, "setting output size to %" G_GSIZE_FORMAT, size);

View file

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

View file

@ -34,14 +34,14 @@
* is allowed, downstream elements are supposed to clip */
static void
copy_samples_m (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
gint channels, gint width)
gint channels)
{
memcpy (out, in[0], samples * sizeof (float));
}
static void
copy_samples_s (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
gint channels, gint width)
gint channels)
{
#ifdef GST_VORBIS_DEC_SEQUENTIAL
memcpy (out, in[0], samples * sizeof (float));
@ -59,7 +59,7 @@ copy_samples_s (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
static void
copy_samples (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
gint channels, gint width)
gint channels)
{
#ifdef GST_VORBIS_DEC_SEQUENTIAL
gint i;
@ -80,12 +80,10 @@ copy_samples (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
}
CopySampleFunc
get_copy_sample_func (gint channels, gint width)
get_copy_sample_func (gint channels)
{
CopySampleFunc f = NULL;
g_assert (width == 4);
switch (channels) {
case 1:
f = copy_samples_m;
@ -130,51 +128,9 @@ CLIP_TO_15 (ogg_int32_t x)
}
#endif
static void
copy_samples_32_m (vorbis_sample_t * _out, vorbis_sample_t ** _in,
guint samples, gint channels, gint width)
{
gint32 *out = (gint32 *) _out;
ogg_int32_t **in = (ogg_int32_t **) _in;
gint j;
for (j = 0; j < samples; j++) {
*out++ = CLIP_TO_15 (in[0][j] >> 9);
}
}
static void
copy_samples_32_s (vorbis_sample_t * _out, vorbis_sample_t ** _in,
guint samples, gint channels, gint width)
{
gint32 *out = (gint32 *) _out;
ogg_int32_t **in = (ogg_int32_t **) _in;
gint j;
for (j = 0; j < samples; j++) {
*out++ = CLIP_TO_15 (in[0][j] >> 9);
*out++ = CLIP_TO_15 (in[1][j] >> 9);
}
}
static void
copy_samples_32 (vorbis_sample_t * _out, vorbis_sample_t ** _in, guint samples,
gint channels, gint width)
{
gint32 *out = (gint32 *) _out;
ogg_int32_t **in = (ogg_int32_t **) _in;
gint i, j;
for (j = 0; j < samples; j++) {
for (i = 0; i < channels; i++) {
*out++ = CLIP_TO_15 (in[i][j] >> 9);
}
}
}
static void
copy_samples_16_m (vorbis_sample_t * _out, vorbis_sample_t ** _in,
guint samples, gint channels, gint width)
guint samples, gint channels)
{
gint16 *out = (gint16 *) _out;
ogg_int32_t **in = (ogg_int32_t **) _in;
@ -187,7 +143,7 @@ copy_samples_16_m (vorbis_sample_t * _out, vorbis_sample_t ** _in,
static void
copy_samples_16_s (vorbis_sample_t * _out, vorbis_sample_t ** _in,
guint samples, gint channels, gint width)
guint samples, gint channels)
{
gint16 *out = (gint16 *) _out;
ogg_int32_t **in = (ogg_int32_t **) _in;
@ -201,7 +157,7 @@ copy_samples_16_s (vorbis_sample_t * _out, vorbis_sample_t ** _in,
static void
copy_samples_16 (vorbis_sample_t * _out, vorbis_sample_t ** _in, guint samples,
gint channels, gint width)
gint channels)
{
gint16 *out = (gint16 *) _out;
ogg_int32_t **in = (ogg_int32_t **) _in;
@ -215,36 +171,20 @@ copy_samples_16 (vorbis_sample_t * _out, vorbis_sample_t ** _in, guint samples,
}
CopySampleFunc
get_copy_sample_func (gint channels, gint width)
get_copy_sample_func (gint channels)
{
CopySampleFunc f = NULL;
if (width == 4) {
switch (channels) {
case 1:
f = copy_samples_32_m;
break;
case 2:
f = copy_samples_32_s;
break;
default:
f = copy_samples_32;
break;
}
} else if (width == 2) {
switch (channels) {
case 1:
f = copy_samples_16_m;
break;
case 2:
f = copy_samples_16_s;
break;
default:
f = copy_samples_16;
break;
}
} else {
g_assert_not_reached ();
switch (channels) {
case 1:
f = copy_samples_16_m;
break;
case 2:
f = copy_samples_16_s;
break;
default:
f = copy_samples_16;
break;
}
return f;
}

View file

@ -26,6 +26,7 @@
#define __GST_VORBIS_DEC_LIB_H__
#include <gst/gst.h>
#include <gst/audio/audio.h>
#ifndef TREMOR
@ -36,12 +37,19 @@ typedef ogg_packet ogg_packet_wrapper;
#define GST_VORBIS_DEC_DESCRIPTION "decode raw vorbis streams to float audio"
#define GST_VORBIS_DEC_SRC_CAPS \
GST_STATIC_CAPS ("audio/x-raw-float, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, 256 ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 32")
#define GST_VORBIS_AUDIO_FORMAT GST_AUDIO_FORMAT_F32
#if G_BYTE_ORDER == G_BIG_ENDIAN
#define GST_VORBIS_AUDIO_FORMAT_STR "F32_BE"
#else
#define GST_VORBIS_AUDIO_FORMAT_STR "F32_LE"
#endif
#define GST_VORBIS_DEC_SRC_CAPS \
GST_STATIC_CAPS ("audio/x-raw, " \
"format = (string)" GST_VORBIS_AUDIO_FORMAT_STR ", " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, 256 ]")
#define GST_VORBIS_DEC_DEFAULT_SAMPLE_WIDTH (32)
@ -101,16 +109,19 @@ struct _ogg_packet_wrapper {
#define GST_VORBIS_DEC_DESCRIPTION "decode raw vorbis streams to integer audio"
#define GST_VORBIS_DEC_SRC_CAPS \
GST_STATIC_CAPS ("audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, 6 ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) { 16, 32 }, " \
"depth = (int) 16, " \
"signed = (boolean) true")
#define GST_VORBIS_AUDIO_FORMAT GST_AUDIO_FORMAT_S16
#define GST_VORBIS_DEC_DEFAULT_SAMPLE_WIDTH (16)
#if G_BYTE_ORDER == G_BIG_ENDIAN
#define GST_VORBIS_AUDIO_FORMAT_STR "S16_BE"
#else
#define GST_VORBIS_AUDIO_FORMAT_STR "S16_LE"
#endif
#define GST_VORBIS_DEC_SRC_CAPS \
GST_STATIC_CAPS ("audio/x-raw, " \
"format = (string) " GST_VORBIS_AUDIO_FORMAT_STR ", " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, 6 ]")
/* we need a different type name here */
#define GST_VORBIS_DEC_GLIB_TYPE_NAME GstIVorbisDec
@ -176,8 +187,8 @@ gst_ogg_packet_from_wrapper (ogg_packet_wrapper * packet)
#endif
typedef void (*CopySampleFunc)(vorbis_sample_t *out, vorbis_sample_t **in,
guint samples, gint channels, gint width);
guint samples, gint channels);
CopySampleFunc get_copy_sample_func (gint channels, gint width);
CopySampleFunc get_copy_sample_func (gint channels);
#endif /* __GST_VORBIS_DEC_LIB_H__ */

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 \
$(INTROSPECTION_SCANNER) -v --namespace GstAudio \
--nsversion=@GST_MAJORMINOR@ \
--warn-all \
--strip-prefix=Gst \
-DGST_USE_UNSTABLE_API \
-I$(top_srcdir)/gst-libs \

View file

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

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* 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
* modify it under the terms of the GNU Library General Public
@ -23,38 +24,322 @@
#ifndef __GST_AUDIO_AUDIO_H__
#define __GST_AUDIO_AUDIO_H__
#include <gst/audio/multichannel.h>
G_BEGIN_DECLS
/* For people that are looking at this source: the purpose of these defines is
* to make GstCaps a bit easier, in that you don't have to know all of the
* properties that need to be defined. you can just use these macros. currently
* (8/01) the only plugins that use these are the passthrough, speed, volume,
* adder, and [de]interleave plugins. These are for convenience only, and do not
* specify the 'limits' of GStreamer. you might also use these definitions as a
* base for making your own caps, if need be.
/**
* GstAudioFormat:
* @GST_AUDIO_FORMAT_UNKNOWN: unknown audio format
* @GST_AUDIO_FORMAT_S8: sample
* @GST_AUDIO_FORMAT_U8: sample
* @GST_AUDIO_FORMAT_S16_LE: sample
* @GST_AUDIO_FORMAT_S16_BE: sample
* @GST_AUDIO_FORMAT_U16_LE: sample
* @GST_AUDIO_FORMAT_U16_BE: sample
* @GST_AUDIO_FORMAT_S24_LE: sample
* @GST_AUDIO_FORMAT_S24_BE: sample
* @GST_AUDIO_FORMAT_U24_LE: sample
* @GST_AUDIO_FORMAT_U24_BE: sample
* @GST_AUDIO_FORMAT_S32_LE: sample
* @GST_AUDIO_FORMAT_S32_BE: sample
* @GST_AUDIO_FORMAT_U32_LE: sample
* @GST_AUDIO_FORMAT_U32_BE: sample
* @GST_AUDIO_FORMAT_S24_3LE: sample
* @GST_AUDIO_FORMAT_S24_3BE: sample
* @GST_AUDIO_FORMAT_U24_3LE: sample
* @GST_AUDIO_FORMAT_U24_3BE: sample
* @GST_AUDIO_FORMAT_S20_3LE: sample
* @GST_AUDIO_FORMAT_S20_3BE: sample
* @GST_AUDIO_FORMAT_U20_3LE: sample
* @GST_AUDIO_FORMAT_U20_3BE: sample
* @GST_AUDIO_FORMAT_S18_3LE: sample
* @GST_AUDIO_FORMAT_S18_3BE: sample
* @GST_AUDIO_FORMAT_U18_3LE: sample
* @GST_AUDIO_FORMAT_U18_3BE: sample
* @GST_AUDIO_FORMAT_F32_LE: sample
* @GST_AUDIO_FORMAT_F32_BE: sample
* @GST_AUDIO_FORMAT_F64_LE: sample
* @GST_AUDIO_FORMAT_F64_BE: sample
*
* For example, to make a source pad that can output streams of either mono
* float or any channel int:
* Enum value describing the most common audio formats.
*/
typedef enum {
GST_AUDIO_FORMAT_UNKNOWN,
/* 8 bit */
GST_AUDIO_FORMAT_S8,
GST_AUDIO_FORMAT_U8,
/* 16 bit */
GST_AUDIO_FORMAT_S16_LE,
GST_AUDIO_FORMAT_S16_BE,
GST_AUDIO_FORMAT_U16_LE,
GST_AUDIO_FORMAT_U16_BE,
/* 24 bit in low 3 bytes of 32 bits*/
GST_AUDIO_FORMAT_S24_LE,
GST_AUDIO_FORMAT_S24_BE,
GST_AUDIO_FORMAT_U24_LE,
GST_AUDIO_FORMAT_U24_BE,
/* 32 bit */
GST_AUDIO_FORMAT_S32_LE,
GST_AUDIO_FORMAT_S32_BE,
GST_AUDIO_FORMAT_U32_LE,
GST_AUDIO_FORMAT_U32_BE,
/* 24 bit in 3 bytes*/
GST_AUDIO_FORMAT_S24_3LE,
GST_AUDIO_FORMAT_S24_3BE,
GST_AUDIO_FORMAT_U24_3LE,
GST_AUDIO_FORMAT_U24_3BE,
/* 20 bit in 3 bytes*/
GST_AUDIO_FORMAT_S20_3LE,
GST_AUDIO_FORMAT_S20_3BE,
GST_AUDIO_FORMAT_U20_3LE,
GST_AUDIO_FORMAT_U20_3BE,
/* 18 bit in 3 bytes*/
GST_AUDIO_FORMAT_S18_3LE,
GST_AUDIO_FORMAT_S18_3BE,
GST_AUDIO_FORMAT_U18_3LE,
GST_AUDIO_FORMAT_U18_3BE,
/* float */
GST_AUDIO_FORMAT_F32_LE,
GST_AUDIO_FORMAT_F32_BE,
GST_AUDIO_FORMAT_F64_LE,
GST_AUDIO_FORMAT_F64_BE,
#if G_BYTE_ORDER == G_BIG_ENDIAN
GST_AUDIO_FORMAT_S16 = GST_AUDIO_FORMAT_S16_BE,
GST_AUDIO_FORMAT_U16 = GST_AUDIO_FORMAT_U16_BE,
GST_AUDIO_FORMAT_S24 = GST_AUDIO_FORMAT_S24_BE,
GST_AUDIO_FORMAT_U24 = GST_AUDIO_FORMAT_U24_BE,
GST_AUDIO_FORMAT_S32 = GST_AUDIO_FORMAT_S32_BE,
GST_AUDIO_FORMAT_U32 = GST_AUDIO_FORMAT_U32_BE,
GST_AUDIO_FORMAT_S24_3 = GST_AUDIO_FORMAT_S24_3BE,
GST_AUDIO_FORMAT_U24_3 = GST_AUDIO_FORMAT_U24_3BE,
GST_AUDIO_FORMAT_S20_3 = GST_AUDIO_FORMAT_S20_3BE,
GST_AUDIO_FORMAT_U20_3 = GST_AUDIO_FORMAT_U20_3BE,
GST_AUDIO_FORMAT_S18_3 = GST_AUDIO_FORMAT_S18_3BE,
GST_AUDIO_FORMAT_U18_3 = GST_AUDIO_FORMAT_U18_3BE,
GST_AUDIO_FORMAT_F32 = GST_AUDIO_FORMAT_F32_BE,
GST_AUDIO_FORMAT_F64 = GST_AUDIO_FORMAT_F64_BE
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
GST_AUDIO_FORMAT_S16 = GST_AUDIO_FORMAT_S16_LE,
GST_AUDIO_FORMAT_U16 = GST_AUDIO_FORMAT_U16_LE,
GST_AUDIO_FORMAT_S24 = GST_AUDIO_FORMAT_S24_LE,
GST_AUDIO_FORMAT_U24 = GST_AUDIO_FORMAT_U24_LE,
GST_AUDIO_FORMAT_S32 = GST_AUDIO_FORMAT_S32_LE,
GST_AUDIO_FORMAT_U32 = GST_AUDIO_FORMAT_U32_LE,
GST_AUDIO_FORMAT_S24_3 = GST_AUDIO_FORMAT_S24_3LE,
GST_AUDIO_FORMAT_U24_3 = GST_AUDIO_FORMAT_U24_3LE,
GST_AUDIO_FORMAT_S20_3 = GST_AUDIO_FORMAT_S20_3LE,
GST_AUDIO_FORMAT_U20_3 = GST_AUDIO_FORMAT_U20_3LE,
GST_AUDIO_FORMAT_S18_3 = GST_AUDIO_FORMAT_S18_3LE,
GST_AUDIO_FORMAT_U18_3 = GST_AUDIO_FORMAT_U18_3LE,
GST_AUDIO_FORMAT_F32 = GST_AUDIO_FORMAT_F32_LE,
GST_AUDIO_FORMAT_F64 = GST_AUDIO_FORMAT_F64_LE
#endif
} GstAudioFormat;
typedef struct _GstAudioFormatInfo GstAudioFormatInfo;
typedef struct _GstAudioInfo GstAudioInfo;
/**
* GstAudioFormatFlags:
* @GST_AUDIO_FORMAT_FLAG_INT: int samples
* @GST_AUDIO_FORMAT_FLAG_FLOAT: float samples
* @GST_AUDIO_FORMAT_FLAG_SIGNED: signed samples
* @GST_AUDIO_FORMAT_FLAG_COMPLEX: complex layout
*
* template = gst_pad_template_new
* ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
* gst_caps_append(gst_caps_new ("sink_int", "audio/x-raw-int",
* GST_AUDIO_INT_PAD_TEMPLATE_PROPS),
* gst_caps_new ("sink_float", "audio/x-raw-float",
* GST_AUDIO_FLOAT_PAD_TEMPLATE_PROPS)),
* NULL);
* The different audio flags that a format info can have.
*/
typedef enum
{
GST_AUDIO_FORMAT_FLAG_INT = (1 << 0),
GST_AUDIO_FORMAT_FLAG_FLOAT = (1 << 1),
GST_AUDIO_FORMAT_FLAG_SIGNED = (1 << 2),
GST_AUDIO_FORMAT_FLAG_COMPLEX = (1 << 4)
} GstAudioFormatFlags;
/**
* GstAudioFormatUnpack:
* @info: a #GstAudioFormatInfo
* @dest: a destination array
* @data: pointer to the audio data
* @length: the amount of samples to unpack.
*
* sinkpad = gst_pad_new_from_template(template, "sink");
* Unpacks @length samples from the given data of format @info.
* The samples will be unpacked into @dest which each channel
* interleaved. @dest should at least be big enough to hold @length *
* channels * unpack_size bytes.
*/
typedef void (*GstAudioFormatUnpack) (GstAudioFormatInfo *info, gpointer dest,
const gpointer data, gint length);
/**
* GstAudioFormatPack:
* @info: a #GstAudioFormatInfo
* @src: a source array
* @data: pointer to the destination data
* @length: the amount of samples to pack.
*
* Andy Wingo, 18 August 2001
* Thomas, 6 September 2002 */
* Packs @length samples from @src to the data array in format @info.
* The samples from source have each channel interleaved
* and will be packed into @data.
*/
typedef void (*GstAudioFormatPack) (GstAudioFormatInfo *info, const gpointer src,
gpointer data, gint length);
/**
* GstAudioFormatInfo:
* @format: #GstAudioFormat
* @name: string representation of the format
* @flags: #GstAudioFormatFlags
* @endianness: the endianness
* @width: amount of bits used for one sample
* @depth: amount of valid bits in @width
* @silence: @width/8 bytes with 1 silent sample
* @unpack_size: number of bytes for the unpack functions
* @unpack_func: function to unpack samples
* @pack_func: function to pack samples
*
* Information for an audio format.
*/
struct _GstAudioFormatInfo {
GstAudioFormat format;
const gchar *name;
GstAudioFormatFlags flags;
gint endianness;
gint width;
gint depth;
guint8 silence[8];
guint unpack_size;
GstAudioFormatUnpack unpack_func;
GstAudioFormatPack pack_func;
};
#define GST_AUDIO_FORMAT_INFO_FORMAT(info) ((info)->format)
#define GST_AUDIO_FORMAT_INFO_NAME(info) ((info)->name)
#define GST_AUDIO_FORMAT_INFO_FLAGS(info) ((info)->flags)
#define GST_AUDIO_FORMAT_INFO_IS_INT(info) ((info)->flags & GST_AUDIO_FORMAT_FLAG_INT)
#define GST_AUDIO_FORMAT_INFO_IS_FLOAT(info) ((info)->flags & GST_AUDIO_FORMAT_FLAG_FLOAT)
#define GST_AUDIO_FORMAT_INFO_IS_SIGNED(info) ((info)->flags & GST_AUDIO_FORMAT_FLAG_SIGNED)
#define GST_AUDIO_FORMAT_INFO_ENDIANNESS(info) ((info)->endianness)
#define GST_AUDIO_FORMAT_INFO_IS_LE(info) ((info)->endianness == G_LITTLE_ENDIAN)
#define GST_AUDIO_FORMAT_INFO_IS_BE(info) ((info)->endianness == G_BIG_ENDIAN)
#define GST_AUDIO_FORMAT_INFO_WIDTH(info) ((info)->width)
#define GST_AUDIO_FORMAT_INFO_DEPTH(info) ((info)->depth)
GstAudioFormat gst_audio_format_from_string (const gchar *format) G_GNUC_CONST;
const gchar * gst_audio_format_to_string (GstAudioFormat format) G_GNUC_CONST;
const GstAudioFormatInfo *
gst_audio_format_get_info (GstAudioFormat format) G_GNUC_CONST;
void gst_audio_format_fill_silence (const GstAudioFormatInfo *info,
gpointer dest, gsize length);
/**
* GstAudioFlags:
* @GST_AUDIO_FLAG_NONE: no valid flag
* @GST_AUDIO_FLAG_UNPOSITIONED: unpositioned audio layout, position array
* contains the default layout.
*
* Extra audio flags
*/
typedef enum {
GST_AUDIO_FLAG_NONE = 0,
GST_AUDIO_FLAG_UNPOSITIONED = (1 << 0)
} GstAudioFlags;
/**
* GstAudioInfo:
* @finfo: the format info of the audio
* @flags: additional audio flags
* @rate: the audio sample rate
* @channels: the number of channels
* @bpf: the number of bytes for one frame, this is the size of one
* sample * @channels
* @positions: the positions for each channel
*
* Information describing audio properties. This information can be filled
* in from GstCaps with gst_audio_info_from_caps().
*
* Use the provided macros to access the info in this structure.
*/
struct _GstAudioInfo {
const GstAudioFormatInfo *finfo;
GstAudioFlags flags;
gint rate;
gint channels;
gint bpf;
GstAudioChannelPosition position[64];
};
#define GST_AUDIO_INFO_FORMAT(i) (GST_AUDIO_FORMAT_INFO_FORMAT((i)->finfo))
#define GST_AUDIO_INFO_NAME(i) (GST_AUDIO_FORMAT_INFO_NAME((i)->finfo))
#define GST_AUDIO_INFO_FLAGS(info) ((info)->flags)
#define GST_AUDIO_INFO_IS_UNPOSITIONED(info) ((info)->flags & GST_AUDIO_FLAG_UNPOSITIONED)
#define GST_AUDIO_INFO_RATE(info) ((info)->rate)
#define GST_AUDIO_INFO_CHANNELS(info) ((info)->channels)
#define GST_AUDIO_INFO_BPF(info) ((info)->bpf)
#define GST_AUDIO_INFO_POSITION(info,c) ((info)->position[c])
void gst_audio_info_init (GstAudioInfo *info);
void gst_audio_info_set_format (GstAudioInfo *info, GstAudioFormat format,
gint rate, gint channels);
gboolean gst_audio_info_from_caps (GstAudioInfo *info, const GstCaps *caps);
GstCaps * gst_audio_info_to_caps (GstAudioInfo *info);
#define GST_AUDIO_RATE_RANGE "(int) [ 1, max ]"
#define GST_AUDIO_CHANNELS_RANGE "(int) [ 1, max ]"
#define GST_AUDIO_FORMATS_ALL " { S8, U8, " \
"S16_LE, S16_BE, U16_LE, U16_BE, " \
"S24_LE, S24_BE, U24_LE, U24_BE, " \
"S32_LE, S32_BE, U32_LE, U32_BE, " \
"S24_3LE, S24_3BE, U24_3LE, U24_3BE, " \
"S20_3LE, S20_3BE, U20_3LE, U20_3BE, " \
"S18_3LE, S18_3BE, U18_3LE, U18_3BE, " \
"F32_LE, F32_BE, F64_LE, F64_BE }"
/**
* GST_AUDIO_CAPS_MAKE:
* @format: string format that describes the pixel layout, as string
* (e.g. "S16_LE", "S8", etc.)
*
* Generic caps string for audio, for use in pad templates.
*/
#define GST_AUDIO_CAPS_MAKE(format) \
"audio/x-raw, " \
"format = (string) " format ", " \
"rate = " GST_AUDIO_RATE_RANGE ", " \
"channels = " GST_AUDIO_CHANNELS_RANGE
/**
* GST_AUDIO_DEF_RATE:
*
* Standard sampling rate used in consumer audio.
*/
#define GST_AUDIO_DEF_RATE 44100
/**
* GST_AUDIO_DEF_CHANNELS:
*
* Standard number of channels used in consumer audio.
*/
#define GST_AUDIO_DEF_CHANNELS 2
/**
* GST_AUDIO_DEF_FORMAT:
*
* Standard format used in consumer audio.
*/
#define GST_AUDIO_DEF_FORMAT "S16_LE"
/* conversion macros */
/**
* GST_FRAMES_TO_CLOCK_TIME:
* @frames: sample frames
* @rate: sampling rate
*
*
* Calculate clocktime from sample @frames and @rate.
*/
#define GST_FRAMES_TO_CLOCK_TIME(frames, rate) \
@ -64,75 +349,12 @@ G_BEGIN_DECLS
* GST_CLOCK_TIME_TO_FRAMES:
* @clocktime: clock time
* @rate: sampling rate
*
*
* Calculate frames from @clocktime and sample @rate.
*/
#define GST_CLOCK_TIME_TO_FRAMES(clocktime, rate) \
gst_util_uint64_scale_round (clocktime, rate, GST_SECOND)
/**
* GST_AUDIO_DEF_RATE:
*
* Standard sampling rate used in consumer audio.
*/
#define GST_AUDIO_DEF_RATE 44100
/**
* GST_AUDIO_INT_PAD_TEMPLATE_CAPS:
*
* Template caps for integer audio. Can be used when defining a
* #GstStaticPadTemplate
*/
#define GST_AUDIO_INT_PAD_TEMPLATE_CAPS \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
"width = (int) { 8, 16, 24, 32 }, " \
"depth = (int) [ 1, 32 ], " \
"signed = (boolean) { true, false }"
/**
* GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS:
*
* Template caps for 16bit integer stereo audio in native byte-order.
* Can be used when defining a #GstStaticPadTemplate
*/
#define GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) 2, " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 16, " \
"depth = (int) 16, " \
"signed = (boolean) true"
/**
* GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS:
*
* Template caps for float audio. Can be used when defining a
* #GstStaticPadTemplate
*/
#define GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS \
"audio/x-raw-float, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, " \
"width = (int) { 32, 64 }"
/**
* GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS:
*
* Template caps for 32bit float mono audio in native byte-order.
* Can be used when defining a #GstStaticPadTemplate
*/
#define GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS \
"audio/x-raw-float, " \
"width = (int) 32, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) 1, " \
"endianness = (int) BYTE_ORDER"
/*
* this library defines and implements some helper functions for audio
* handling

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

View file

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

View file

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

View file

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

View file

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

View file

@ -111,95 +111,9 @@ gst_ring_buffer_finalize (GObject * object)
(ringbuffer));
}
typedef struct
{
const GstBufferFormat format;
const guint8 silence[4];
} FormatDef;
static const FormatDef linear_defs[4 * 2 * 2] = {
{GST_S8, {0x00, 0x00, 0x00, 0x00}},
{GST_S8, {0x00, 0x00, 0x00, 0x00}},
{GST_U8, {0x80, 0x80, 0x80, 0x80}},
{GST_U8, {0x80, 0x80, 0x80, 0x80}},
{GST_S16_LE, {0x00, 0x00, 0x00, 0x00}},
{GST_S16_BE, {0x00, 0x00, 0x00, 0x00}},
{GST_U16_LE, {0x00, 0x80, 0x00, 0x80}},
{GST_U16_BE, {0x80, 0x00, 0x80, 0x00}},
{GST_S24_LE, {0x00, 0x00, 0x00, 0x00}},
{GST_S24_BE, {0x00, 0x00, 0x00, 0x00}},
{GST_U24_LE, {0x00, 0x00, 0x80, 0x00}},
{GST_U24_BE, {0x80, 0x00, 0x00, 0x00}},
{GST_S32_LE, {0x00, 0x00, 0x00, 0x00}},
{GST_S32_BE, {0x00, 0x00, 0x00, 0x00}},
{GST_U32_LE, {0x00, 0x00, 0x00, 0x80}},
{GST_U32_BE, {0x80, 0x00, 0x00, 0x00}}
};
static const FormatDef linear24_defs[3 * 2 * 2] = {
{GST_S24_3LE, {0x00, 0x00, 0x00, 0x00}},
{GST_S24_3BE, {0x00, 0x00, 0x00, 0x00}},
{GST_U24_3LE, {0x00, 0x00, 0x80, 0x00}},
{GST_U24_3BE, {0x80, 0x00, 0x00, 0x00}},
{GST_S20_3LE, {0x00, 0x00, 0x00, 0x00}},
{GST_S20_3BE, {0x00, 0x00, 0x00, 0x00}},
{GST_U20_3LE, {0x00, 0x00, 0x08, 0x00}},
{GST_U20_3BE, {0x08, 0x00, 0x00, 0x00}},
{GST_S18_3LE, {0x00, 0x00, 0x00, 0x00}},
{GST_S18_3BE, {0x00, 0x00, 0x00, 0x00}},
{GST_U18_3LE, {0x00, 0x00, 0x02, 0x00}},
{GST_U18_3BE, {0x02, 0x00, 0x00, 0x00}}
};
static const FormatDef *
build_linear_format (int depth, int width, int unsignd, int big_endian)
{
const FormatDef *formats;
if (width == 24) {
switch (depth) {
case 24:
formats = &linear24_defs[0];
break;
case 20:
formats = &linear24_defs[4];
break;
case 18:
formats = &linear24_defs[8];
break;
default:
return NULL;
}
} else {
switch (depth) {
case 8:
formats = &linear_defs[0];
break;
case 16:
formats = &linear_defs[4];
break;
case 24:
formats = &linear_defs[8];
break;
case 32:
formats = &linear_defs[12];
break;
default:
return NULL;
}
}
if (unsignd)
formats += 2;
if (big_endian)
formats += 1;
return formats;
}
#ifndef GST_DISABLE_GST_DEBUG
static const gchar *format_type_names[] = {
"linear",
"float",
"raw",
"mu law",
"a law",
"ima adpcm",
@ -210,49 +124,6 @@ static const gchar *format_type_names[] = {
"eac3",
"dts"
};
static const gchar *format_names[] = {
"unknown",
"s8",
"u8",
"s16_le",
"s16_be",
"u16_le",
"u16_be",
"s24_le",
"s24_be",
"u24_le",
"u24_be",
"s32_le",
"s32_be",
"u32_le",
"u32_be",
"s24_3le",
"s24_3be",
"u24_3le",
"u24_3be",
"s20_3le",
"s20_3be",
"u20_3le",
"u20_3be",
"s18_3le",
"s18_3be",
"u18_3le",
"u18_3be",
"float32_le",
"float32_be",
"float64_le",
"float64_be",
"mu_law",
"a_law",
"ima_adpcm",
"mpeg",
"gsm",
"iec958",
"ac3",
"eac3",
"dts"
};
#endif
/**
@ -264,15 +135,15 @@ static const gchar *format_names[] = {
void
gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec)
{
#if 0
gint i, bytes;
#endif
GST_DEBUG ("spec caps: %p %" GST_PTR_FORMAT, spec->caps, spec->caps);
GST_DEBUG ("parsed caps: type: %d, '%s'", spec->type,
format_type_names[spec->type]);
GST_DEBUG ("parsed caps: format: %d, '%s'", spec->format,
format_names[spec->format]);
#if 0
GST_DEBUG ("parsed caps: width: %d", spec->width);
GST_DEBUG ("parsed caps: depth: %d", spec->depth);
GST_DEBUG ("parsed caps: sign: %d", spec->sign);
GST_DEBUG ("parsed caps: bigend: %d", spec->bigend);
GST_DEBUG ("parsed caps: rate: %d", spec->rate);
@ -282,6 +153,7 @@ gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec)
for (i = 0; i < bytes; i++) {
GST_DEBUG ("silence byte %d: %02x", i, spec->silence_sample[i]);
}
#endif
}
/**
@ -293,6 +165,8 @@ gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec)
void
gst_ring_buffer_debug_spec_buff (GstRingBufferSpec * spec)
{
gint bpf = GST_AUDIO_INFO_BPF (&spec->info);
GST_DEBUG ("acquire ringbuffer: buffer time: %" G_GINT64_FORMAT " usec",
spec->buffer_time);
GST_DEBUG ("acquire ringbuffer: latency time: %" G_GINT64_FORMAT " usec",
@ -300,10 +174,9 @@ gst_ring_buffer_debug_spec_buff (GstRingBufferSpec * spec)
GST_DEBUG ("acquire ringbuffer: total segments: %d", spec->segtotal);
GST_DEBUG ("acquire ringbuffer: latency segments: %d", spec->seglatency);
GST_DEBUG ("acquire ringbuffer: segment size: %d bytes = %d samples",
spec->segsize, spec->segsize / spec->bytes_per_sample);
spec->segsize, spec->segsize / bpf);
GST_DEBUG ("acquire ringbuffer: buffer size: %d bytes = %d samples",
spec->segsize * spec->segtotal,
spec->segsize * spec->segtotal / spec->bytes_per_sample);
spec->segsize * spec->segtotal, spec->segsize * spec->segtotal / bpf);
}
/**
@ -321,160 +194,77 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
const gchar *mimetype;
GstStructure *structure;
gint i;
GstAudioInfo info;
structure = gst_caps_get_structure (caps, 0);
gst_audio_info_init (&info);
/* we have to differentiate between int and float formats */
mimetype = gst_structure_get_name (structure);
if (g_str_equal (mimetype, "audio/x-raw-int")) {
gint endianness;
const FormatDef *def;
gint j, bytes;
spec->type = GST_BUFTYPE_LINEAR;
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate) &&
gst_structure_get_int (structure, "channels", &spec->channels) &&
gst_structure_get_int (structure, "width", &spec->width) &&
gst_structure_get_int (structure, "depth", &spec->depth) &&
gst_structure_get_boolean (structure, "signed", &spec->sign)))
if (g_str_equal (mimetype, "audio/x-raw")) {
if (!gst_audio_info_from_caps (&info, caps))
goto parse_error;
/* extract endianness if needed */
if (spec->width > 8) {
if (!gst_structure_get_int (structure, "endianness", &endianness))
goto parse_error;
} else {
endianness = G_BYTE_ORDER;
}
spec->bigend = endianness == G_LITTLE_ENDIAN ? FALSE : TRUE;
def = build_linear_format (spec->depth, spec->width, spec->sign ? 0 : 1,
spec->bigend ? 1 : 0);
if (def == NULL)
goto parse_error;
spec->format = def->format;
bytes = spec->width >> 3;
for (i = 0; i < spec->channels; i++) {
for (j = 0; j < bytes; j++) {
spec->silence_sample[i * bytes + j] = def->silence[j];
}
}
} else if (g_str_equal (mimetype, "audio/x-raw-float")) {
spec->type = GST_BUFTYPE_FLOAT;
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate) &&
gst_structure_get_int (structure, "channels", &spec->channels) &&
gst_structure_get_int (structure, "width", &spec->width)))
goto parse_error;
/* match layout to format wrt to endianness */
switch (spec->width) {
case 32:
spec->format =
G_BYTE_ORDER == G_LITTLE_ENDIAN ? GST_FLOAT32_LE : GST_FLOAT32_BE;
break;
case 64:
spec->format =
G_BYTE_ORDER == G_LITTLE_ENDIAN ? GST_FLOAT64_LE : GST_FLOAT64_BE;
break;
default:
goto parse_error;
}
/* float silence is all zeros.. */
memset (spec->silence_sample, 0, 32);
spec->type = GST_BUFTYPE_RAW;
} else if (g_str_equal (mimetype, "audio/x-alaw")) {
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate) &&
gst_structure_get_int (structure, "channels", &spec->channels)))
if (!(gst_structure_get_int (structure, "rate", &info.rate) &&
gst_structure_get_int (structure, "channels", &info.channels)))
goto parse_error;
spec->type = GST_BUFTYPE_A_LAW;
spec->format = GST_A_LAW;
spec->width = 8;
spec->depth = 8;
for (i = 0; i < spec->channels; i++)
spec->silence_sample[i] = 0xd5;
spec->info.bpf = info.channels;
} else if (g_str_equal (mimetype, "audio/x-mulaw")) {
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate) &&
gst_structure_get_int (structure, "channels", &spec->channels)))
if (!(gst_structure_get_int (structure, "rate", &info.rate) &&
gst_structure_get_int (structure, "channels", &info.channels)))
goto parse_error;
spec->type = GST_BUFTYPE_MU_LAW;
spec->format = GST_MU_LAW;
spec->width = 8;
spec->depth = 8;
for (i = 0; i < spec->channels; i++)
spec->silence_sample[i] = 0xff;
spec->info.bpf = info.channels;
} else if (g_str_equal (mimetype, "audio/x-iec958")) {
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate)))
if (!(gst_structure_get_int (structure, "rate", &info.rate)))
goto parse_error;
spec->type = GST_BUFTYPE_IEC958;
spec->format = GST_IEC958;
spec->width = 16;
spec->depth = 16;
spec->channels = 2;
spec->info.bpf = 4;
} else if (g_str_equal (mimetype, "audio/x-ac3")) {
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate)))
if (!(gst_structure_get_int (structure, "rate", &info.rate)))
goto parse_error;
spec->type = GST_BUFTYPE_AC3;
spec->format = GST_AC3;
spec->width = 16;
spec->depth = 16;
spec->channels = 2;
spec->info.bpf = 4;
} else if (g_str_equal (mimetype, "audio/x-eac3")) {
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate)))
if (!(gst_structure_get_int (structure, "rate", &info.rate)))
goto parse_error;
spec->type = GST_BUFTYPE_EAC3;
spec->format = GST_EAC3;
spec->width = 64;
spec->depth = 64;
spec->channels = 2;
spec->info.bpf = 16;
} else if (g_str_equal (mimetype, "audio/x-dts")) {
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate)))
if (!(gst_structure_get_int (structure, "rate", &info.rate)))
goto parse_error;
spec->type = GST_BUFTYPE_DTS;
spec->format = GST_DTS;
spec->width = 16;
spec->depth = 16;
spec->channels = 2;
spec->info.bpf = 4;
} else if (g_str_equal (mimetype, "audio/mpeg") &&
gst_structure_get_int (structure, "mpegaudioversion", &i) &&
(i == 1 || i == 2)) {
/* Now we know this is MPEG-1 or MPEG-2 (non AAC) */
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate)))
if (!(gst_structure_get_int (structure, "rate", &info.rate)))
goto parse_error;
spec->type = GST_BUFTYPE_MPEG;
spec->format = GST_MPEG;
spec->width = 16;
spec->depth = 16;
spec->channels = 2;
spec->info.bpf = 4;
} else {
goto parse_error;
}
spec->bytes_per_sample = (spec->width >> 3) * spec->channels;
gst_caps_replace (&spec->caps, caps);
g_return_val_if_fail (spec->latency_time != 0, FALSE);
@ -482,10 +272,10 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
/* calculate suggested segsize and segtotal. segsize should be one unit
* of 'latency_time' samples, scaling for the fact that latency_time is
* currently stored in microseconds (FIXME: in 0.11) */
spec->segsize = gst_util_uint64_scale (spec->rate * spec->bytes_per_sample,
spec->segsize = gst_util_uint64_scale (info.rate * info.bpf,
spec->latency_time, GST_SECOND / GST_USECOND);
/* Round to an integer number of samples */
spec->segsize -= spec->segsize % spec->bytes_per_sample;
spec->segsize -= spec->segsize % info.bpf;
spec->segtotal = spec->buffer_time / spec->latency_time;
/* leave the latency undefined now, implementations can change it but if it's
@ -495,6 +285,8 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
gst_ring_buffer_debug_spec_caps (spec);
gst_ring_buffer_debug_spec_buff (spec);
spec->info = info;
return TRUE;
/* ERRORS */
@ -525,7 +317,7 @@ gst_ring_buffer_convert (GstRingBuffer * buf,
GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val)
{
gboolean res = TRUE;
gint bps, rate;
gint bpf, rate;
GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s (%d) to %s (%d)",
src_val, gst_format_get_name (src_fmt), src_fmt,
@ -538,12 +330,12 @@ gst_ring_buffer_convert (GstRingBuffer * buf,
/* get important info */
GST_OBJECT_LOCK (buf);
bps = buf->spec.bytes_per_sample;
rate = buf->spec.rate;
bpf = GST_AUDIO_INFO_BPF (&buf->spec.info);
rate = GST_AUDIO_INFO_RATE (&buf->spec.info);
GST_OBJECT_UNLOCK (buf);
if (bps == 0 || rate == 0) {
GST_DEBUG ("no rate or bps configured");
if (bpf == 0 || rate == 0) {
GST_DEBUG ("no rate or bpf configured");
res = FALSE;
goto done;
}
@ -552,11 +344,11 @@ gst_ring_buffer_convert (GstRingBuffer * buf,
case GST_FORMAT_BYTES:
switch (dest_fmt) {
case GST_FORMAT_TIME:
*dest_val = gst_util_uint64_scale_int (src_val / bps, GST_SECOND,
*dest_val = gst_util_uint64_scale_int (src_val / bpf, GST_SECOND,
rate);
break;
case GST_FORMAT_DEFAULT:
*dest_val = src_val / bps;
*dest_val = src_val / bpf;
break;
default:
res = FALSE;
@ -569,7 +361,7 @@ gst_ring_buffer_convert (GstRingBuffer * buf,
*dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, rate);
break;
case GST_FORMAT_BYTES:
*dest_val = src_val * bps;
*dest_val = src_val * bpf;
break;
default:
res = FALSE;
@ -583,7 +375,7 @@ gst_ring_buffer_convert (GstRingBuffer * buf,
break;
case GST_FORMAT_BYTES:
*dest_val = gst_util_uint64_scale_int (src_val, rate, GST_SECOND);
*dest_val *= bps;
*dest_val *= bpf;
break;
default:
res = FALSE;
@ -794,8 +586,7 @@ gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
{
gboolean res = FALSE;
GstRingBufferClass *rclass;
gint i, j;
gint segsize, bps;
gint segsize, bpf;
g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
@ -817,8 +608,8 @@ gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
if (G_UNLIKELY (!res))
goto acquire_failed;
if (G_UNLIKELY ((bps = buf->spec.bytes_per_sample) == 0))
goto invalid_bps;
if (G_UNLIKELY ((bpf = buf->spec.info.bpf) == 0))
goto invalid_bpf;
/* if the seglatency was overwritten with something else than -1, use it, else
* assume segtotal as the latency */
@ -827,18 +618,18 @@ gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
segsize = buf->spec.segsize;
buf->samples_per_seg = segsize / bps;
buf->samples_per_seg = segsize / bpf;
/* create an empty segment */
g_free (buf->empty_seg);
buf->empty_seg = g_malloc (segsize);
/* FIXME, we only have 32 silence samples, which might not be enough to
* represent silence in all channels */
bps = MIN (bps, 32);
for (i = 0, j = 0; i < segsize; i++) {
buf->empty_seg[i] = buf->spec.silence_sample[j];
j = (j + 1) % bps;
if (buf->spec.type == GST_BUFTYPE_RAW) {
gst_audio_format_fill_silence (buf->spec.info.finfo, buf->empty_seg,
segsize);
} else {
/* FIXME, non-raw formats get 0 as the empty sample */
memset (buf->empty_seg, 0, segsize);
}
GST_DEBUG_OBJECT (buf, "acquired device");
@ -867,10 +658,10 @@ acquire_failed:
GST_DEBUG_OBJECT (buf, "failed to acquire device");
goto done;
}
invalid_bps:
invalid_bpf:
{
g_warning
("invalid bytes_per_sample from acquire ringbuffer %p, fix the element",
("invalid bytes_per_frame from acquire ringbuffer %p, fix the element",
buf);
buf->acquired = FALSE;
res = FALSE;
@ -1547,12 +1338,12 @@ no_start:
#define FWD_SAMPLES(s,se,d,de) \
G_STMT_START { \
/* no rate conversion */ \
guint towrite = MIN (se + bps - s, de - d); \
guint towrite = MIN (se + bpf - s, de - d); \
/* simple copy */ \
if (!skip) \
memcpy (d, s, towrite); \
in_samples -= towrite / bps; \
out_samples -= towrite / bps; \
in_samples -= towrite / bpf; \
out_samples -= towrite / bpf; \
s += towrite; \
GST_DEBUG ("copy %u bytes", towrite); \
} G_STMT_END
@ -1563,16 +1354,16 @@ G_STMT_START { \
guint8 *sb = s, *db = d; \
while (s <= se && d < de) { \
if (!skip) \
memcpy (d, s, bps); \
s += bps; \
memcpy (d, s, bpf); \
s += bpf; \
*accum += outr; \
if ((*accum << 1) >= inr) { \
*accum -= inr; \
d += bps; \
d += bpf; \
} \
} \
in_samples -= (s - sb)/bps; \
out_samples -= (d - db)/bps; \
in_samples -= (s - sb)/bpf; \
out_samples -= (d - db)/bpf; \
GST_DEBUG ("fwd_up end %d/%d",*accum,*toprocess); \
} G_STMT_END
@ -1582,16 +1373,16 @@ G_STMT_START { \
guint8 *sb = s, *db = d; \
while (s <= se && d < de) { \
if (!skip) \
memcpy (d, s, bps); \
d += bps; \
memcpy (d, s, bpf); \
d += bpf; \
*accum += inr; \
if ((*accum << 1) >= outr) { \
*accum -= outr; \
s += bps; \
s += bpf; \
} \
} \
in_samples -= (s - sb)/bps; \
out_samples -= (d - db)/bps; \
in_samples -= (s - sb)/bpf; \
out_samples -= (d - db)/bpf; \
GST_DEBUG ("fwd_down end %d/%d",*accum,*toprocess); \
} G_STMT_END
@ -1600,16 +1391,16 @@ G_STMT_START { \
guint8 *sb = se, *db = d; \
while (s <= se && d < de) { \
if (!skip) \
memcpy (d, se, bps); \
se -= bps; \
memcpy (d, se, bpf); \
se -= bpf; \
*accum += outr; \
while (d < de && (*accum << 1) >= inr) { \
*accum -= inr; \
d += bps; \
d += bpf; \
} \
} \
in_samples -= (sb - se)/bps; \
out_samples -= (d - db)/bps; \
in_samples -= (sb - se)/bpf; \
out_samples -= (d - db)/bpf; \
GST_DEBUG ("rev_up end %d/%d",*accum,*toprocess); \
} G_STMT_END
@ -1618,16 +1409,16 @@ G_STMT_START { \
guint8 *sb = se, *db = d; \
while (s <= se && d < de) { \
if (!skip) \
memcpy (d, se, bps); \
d += bps; \
memcpy (d, se, bpf); \
d += bpf; \
*accum += inr; \
while (s <= se && (*accum << 1) >= outr) { \
*accum -= outr; \
se -= bps; \
se -= bpf; \
} \
} \
in_samples -= (sb - se)/bps; \
out_samples -= (d - db)/bps; \
in_samples -= (sb - se)/bpf; \
out_samples -= (d - db)/bpf; \
GST_DEBUG ("rev_down end %d/%d",*accum,*toprocess); \
} G_STMT_END
@ -1636,7 +1427,7 @@ default_commit (GstRingBuffer * buf, guint64 * sample,
guchar * data, gint in_samples, gint out_samples, gint * accum)
{
gint segdone;
gint segsize, segtotal, bps, sps;
gint segsize, segtotal, bpf, sps;
guint8 *dest, *data_end;
gint writeseg, sampleoff;
gint *toprocess;
@ -1649,7 +1440,7 @@ default_commit (GstRingBuffer * buf, guint64 * sample,
dest = buf->memory;
segsize = buf->spec.segsize;
segtotal = buf->spec.segtotal;
bps = buf->spec.bytes_per_sample;
bpf = buf->spec.info.bpf;
sps = buf->samples_per_seg;
reverse = out_samples < 0;
@ -1665,12 +1456,12 @@ default_commit (GstRingBuffer * buf, guint64 * sample,
/* data_end points to the last sample we have to write, not past it. This is
* needed to properly handle reverse playback: it points to the last sample. */
data_end = data + (bps * inr);
data_end = data + (bpf * inr);
/* figure out the segment and the offset inside the segment where
* the first sample should be written. */
writeseg = *sample / sps;
sampleoff = (*sample % sps) * bps;
sampleoff = (*sample % sps) * bpf;
/* write out all samples */
while (*toprocess > 0) {
@ -1714,11 +1505,11 @@ default_commit (GstRingBuffer * buf, guint64 * sample,
/* we can write now */
ws = writeseg % segtotal;
avail = MIN (segsize - sampleoff, bps * out_samples);
avail = MIN (segsize - sampleoff, bpf * out_samples);
d = dest + (ws * segsize) + sampleoff;
d_end = d + avail;
*sample += avail / bps;
*sample += avail / bpf;
GST_DEBUG_OBJECT (buf, "write @%p seg %d, sps %d, off %d, avail %d",
dest + ws * segsize, ws, sps, sampleoff, avail);
@ -1747,10 +1538,10 @@ default_commit (GstRingBuffer * buf, guint64 * sample,
sampleoff = 0;
}
/* we consumed all samples here */
data = data_end + bps;
data = data_end + bpf;
done:
return inr - ((data_end - data) / bps);
return inr - ((data_end - data) / bpf);
/* ERRORS */
not_started:
@ -1867,7 +1658,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
guint len)
{
gint segdone;
gint segsize, segtotal, bps, sps;
gint segsize, segtotal, bpf, sps;
guint8 *dest;
guint to_read;
@ -1878,7 +1669,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
dest = buf->memory;
segsize = buf->spec.segsize;
segtotal = buf->spec.segtotal;
bps = buf->spec.bytes_per_sample;
bpf = buf->spec.info.bpf;
sps = buf->samples_per_seg;
to_read = len;
@ -1913,7 +1704,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
if (G_UNLIKELY (diff >= segtotal)) {
/* pretend we read an empty segment. */
sampleslen = MIN (sps, to_read);
memcpy (data, buf->empty_seg, sampleslen * bps);
memcpy (data, buf->empty_seg, sampleslen * bpf);
goto next;
}
@ -1934,13 +1725,13 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
GST_DEBUG_OBJECT (buf, "read @%p seg %d, off %d, sampleslen %d",
dest + readseg * segsize, readseg, sampleoff, sampleslen);
memcpy (data, dest + (readseg * segsize) + (sampleoff * bps),
(sampleslen * bps));
memcpy (data, dest + (readseg * segsize) + (sampleoff * bpf),
(sampleslen * bpf));
next:
to_read -= sampleslen;
sample += sampleslen;
data += sampleslen * bps;
data += sampleslen * bpf;
}
return len - to_read;

View file

@ -24,6 +24,7 @@
#define __GST_RING_BUFFER_H__
#include <gst/gst.h>
#include <gst/audio/audio.h>
G_BEGIN_DECLS
@ -83,8 +84,7 @@ typedef enum {
/**
* GstBufferFormatType:
* @GST_BUFTYPE_LINEAR: samples in linear PCM
* @GST_BUFTYPE_FLOAT: samples in float
* @GST_BUFTYPE_RAW: samples in linear or float
* @GST_BUFTYPE_MU_LAW: samples in mulaw
* @GST_BUFTYPE_A_LAW: samples in alaw
* @GST_BUFTYPE_IMA_ADPCM: samples in ima adpcm
@ -101,8 +101,7 @@ typedef enum {
*/
typedef enum
{
GST_BUFTYPE_LINEAR,
GST_BUFTYPE_FLOAT,
GST_BUFTYPE_RAW,
GST_BUFTYPE_MU_LAW,
GST_BUFTYPE_A_LAW,
GST_BUFTYPE_IMA_ADPCM,
@ -116,107 +115,6 @@ typedef enum
GST_BUFTYPE_MPEG4_AAC,
} GstBufferFormatType;
/**
* GstBufferFormat:
* @GST_UNKNOWN: unspecified
* @GST_S8: integer signed 8 bit
* @GST_U8: integer unsigned 8 bit
* @GST_S16_LE: integer signed 16 bit little endian
* @GST_S16_BE: integer signed 16 bit big endian
* @GST_U16_LE: integer unsigned 16 bit little endian
* @GST_U16_BE: integer unsigned 16 bit big endian
* @GST_S24_LE: integer signed 24 bit little endian
* @GST_S24_BE: integer signed 24 bit big endian
* @GST_U24_LE: integer unsigned 24 bit little endian
* @GST_U24_BE: integer unsigned 24 bit big endian
* @GST_S32_LE: integer signed 32 bit little endian
* @GST_S32_BE: integer signed 32 bit big endian
* @GST_U32_LE: integer unsigned 32 bit little endian
* @GST_U32_BE: integer unsigned 32 bit big endian
* @GST_S24_3LE: integer signed 24 bit little endian packed in 3 bytes
* @GST_S24_3BE: integer signed 24 bit big endian packed in 3 bytes
* @GST_U24_3LE: integer unsigned 24 bit little endian packed in 3 bytes
* @GST_U24_3BE: integer unsigned 24 bit big endian packed in 3 bytes
* @GST_S20_3LE: integer signed 20 bit little endian packed in 3 bytes
* @GST_S20_3BE: integer signed 20 bit big endian packed in 3 bytes
* @GST_U20_3LE: integer unsigned 20 bit little endian packed in 3 bytes
* @GST_U20_3BE: integer unsigned 20 bit big endian packed in 3 bytes
* @GST_S18_3LE: integer signed 18 bit little endian packed in 3 bytes
* @GST_S18_3BE: integer signed 18 bit big endian packed in 3 bytes
* @GST_U18_3LE: integer unsigned 18 bit little endian packed in 3 bytes
* @GST_U18_3BE: integer unsigned 18 bit big endian packed in 3 bytes
* @GST_FLOAT32_LE: floating 32 bit little endian
* @GST_FLOAT32_BE: floating 32 bit big endian
* @GST_FLOAT64_LE: floating 64 bit little endian
* @GST_FLOAT64_BE: floating 64 bit big endian
* @GST_MU_LAW: mu-law
* @GST_A_LAW: a-law
* @GST_IMA_ADPCM: ima adpcm
* @GST_MPEG: mpeg audio (but not aac)
* @GST_GSM: gsm
* @GST_IEC958: IEC958 frames
* @GST_AC3: ac3
* @GST_EAC3: eac3
* @GST_DTS: dts
* @GST_MPEG2_AAC: mpeg-2 aac
* @GST_MPEG4_AAC: mpeg-4 aac
*
* The detailed format of the samples in the ringbuffer.
*/
typedef enum
{
GST_UNKNOWN,
GST_S8,
GST_U8,
GST_S16_LE,
GST_S16_BE,
GST_U16_LE,
GST_U16_BE,
GST_S24_LE,
GST_S24_BE,
GST_U24_LE,
GST_U24_BE,
GST_S32_LE,
GST_S32_BE,
GST_U32_LE,
GST_U32_BE,
GST_S24_3LE,
GST_S24_3BE,
GST_U24_3LE,
GST_U24_3BE,
GST_S20_3LE,
GST_S20_3BE,
GST_U20_3LE,
GST_U20_3BE,
GST_S18_3LE,
GST_S18_3BE,
GST_U18_3LE,
GST_U18_3BE,
GST_FLOAT32_LE,
GST_FLOAT32_BE,
GST_FLOAT64_LE,
GST_FLOAT64_BE,
GST_MU_LAW,
GST_A_LAW,
GST_IMA_ADPCM,
GST_MPEG,
GST_GSM,
GST_IEC958,
GST_AC3,
GST_EAC3,
GST_DTS,
GST_MPEG2_AAC,
GST_MPEG4_AAC,
} GstBufferFormat;
/**
* GstRingBufferSpec:
* @caps: The caps that generated the Spec.
@ -246,14 +144,8 @@ struct _GstRingBufferSpec
GstCaps *caps; /* the caps of the buffer */
/* in/out */
GstBufferFormatType type;
GstBufferFormat format;
gboolean sign;
gboolean bigend;
gint width;
gint depth;
gint rate;
gint channels;
GstBufferFormatType type;
GstAudioInfo info;
guint64 latency_time; /* the required/actual latency time, this is the
* actual the size of one segment and the
@ -268,10 +160,6 @@ struct _GstRingBufferSpec
* number of segments of @segsize and should be
* chosen so that it matches buffer_time as
* close as possible. */
/* out */
gint bytes_per_sample; /* number of bytes of one sample */
guint8 silence_sample[32]; /* bytes representing silence */
/* ABI added 0.10.20 */
gint seglatency; /* number of segments queued in the lower
* level device, defaults to segtotal. */

View file

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

View file

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

View file

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

View file

@ -75,32 +75,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
/* elementfactory information */
#define CAPS \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 32, " \
"depth = (int) 32, " \
"signed = (boolean) { true, false } ;" \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 16, " \
"depth = (int) 16, " \
"signed = (boolean) { true, false } ;" \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 8, " \
"depth = (int) 8, " \
"signed = (boolean) { true, false } ;" \
"audio/x-raw-float, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) { 32, 64 }"
GST_AUDIO_CAPS_MAKE ("{ S32, U32, S16, U16, S8, U8, F32, F64 }")
static GstStaticPadTemplate gst_adder_src_template =
GST_STATIC_PAD_TEMPLATE ("src",

View file

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

View file

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

View file

@ -1,7 +1,7 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
* 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
*
@ -31,7 +31,7 @@
* <refsect2>
* <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
* the output levels still match the one for a sine wave.
* |[
@ -91,8 +91,6 @@ static void gst_audio_convert_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_audio_convert_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean structure_has_fixed_channel_positions (GstStructure * s,
gboolean * unpositioned_layout);
/* AudioConvert signals and args */
enum
@ -118,45 +116,7 @@ G_DEFINE_TYPE_WITH_CODE (GstAudioConvert, gst_audio_convert,
/*** GSTREAMER PROTOTYPES *****************************************************/
#define STATIC_CAPS \
GST_STATIC_CAPS ( \
"audio/x-raw-float, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
"width = (int) 64;" \
"audio/x-raw-float, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
"width = (int) 32;" \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
"width = (int) 32, " \
"depth = (int) [ 1, 32 ], " \
"signed = (boolean) { true, false }; " \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
"width = (int) 24, " \
"depth = (int) [ 1, 24 ], " "signed = (boolean) { true, false }; " \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
"width = (int) 16, " \
"depth = (int) [ 1, 16 ], " \
"signed = (boolean) { true, false }; " \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
"width = (int) 8, " \
"depth = (int) [ 1, 8 ], " \
"signed = (boolean) { true, false } " \
)
GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL))
static GstStaticPadTemplate gst_audio_convert_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
@ -284,90 +244,20 @@ gst_audio_convert_dispose (GObject * obj)
/*** GSTREAMER FUNCTIONS ******************************************************/
/* convert the given GstCaps to our format */
static gboolean
gst_audio_convert_parse_caps (const GstCaps * caps, AudioConvertFmt * fmt)
{
GstStructure *structure = gst_caps_get_structure (caps, 0);
GST_DEBUG ("parse caps %p and %" GST_PTR_FORMAT, caps, caps);
g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
g_return_val_if_fail (fmt != NULL, FALSE);
/* cleanup old */
audio_convert_clean_fmt (fmt);
fmt->endianness = G_BYTE_ORDER;
fmt->is_int =
(strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0);
/* parse common fields */
if (!gst_structure_get_int (structure, "channels", &fmt->channels))
goto no_values;
if (!(fmt->pos = gst_audio_get_channel_positions (structure)))
goto no_values;
fmt->unpositioned_layout = FALSE;
structure_has_fixed_channel_positions (structure, &fmt->unpositioned_layout);
if (!gst_structure_get_int (structure, "width", &fmt->width))
goto no_values;
if (!gst_structure_get_int (structure, "rate", &fmt->rate))
goto no_values;
/* width != 8 needs an endianness field */
if (fmt->width != 8) {
if (!gst_structure_get_int (structure, "endianness", &fmt->endianness))
goto no_values;
}
if (fmt->is_int) {
/* int specific fields */
if (!gst_structure_get_boolean (structure, "signed", &fmt->sign))
goto no_values;
if (!gst_structure_get_int (structure, "depth", &fmt->depth))
goto no_values;
/* depth cannot be bigger than the width */
if (fmt->depth > fmt->width)
goto not_allowed;
}
fmt->unit_size = (fmt->width * fmt->channels) / 8;
return TRUE;
/* ERRORS */
no_values:
{
GST_DEBUG ("could not get some values from structure");
audio_convert_clean_fmt (fmt);
return FALSE;
}
not_allowed:
{
GST_DEBUG ("width > depth, not allowed - make us advertise correct fmt");
audio_convert_clean_fmt (fmt);
return FALSE;
}
}
/* BaseTransform vmethods */
static gboolean
gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
gsize * size)
{
AudioConvertFmt fmt = { 0 };
GstAudioInfo info;
g_assert (size);
if (!gst_audio_convert_parse_caps (caps, &fmt))
if (!gst_audio_info_from_caps (&info, caps))
goto parse_error;
GST_INFO_OBJECT (base, "unit_size = %u", fmt.unit_size);
*size = fmt.unit_size;
audio_convert_clean_fmt (&fmt);
*size = info.bpf;
GST_INFO_OBJECT (base, "unit_size = %" G_GSIZE_FORMAT, *size);
return TRUE;
@ -378,351 +268,61 @@ parse_error:
}
}
/* Set widths (a list); multiples of 8 between min and max */
static void
set_structure_widths (GstStructure * s, int min, int max)
{
GValue list = { 0 };
GValue val = { 0 };
int width;
if (min == max) {
gst_structure_set (s, "width", G_TYPE_INT, min, NULL);
return;
}
g_value_init (&list, GST_TYPE_LIST);
g_value_init (&val, G_TYPE_INT);
for (width = min; width <= max; width += 8) {
g_value_set_int (&val, width);
gst_value_list_append_value (&list, &val);
}
gst_structure_set_value (s, "width", &list);
g_value_unset (&val);
g_value_unset (&list);
}
/* Set widths of 32 bits and 64 bits (as list) */
static void
set_structure_widths_32_and_64 (GstStructure * s)
{
GValue list = { 0 };
GValue val = { 0 };
g_value_init (&list, GST_TYPE_LIST);
g_value_init (&val, G_TYPE_INT);
g_value_set_int (&val, 32);
gst_value_list_append_value (&list, &val);
g_value_set_int (&val, 64);
gst_value_list_append_value (&list, &val);
gst_structure_set_value (s, "width", &list);
g_value_unset (&val);
g_value_unset (&list);
}
/* Modify the structure so that things that must always have a single
* value (for float), or can always be losslessly converted (for int), have
* appropriate values.
*/
static GstStructure *
make_lossless_changes (GstStructure * s, gboolean isfloat)
{
GValue list = { 0 };
GValue val = { 0 };
int i;
const gint endian[] = { G_LITTLE_ENDIAN, G_BIG_ENDIAN };
const gboolean booleans[] = { TRUE, FALSE };
g_value_init (&list, GST_TYPE_LIST);
g_value_init (&val, G_TYPE_INT);
for (i = 0; i < 2; i++) {
g_value_set_int (&val, endian[i]);
gst_value_list_append_value (&list, &val);
}
gst_structure_set_value (s, "endianness", &list);
g_value_unset (&val);
g_value_unset (&list);
if (isfloat) {
/* float doesn't have a depth or signedness field and only supports
* widths of 32 and 64 bits */
gst_structure_remove_field (s, "depth");
gst_structure_remove_field (s, "signed");
set_structure_widths_32_and_64 (s);
} else {
/* int supports signed and unsigned. GValues are a pain */
g_value_init (&list, GST_TYPE_LIST);
g_value_init (&val, G_TYPE_BOOLEAN);
for (i = 0; i < 2; i++) {
g_value_set_boolean (&val, booleans[i]);
gst_value_list_append_value (&list, &val);
}
gst_structure_set_value (s, "signed", &list);
g_value_unset (&val);
g_value_unset (&list);
}
return s;
}
static void
strip_width_64 (GstStructure * s)
{
const GValue *v = gst_structure_get_value (s, "width");
GValue widths = { 0 };
if (GST_VALUE_HOLDS_LIST (v)) {
int i;
int len = gst_value_list_get_size (v);
g_value_init (&widths, GST_TYPE_LIST);
for (i = 0; i < len; i++) {
const GValue *width = gst_value_list_get_value (v, i);
if (g_value_get_int (width) != 64)
gst_value_list_append_value (&widths, width);
}
gst_structure_set_value (s, "width", &widths);
g_value_unset (&widths);
}
}
/* Little utility function to create a related structure for float/int */
static void
append_with_other_format (GstCaps * caps, const GstStructure * s,
gboolean isfloat)
{
GstStructure *s2;
if (isfloat) {
s2 = gst_structure_copy (s);
gst_structure_set_name (s2, "audio/x-raw-int");
make_lossless_changes (s2, FALSE);
/* If 64 bit float was allowed; remove width 64: we don't support it for
* integer*/
strip_width_64 (s2);
gst_caps_merge_structure (caps, s2);
} else {
s2 = gst_structure_copy (s);
gst_structure_set_name (s2, "audio/x-raw-float");
make_lossless_changes (s2, TRUE);
gst_caps_merge_structure (caps, s2);
}
}
static gboolean
structure_has_fixed_channel_positions (GstStructure * s,
gboolean * unpositioned_layout)
{
GstAudioChannelPosition *pos;
const GValue *val;
gint channels = 0;
if (!gst_structure_get_int (s, "channels", &channels))
return FALSE; /* probably a range */
val = gst_structure_get_value (s, "channel-positions");
if ((val == NULL || !gst_value_is_fixed (val)) && channels <= 8) {
GST_LOG ("no or unfixed channel-positions in %" GST_PTR_FORMAT, s);
return FALSE;
} else if (val == NULL || !gst_value_is_fixed (val)) {
GST_LOG ("implicit undefined channel-positions");
*unpositioned_layout = TRUE;
return TRUE;
}
pos = gst_audio_get_channel_positions (s);
if (pos && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) {
GST_LOG ("fixed undefined channel-positions in %" GST_PTR_FORMAT, s);
*unpositioned_layout = TRUE;
} else {
GST_LOG ("fixed defined channel-positions in %" GST_PTR_FORMAT, s);
*unpositioned_layout = FALSE;
}
g_free (pos);
return TRUE;
}
/* Audioconvert can perform all conversions on audio except for resampling.
* However, there are some conversions we _prefer_ not to do. For example, it's
* better to convert format (float<->int, endianness, etc) than the number of
* channels, as the latter conversion is not lossless.
*
* So, we return, in order (assuming input caps have only one structure;
* which is enforced by basetransform):
* - input caps with a different format (lossless conversions).
* - input caps with a different format (slightly lossy conversions).
* - input caps with a different number of channels (very lossy!)
*/
/* copies the given caps */
static GstCaps *
gst_audio_convert_transform_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps, GstCaps * filter)
gst_audio_convert_caps_remove_format_info (GstCaps * caps)
{
GstCaps *ret;
GstStructure *s, *structure;
gboolean isfloat, allow_mixing;
gint width, depth, channels = 0;
const gchar *fields_used[] = {
"width", "depth", "rate", "channels", "endianness", "signed"
};
const gchar *structure_name;
gint n, j;
int i;
GstStructure *st;
gint i, n;
GstCaps *res;
res = gst_caps_new_empty ();
n = gst_caps_get_size (caps);
for (i = 0; i < n; i++) {
st = gst_caps_get_structure (caps, i);
ret = gst_caps_new_empty ();
/* If this is already expressed by the existing caps
* skip this structure */
if (i > 0 && gst_caps_is_subset_structure (res, st))
continue;
for (j = 0; j < n; j++) {
structure = gst_caps_get_structure (caps, j);
st = gst_structure_copy (st);
gst_structure_remove_fields (st, "format", "channel-positions", NULL);
if (j > 0) {
/* If the new structure is a subset of the already existing transformed
* caps we can safely skip it because we would transform it to the
* same caps again.
*/
if (gst_caps_is_subset_structure (ret, structure))
continue;
}
structure_name = gst_structure_get_name (structure);
isfloat = strcmp (structure_name, "audio/x-raw-float") == 0;
/* We operate on a version of the original structure with any additional
* fields absent */
s = gst_structure_empty_new (structure_name);
for (i = 0; i < sizeof (fields_used) / sizeof (*fields_used); i++) {
if (gst_structure_has_field (structure, fields_used[i]))
gst_structure_set_value (s, fields_used[i],
gst_structure_get_value (structure, fields_used[i]));
}
if (!isfloat) {
/* Commonly, depth is left out: set it equal to width if we have a fixed
* width, if so */
if (!gst_structure_has_field (s, "depth") &&
gst_structure_get_int (s, "width", &width))
gst_structure_set (s, "depth", G_TYPE_INT, width, NULL);
}
/* All lossless conversions */
s = make_lossless_changes (s, isfloat);
gst_caps_merge_structure (ret, gst_structure_copy (s));
/* Same, plus a float<->int conversion */
append_with_other_format (ret, s, isfloat);
GST_DEBUG_OBJECT (base, " step1: (%d) %" GST_PTR_FORMAT,
gst_caps_get_size (ret), ret);
/* We don't mind increasing width/depth/channels, but reducing them is
* Very Bad. Only available if width, depth, channels are already fixed. */
if (!isfloat) {
if (gst_structure_get_int (structure, "width", &width))
set_structure_widths (s, width, 32);
if (gst_structure_get_int (structure, "depth", &depth)) {
if (depth == 32)
gst_structure_set (s, "depth", G_TYPE_INT, 32, NULL);
else
gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, depth, 32, NULL);
}
}
allow_mixing = TRUE;
if (gst_structure_get_int (structure, "channels", &channels)) {
gboolean unpositioned;
/* we don't support mixing for channels without channel positions */
if (structure_has_fixed_channel_positions (structure, &unpositioned))
allow_mixing = (unpositioned == FALSE);
}
if (!allow_mixing) {
gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
if (gst_structure_has_field (structure, "channel-positions"))
gst_structure_set_value (s, "channel-positions",
gst_structure_get_value (structure, "channel-positions"));
} else {
if (channels == 0)
gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 11, NULL);
else if (channels == 11)
gst_structure_set (s, "channels", G_TYPE_INT, 11, NULL);
else
gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, channels, 11,
NULL);
gst_structure_remove_field (s, "channel-positions");
}
gst_caps_merge_structure (ret, gst_structure_copy (s));
/* Same, plus a float<->int conversion */
append_with_other_format (ret, s, isfloat);
/* We'll reduce depth if we must. We reduce as low as 16 bits (for integer);
* reducing to less than this is even worse than dropping channels. We only
* do this if we haven't already done the equivalent above. */
if (!gst_structure_get_int (structure, "width", &width) || width > 16) {
if (isfloat) {
GstStructure *s2 = gst_structure_copy (s);
set_structure_widths_32_and_64 (s2);
append_with_other_format (ret, s2, TRUE);
gst_structure_free (s2);
} else {
GstStructure *s2 = gst_structure_copy (s);
set_structure_widths (s2, 16, 32);
gst_structure_set (s2, "depth", GST_TYPE_INT_RANGE, 16, 32, NULL);
gst_caps_merge_structure (ret, s2);
}
}
/* Channel conversions to fewer channels is only done if needed - generally
* it's very bad to drop channels entirely.
*/
if (allow_mixing) {
gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 11, NULL);
gst_structure_remove_field (s, "channel-positions");
} else {
/* allow_mixing can only be FALSE if we got a fixed number of channels */
gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
if (gst_structure_has_field (structure, "channel-positions"))
gst_structure_set_value (s, "channel-positions",
gst_structure_get_value (structure, "channel-positions"));
}
gst_caps_merge_structure (ret, gst_structure_copy (s));
/* Same, plus a float<->int conversion */
append_with_other_format (ret, s, isfloat);
/* And, finally, for integer only, we allow conversion to any width/depth we
* support: this should be equivalent to our (non-float) template caps. (the
* floating point case should be being handled just above) */
set_structure_widths (s, 8, 32);
gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, 1, 32, NULL);
if (isfloat) {
append_with_other_format (ret, s, TRUE);
gst_structure_free (s);
} else
gst_caps_merge_structure (ret, s);
gst_caps_append_structure (res, st);
}
GST_DEBUG_OBJECT (base, "Caps transformed to %" GST_PTR_FORMAT, ret);
return res;
}
/* The caps can be transformed into any other caps with format info removed.
* However, we should prefer passthrough, so if passthrough is possible,
* put it first in the list. */
static GstCaps *
gst_audio_convert_transform_caps (GstBaseTransform * btrans,
GstPadDirection direction, GstCaps * caps, GstCaps * filter)
{
GstCaps *tmp, *tmp2;
GstCaps *result;
result = gst_caps_copy (caps);
/* Get all possible caps that we can transform to */
tmp = gst_audio_convert_caps_remove_format_info (caps);
if (filter) {
GstCaps *intersection;
GST_DEBUG_OBJECT (base, "Using filter caps %" GST_PTR_FORMAT, filter);
intersection =
gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (ret);
ret = intersection;
GST_DEBUG_OBJECT (base, "Intersection %" GST_PTR_FORMAT, ret);
tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (tmp);
tmp = tmp2;
}
return ret;
result = tmp;
GST_DEBUG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " into %"
GST_PTR_FORMAT, caps, result);
return result;
}
static const GstAudioChannelPosition default_positions[8][8] = {
@ -924,8 +524,8 @@ gst_audio_convert_fixate_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
{
GstStructure *ins, *outs;
gint rate, endianness, depth, width;
gboolean signedness;
gint rate;
const gchar *fmt;
g_return_if_fail (gst_caps_is_fixed (caps));
@ -937,41 +537,16 @@ gst_audio_convert_fixate_caps (GstBaseTransform * base,
gst_audio_convert_fixate_channels (base, ins, outs);
if ((fmt = gst_structure_get_string (ins, "format"))) {
/* FIXME, find the best format */
gst_structure_fixate_field_string (outs, "format", fmt);
}
if (gst_structure_get_int (ins, "rate", &rate)) {
if (gst_structure_has_field (outs, "rate")) {
gst_structure_fixate_field_nearest_int (outs, "rate", rate);
}
}
if (gst_structure_get_int (ins, "endianness", &endianness)) {
if (gst_structure_has_field (outs, "endianness")) {
gst_structure_fixate_field_nearest_int (outs, "endianness", endianness);
}
}
if (gst_structure_get_int (ins, "width", &width)) {
if (gst_structure_has_field (outs, "width")) {
gst_structure_fixate_field_nearest_int (outs, "width", width);
}
} else {
/* this is not allowed */
}
if (gst_structure_get_int (ins, "depth", &depth)) {
if (gst_structure_has_field (outs, "depth")) {
gst_structure_fixate_field_nearest_int (outs, "depth", depth);
}
} else {
/* set depth as width */
if (gst_structure_has_field (outs, "depth")) {
gst_structure_fixate_field_nearest_int (outs, "depth", width);
}
}
if (gst_structure_get_boolean (ins, "signed", &signedness)) {
if (gst_structure_has_field (outs, "signed")) {
gst_structure_fixate_field_boolean (outs, "signed", signedness);
}
}
GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
}
@ -979,26 +554,38 @@ static gboolean
gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
GstCaps * outcaps)
{
AudioConvertFmt in_ac_caps = { 0 };
AudioConvertFmt out_ac_caps = { 0 };
GstAudioConvert *this = GST_AUDIO_CONVERT (base);
GstAudioInfo in_info;
GstAudioInfo out_info;
GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
GST_PTR_FORMAT, incaps, outcaps);
if (!gst_audio_convert_parse_caps (incaps, &in_ac_caps))
return FALSE;
if (!gst_audio_convert_parse_caps (outcaps, &out_ac_caps))
return FALSE;
if (!gst_audio_info_from_caps (&in_info, incaps))
goto invalid_in;
if (!gst_audio_info_from_caps (&out_info, outcaps))
goto invalid_out;
if (!audio_convert_prepare_context (&this->ctx, &in_ac_caps, &out_ac_caps,
if (!audio_convert_prepare_context (&this->ctx, &in_info, &out_info,
this->dither, this->ns))
goto no_converter;
return TRUE;
/* ERRORS */
invalid_in:
{
GST_ERROR_OBJECT (base, "invalid input caps");
return FALSE;
}
invalid_out:
{
GST_ERROR_OBJECT (base, "invalid output caps");
return FALSE;
}
no_converter:
{
GST_ERROR_OBJECT (base, "could not find converter");
return FALSE;
}
}
@ -1010,79 +597,6 @@ gst_audio_convert_transform_ip (GstBaseTransform * base, GstBuffer * buf)
return GST_FLOW_OK;
}
static void
gst_audio_convert_create_silence_buffer (GstAudioConvert * this, gpointer dst,
gint size)
{
if (this->ctx.out.is_int && !this->ctx.out.sign) {
gint i;
switch (this->ctx.out.width) {
case 8:{
guint8 zero = 0x80 >> (8 - this->ctx.out.depth);
memset (dst, zero, size);
break;
}
case 16:{
guint16 *data = (guint16 *) dst;
guint16 zero = 0x8000 >> (16 - this->ctx.out.depth);
if (this->ctx.out.endianness == G_LITTLE_ENDIAN)
zero = GUINT16_TO_LE (zero);
else
zero = GUINT16_TO_BE (zero);
size /= 2;
for (i = 0; i < size; i++)
data[i] = zero;
break;
}
case 24:{
guint32 zero = 0x800000 >> (24 - this->ctx.out.depth);
guint8 *data = (guint8 *) dst;
if (this->ctx.out.endianness == G_LITTLE_ENDIAN) {
for (i = 0; i < size; i += 3) {
data[i] = zero & 0xff;
data[i + 1] = (zero >> 8) & 0xff;
data[i + 2] = (zero >> 16) & 0xff;
}
} else {
for (i = 0; i < size; i += 3) {
data[i + 2] = zero & 0xff;
data[i + 1] = (zero >> 8) & 0xff;
data[i] = (zero >> 16) & 0xff;
}
}
break;
}
case 32:{
guint32 *data = (guint32 *) dst;
guint32 zero = (0x80000000 >> (32 - this->ctx.out.depth));
if (this->ctx.out.endianness == G_LITTLE_ENDIAN)
zero = GUINT32_TO_LE (zero);
else
zero = GUINT32_TO_BE (zero);
size /= 4;
for (i = 0; i < size; i++)
data[i] = zero;
break;
}
default:
memset (dst, 0, size);
g_return_if_reached ();
break;
}
} else {
memset (dst, 0, size);
}
}
static GstFlowReturn
gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
GstBuffer * outbuf)
@ -1095,7 +609,7 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
gpointer src, dst;
/* get amount of samples to convert. */
samples = gst_buffer_get_size (inbuf) / this->ctx.in.unit_size;
samples = gst_buffer_get_size (inbuf) / this->ctx.in.bpf;
/* get in/output sizes, to see if the buffers we got are of correct
* sizes */
@ -1122,7 +636,7 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
goto convert_error;
} else {
/* Create silence buffer */
gst_audio_convert_create_silence_buffer (this, dst, outsize);
gst_audio_format_fill_silence (this->ctx.out.finfo, dst, outsize);
}
ret = GST_FLOW_OK;

View file

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

View file

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

View file

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

View file

@ -5,7 +5,9 @@ plugin_LTLIBRARIES = libgstaudiorate.la
libgstaudiorate_la_SOURCES = gstaudiorate.c
libgstaudiorate_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
libgstaudiorate_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstaudiorate_la_LIBADD = $(GST_LIBS)
libgstaudiorate_la_LIBADD = $(GST_LIBS) \
$(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la
libgstaudiorate_la_LIBTOOLFLAGS = --tag=disable-static
Android.mk: Makefile.am $(BUILT_SOURCES)

View file

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

View file

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

View file

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

View file

@ -28,7 +28,7 @@
* <refsect2>
* <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.
* To create the Ogg/Vorbis file refer to the documentation of vorbisenc.
* </refsect2>
@ -65,42 +65,13 @@ enum
PROP_QUALITY
};
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define SUPPORTED_CAPS \
GST_STATIC_CAPS ( \
"audio/x-raw-float, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) { 32, 64 }; " \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 32, " \
"depth = (int) 32, " \
"signed = (boolean) true; " \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 24, " \
"depth = (int) 24, " \
"signed = (boolean) true; " \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 16, " \
"depth = (int) 16, " \
"signed = (boolean) true; " \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 8, " \
"depth = (int) 8, " \
"signed = (boolean) true" \
)
GST_AUDIO_CAPS_MAKE ("{ F32_LE, F64_LE, S32_LE, S24_3LE, S16_LE, S8 }")
#else
#define SUPPORTED_CAPS \
GST_AUDIO_CAPS_MAKE ("{ F32_BE, F64_BE, S32_BE, S24_3BE, S16_BE, S8 }")
#endif
/* If TRUE integer arithmetic resampling is faster and will be used if appropiate */
#if defined AUDIORESAMPLE_FORMAT_INT
@ -113,11 +84,15 @@ static gboolean gst_audio_resample_use_int = FALSE;
static GstStaticPadTemplate gst_audio_resample_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS);
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (SUPPORTED_CAPS));
static GstStaticPadTemplate gst_audio_resample_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS);
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (SUPPORTED_CAPS));
static void gst_audio_resample_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
@ -252,9 +227,6 @@ gst_audio_resample_stop (GstBaseTransform * base)
resample->tmp_out = NULL;
resample->tmp_out_size = 0;
gst_caps_replace (&resample->sinkcaps, NULL);
gst_caps_replace (&resample->srccaps, NULL);
return TRUE;
}
@ -262,23 +234,21 @@ static gboolean
gst_audio_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
gsize * size)
{
gint width, channels;
GstStructure *structure;
gboolean ret;
GstAudioInfo info;
g_return_val_if_fail (size != NULL, FALSE);
if (!gst_audio_info_from_caps (&info, caps))
goto invalid_caps;
/* this works for both float and int */
structure = gst_caps_get_structure (caps, 0);
ret = gst_structure_get_int (structure, "width", &width);
ret &= gst_structure_get_int (structure, "channels", &channels);
if (G_UNLIKELY (!ret))
return FALSE;
*size = (width / 8) * channels;
*size = GST_AUDIO_INFO_BPF (&info);
return TRUE;
/* ERRORS */
invalid_caps:
{
GST_ERROR_OBJECT (base, "invalid caps");
return FALSE;
}
}
static GstCaps *
@ -455,63 +425,6 @@ gst_audio_resample_reset_state (GstAudioResample * resample)
resample->funcs->reset_mem (resample->state);
}
static gboolean
gst_audio_resample_parse_caps (GstCaps * incaps,
GstCaps * outcaps, gint * width, gint * channels, gint * inrate,
gint * outrate, gboolean * fp)
{
GstStructure *structure;
gboolean ret;
gint mywidth, myinrate, myoutrate, mychannels;
gboolean myfp;
GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %"
GST_PTR_FORMAT, incaps, outcaps);
structure = gst_caps_get_structure (incaps, 0);
if (gst_structure_has_name (structure, "audio/x-raw-float"))
myfp = TRUE;
else
myfp = FALSE;
ret = gst_structure_get_int (structure, "rate", &myinrate);
ret &= gst_structure_get_int (structure, "channels", &mychannels);
ret &= gst_structure_get_int (structure, "width", &mywidth);
if (G_UNLIKELY (!ret))
goto no_in_rate_channels;
structure = gst_caps_get_structure (outcaps, 0);
ret = gst_structure_get_int (structure, "rate", &myoutrate);
if (G_UNLIKELY (!ret))
goto no_out_rate;
if (channels)
*channels = mychannels;
if (inrate)
*inrate = myinrate;
if (outrate)
*outrate = myoutrate;
if (width)
*width = mywidth;
if (fp)
*fp = myfp;
return TRUE;
/* ERRORS */
no_in_rate_channels:
{
GST_DEBUG ("could not get input rate and channels");
return FALSE;
}
no_out_rate:
{
GST_DEBUG ("could not get output rate");
return FALSE;
}
}
static gint
_gcd (gint a, gint b)
{
@ -531,26 +444,29 @@ gst_audio_resample_transform_size (GstBaseTransform * base,
gsize * othersize)
{
gboolean ret = TRUE;
GstAudioInfo in, out;
guint32 ratio_den, ratio_num;
gint inrate, outrate, gcd;
gint bytes_per_samp, channels;
gint bpf;
GST_LOG_OBJECT (base, "asked to transform size %" G_GSIZE_FORMAT
" in direction %s", size, direction == GST_PAD_SINK ? "SINK" : "SRC");
/* Get sample width -> bytes_per_samp, channels, inrate, outrate */
ret =
gst_audio_resample_parse_caps (caps, othercaps, &bytes_per_samp,
&channels, &inrate, &outrate, NULL);
ret = gst_audio_info_from_caps (&in, caps);
ret &= gst_audio_info_from_caps (&out, othercaps);
if (G_UNLIKELY (!ret)) {
GST_ERROR_OBJECT (base, "Wrong caps");
return FALSE;
}
/* Number of samples in either buffer is size / (width*channels) ->
* calculate the factor */
bytes_per_samp = bytes_per_samp * channels / 8;
bpf = GST_AUDIO_INFO_BPF (&in);
inrate = GST_AUDIO_INFO_RATE (&in);
outrate = GST_AUDIO_INFO_RATE (&out);
/* Convert source buffer size to samples */
size /= bytes_per_samp;
size /= bpf;
/* Simplify the conversion ratio factors */
gcd = _gcd (inrate, outrate);
@ -560,16 +476,16 @@ gst_audio_resample_transform_size (GstBaseTransform * base,
if (direction == GST_PAD_SINK) {
/* asked to convert size of an incoming buffer. Round up the output size */
*othersize = gst_util_uint64_scale_int_ceil (size, ratio_den, ratio_num);
*othersize *= bytes_per_samp;
*othersize *= bpf;
} else {
/* asked to convert size of an outgoing buffer. Round down the input size */
*othersize = gst_util_uint64_scale_int (size, ratio_num, ratio_den);
*othersize *= bytes_per_samp;
*othersize *= bpf;
}
GST_LOG_OBJECT (base,
"transformed size %" G_GSIZE_FORMAT " to %" G_GSIZE_FORMAT,
size * bytes_per_samp, *othersize);
size * bpf, *othersize);
return ret;
}
@ -579,18 +495,27 @@ gst_audio_resample_set_caps (GstBaseTransform * base, GstCaps * incaps,
GstCaps * outcaps)
{
gboolean ret;
gint width = 0, inrate = 0, outrate = 0, channels = 0;
gint width, inrate, outrate, channels;
gboolean fp;
GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
GstAudioInfo in, out;
GST_LOG ("incaps %" GST_PTR_FORMAT ", outcaps %"
GST_PTR_FORMAT, incaps, outcaps);
ret = gst_audio_resample_parse_caps (incaps, outcaps,
&width, &channels, &inrate, &outrate, &fp);
if (!gst_audio_info_from_caps (&in, incaps))
goto invalid_incaps;
if (!gst_audio_info_from_caps (&out, outcaps))
goto invalid_outcaps;
if (G_UNLIKELY (!ret))
return FALSE;
/* FIXME do some checks */
/* take new values */
width = GST_AUDIO_FORMAT_INFO_WIDTH (in.finfo);
channels = GST_AUDIO_INFO_CHANNELS (&in);
inrate = GST_AUDIO_INFO_RATE (&in);
outrate = GST_AUDIO_INFO_RATE (&out);
fp = GST_AUDIO_FORMAT_INFO_IS_FLOAT (in.finfo);
ret =
gst_audio_resample_update_state (resample, width, channels, inrate,
@ -599,12 +524,19 @@ gst_audio_resample_set_caps (GstBaseTransform * base, GstCaps * incaps,
if (G_UNLIKELY (!ret))
return FALSE;
/* save caps so we can short-circuit in the size_transform if the caps
* are the same */
gst_caps_replace (&resample->sinkcaps, incaps);
gst_caps_replace (&resample->srccaps, outcaps);
return TRUE;
/* ERROR */
invalid_incaps:
{
GST_ERROR_OBJECT (base, "invalid incaps");
return FALSE;
}
invalid_outcaps:
{
GST_ERROR_OBJECT (base, "invalid outcaps");
return FALSE;
}
}
#define GST_MAXINT24 (8388607)

View file

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

View file

@ -1,9 +1,11 @@
plugin_LTLIBRARIES = libgstaudiotestsrc.la
libgstaudiotestsrc_la_SOURCES = gstaudiotestsrc.c
libgstaudiotestsrc_la_CFLAGS = $(GST_CFLAGS) $(GST_CONTROLLER_CFLAGS)
libgstaudiotestsrc_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GST_CONTROLLER_CFLAGS)
libgstaudiotestsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstaudiotestsrc_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(GST_CONTROLLER_LIBS) $(LIBM)
libgstaudiotestsrc_la_LIBADD = \
$(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la \
$(GST_BASE_LIBS) $(GST_LIBS) $(GST_CONTROLLER_LIBS) $(LIBM)
libgstaudiotestsrc_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstaudiotestsrc.h

View file

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

View file

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

View file

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

View file

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