From d8d6a3b79ecf7c803bfeacbca678b51a61f4ae20 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 9 Mar 2011 11:14:37 +0200 Subject: [PATCH 01/54] spectrum: don't value we already took from the gvalue --- gst/spectrum/gstspectrum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index 9e82829aef..33a68525a5 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -335,7 +335,7 @@ gst_spectrum_set_property (GObject * object, guint prop_id, guint64 interval = g_value_get_uint64 (value); if (filter->interval != interval) { GST_BASE_TRANSFORM_LOCK (filter); - filter->interval = g_value_get_uint64 (value); + filter->interval = interval; gst_spectrum_reset_state (filter); GST_BASE_TRANSFORM_UNLOCK (filter); } From 2fd09ebd89175582342b6558ccc72b2bfee96e75 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 9 Mar 2011 11:18:19 +0200 Subject: [PATCH 02/54] spectrum: call the instance var spectrum instead of filter --- gst/spectrum/gstspectrum.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index 33a68525a5..a5aba20e5d 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -415,9 +415,9 @@ gst_spectrum_stop (GstBaseTransform * trans) static gboolean gst_spectrum_setup (GstAudioFilter * base, GstRingBufferSpec * format) { - GstSpectrum *filter = GST_SPECTRUM (base); + GstSpectrum *spectrum = GST_SPECTRUM (base); - gst_spectrum_reset_state (filter); + gst_spectrum_reset_state (spectrum); return TRUE; } From 787aca6898cf364c9c31b0bd39d4ced2833eaa64 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 9 Mar 2011 11:40:48 +0200 Subject: [PATCH 03/54] spectrum: add a GstSpecrtumChannel context structure We now keep the fft data that is related to one channel in a separate structure to prepare for multichannel support. We also refactor the code to operate more often on the channel context. --- gst/spectrum/gstspectrum.c | 272 ++++++++++++++++++++++--------------- gst/spectrum/gstspectrum.h | 20 ++- 2 files changed, 177 insertions(+), 115 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index a5aba20e5d..edafa58792 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -272,6 +272,56 @@ gst_spectrum_init (GstSpectrum * spectrum, GstSpectrumClass * g_class) spectrum->threshold = DEFAULT_THRESHOLD; } +static void +gst_spectrum_alloc_channel_data (GstSpectrum * spectrum) +{ + gint i; + GstSpectrumChannel *cd; + guint bands = spectrum->bands; + guint nfft = 2 * bands - 2; + guint channels = (spectrum->multi_channel) ? + GST_AUDIO_FILTER (spectrum)->format.channels : 1; + + GST_DEBUG_OBJECT (spectrum, "allocating data for %d channels", channels); + + spectrum->channel_data = g_new (GstSpectrumChannel, channels); + for (i = 0; i < channels; i++) { + cd = &spectrum->channel_data[i]; + cd->fft_ctx = gst_fft_f32_new (nfft, FALSE); + cd->input = g_new0 (gfloat, nfft); + cd->input_tmp = g_new0 (gfloat, nfft); + cd->freqdata = g_new0 (GstFFTF32Complex, bands); + cd->spect_magnitude = g_new0 (gfloat, bands); + cd->spect_phase = g_new0 (gfloat, bands); + } +} + +static void +gst_spectrum_free_channel_data (GstSpectrum * spectrum) +{ + gint i; + GstSpectrumChannel *cd; + guint channels = (spectrum->multi_channel) ? + GST_AUDIO_FILTER (spectrum)->format.channels : 1; + + GST_DEBUG_OBJECT (spectrum, "freeing data for %d channels", channels); + + if (spectrum->channel_data) { + for (i = 0; i < channels; i++) { + cd = &spectrum->channel_data[i]; + if (cd->fft_ctx) + gst_fft_f32_free (cd->fft_ctx); + g_free (cd->input); + g_free (cd->input_tmp); + g_free (cd->freqdata); + g_free (cd->spect_magnitude); + g_free (cd->spect_phase); + } + g_free (spectrum->channel_data); + spectrum->channel_data = NULL; + } +} + static void gst_spectrum_flush (GstSpectrum * spectrum) { @@ -286,21 +336,7 @@ gst_spectrum_reset_state (GstSpectrum * spectrum) { GST_DEBUG_OBJECT (spectrum, "resetting state"); - if (spectrum->fft_ctx) - gst_fft_f32_free (spectrum->fft_ctx); - g_free (spectrum->input); - g_free (spectrum->input_tmp); - g_free (spectrum->freqdata); - g_free (spectrum->spect_magnitude); - g_free (spectrum->spect_phase); - - spectrum->fft_ctx = NULL; - spectrum->input = NULL; - spectrum->input_tmp = NULL; - spectrum->freqdata = NULL; - spectrum->spect_magnitude = NULL; - spectrum->spect_phase = NULL; - + gst_spectrum_free_channel_data (spectrum); gst_spectrum_flush (spectrum); } @@ -418,25 +454,42 @@ gst_spectrum_setup (GstAudioFilter * base, GstRingBufferSpec * format) GstSpectrum *spectrum = GST_SPECTRUM (base); gst_spectrum_reset_state (spectrum); - return TRUE; } +static void +gst_spectrum_message_add_data (GstSpectrum * spectrum, GstStructure * s, + const gchar * name, gfloat * data, guint num_values) +{ + GValue v = { 0, }; + GValue *l; + guint i; + + /* FIXME 0.11: this should be an array, not a list */ + g_value_init (&v, GST_TYPE_LIST); + /* will copy-by-value */ + gst_structure_set_value (s, name, &v); + g_value_unset (&v); + + g_value_init (&v, G_TYPE_FLOAT); + l = (GValue *) gst_structure_get_value (s, name); + for (i = 0; i < num_values; i++) { + g_value_set_float (&v, data[i]); + gst_value_list_append_value (l, &v); /* copies by value */ + } + g_value_unset (&v); +} + static GstMessage * gst_spectrum_message_new (GstSpectrum * spectrum, GstClockTime timestamp, GstClockTime duration) { GstBaseTransform *trans = GST_BASE_TRANSFORM_CAST (spectrum); + GstSpectrumChannel *cd; GstStructure *s; - GValue v = { 0, }; - GValue *l; - guint i; - gfloat *spect_magnitude = spectrum->spect_magnitude; - gfloat *spect_phase = spectrum->spect_phase; GstClockTime endtime, running_time, stream_time; - GST_DEBUG_OBJECT (spectrum, "preparing message, spect = %p, bands =%d ", - spect_magnitude, spectrum->bands); + GST_DEBUG_OBJECT (spectrum, "preparing message, bands =%d ", spectrum->bands); running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME, timestamp); @@ -452,39 +505,90 @@ gst_spectrum_message_new (GstSpectrum * spectrum, GstClockTime timestamp, "running-time", G_TYPE_UINT64, running_time, "duration", G_TYPE_UINT64, duration, NULL); - if (spectrum->message_magnitude) { - /* FIXME 0.11: this should be an array, not a list */ - g_value_init (&v, GST_TYPE_LIST); - /* will copy-by-value */ - gst_structure_set_value (s, "magnitude", &v); - g_value_unset (&v); + cd = &spectrum->channel_data[0]; - g_value_init (&v, G_TYPE_FLOAT); - l = (GValue *) gst_structure_get_value (s, "magnitude"); - for (i = 0; i < spectrum->bands; i++) { - g_value_set_float (&v, spect_magnitude[i]); - gst_value_list_append_value (l, &v); /* copies by value */ + if (spectrum->message_magnitude) { + gst_spectrum_message_add_data (spectrum, s, "magnitude", + cd->spect_magnitude, spectrum->bands); + } + if (spectrum->message_phase) { + gst_spectrum_message_add_data (spectrum, s, "phase", + cd->spect_phase, spectrum->bands); + } + return gst_message_new_element (GST_OBJECT (spectrum), s); +} + +static void +gst_spectrum_run_fft (GstSpectrum * spectrum, GstSpectrumChannel * cd, + guint input_pos) +{ + guint i; + guint bands = spectrum->bands; + guint nfft = 2 * bands - 2; + gint threshold = spectrum->threshold; + gfloat *input = cd->input; + gfloat *input_tmp = cd->input_tmp; + gfloat *spect_magnitude = cd->spect_magnitude; + gfloat *spect_phase = cd->spect_phase; + GstFFTF32Complex *freqdata = cd->freqdata; + GstFFTF32 *fft_ctx = cd->fft_ctx; + + for (i = 0; i < nfft; i++) + input_tmp[i] = input[(input_pos + i) % nfft]; + + gst_fft_f32_window (fft_ctx, input_tmp, GST_FFT_WINDOW_HAMMING); + + gst_fft_f32_fft (fft_ctx, input_tmp, freqdata); + + if (spectrum->message_magnitude) { + gdouble val; + /* Calculate magnitude in db */ + for (i = 0; i < bands; i++) { + val = freqdata[i].r * freqdata[i].r; + val += freqdata[i].i * freqdata[i].i; + val /= nfft * nfft; + val = 10.0 * log10 (val); + if (val < threshold) + val = threshold; + spect_magnitude[i] += val; } - g_value_unset (&v); } if (spectrum->message_phase) { - /* FIXME 0.11: this should be an array, not a list */ - g_value_init (&v, GST_TYPE_LIST); - /* will copy-by-value */ - gst_structure_set_value (s, "phase", &v); - g_value_unset (&v); - - g_value_init (&v, G_TYPE_FLOAT); - l = (GValue *) gst_structure_get_value (s, "phase"); - for (i = 0; i < spectrum->bands; i++) { - g_value_set_float (&v, spect_phase[i]); - gst_value_list_append_value (l, &v); /* copies by value */ - } - g_value_unset (&v); + /* Calculate phase */ + for (i = 0; i < bands; i++) + spect_phase[i] += atan2 (freqdata[i].i, freqdata[i].r); } +} - return gst_message_new_element (GST_OBJECT (spectrum), s); +static void +gst_spectrum_prepare_message_data (GstSpectrum * spectrum, + GstSpectrumChannel * cd) +{ + guint i; + guint bands = spectrum->bands; + guint num_fft = spectrum->num_fft; + gfloat *spect_magnitude = cd->spect_magnitude; + gfloat *spect_phase = cd->spect_phase; + + /* Calculate average */ + for (i = 0; i < bands; i++) { + spect_magnitude[i] /= num_fft; + spect_phase[i] /= num_fft; + } +} + +static void +gst_spectrum_reset_message_data (GstSpectrum * spectrum, + GstSpectrumChannel * cd) +{ + guint bands = spectrum->bands; + gfloat *spect_magnitude = cd->spect_magnitude; + gfloat *spect_phase = cd->spect_phase; + + /* reset spectrum accumulators */ + memset (spect_magnitude, 0, bands * sizeof (gfloat)); + memset (spect_phase, 0, bands * sizeof (gfloat)); } static GstFlowReturn @@ -500,17 +604,12 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) gboolean fp = (GST_AUDIO_FILTER (spectrum)->format.type == GST_BUFTYPE_FLOAT); guint bands = spectrum->bands; guint nfft = 2 * bands - 2; - gint threshold = spectrum->threshold; guint input_pos; gfloat *input; - gfloat *input_tmp; - GstFFTF32Complex *freqdata; - gfloat *spect_magnitude; - gfloat *spect_phase; - GstFFTF32 *fft_ctx; const guint8 *data = GST_BUFFER_DATA (buffer); guint size = GST_BUFFER_SIZE (buffer); gboolean have_full_interval; + GstSpectrumChannel *cd; GST_LOG_OBJECT (spectrum, "input size: %d bytes", GST_BUFFER_SIZE (buffer)); @@ -522,15 +621,10 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) /* If we don't have a FFT context yet (or it was reset due to parameter * changes) get one and allocate memory for everything */ - if (spectrum->fft_ctx == NULL) { + if (spectrum->channel_data == NULL) { GST_DEBUG_OBJECT (spectrum, "allocating for bands %u", bands); - spectrum->fft_ctx = gst_fft_f32_new (nfft, FALSE); - spectrum->input = g_new0 (gfloat, nfft); - spectrum->input_tmp = g_new0 (gfloat, nfft); - spectrum->freqdata = g_new0 (GstFFTF32Complex, bands); - spectrum->spect_magnitude = g_new0 (gfloat, bands); - spectrum->spect_phase = g_new0 (gfloat, bands); + gst_spectrum_alloc_channel_data (spectrum); spectrum->frames_per_interval = gst_util_uint64_scale (spectrum->interval, rate, GST_SECOND); @@ -546,17 +640,12 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) if (spectrum->num_frames == 0) spectrum->message_ts = GST_BUFFER_TIMESTAMP (buffer); - input = spectrum->input; - input_tmp = spectrum->input_tmp; - freqdata = spectrum->freqdata; - spect_magnitude = spectrum->spect_magnitude; - spect_phase = spectrum->spect_phase; - fft_ctx = spectrum->fft_ctx; - input_pos = spectrum->input_pos; - while (size >= width * channels) { + cd = &spectrum->channel_data[0]; + input = cd->input; + while (size >= width * channels) { /* Move the current frame into our ringbuffer and * take the average of all channels */ @@ -608,40 +697,13 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) && spectrum->num_frames - 1 == spectrum->frames_per_interval) ); - /* If we have enough frames for an FFT or we - * have all frames required for the interval run - * an FFT. In the last case we probably take the + /* If we have enough frames for an FFT or we have all frames required for + * the interval run an FFT. In the last case we probably take the * FFT of frames that we already handled. */ if ((spectrum->num_frames % nfft == 0) || have_full_interval) { - - for (i = 0; i < nfft; i++) - input_tmp[i] = input[(input_pos + i) % nfft]; - - gst_fft_f32_window (fft_ctx, input_tmp, GST_FFT_WINDOW_HAMMING); - - gst_fft_f32_fft (fft_ctx, input_tmp, freqdata); + gst_spectrum_run_fft (spectrum, cd, input_pos); spectrum->num_fft++; - - if (spectrum->message_magnitude) { - gdouble val; - /* Calculate magnitude in db */ - for (i = 0; i < bands; i++) { - val = freqdata[i].r * freqdata[i].r; - val += freqdata[i].i * freqdata[i].i; - val /= nfft * nfft; - val = 10.0 * log10 (val); - if (val < threshold) - val = threshold; - spect_magnitude[i] += val; - } - } - - if (spectrum->message_phase) { - /* Calculate phase */ - for (i = 0; i < bands; i++) - spect_phase[i] += atan2 (freqdata[i].i, freqdata[i].r); - } } /* Do we have the FFTs for one interval? */ @@ -660,11 +722,7 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) if (spectrum->post_messages) { GstMessage *m; - /* Calculate average */ - for (i = 0; i < bands; i++) { - spect_magnitude[i] /= spectrum->num_fft; - spect_phase[i] /= spectrum->num_fft; - } + gst_spectrum_prepare_message_data (spectrum, cd); m = gst_spectrum_message_new (spectrum, spectrum->message_ts, spectrum->interval); @@ -676,9 +734,7 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) spectrum->message_ts += gst_util_uint64_scale (spectrum->num_frames, GST_SECOND, rate); - /* reset spectrum accumulators */ - memset (spect_magnitude, 0, bands * sizeof (gfloat)); - memset (spect_phase, 0, bands * sizeof (gfloat)); + gst_spectrum_reset_message_data (spectrum, cd); spectrum->num_frames = 0; spectrum->num_fft = 0; } diff --git a/gst/spectrum/gstspectrum.h b/gst/spectrum/gstspectrum.h index d172f6cee3..7f055ec93b 100644 --- a/gst/spectrum/gstspectrum.h +++ b/gst/spectrum/gstspectrum.h @@ -35,6 +35,17 @@ G_BEGIN_DECLS #define GST_IS_SPECTRUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_SPECTRUM)) typedef struct _GstSpectrum GstSpectrum; typedef struct _GstSpectrumClass GstSpectrumClass; +typedef struct _GstSpectrumChannel GstSpectrumChannel; + +struct _GstSpectrumChannel +{ + gfloat *input; + gfloat *input_tmp; + GstFFTF32Complex *freqdata; + gfloat *spect_magnitude; /* accumulated mangitude and phase */ + gfloat *spect_phase; /* will be scaled by num_fft before sending */ + GstFFTF32 *fft_ctx; +}; struct _GstSpectrum { @@ -55,14 +66,9 @@ struct _GstSpectrum GstClockTime message_ts; /* starttime for next message */ /* */ - gfloat *input; - guint input_pos; - gfloat *input_tmp; - GstFFTF32Complex *freqdata; - gfloat *spect_magnitude; /* accumulated mangitude and phase */ - gfloat *spect_phase; /* will be scaled by num_fft before sending */ - GstFFTF32 *fft_ctx; + GstSpectrumChannel *channel_data; + guint input_pos; guint64 error_per_interval; guint64 accumulated_error; }; From b60675acaf0893db1bf9292d91cec1eae88628ec Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 9 Mar 2011 12:20:11 +0200 Subject: [PATCH 04/54] spectrum: code cleanup for copying data to ring-buffer Rename fp to is_float and restructure if-else part for handling the different formats. --- gst/spectrum/gstspectrum.c | 69 +++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index edafa58792..1433d76c2b 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -601,7 +601,8 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) gfloat max_value = (1UL << (GST_AUDIO_FILTER (spectrum)->format.depth - 1)) - 1; guint width = GST_AUDIO_FILTER (spectrum)->format.width / 8; - gboolean fp = (GST_AUDIO_FILTER (spectrum)->format.type == GST_BUFTYPE_FLOAT); + gboolean is_float = + (GST_AUDIO_FILTER (spectrum)->format.type == GST_BUFTYPE_FLOAT); guint bands = spectrum->bands; guint nfft = 2 * bands - 2; guint input_pos; @@ -650,38 +651,44 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) * take the average of all channels */ input[input_pos] = 0.0; - if (fp && width == 4) { - gfloat *in = (gfloat *) data; - for (i = 0; i < channels; i++) - input[input_pos] += in[i]; - } else if (fp && width == 8) { - gdouble *in = (gdouble *) data; - for (i = 0; i < channels; i++) - input[input_pos] += in[i]; - } else if (!fp && width == 4) { - gint32 *in = (gint32 *) data; - for (i = 0; i < channels; i++) - /* max_value will be 0 when depth is 1, interpret -1 and 0 - * as -1 and +1 if that's the case. - */ - input[input_pos] += max_value ? in[i] / max_value : in[i] * 2 + 1; - } else if (!fp && width == 3) { - for (i = 0; i < channels; i++) { -#if G_BYTE_ORDER == G_BIG_ENDIAN - gint32 value = GST_READ_UINT24_BE (data); -#else - gint32 value = GST_READ_UINT24_LE (data); -#endif - if (value & 0x00800000) - value |= 0xff000000; - input[input_pos] += max_value ? value / max_value : value * 2 + 1; + if (is_float) { + if (width == 4) { + gfloat *in = (gfloat *) data; + for (i = 0; i < channels; i++) + input[input_pos] += in[i]; + } else if (width == 8) { + gdouble *in = (gdouble *) data; + for (i = 0; i < channels; i++) + input[input_pos] += in[i]; + } else { + g_assert_not_reached (); } - } else if (!fp && width == 2) { - gint16 *in = (gint16 *) data; - for (i = 0; i < channels; i++) - input[input_pos] += max_value ? in[i] / max_value : in[i] * 2 + 1; } else { - g_assert_not_reached (); + if (width == 4) { + gint32 *in = (gint32 *) data; + for (i = 0; i < channels; i++) + /* max_value will be 0 when depth is 1, interpret -1 and 0 + * as -1 and +1 if that's the case. + */ + input[input_pos] += max_value ? in[i] / max_value : in[i] * 2 + 1; + } else if (width == 3) { + for (i = 0; i < channels; i++) { +#if G_BYTE_ORDER == G_BIG_ENDIAN + gint32 value = GST_READ_UINT24_BE (data); +#else + gint32 value = GST_READ_UINT24_LE (data); +#endif + if (value & 0x00800000) + value |= 0xff000000; + input[input_pos] += max_value ? value / max_value : value * 2 + 1; + } + } else if (width == 2) { + gint16 *in = (gint16 *) data; + for (i = 0; i < channels; i++) + input[input_pos] += max_value ? in[i] / max_value : in[i] * 2 + 1; + } else { + g_assert_not_reached (); + } } input[input_pos] /= channels; From 5b9028c52c1c897d5f61cb90ccedd20234a0ae4c Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 9 Mar 2011 12:38:52 +0200 Subject: [PATCH 05/54] spectrum: pull format to temp var to improve readability of lines using it --- gst/spectrum/gstspectrum.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index 1433d76c2b..14894debd1 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -596,13 +596,12 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) { GstSpectrum *spectrum = GST_SPECTRUM (trans); guint i; - guint rate = GST_AUDIO_FILTER (spectrum)->format.rate; - guint channels = GST_AUDIO_FILTER (spectrum)->format.channels; - gfloat max_value = - (1UL << (GST_AUDIO_FILTER (spectrum)->format.depth - 1)) - 1; - guint width = GST_AUDIO_FILTER (spectrum)->format.width / 8; - gboolean is_float = - (GST_AUDIO_FILTER (spectrum)->format.type == GST_BUFTYPE_FLOAT); + GstRingBufferSpec *format = &GST_AUDIO_FILTER (spectrum)->format; + guint rate = format->rate; + guint channels = format->channels; + guint width = format->width / 8; + gboolean is_float = (format->type == GST_BUFTYPE_FLOAT); + gfloat max_value = (1UL << (format->depth - 1)) - 1; guint bands = spectrum->bands; guint nfft = 2 * bands - 2; guint input_pos; From 65f4c4b3e675bc920c2257e267618b232710b205 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 9 Mar 2011 12:41:15 +0200 Subject: [PATCH 06/54] spectrum: factor out the code that accumulated samples into the ring-buffer Use a separate function to read a sample frame into a ringbuffer slot. In the future we can use format-specific function pointer to avoid the reoccuring format checks. --- gst/spectrum/gstspectrum.c | 97 ++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index 14894debd1..ff1bd46cc6 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -518,6 +518,55 @@ gst_spectrum_message_new (GstSpectrum * spectrum, GstClockTime timestamp, return gst_message_new_element (GST_OBJECT (spectrum), s); } +/* FIXME: have dedicated read function pointers for each format */ +static gfloat +gst_spectrum_input_data_mixed (const guint8 * data, gfloat is_float, + guint width, guint channels, gfloat max_value) +{ + guint i; + gfloat v = 0.0; + + if (is_float) { + if (width == 4) { + gfloat *in = (gfloat *) data; + for (i = 0; i < channels; i++) + v += in[i]; + } else if (width == 8) { + gdouble *in = (gdouble *) data; + for (i = 0; i < channels; i++) + v += in[i]; + } else { + g_assert_not_reached (); + } + } else { + if (width == 4) { + gint32 *in = (gint32 *) data; + /* max_value will be 0 when depth is 1, + * interpret -1 and 0 as -1 and +1 if that's the case. */ + for (i = 0; i < channels; i++) + v += max_value ? in[i] / max_value : in[i] * 2 + 1; + } else if (width == 3) { + for (i = 0; i < channels; i++) { +#if G_BYTE_ORDER == G_BIG_ENDIAN + gint32 value = GST_READ_UINT24_BE (data); +#else + gint32 value = GST_READ_UINT24_LE (data); +#endif + if (value & 0x00800000) + value |= 0xff000000; + v += max_value ? value / max_value : value * 2 + 1; + } + } else if (width == 2) { + gint16 *in = (gint16 *) data; + for (i = 0; i < channels; i++) + v += max_value ? in[i] / max_value : in[i] * 2 + 1; + } else { + g_assert_not_reached (); + } + } + return v / channels; +} + static void gst_spectrum_run_fft (GstSpectrum * spectrum, GstSpectrumChannel * cd, guint input_pos) @@ -595,7 +644,6 @@ static GstFlowReturn gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) { GstSpectrum *spectrum = GST_SPECTRUM (trans); - guint i; GstRingBufferSpec *format = &GST_AUDIO_FILTER (spectrum)->format; guint rate = format->rate; guint channels = format->channels; @@ -646,50 +694,9 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) input = cd->input; while (size >= width * channels) { - /* Move the current frame into our ringbuffer and - * take the average of all channels - */ - input[input_pos] = 0.0; - if (is_float) { - if (width == 4) { - gfloat *in = (gfloat *) data; - for (i = 0; i < channels; i++) - input[input_pos] += in[i]; - } else if (width == 8) { - gdouble *in = (gdouble *) data; - for (i = 0; i < channels; i++) - input[input_pos] += in[i]; - } else { - g_assert_not_reached (); - } - } else { - if (width == 4) { - gint32 *in = (gint32 *) data; - for (i = 0; i < channels; i++) - /* max_value will be 0 when depth is 1, interpret -1 and 0 - * as -1 and +1 if that's the case. - */ - input[input_pos] += max_value ? in[i] / max_value : in[i] * 2 + 1; - } else if (width == 3) { - for (i = 0; i < channels; i++) { -#if G_BYTE_ORDER == G_BIG_ENDIAN - gint32 value = GST_READ_UINT24_BE (data); -#else - gint32 value = GST_READ_UINT24_LE (data); -#endif - if (value & 0x00800000) - value |= 0xff000000; - input[input_pos] += max_value ? value / max_value : value * 2 + 1; - } - } else if (width == 2) { - gint16 *in = (gint16 *) data; - for (i = 0; i < channels; i++) - input[input_pos] += max_value ? in[i] / max_value : in[i] * 2 + 1; - } else { - g_assert_not_reached (); - } - } - input[input_pos] /= channels; + /* Move the mixdown of current frame into our ringbuffer */ + input[input_pos] = gst_spectrum_input_data_mixed (data, is_float, width, + channels, max_value); data += width * channels; size -= width * channels; From 832aac534a25d56ff5ec97be313af3fc5d403b7a Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 9 Mar 2011 16:55:56 +0200 Subject: [PATCH 07/54] spectrum: more xrefs in the docs --- gst/spectrum/gstspectrum.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index ff1bd46cc6..b7960d8d85 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -71,7 +71,7 @@ * "magnitude": * the level for each frequency band in dB. All values below the value of the * #GstSpectrum:threshold property will be set to the threshold. Only present - * if the message-magnitude property is true. + * if the #GstSpectrum:message-magnitude property is %TRUE. * * * @@ -79,7 +79,7 @@ * #GstValueList of #gfloat * "phase": * The phase for each frequency band. The value is between -pi and pi. Only - * present if the message-phase property is true. + * present if the #GstSpectrum:message-phase property is %TRUE. * * * From c622477a92aaa0910d91530b2f17083c96d2b17d Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 9 Mar 2011 16:57:28 +0200 Subject: [PATCH 08/54] spectrum: multi-channel support Add a boolean multi-channel property with a default of FALSE. When set to TRUE the element won't mix all input channels to mono, but instead run a FFT on each channel. In that case the result message would contain a 2 dimensional array of channel x data for magnitude and phase. API: GstSpectrum:multi-channel https://bugzilla.gnome.org/show_bug.cgi?id=593482 --- gst/spectrum/gstspectrum.c | 340 +++++++++++++++++++++++++++++-------- gst/spectrum/gstspectrum.h | 1 + 2 files changed, 270 insertions(+), 71 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index b7960d8d85..574457a350 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -84,6 +84,10 @@ * * * + * If #GstSpectrum:multi-channel property is set to true. magnitude and phase + * fields will be each a nested #GstValueArray. The first dimension are the + * channels and the second dimension are the values. + * * * Example application * |[ @@ -143,6 +147,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_spectrum_debug); #define DEFAULT_INTERVAL (GST_SECOND / 10) #define DEFAULT_BANDS 128 #define DEFAULT_THRESHOLD -60 +#define DEFAULT_MULTI_CHANNEL FALSE enum { @@ -153,7 +158,8 @@ enum PROP_MESSAGE_PHASE, PROP_INTERVAL, PROP_BANDS, - PROP_THRESHOLD + PROP_THRESHOLD, + PROP_MULTI_CHANNEL }; GST_BOILERPLATE (GstSpectrum, gst_spectrum, GstAudioFilter, @@ -257,6 +263,18 @@ gst_spectrum_class_init (GstSpectrumClass * klass) G_MININT, 0, DEFAULT_THRESHOLD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstSpectrum:multi-channel + * + * Send separate results for each channel + * + * Since: 0.10.29 + */ + g_object_class_install_property (gobject_class, PROP_MULTI_CHANNEL, + g_param_spec_boolean ("multi-channel", "Multichannel results", + "Send separate results for each channel", + DEFAULT_MULTI_CHANNEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_DEBUG_CATEGORY_INIT (gst_spectrum_debug, "spectrum", 0, "audio spectrum analyser element"); } @@ -390,6 +408,16 @@ gst_spectrum_set_property (GObject * object, guint prop_id, case PROP_THRESHOLD: filter->threshold = g_value_get_int (value); break; + case PROP_MULTI_CHANNEL:{ + gboolean multi_channel = g_value_get_boolean (value); + if (filter->multi_channel != multi_channel) { + GST_BASE_TRANSFORM_LOCK (filter); + filter->multi_channel = multi_channel; + gst_spectrum_reset_state (filter); + GST_BASE_TRANSFORM_UNLOCK (filter); + } + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -422,6 +450,9 @@ gst_spectrum_get_property (GObject * object, guint prop_id, case PROP_THRESHOLD: g_value_set_int (value, filter->threshold); break; + case PROP_MULTI_CHANNEL: + g_value_set_boolean (value, filter->multi_channel); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -457,29 +488,53 @@ gst_spectrum_setup (GstAudioFilter * base, GstRingBufferSpec * format) return TRUE; } -static void -gst_spectrum_message_add_data (GstSpectrum * spectrum, GstStructure * s, - const gchar * name, gfloat * data, guint num_values) +static GValue * +gst_spectrum_message_add_container (GstStructure * s, GType type, + const gchar * name) { GValue v = { 0, }; - GValue *l; - guint i; - /* FIXME 0.11: this should be an array, not a list */ - g_value_init (&v, GST_TYPE_LIST); + g_value_init (&v, type); /* will copy-by-value */ gst_structure_set_value (s, name, &v); g_value_unset (&v); + return (GValue *) gst_structure_get_value (s, name); +} + +static void +gst_spectrum_message_add_list (GValue * cv, gfloat * data, guint num_values) +{ + GValue v = { 0, }; + guint i; g_value_init (&v, G_TYPE_FLOAT); - l = (GValue *) gst_structure_get_value (s, name); for (i = 0; i < num_values; i++) { g_value_set_float (&v, data[i]); - gst_value_list_append_value (l, &v); /* copies by value */ + gst_value_list_append_value (cv, &v); /* copies by value */ } g_value_unset (&v); } +static void +gst_spectrum_message_add_array (GValue * cv, gfloat * data, guint num_values) +{ + GValue v = { 0, }; + GValue a = { 0, }; + guint i; + + g_value_init (&a, GST_TYPE_ARRAY); + + g_value_init (&v, G_TYPE_FLOAT); + for (i = 0; i < num_values; i++) { + g_value_set_float (&v, data[i]); + gst_value_array_append_value (&a, &v); /* copies by value */ + } + g_value_unset (&v); + + gst_value_array_append_value (cv, &a); /* copies by value */ + g_value_unset (&a); +} + static GstMessage * gst_spectrum_message_new (GstSpectrum * spectrum, GstClockTime timestamp, GstClockTime duration) @@ -487,6 +542,7 @@ gst_spectrum_message_new (GstSpectrum * spectrum, GstClockTime timestamp, GstBaseTransform *trans = GST_BASE_TRANSFORM_CAST (spectrum); GstSpectrumChannel *cd; GstStructure *s; + GValue *mcv = NULL, *pcv = NULL; GstClockTime endtime, running_time, stream_time; GST_DEBUG_OBJECT (spectrum, "preparing message, bands =%d ", spectrum->bands); @@ -505,15 +561,42 @@ gst_spectrum_message_new (GstSpectrum * spectrum, GstClockTime timestamp, "running-time", G_TYPE_UINT64, running_time, "duration", G_TYPE_UINT64, duration, NULL); - cd = &spectrum->channel_data[0]; + if (!spectrum->multi_channel) { + cd = &spectrum->channel_data[0]; - if (spectrum->message_magnitude) { - gst_spectrum_message_add_data (spectrum, s, "magnitude", - cd->spect_magnitude, spectrum->bands); - } - if (spectrum->message_phase) { - gst_spectrum_message_add_data (spectrum, s, "phase", - cd->spect_phase, spectrum->bands); + if (spectrum->message_magnitude) { + /* FIXME 0.11: this should be an array, not a list */ + mcv = gst_spectrum_message_add_container (s, GST_TYPE_LIST, "magnitude"); + gst_spectrum_message_add_list (mcv, cd->spect_magnitude, spectrum->bands); + } + if (spectrum->message_phase) { + /* FIXME 0.11: this should be an array, not a list */ + pcv = gst_spectrum_message_add_container (s, GST_TYPE_LIST, "phase"); + gst_spectrum_message_add_list (pcv, cd->spect_phase, spectrum->bands); + } + } else { + guint c; + guint channels = GST_AUDIO_FILTER (spectrum)->format.channels; + + if (spectrum->message_magnitude) { + mcv = gst_spectrum_message_add_container (s, GST_TYPE_ARRAY, "magnitude"); + } + if (spectrum->message_phase) { + pcv = gst_spectrum_message_add_container (s, GST_TYPE_ARRAY, "phase"); + } + + for (c = 0; c < channels; c++) { + cd = &spectrum->channel_data[c]; + + if (spectrum->message_magnitude) { + gst_spectrum_message_add_array (mcv, cd->spect_magnitude, + spectrum->bands); + } + if (spectrum->message_phase) { + gst_spectrum_message_add_array (pcv, cd->spect_magnitude, + spectrum->bands); + } + } } return gst_message_new_element (GST_OBJECT (spectrum), s); } @@ -567,6 +650,45 @@ gst_spectrum_input_data_mixed (const guint8 * data, gfloat is_float, return v / channels; } +static gfloat +gst_spectrum_input_data (const guint8 * data, gfloat is_float, guint width, + gfloat max_value) +{ + gfloat v = 0.0; + + if (is_float) { + if (width == 4) { + v = ((gfloat *) data)[0]; + } else if (width == 8) { + v = ((gdouble *) data)[0]; + } else { + g_assert_not_reached (); + } + } else { + if (width == 4) { + gint32 *in = (gint32 *) data; + /* max_value will be 0 when depth is 1, + * interpret -1 and 0 as -1 and +1 if that's the case. */ + v = max_value ? in[0] / max_value : in[0] * 2 + 1; + } else if (width == 3) { +#if G_BYTE_ORDER == G_BIG_ENDIAN + gint32 in = GST_READ_UINT24_BE (data); +#else + gint32 in = GST_READ_UINT24_LE (data); +#endif + if (in & 0x00800000) + in |= 0xff000000; + v = max_value ? in / max_value : in * 2 + 1; + } else if (width == 2) { + gint16 *in = (gint16 *) data; + v = max_value ? in[0] / max_value : in[0] * 2 + 1; + } else { + g_assert_not_reached (); + } + } + return v; +} + static void gst_spectrum_run_fft (GstSpectrum * spectrum, GstSpectrumChannel * cd, guint input_pos) @@ -690,66 +812,142 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) input_pos = spectrum->input_pos; - cd = &spectrum->channel_data[0]; - input = cd->input; + if (!spectrum->multi_channel) { + cd = &spectrum->channel_data[0]; + input = cd->input; - while (size >= width * channels) { - /* Move the mixdown of current frame into our ringbuffer */ - input[input_pos] = gst_spectrum_input_data_mixed (data, is_float, width, - channels, max_value); + while (size >= width * channels) { + /* Move the mixdown of current frame into our ringbuffer */ + input[input_pos] = gst_spectrum_input_data_mixed (data, is_float, width, + channels, max_value); - data += width * channels; - size -= width * channels; - input_pos = (input_pos + 1) % nfft; - spectrum->num_frames++; + data += width * channels; + size -= width * channels; + input_pos = (input_pos + 1) % nfft; + spectrum->num_frames++; - have_full_interval = ( - (spectrum->accumulated_error < GST_SECOND - && spectrum->num_frames == spectrum->frames_per_interval) || - (spectrum->accumulated_error >= GST_SECOND - && spectrum->num_frames - 1 == spectrum->frames_per_interval) - ); + have_full_interval = ( + (spectrum->accumulated_error < GST_SECOND + && spectrum->num_frames == spectrum->frames_per_interval) || + (spectrum->accumulated_error >= GST_SECOND + && spectrum->num_frames - 1 == spectrum->frames_per_interval) + ); - /* If we have enough frames for an FFT or we have all frames required for - * the interval run an FFT. In the last case we probably take the - * FFT of frames that we already handled. - */ - if ((spectrum->num_frames % nfft == 0) || have_full_interval) { - gst_spectrum_run_fft (spectrum, cd, input_pos); - spectrum->num_fft++; - } - - /* Do we have the FFTs for one interval? */ - if (have_full_interval) { - - GST_INFO ("nfft: %u num_frames: %" G_GUINT64_FORMAT " fpi: %" - G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft, - spectrum->num_frames, spectrum->frames_per_interval, - GST_TIME_ARGS (spectrum->accumulated_error)); - - if (spectrum->accumulated_error >= GST_SECOND) - spectrum->accumulated_error -= GST_SECOND; - else - spectrum->accumulated_error += spectrum->error_per_interval; - - if (spectrum->post_messages) { - GstMessage *m; - - gst_spectrum_prepare_message_data (spectrum, cd); - - m = gst_spectrum_message_new (spectrum, spectrum->message_ts, - spectrum->interval); - - gst_element_post_message (GST_ELEMENT (spectrum), m); + /* If we have enough frames for an FFT or we have all frames required for + * the interval run an FFT. In the last case we probably take the + * FFT of frames that we already handled. + */ + if ((spectrum->num_frames % nfft == 0) || have_full_interval) { + gst_spectrum_run_fft (spectrum, cd, input_pos); + spectrum->num_fft++; } - if (GST_CLOCK_TIME_IS_VALID (spectrum->message_ts)) - spectrum->message_ts += - gst_util_uint64_scale (spectrum->num_frames, GST_SECOND, rate); + /* Do we have the FFTs for one interval? */ + if (have_full_interval) { - gst_spectrum_reset_message_data (spectrum, cd); - spectrum->num_frames = 0; - spectrum->num_fft = 0; + GST_INFO ("nfft: %u num_frames: %" G_GUINT64_FORMAT " fpi: %" + G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft, + spectrum->num_frames, spectrum->frames_per_interval, + GST_TIME_ARGS (spectrum->accumulated_error)); + + if (spectrum->accumulated_error >= GST_SECOND) + spectrum->accumulated_error -= GST_SECOND; + else + spectrum->accumulated_error += spectrum->error_per_interval; + + if (spectrum->post_messages) { + GstMessage *m; + + gst_spectrum_prepare_message_data (spectrum, cd); + + m = gst_spectrum_message_new (spectrum, spectrum->message_ts, + spectrum->interval); + + gst_element_post_message (GST_ELEMENT (spectrum), m); + } + + if (GST_CLOCK_TIME_IS_VALID (spectrum->message_ts)) + spectrum->message_ts += + gst_util_uint64_scale (spectrum->num_frames, GST_SECOND, rate); + + gst_spectrum_reset_message_data (spectrum, cd); + spectrum->num_frames = 0; + spectrum->num_fft = 0; + } + } + } else { + guint c; + + while (size >= width * channels) { + for (c = 0; c < channels; c++) { + cd = &spectrum->channel_data[c]; + input = cd->input; + /* Move the current frames into our ringbuffers */ + input[input_pos] = gst_spectrum_input_data (data, is_float, width, + max_value); + data += width; + } + size -= width * channels; + input_pos = (input_pos + 1) % nfft; + spectrum->num_frames++; + + have_full_interval = ( + (spectrum->accumulated_error < GST_SECOND + && spectrum->num_frames == spectrum->frames_per_interval) || + (spectrum->accumulated_error >= GST_SECOND + && spectrum->num_frames - 1 == spectrum->frames_per_interval) + ); + + /* If we have enough frames for an FFT or we have all frames required for + * the interval run an FFT. In the last case we probably take the + * FFT of frames that we already handled. + */ + if ((spectrum->num_frames % nfft == 0) || have_full_interval) { + for (c = 0; c < channels; c++) { + cd = &spectrum->channel_data[c]; + gst_spectrum_run_fft (spectrum, cd, input_pos); + } + spectrum->num_fft++; + } + + /* Do we have the FFTs for one interval? */ + if (have_full_interval) { + + GST_INFO ("nfft: %u num_frames: %" G_GUINT64_FORMAT " fpi: %" + G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft, + spectrum->num_frames, spectrum->frames_per_interval, + GST_TIME_ARGS (spectrum->accumulated_error)); + + if (spectrum->accumulated_error >= GST_SECOND) + spectrum->accumulated_error -= GST_SECOND; + else + spectrum->accumulated_error += spectrum->error_per_interval; + + if (spectrum->post_messages) { + GstMessage *m; + + for (c = 0; c < channels; c++) { + cd = &spectrum->channel_data[c]; + gst_spectrum_prepare_message_data (spectrum, cd); + } + + m = gst_spectrum_message_new (spectrum, spectrum->message_ts, + spectrum->interval); + + gst_element_post_message (GST_ELEMENT (spectrum), m); + } + + if (GST_CLOCK_TIME_IS_VALID (spectrum->message_ts)) + spectrum->message_ts += + gst_util_uint64_scale (spectrum->num_frames, GST_SECOND, rate); + + for (c = 0; c < channels; c++) { + cd = &spectrum->channel_data[c]; + gst_spectrum_reset_message_data (spectrum, cd); + } + spectrum->num_frames = 0; + spectrum->num_fft = 0; + } } } diff --git a/gst/spectrum/gstspectrum.h b/gst/spectrum/gstspectrum.h index 7f055ec93b..8f79e99654 100644 --- a/gst/spectrum/gstspectrum.h +++ b/gst/spectrum/gstspectrum.h @@ -59,6 +59,7 @@ struct _GstSpectrum guint64 frames_per_interval; /* how many frames per interval */ guint bands; /* number of spectrum bands */ gint threshold; /* energy level treshold */ + gboolean multi_channel; /* send separate channel results */ guint64 num_frames; /* frame count (1 sample per channel) * since last emit */ From 6bc1aa0e594f9a0fe24020d8b4f2b6436347c92e Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 9 Mar 2011 16:51:00 +0100 Subject: [PATCH 09/54] jitterbuffer: handle position query --- gst/rtpmanager/gstrtpjitterbuffer.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/gst/rtpmanager/gstrtpjitterbuffer.c b/gst/rtpmanager/gstrtpjitterbuffer.c index 9f08203221..1d253eb829 100644 --- a/gst/rtpmanager/gstrtpjitterbuffer.c +++ b/gst/rtpmanager/gstrtpjitterbuffer.c @@ -2129,6 +2129,35 @@ gst_rtp_jitter_buffer_query (GstPad * pad, GstQuery * query) } break; } + case GST_QUERY_POSITION: + { + GstClockTime start, last_out; + GstFormat fmt; + + gst_query_parse_position (query, &fmt, NULL); + if (fmt != GST_FORMAT_TIME) { + res = gst_pad_query_default (pad, query); + break; + } + + JBUF_LOCK (priv); + start = priv->npt_start; + last_out = priv->last_out_time; + JBUF_UNLOCK (priv); + + GST_DEBUG_OBJECT (jitterbuffer, "npt start %" GST_TIME_FORMAT + ", last out %" GST_TIME_FORMAT, GST_TIME_ARGS (start), + GST_TIME_ARGS (last_out)); + + if (GST_CLOCK_TIME_IS_VALID (start) && GST_CLOCK_TIME_IS_VALID (last_out)) { + /* bring 0-based outgoing time to stream time */ + gst_query_set_position (query, GST_FORMAT_TIME, start + last_out); + res = TRUE; + } else { + res = gst_pad_query_default (pad, query); + } + break; + } default: res = gst_pad_query_default (pad, query); break; From 27389178522e04512bb6aa086aa8465fe64599fc Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 9 Mar 2011 17:07:47 +0100 Subject: [PATCH 10/54] rtspsrc: improve recovery from failed seek In case server-side fails to perform seek, i.e. PLAY at non-zero requested position, recovery so far would arrange for streaming to continue, albeit having lost position tracking in the process. So, query position prior to seek and use upon failed seek. --- gst/rtsp/gstrtspsrc.c | 34 ++++++++++++++++++++++++++++++++-- gst/rtsp/gstrtspsrc.h | 2 ++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index 980fd026f9..e1c8f9b404 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -1716,6 +1716,33 @@ gst_rtspsrc_connection_receive (GstRTSPSrc * src, GstRTSPConnection * conn, return ret; } +static void +gst_rtspsrc_get_position (GstRTSPSrc * src) +{ + GstQuery *query; + GList *walk; + + query = gst_query_new_position (GST_FORMAT_TIME); + /* should be known somewhere down the stream (e.g. jitterbuffer) */ + for (walk = src->streams; walk; walk = g_list_next (walk)) { + GstRTSPStream *stream = (GstRTSPStream *) walk->data; + GstFormat fmt; + gint64 pos; + + if (stream->srcpad) { + if (gst_pad_query (stream->srcpad, query)) { + gst_query_parse_position (query, &fmt, &pos); + GST_DEBUG_OBJECT (src, "retaining position %" GST_TIME_FORMAT, + GST_TIME_ARGS (pos)); + src->last_pos = pos; + return; + } + } + } + + src->last_pos = 0; +} + static gboolean gst_rtspsrc_do_seek (GstRTSPSrc * src, GstSegment * segment) { @@ -1808,8 +1835,11 @@ gst_rtspsrc_perform_seek (GstRTSPSrc * src, GstEvent * event) playing = (src->state == GST_RTSP_STATE_PLAYING); /* if we were playing, pause first */ - if (playing) + if (playing) { + /* obtain current position in case seek fails */ + gst_rtspsrc_get_position (src); gst_rtspsrc_pause (src, FALSE); + } gst_rtspsrc_do_seek (src, &seeksegment); @@ -5885,7 +5915,7 @@ gst_rtspsrc_play (GstRTSPSrc * src, GstSegment * segment) /* NOTE the above also disables npt based eos detection */ /* and below forces position to 0, * which is visible feedback we lost the plot */ - segment->start = segment->last_stop = 0; + segment->start = segment->last_stop = src->last_pos; } gst_rtsp_message_unset (&request); diff --git a/gst/rtsp/gstrtspsrc.h b/gst/rtsp/gstrtspsrc.h index 00861b6da9..460f29a0f5 100644 --- a/gst/rtsp/gstrtspsrc.h +++ b/gst/rtsp/gstrtspsrc.h @@ -233,7 +233,9 @@ struct _GstRTSPSrc { /* supported methods */ gint methods; + gboolean seekable; + GstClockTime last_pos; /* session management */ GstElement *manager; From b792b100e27b4f803a859ab2422c3c43961d7c80 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 10 Mar 2011 10:22:29 +0200 Subject: [PATCH 11/54] spectrum: use function pointers for data readers Don't check the format for each sample frame to read. We can make that decission in _setup already. This is still not ideal as we call the function per frame. Ideally we determine how many samples we can copy and have a loop in the input reader. As an alternative we might also consider to use the fft variants for the various formats and not convert to float for all cases - we would still need to mix or deinterleave though. --- gst/spectrum/gstspectrum.c | 330 ++++++++++++++++++++++++++----------- gst/spectrum/gstspectrum.h | 7 + 2 files changed, 244 insertions(+), 93 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index 574457a350..e814ca947a 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -479,10 +479,245 @@ gst_spectrum_stop (GstBaseTransform * trans) return TRUE; } +/* mixing data readers */ + +static gfloat +input_data_mixed_float (const guint8 * data, guint channels, gfloat max_value) +{ + guint i; + gfloat v = 0.0; + gfloat *in = (gfloat *) data; + + for (i = 0; i < channels; i++) + v += in[i]; + + return v / channels; +} + +static gfloat +input_data_mixed_double (const guint8 * data, guint channels, gfloat max_value) +{ + guint i; + gfloat v = 0.0; + gdouble *in = (gdouble *) data; + + for (i = 0; i < channels; i++) + v += in[i]; + + return v / channels; +} + +static gfloat +input_data_mixed_int32 (const guint8 * data, guint channels, gfloat max_value) +{ + guint i; + gfloat v = 0.0; + gint32 *in = (gint32 *) data; + + for (i = 0; i < channels; i++) + v += in[i] * 2 + 1; + + return v / channels; +} + +static gfloat +input_data_mixed_int32_max (const guint8 * data, guint channels, + gfloat max_value) +{ + guint i; + gfloat v = 0.0; + gint32 *in = (gint32 *) data; + + for (i = 0; i < channels; i++) + v += in[i] / max_value; + + return v / channels; +} + +static gfloat +input_data_mixed_int24 (const guint8 * data, guint channels, gfloat max_value) +{ + guint i; + gfloat v = 0.0; + + for (i = 0; i < channels; i++) { +#if G_BYTE_ORDER == G_BIG_ENDIAN + gint32 value = GST_READ_UINT24_BE (data); +#else + gint32 value = GST_READ_UINT24_LE (data); +#endif + if (value & 0x00800000) + value |= 0xff000000; + v += value * 2 + 1; + } + + return v / channels; +} + +static gfloat +input_data_mixed_int24_max (const guint8 * data, guint channels, + gfloat max_value) +{ + guint i; + gfloat v = 0.0; + + for (i = 0; i < channels; i++) { +#if G_BYTE_ORDER == G_BIG_ENDIAN + gint32 value = GST_READ_UINT24_BE (data); +#else + gint32 value = GST_READ_UINT24_LE (data); +#endif + if (value & 0x00800000) + value |= 0xff000000; + v += value / max_value; + } + + return v / channels; +} + +static gfloat +input_data_mixed_int16 (const guint8 * data, guint channels, gfloat max_value) +{ + guint i; + gfloat v = 0.0; + gint16 *in = (gint16 *) data; + + for (i = 0; i < channels; i++) + v += in[i] * 2 + 1; + + return v / channels; +} + +static gfloat +input_data_mixed_int16_max (const guint8 * data, guint channels, + gfloat max_value) +{ + guint i; + gfloat v = 0.0; + gint16 *in = (gint16 *) data; + + for (i = 0; i < channels; i++) + v += in[i] / max_value; + + return v / channels; +} + +/* non mixing data readers */ + +static gfloat +input_data_float (const guint8 * data, gfloat max_value) +{ + return ((gfloat *) data)[0]; +} + +static gfloat +input_data_double (const guint8 * data, gfloat max_value) +{ + return (gfloat) ((gdouble *) data)[0]; +} + +static gfloat +input_data_int32 (const guint8 * data, gfloat max_value) +{ + return ((gint32 *) data)[0] * 2 + 1; +} + +static gfloat +input_data_int32_max (const guint8 * data, gfloat max_value) +{ + return ((gint32 *) data)[0] / max_value; +} + +static gfloat +input_data_int24 (const guint8 * data, gfloat max_value) +{ +#if G_BYTE_ORDER == G_BIG_ENDIAN + gint32 in = GST_READ_UINT24_BE (data); +#else + gint32 in = GST_READ_UINT24_LE (data); +#endif + if (in & 0x00800000) + in |= 0xff000000; + return in * 2 + 1; +} + +static gfloat +input_data_int24_max (const guint8 * data, gfloat max_value) +{ +#if G_BYTE_ORDER == G_BIG_ENDIAN + gint32 in = GST_READ_UINT24_BE (data); +#else + gint32 in = GST_READ_UINT24_LE (data); +#endif + if (in & 0x00800000) + in |= 0xff000000; + return in / max_value; +} + +static gfloat +input_data_int16 (const guint8 * data, gfloat max_value) +{ + return ((gint16 *) data)[0] * 2 + 1; +} + +static gfloat +input_data_int16_max (const guint8 * data, gfloat max_value) +{ + return ((gint16 *) data)[0] / max_value; +} + static gboolean gst_spectrum_setup (GstAudioFilter * base, GstRingBufferSpec * format) { GstSpectrum *spectrum = GST_SPECTRUM (base); + guint width = format->width / 8; + gboolean is_float = (format->type == GST_BUFTYPE_FLOAT); + /* max_value will be 0 when depth is 1, + * interpret -1 and 0 as -1 and +1 if that's the case. */ + gfloat max_value = (1UL << (format->depth - 1)) - 1; + + spectrum->input_data_mixed = NULL; + spectrum->input_data = NULL; + + if (is_float) { + if (width == 4) { + spectrum->input_data_mixed = input_data_mixed_float; + spectrum->input_data = input_data_float; + } else if (width == 8) { + spectrum->input_data_mixed = input_data_mixed_double; + spectrum->input_data = input_data_double; + } else { + g_assert_not_reached (); + } + } else { + if (width == 4) { + if (max_value) { + spectrum->input_data_mixed = input_data_mixed_int32_max; + spectrum->input_data = input_data_int32_max; + } else { + spectrum->input_data_mixed = input_data_mixed_int32; + spectrum->input_data = input_data_int32; + } + } else if (width == 3) { + if (max_value) { + spectrum->input_data_mixed = input_data_mixed_int24_max; + spectrum->input_data = input_data_int24_max; + } else { + spectrum->input_data_mixed = input_data_mixed_int24; + spectrum->input_data = input_data_int24; + } + } else if (width == 2) { + if (max_value) { + spectrum->input_data_mixed = input_data_mixed_int16_max; + spectrum->input_data = input_data_int16_max; + } else { + spectrum->input_data_mixed = input_data_mixed_int16; + spectrum->input_data = input_data_int16; + } + } else { + g_assert_not_reached (); + } + } gst_spectrum_reset_state (spectrum); return TRUE; @@ -601,94 +836,6 @@ gst_spectrum_message_new (GstSpectrum * spectrum, GstClockTime timestamp, return gst_message_new_element (GST_OBJECT (spectrum), s); } -/* FIXME: have dedicated read function pointers for each format */ -static gfloat -gst_spectrum_input_data_mixed (const guint8 * data, gfloat is_float, - guint width, guint channels, gfloat max_value) -{ - guint i; - gfloat v = 0.0; - - if (is_float) { - if (width == 4) { - gfloat *in = (gfloat *) data; - for (i = 0; i < channels; i++) - v += in[i]; - } else if (width == 8) { - gdouble *in = (gdouble *) data; - for (i = 0; i < channels; i++) - v += in[i]; - } else { - g_assert_not_reached (); - } - } else { - if (width == 4) { - gint32 *in = (gint32 *) data; - /* max_value will be 0 when depth is 1, - * interpret -1 and 0 as -1 and +1 if that's the case. */ - for (i = 0; i < channels; i++) - v += max_value ? in[i] / max_value : in[i] * 2 + 1; - } else if (width == 3) { - for (i = 0; i < channels; i++) { -#if G_BYTE_ORDER == G_BIG_ENDIAN - gint32 value = GST_READ_UINT24_BE (data); -#else - gint32 value = GST_READ_UINT24_LE (data); -#endif - if (value & 0x00800000) - value |= 0xff000000; - v += max_value ? value / max_value : value * 2 + 1; - } - } else if (width == 2) { - gint16 *in = (gint16 *) data; - for (i = 0; i < channels; i++) - v += max_value ? in[i] / max_value : in[i] * 2 + 1; - } else { - g_assert_not_reached (); - } - } - return v / channels; -} - -static gfloat -gst_spectrum_input_data (const guint8 * data, gfloat is_float, guint width, - gfloat max_value) -{ - gfloat v = 0.0; - - if (is_float) { - if (width == 4) { - v = ((gfloat *) data)[0]; - } else if (width == 8) { - v = ((gdouble *) data)[0]; - } else { - g_assert_not_reached (); - } - } else { - if (width == 4) { - gint32 *in = (gint32 *) data; - /* max_value will be 0 when depth is 1, - * interpret -1 and 0 as -1 and +1 if that's the case. */ - v = max_value ? in[0] / max_value : in[0] * 2 + 1; - } else if (width == 3) { -#if G_BYTE_ORDER == G_BIG_ENDIAN - gint32 in = GST_READ_UINT24_BE (data); -#else - gint32 in = GST_READ_UINT24_LE (data); -#endif - if (in & 0x00800000) - in |= 0xff000000; - v = max_value ? in / max_value : in * 2 + 1; - } else if (width == 2) { - gint16 *in = (gint16 *) data; - v = max_value ? in[0] / max_value : in[0] * 2 + 1; - } else { - g_assert_not_reached (); - } - } - return v; -} - static void gst_spectrum_run_fft (GstSpectrum * spectrum, GstSpectrumChannel * cd, guint input_pos) @@ -770,7 +917,6 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) guint rate = format->rate; guint channels = format->channels; guint width = format->width / 8; - gboolean is_float = (format->type == GST_BUFTYPE_FLOAT); gfloat max_value = (1UL << (format->depth - 1)) - 1; guint bands = spectrum->bands; guint nfft = 2 * bands - 2; @@ -818,8 +964,7 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) while (size >= width * channels) { /* Move the mixdown of current frame into our ringbuffer */ - input[input_pos] = gst_spectrum_input_data_mixed (data, is_float, width, - channels, max_value); + input[input_pos] = spectrum->input_data_mixed (data, channels, max_value); data += width * channels; size -= width * channels; @@ -883,8 +1028,7 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) cd = &spectrum->channel_data[c]; input = cd->input; /* Move the current frames into our ringbuffers */ - input[input_pos] = gst_spectrum_input_data (data, is_float, width, - max_value); + input[input_pos] = spectrum->input_data (data, max_value); data += width; } size -= width * channels; diff --git a/gst/spectrum/gstspectrum.h b/gst/spectrum/gstspectrum.h index 8f79e99654..e8508851cb 100644 --- a/gst/spectrum/gstspectrum.h +++ b/gst/spectrum/gstspectrum.h @@ -37,6 +37,10 @@ typedef struct _GstSpectrum GstSpectrum; typedef struct _GstSpectrumClass GstSpectrumClass; typedef struct _GstSpectrumChannel GstSpectrumChannel; +typedef gfloat (*GstSpectrumInputDataMixed)(const guint8 * data, guint channels, + gfloat max_value); +typedef gfloat (*GstSpectrumInputData)(const guint8 * data, gfloat max_value); + struct _GstSpectrumChannel { gfloat *input; @@ -72,6 +76,9 @@ struct _GstSpectrum guint input_pos; guint64 error_per_interval; guint64 accumulated_error; + + GstSpectrumInputDataMixed input_data_mixed; + GstSpectrumInputData input_data; }; struct _GstSpectrumClass From dc1fe1d77fa5eaa53765c38214c3abbb399565e8 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 10 Mar 2011 10:27:14 +0200 Subject: [PATCH 12/54] spectrum: update doc review stamp --- gst/spectrum/gstspectrum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index e814ca947a..2790d63a83 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -95,7 +95,7 @@ * ]| * * - * Last reviewed on 2009-01-14 (0.10.12) + * Last reviewed on 2011-03-10 (0.10.29) */ #ifdef HAVE_CONFIG_H From 5bf267c485493db9912926044c4e590e83ccfe3d Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 10 Mar 2011 14:10:25 +0200 Subject: [PATCH 13/54] spectrum: put number of channels to instance variable When freeing data the format might have changed. Thus we need to remember for which format we allocated memory. --- gst/spectrum/gstspectrum.c | 27 +++++++++++++++------------ gst/spectrum/gstspectrum.h | 1 + 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index 2790d63a83..ecc8a29f89 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -297,13 +297,17 @@ gst_spectrum_alloc_channel_data (GstSpectrum * spectrum) GstSpectrumChannel *cd; guint bands = spectrum->bands; guint nfft = 2 * bands - 2; - guint channels = (spectrum->multi_channel) ? + + g_assert (spectrum->channel_data == NULL); + + spectrum->num_channels = (spectrum->multi_channel) ? GST_AUDIO_FILTER (spectrum)->format.channels : 1; - GST_DEBUG_OBJECT (spectrum, "allocating data for %d channels", channels); + GST_DEBUG_OBJECT (spectrum, "allocating data for %d channels", + spectrum->num_channels); - spectrum->channel_data = g_new (GstSpectrumChannel, channels); - for (i = 0; i < channels; i++) { + spectrum->channel_data = g_new (GstSpectrumChannel, spectrum->num_channels); + for (i = 0; i < spectrum->num_channels; i++) { cd = &spectrum->channel_data[i]; cd->fft_ctx = gst_fft_f32_new (nfft, FALSE); cd->input = g_new0 (gfloat, nfft); @@ -317,15 +321,14 @@ gst_spectrum_alloc_channel_data (GstSpectrum * spectrum) static void gst_spectrum_free_channel_data (GstSpectrum * spectrum) { - gint i; - GstSpectrumChannel *cd; - guint channels = (spectrum->multi_channel) ? - GST_AUDIO_FILTER (spectrum)->format.channels : 1; - - GST_DEBUG_OBJECT (spectrum, "freeing data for %d channels", channels); - if (spectrum->channel_data) { - for (i = 0; i < channels; i++) { + gint i; + GstSpectrumChannel *cd; + + GST_DEBUG_OBJECT (spectrum, "freeing data for %d channels", + spectrum->num_channels); + + for (i = 0; i < spectrum->num_channels; i++) { cd = &spectrum->channel_data[i]; if (cd->fft_ctx) gst_fft_f32_free (cd->fft_ctx); diff --git a/gst/spectrum/gstspectrum.h b/gst/spectrum/gstspectrum.h index e8508851cb..60ebd503e9 100644 --- a/gst/spectrum/gstspectrum.h +++ b/gst/spectrum/gstspectrum.h @@ -72,6 +72,7 @@ struct _GstSpectrum /* */ GstSpectrumChannel *channel_data; + guint num_channels; guint input_pos; guint64 error_per_interval; From f1785b0e4aafc014354f732cec9485fdfbcafe4b Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 10 Mar 2011 14:12:01 +0200 Subject: [PATCH 14/54] spectrum: only scale the vectors that we are processing Phase is not produced by default, so lets not scale it unconditionally to save a few cycles. --- gst/spectrum/gstspectrum.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index ecc8a29f89..d09fbbe2e2 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -889,13 +889,17 @@ gst_spectrum_prepare_message_data (GstSpectrum * spectrum, guint i; guint bands = spectrum->bands; guint num_fft = spectrum->num_fft; - gfloat *spect_magnitude = cd->spect_magnitude; - gfloat *spect_phase = cd->spect_phase; /* Calculate average */ - for (i = 0; i < bands; i++) { - spect_magnitude[i] /= num_fft; - spect_phase[i] /= num_fft; + if (spectrum->message_magnitude) { + gfloat *spect_magnitude = cd->spect_magnitude; + for (i = 0; i < bands; i++) + spect_magnitude[i] /= num_fft; + } + if (spectrum->message_phase) { + gfloat *spect_phase = cd->spect_phase; + for (i = 0; i < bands; i++) + spect_phase[i] /= num_fft; } } From 1a32265b5108a4c7c7cc46b52ae84f12f3241050 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 10 Mar 2011 14:15:42 +0200 Subject: [PATCH 15/54] spectrum: avoid unneccesary extra fft runs Before it was possible that we run an extra fft when the time for sending a new message is due. Only do this if we have not run the fft for the interval at all. --- gst/spectrum/gstspectrum.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index d09fbbe2e2..ab3a556b1f 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -986,10 +986,9 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) ); /* If we have enough frames for an FFT or we have all frames required for - * the interval run an FFT. In the last case we probably take the - * FFT of frames that we already handled. - */ - if ((spectrum->num_frames % nfft == 0) || have_full_interval) { + * the interval and we haven't run a FFT, then run an FFT */ + if ((spectrum->num_frames % nfft == 0) || + (have_full_interval && !spectrum->num_fft)) { gst_spectrum_run_fft (spectrum, cd, input_pos); spectrum->num_fft++; } @@ -1050,10 +1049,9 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) ); /* If we have enough frames for an FFT or we have all frames required for - * the interval run an FFT. In the last case we probably take the - * FFT of frames that we already handled. - */ - if ((spectrum->num_frames % nfft == 0) || have_full_interval) { + * the interval and we haven't run a FFT, then run an FFT */ + if ((spectrum->num_frames % nfft == 0) || + (have_full_interval && !spectrum->num_fft)) { for (c = 0; c < channels; c++) { cd = &spectrum->channel_data[c]; gst_spectrum_run_fft (spectrum, cd, input_pos); From 32afdea96d5c2b2417da9b659b4ac50ddca7619d Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 10 Mar 2011 14:29:25 +0200 Subject: [PATCH 16/54] spectrum: more comments and tune and logging --- gst/spectrum/gstspectrum.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index ab3a556b1f..0dbf37273f 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -949,12 +949,20 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) gst_spectrum_alloc_channel_data (spectrum); + /* number of sample frames we process before posting a message + * interval is in ns */ spectrum->frames_per_interval = gst_util_uint64_scale (spectrum->interval, rate, GST_SECOND); + /* rounding error in ns, aggregated it in accumulated_error */ spectrum->error_per_interval = (spectrum->interval * rate) % GST_SECOND; if (spectrum->frames_per_interval == 0) spectrum->frames_per_interval = 1; + GST_INFO_OBJECT (spectrum, "interval %" GST_TIME_FORMAT ", fpi %" + G_GUINT64_FORMAT ", error %" GST_TIME_FORMAT, + GST_TIME_ARGS (spectrum->interval), spectrum->frames_per_interval, + GST_TIME_ARGS (spectrum->error_per_interval)); + spectrum->input_pos = 0; gst_spectrum_flush (spectrum); @@ -995,9 +1003,8 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) /* Do we have the FFTs for one interval? */ if (have_full_interval) { - - GST_INFO ("nfft: %u num_frames: %" G_GUINT64_FORMAT " fpi: %" - G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft, + GST_DEBUG_OBJECT (spectrum, "nfft: %u frames: %" G_GUINT64_FORMAT + " fpi: %" G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft, spectrum->num_frames, spectrum->frames_per_interval, GST_TIME_ARGS (spectrum->accumulated_error)); @@ -1062,8 +1069,8 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) /* Do we have the FFTs for one interval? */ if (have_full_interval) { - GST_INFO ("nfft: %u num_frames: %" G_GUINT64_FORMAT " fpi: %" - G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft, + GST_DEBUG_OBJECT (spectrum, "nfft: %u frames: %" G_GUINT64_FORMAT + " fpi: %" G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft, spectrum->num_frames, spectrum->frames_per_interval, GST_TIME_ARGS (spectrum->accumulated_error)); From 9544622674c0d0a3147a9b51145159b02eec68e9 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Fri, 11 Mar 2011 10:29:08 +0100 Subject: [PATCH 17/54] jack: fix build against jack 0.120.2 jack_port_get_total_latency() has been deprecated in favor of jack_port_get_latency_range(). https://bugzilla.gnome.org/show_bug.cgi?id=644477 --- configure.ac | 6 ++++++ ext/jack/gstjackaudiosink.c | 15 +++++++++++++-- ext/jack/gstjackaudiosrc.c | 13 ++++++++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 422ee16431..bd6cbb0625 100644 --- a/configure.ac +++ b/configure.ac @@ -766,6 +766,12 @@ AG_GST_CHECK_FEATURE(JACK, Jack, jack, [ PKG_CHECK_MODULES(JACK, jack >= 0.99.10, HAVE_JACK="yes", HAVE_JACK="no") AC_SUBST(JACK_CFLAGS) AC_SUBST(JACK_LIBS) + + AG_GST_PKG_CHECK_MODULES(JACK_0_120_2, jack >= 0.120.2) + if test x$HAVE_JACK_0_120_2 = xyes; then + AC_DEFINE(HAVE_JACK_0_120_2, 1, [defined if jack >= 0.120.2 is available]) + fi + ]) dnl *** jpeg *** diff --git a/ext/jack/gstjackaudiosink.c b/ext/jack/gstjackaudiosink.c index 4620bce712..0abcfe79fd 100644 --- a/ext/jack/gstjackaudiosink.c +++ b/ext/jack/gstjackaudiosink.c @@ -592,16 +592,27 @@ static guint gst_jack_ring_buffer_delay (GstRingBuffer * buf) { GstJackAudioSink *sink; - guint i, res = 0, latency; + guint i, res = 0; +#ifdef HAVE_JACK_0_120_2 + jack_latency_range_t range; +#else + guint latency; +#endif jack_client_t *client; sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf)); client = gst_jack_audio_client_get_client (sink->client); for (i = 0; i < sink->port_count; i++) { - latency = jack_port_get_total_latency (client, sink->ports[i]); +#ifdef HAVE_JACK_0_120_2 + jack_port_get_latency_range (sink->ports[i], JackPlaybackLatency, &range); + if (range.max > res) + res = range.max; +#else + latency = jack_port_get_total_latency (client, src->ports[i]); if (latency > res) res = latency; +#endif } GST_LOG_OBJECT (sink, "delay %u", res); diff --git a/ext/jack/gstjackaudiosrc.c b/ext/jack/gstjackaudiosrc.c index 08b325ead7..b4840574a3 100644 --- a/ext/jack/gstjackaudiosrc.c +++ b/ext/jack/gstjackaudiosrc.c @@ -603,16 +603,27 @@ static guint gst_jack_ring_buffer_delay (GstRingBuffer * buf) { GstJackAudioSrc *src; - guint i, res = 0, latency; + guint i, res = 0; +#ifdef HAVE_JACK_0_120_2 + jack_latency_range_t range; +#else + guint latency; +#endif jack_client_t *client; src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); client = gst_jack_audio_client_get_client (src->client); for (i = 0; i < src->port_count; i++) { +#ifdef HAVE_JACK_0_120_2 + jack_port_get_latency_range (src->ports[i], JackCaptureLatency, &range); + if (range.max > res) + res = range.max; +#else latency = jack_port_get_total_latency (client, src->ports[i]); if (latency > res) res = latency; +#endif } GST_DEBUG_OBJECT (src, "delay %u", res); From 14e1d9de3d4197e633c839ea0ce2e4d9057957a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 11 Mar 2011 09:54:02 +0000 Subject: [PATCH 18/54] docs: fix pulsesink gtk-doc markup --- ext/pulse/pulsesink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/pulse/pulsesink.c b/ext/pulse/pulsesink.c index 59e14058d1..6ddc490f3e 100644 --- a/ext/pulse/pulsesink.c +++ b/ext/pulse/pulsesink.c @@ -38,7 +38,7 @@ * ]| Play a 440Hz sine wave. * |[ * gst-launch -v audiotestsrc ! pulsesink stream-properties="props,media.title=test" - * ]] Play a sine wave and set a stream property. The property can be checked + * ]| Play a sine wave and set a stream property. The property can be checked * with "pactl list". * */ From bc6c1bbbaba337538fd9cbaa307d6233ee03db4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 11 Mar 2011 13:46:05 +0100 Subject: [PATCH 19/54] dvdemux: Fix refcount issues with the seek event Fixes bug #642963. --- ext/dv/gstdvdemux.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ext/dv/gstdvdemux.c b/ext/dv/gstdvdemux.c index c1ecd9261c..967c369c49 100644 --- a/ext/dv/gstdvdemux.c +++ b/ext/dv/gstdvdemux.c @@ -915,7 +915,7 @@ gst_dvdemux_handle_push_seek (GstDVDemux * dvdemux, GstPad * pad, /* First try if upstream can handle time based seeks */ if (format == GST_FORMAT_TIME) - res = gst_pad_push_event (dvdemux->sinkpad, event); + res = gst_pad_push_event (dvdemux->sinkpad, gst_event_ref (event)); if (!res) { /* we convert the start/stop on the srcpad to the byte format @@ -1153,8 +1153,10 @@ gst_dvdemux_send_event (GstElement * element, GstEvent * event) } else { GST_OBJECT_UNLOCK (dvdemux); - if (dvdemux->seek_handler) + if (dvdemux->seek_handler) { res = dvdemux->seek_handler (dvdemux, dvdemux->videosrcpad, event); + gst_event_unref (event); + } } break; } From 9e44fff3dbcc9c75e048f9554216f0f0501e7b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 11 Mar 2011 13:47:26 +0100 Subject: [PATCH 20/54] dvdemux: Chain up to the parent class' ::send_event for non-seek events --- ext/dv/gstdvdemux.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/dv/gstdvdemux.c b/ext/dv/gstdvdemux.c index 967c369c49..90a26511bc 100644 --- a/ext/dv/gstdvdemux.c +++ b/ext/dv/gstdvdemux.c @@ -1161,6 +1161,7 @@ gst_dvdemux_send_event (GstElement * element, GstEvent * event) break; } default: + res = GST_ELEMENT_CLASS (parent_class)->send_event (element, event); break; } From 9bfa7defdf9e8e060adbb975637231f2efb16bea Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Fri, 11 Mar 2011 16:59:10 +0200 Subject: [PATCH 21/54] tests: order state-test blacklist and add jack elements Jack audio src/sink elements recently got moved from bad and should be excluded from the test (like the other device specific source and sinks). Fixes #644288 --- tests/check/Makefile.am | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index ccce33cf03..1ffb7a33f4 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -13,8 +13,9 @@ TESTS_ENVIRONMENT = \ GST_PLUGIN_LOADING_WHITELIST="gstreamer@$(GST_PLUGINS_DIR):gst-plugins-base@$(GSTPB_PLUGINS_DIR):gst-plugins-good@$(top_builddir)" \ GST_STATE_IGNORE_ELEMENTS="aasink autoaudiosrc autoaudiosink autovideosrc autovideosink \ cacasink cairotextoverlay gconfaudiosrc gconfvideosrc gconfaudiosink gconfvideosink \ - halaudiosrc halaudiosink v4l2src osssrc osssink pulsesink pulsesrc pulsemixer \ - osxaudiosink osxaudiosrc osxvideosrc osxvideosink" + halaudiosrc halaudiosink jackaudiosrc jackaudiosink \ + osssrc osssink osxaudiosink osxaudiosrc osxvideosrc osxvideosink \ + pulsesink pulsesrc pulsemixer v4l2src" # fake device drivers: we could run hardware element tests against dummy drivers # v4l2: vivo (part of normal kernel) @@ -39,7 +40,7 @@ check_annodex = \ elements/cmmldec \ elements/cmmlenc else -check_annodex = +check_annodex = endif if USE_FLAC @@ -51,7 +52,7 @@ endif if USE_GDK_PIXBUF check_gdkpixbuf = elements/gdkpixbufsink else -check_gdkpixbuf = +check_gdkpixbuf = endif if USE_JPEG @@ -69,7 +70,7 @@ endif if USE_SUNAUDIO check_sunaudio = elements/sunaudio else -check_sunaudio = +check_sunaudio = endif if USE_TAGLIB From 387f533a0733de7f6b8cb6e415f09e4fb24f151e Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Fri, 11 Mar 2011 23:06:31 +0530 Subject: [PATCH 22/54] pulsesink: Fix deadlock if connecting to PA fails Commit dd4ec22e introduced a deadlock in the failure path while trying to connect to PulseAudio. This makes sure we drop the lock on the resource mutex to avoid this. https://bugzilla.gnome.org/show_bug.cgi?id=644510 --- ext/pulse/pulsesink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/pulse/pulsesink.c b/ext/pulse/pulsesink.c index 6ddc490f3e..110adde3da 100644 --- a/ext/pulse/pulsesink.c +++ b/ext/pulse/pulsesink.c @@ -527,6 +527,7 @@ gst_pulseringbuffer_open_device (GstRingBuffer * buf) /* ERRORS */ unlock_and_fail: { + g_mutex_unlock (pa_shared_resource_mutex); gst_pulsering_destroy_context (pbuf); pa_threaded_mainloop_unlock (mainloop); return FALSE; From 84decd731f0f188ae688fc7a98abe1d564de94b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20J=C3=A4genstedt?= Date: Sat, 12 Mar 2011 00:44:31 +0530 Subject: [PATCH 23/54] pulsesink: Better fix for deadlock on failed connect This reverts the previous fix that would cause a double-unlock when the stream connect failed. https://bugzilla.gnome.org/show_bug.cgi?id=644510 --- ext/pulse/pulsesink.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ext/pulse/pulsesink.c b/ext/pulse/pulsesink.c index 110adde3da..5a60cda0e6 100644 --- a/ext/pulse/pulsesink.c +++ b/ext/pulse/pulsesink.c @@ -442,6 +442,7 @@ gst_pulseringbuffer_open_device (GstRingBuffer * buf) GstPulseRingBuffer *pbuf; GstPulseContext *pctx; pa_mainloop_api *api; + gboolean need_unlock_shared; psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (buf)); pbuf = GST_PULSERING_BUFFER_CAST (buf); @@ -458,6 +459,7 @@ gst_pulseringbuffer_open_device (GstRingBuffer * buf) pa_threaded_mainloop_lock (mainloop); g_mutex_lock (pa_shared_resource_mutex); + need_unlock_shared = TRUE; pctx = g_hash_table_lookup (gst_pulse_shared_contexts, pbuf->context_name); if (pctx == NULL) { @@ -481,7 +483,7 @@ gst_pulseringbuffer_open_device (GstRingBuffer * buf) gst_pulsering_context_subscribe_cb, pctx); #endif - /* try to connect to the server and wait for completioni, we don't want to + /* try to connect to the server and wait for completion, we don't want to * autospawn a deamon */ GST_LOG_OBJECT (psink, "connect to server %s", GST_STR_NULL (psink->server)); @@ -496,6 +498,7 @@ gst_pulseringbuffer_open_device (GstRingBuffer * buf) } g_mutex_unlock (pa_shared_resource_mutex); + need_unlock_shared = FALSE; /* context created or shared okay */ pbuf->context = pa_context_ref (pctx->context); @@ -527,7 +530,8 @@ gst_pulseringbuffer_open_device (GstRingBuffer * buf) /* ERRORS */ unlock_and_fail: { - g_mutex_unlock (pa_shared_resource_mutex); + if (need_unlock_shared) + g_mutex_unlock (pa_shared_resource_mutex); gst_pulsering_destroy_context (pbuf); pa_threaded_mainloop_unlock (mainloop); return FALSE; From 0ed0174ea98923186112458512e5a026ac69716c Mon Sep 17 00:00:00 2001 From: Andoni Morales Alastruey Date: Mon, 14 Mar 2011 15:46:50 +0100 Subject: [PATCH 24/54] matroskamux: return TRUE from sink pad event function for tag events, which are handled https://bugzilla.gnome.org/show_bug.cgi?id=644730 --- gst/matroska/matroska-mux.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c index 31fe40bfc3..b94a434544 100644 --- a/gst/matroska/matroska-mux.c +++ b/gst/matroska/matroska-mux.c @@ -644,22 +644,23 @@ gst_matroska_mux_handle_sink_event (GstPad * pad, GstEvent * event) gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list, gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux))); - /* handled this, don't want collectpads to forward it downstream */ - ret = FALSE; gst_event_unref (event); + /* handled this, don't want collectpads to forward it downstream */ + event = NULL; break; } case GST_EVENT_NEWSEGMENT: /* We don't support NEWSEGMENT events */ ret = FALSE; gst_event_unref (event); + event = NULL; break; default: break; } /* now GstCollectPads can take care of the rest, e.g. EOS */ - if (ret) + if (event) ret = mux->collect_event (pad, event); gst_object_unref (mux); From 4d7b4ca2ae5d0c93cf040107aaa0c1f7c46a66a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 14 Mar 2011 19:28:07 +0100 Subject: [PATCH 25/54] speexdec: Always process the number of frames per packet as specified in the header Looking at the remaining bits in the bitstream after decoding a single frame can't be used as loop condition. The remaining bits might not give a complete frame and the speex decoder will then output nothing but access uninitialized memory, which leads to valgrind warnings. Fixes bug #644669. --- ext/speex/gstspeexdec.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ext/speex/gstspeexdec.c b/ext/speex/gstspeexdec.c index ef2300fede..c866ef8fe6 100644 --- a/ext/speex/gstspeexdec.c +++ b/ext/speex/gstspeexdec.c @@ -662,7 +662,7 @@ speex_dec_chain_parse_data (GstSpeexDec * dec, GstBuffer * buf, /* send data to the bitstream */ speex_bits_read_from (&dec->bits, (char *) data, size); - fpp = 0; + fpp = dec->header->frames_per_packet; bits = &dec->bits; GST_DEBUG_OBJECT (dec, "received buffer of size %u, fpp %d", size, fpp); @@ -675,8 +675,7 @@ speex_dec_chain_parse_data (GstSpeexDec * dec, GstBuffer * buf, /* now decode each frame, catering for unknown number of them (e.g. rtp) */ - for (i = 0; (!fpp || i < fpp) && (!bits || speex_bits_remaining (bits) > 0); - i++) { + for (i = 0; i < fpp; i++) { GstBuffer *outbuf; gint16 *out_data; gint ret; From 3e1c70749593ba171fe215331ba13c43e8576975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 15 Mar 2011 09:43:35 +0000 Subject: [PATCH 26/54] tests: in videofilter unit test also check with 'odd' widths and heights And only use one test suite. --- tests/check/elements/videofilter.c | 44 ++++++++++-------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/tests/check/elements/videofilter.c b/tests/check/elements/videofilter.c index b3034a4dfa..0bd148ab66 100644 --- a/tests/check/elements/videofilter.c +++ b/tests/check/elements/videofilter.c @@ -146,13 +146,24 @@ check_filter (const gchar * name, gint num_buffers, const gchar * prop, ...) 288, "framerate", GST_TYPE_FRACTION, 25, 1, NULL); GST_DEBUG ("Testing with caps: %" GST_PTR_FORMAT, caps); - gst_video_format_parse_caps (caps, &format, NULL, NULL); size = gst_video_format_get_size (format, 384, 288); va_start (varargs, prop); check_filter_caps (name, caps, size, num_buffers, prop, varargs); va_end (varargs); + /* and again with 'odd' width/height */ + caps = gst_caps_make_writable (caps); + gst_caps_set_simple (caps, "width", G_TYPE_INT, 385, "height", G_TYPE_INT, + 289, "framerate", GST_TYPE_FRACTION, 25, 1, NULL); + + GST_DEBUG ("Testing with caps: %" GST_PTR_FORMAT, caps); + gst_video_format_parse_caps (caps, &format, NULL, NULL); + size = gst_video_format_get_size (format, 385, 289); + va_start (varargs, prop); + check_filter_caps (name, caps, size, num_buffers, prop, varargs); + va_end (varargs); + gst_caps_unref (caps); } @@ -189,36 +200,14 @@ GST_END_TEST; static Suite * -videobalance_suite (void) +videofilter_suite (void) { - Suite *s = suite_create ("videobalance"); + Suite *s = suite_create ("videofilter"); TCase *tc_chain = tcase_create ("general"); suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_videobalance); - - return s; -} - -static Suite * -videoflip_suite (void) -{ - Suite *s = suite_create ("videoflip"); - TCase *tc_chain = tcase_create ("general"); - - suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_videoflip); - - return s; -} - -static Suite * -gamma_suite (void) -{ - Suite *s = suite_create ("gamma"); - TCase *tc_chain = tcase_create ("general"); - - suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_gamma); return s; @@ -229,12 +218,9 @@ main (int argc, char **argv) { int nf; - Suite *s = videobalance_suite (); + Suite *s = videofilter_suite (); SRunner *sr = srunner_create (s); - srunner_add_suite (sr, videoflip_suite ()); - srunner_add_suite (sr, gamma_suite ()); - gst_check_init (&argc, &argv); srunner_run_all (sr, CK_NORMAL); From a3ed3d93745a0b1030fd627394c26c4f1ca1f06e Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Mon, 14 Mar 2011 19:14:07 -0400 Subject: [PATCH 27/54] videoflip: Add support for YUY2, UVYV and YVYU colorspaces https://bugzilla.gnome.org/show_bug.cgi?id=644773 --- gst/videofilter/gstvideoflip.c | 214 ++++++++++++++++++++++++++++++++- 1 file changed, 212 insertions(+), 2 deletions(-) diff --git a/gst/videofilter/gstvideoflip.c b/gst/videofilter/gstvideoflip.c index 150017b3e6..af01cc054f 100644 --- a/gst/videofilter/gstvideoflip.c +++ b/gst/videofilter/gstvideoflip.c @@ -2,6 +2,7 @@ * Copyright (C) <1999> Erik Walthinsen * Copyright (C) <2003> David Schleef * Copyright (C) <2010> Sebastian Dröge + * Copyright (C) <2011> Youness Alaoui * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -75,7 +76,10 @@ static GstStaticPadTemplate gst_video_flip_src_template = GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";" GST_VIDEO_CAPS_YUV ("I420") ";" - GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("IYUV") + GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("IYUV") ";" + GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("UYVY") ";" + GST_VIDEO_CAPS_YUV ("YVYU") + ) ); @@ -91,7 +95,9 @@ static GstStaticPadTemplate gst_video_flip_sink_template = GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";" GST_VIDEO_CAPS_YUV ("I420") ";" - GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("IYUV") + GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("IYUV") ";" + GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("UYVY") ";" + GST_VIDEO_CAPS_YUV ("YVYU") ) ); @@ -563,6 +569,205 @@ gst_video_flip_packed_simple (GstVideoFlip * videoflip, guint8 * dest, } } + +static void +gst_video_flip_y422 (GstVideoFlip * videoflip, guint8 * dest, + const guint8 * src) +{ + gint x, y; + guint8 const *s = src; + guint8 *d = dest; + GstVideoFormat format = videoflip->format; + gint sw = videoflip->from_width; + gint sh = videoflip->from_height; + gint dw = videoflip->to_width; + gint dh = videoflip->to_height; + gint src_stride, dest_stride; + gint bpp; + gint y_offset; + gint u_offset; + gint v_offset; + gint y_stride; + gint u_stride; + gint v_stride; + + src_stride = gst_video_format_get_row_stride (format, 0, sw); + dest_stride = gst_video_format_get_row_stride (format, 0, dw); + + y_offset = gst_video_format_get_component_offset (format, 0, sw, sh); + u_offset = gst_video_format_get_component_offset (format, 1, sw, sh); + v_offset = gst_video_format_get_component_offset (format, 2, sw, sh); + y_stride = gst_video_format_get_pixel_stride (format, 0); + u_stride = gst_video_format_get_pixel_stride (format, 1); + v_stride = gst_video_format_get_pixel_stride (format, 2); + bpp = y_stride; + + switch (videoflip->method) { + case GST_VIDEO_FLIP_METHOD_90R: + for (y = 0; y < dh; y++) { + for (x = 0; x < dw; x += 2) { + guint8 u; + guint8 v; + /* u/v must be calculated using the offset of the even column */ + gint even_y = (y & ~1); + + u = (s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset] + + s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]) / 2; + v = (s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset] + + s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]) / 2; + d[y * dest_stride + x * bpp + u_offset] = u; + d[y * dest_stride + x * bpp + v_offset] = v; + d[y * dest_stride + x * bpp + y_offset] = + s[(sh - 1 - x) * src_stride + y * bpp + y_offset]; + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[(sh - 1 - (x + 1)) * src_stride + y * bpp + y_offset]; + } + } + break; + case GST_VIDEO_FLIP_METHOD_90L: + for (y = 0; y < dh; y++) { + for (x = 0; x < dw; x += 2) { + guint8 u; + guint8 v; + /* u/v must be calculated using the offset of the even column */ + gint even_y = ((sw - 1 - y) & ~1); + + u = (s[x * src_stride + even_y * bpp + u_offset] + + s[(x + 1) * src_stride + even_y * bpp + u_offset]) / 2; + v = (s[x * src_stride + even_y * bpp + v_offset] + + s[(x + 1) * src_stride + even_y * bpp + v_offset]) / 2; + + d[y * dest_stride + x * bpp + u_offset] = u; + d[y * dest_stride + x * bpp + v_offset] = v; + d[y * dest_stride + x * bpp + y_offset] = + s[x * src_stride + (sw - 1 - y) * bpp + y_offset]; + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[(x + 1) * src_stride + (sw - 1 - y) * bpp + y_offset]; + } + } + break; + case GST_VIDEO_FLIP_METHOD_180: + for (y = 0; y < dh; y++) { + for (x = 0; x < dw; x += 2) { + guint8 u; + guint8 v; + /* u/v must be calculated using the offset of the even column */ + gint even_x = ((sw - 1 - x) & ~1); + + u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] + + s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2; + v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] + + s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2; + + d[y * dest_stride + x * bpp + u_offset] = u; + d[y * dest_stride + x * bpp + v_offset] = v; + d[y * dest_stride + x * bpp + y_offset] = + s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + y_offset]; + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[(sh - 1 - y) * src_stride + (sw - 1 - (x + 1)) * bpp + + y_offset]; + } + } + break; + case GST_VIDEO_FLIP_METHOD_HORIZ: + for (y = 0; y < dh; y++) { + for (x = 0; x < dw; x += 2) { + guint8 u; + guint8 v; + /* u/v must be calculated using the offset of the even column */ + gint even_x = ((sw - 1 - x) & ~1); + + u = (s[y * src_stride + even_x * bpp + u_offset] + + s[y * src_stride + even_x * bpp + u_offset]) / 2; + v = (s[y * src_stride + even_x * bpp + v_offset] + + s[y * src_stride + even_x * bpp + v_offset]) / 2; + + d[y * dest_stride + x * bpp + u_offset] = u; + d[y * dest_stride + x * bpp + v_offset] = v; + d[y * dest_stride + x * bpp + y_offset] = + s[y * src_stride + (sw - 1 - x) * bpp + y_offset]; + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[y * src_stride + (sw - 1 - (x + 1)) * bpp + y_offset]; + } + } + break; + case GST_VIDEO_FLIP_METHOD_VERT: + for (y = 0; y < dh; y++) { + for (x = 0; x < dw; x += 2) { + guint8 u; + guint8 v; + /* u/v must be calculated using the offset of the even column */ + gint even_x = (x & ~1); + + u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] + + s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2; + v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] + + s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2; + + d[y * dest_stride + x * bpp + u_offset] = u; + d[y * dest_stride + x * bpp + v_offset] = v; + d[y * dest_stride + x * bpp + y_offset] = + s[(sh - 1 - y) * src_stride + x * bpp + y_offset]; + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[(sh - 1 - y) * src_stride + (x + 1) * bpp + y_offset]; + } + } + break; + case GST_VIDEO_FLIP_METHOD_TRANS: + for (y = 0; y < dh; y++) { + for (x = 0; x < dw; x += 2) { + guint8 u; + guint8 v; + /* u/v must be calculated using the offset of the even column */ + gint even_y = (y & ~1); + + u = (s[x * src_stride + even_y * bpp + u_offset] + + s[(x + 1) * src_stride + even_y * bpp + u_offset]) / 2; + v = (s[x * src_stride + even_y * bpp + v_offset] + + s[(x + 1) * src_stride + even_y * bpp + v_offset]) / 2; + + d[y * dest_stride + x * bpp + u_offset] = u; + d[y * dest_stride + x * bpp + v_offset] = v; + d[y * dest_stride + x * bpp + y_offset] = + s[x * src_stride + y * bpp + y_offset]; + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[(x + 1) * src_stride + y * bpp + y_offset]; + } + } + break; + case GST_VIDEO_FLIP_METHOD_OTHER: + for (y = 0; y < dh; y++) { + for (x = 0; x < dw; x += 2) { + guint8 u; + guint8 v; + /* u/v must be calculated using the offset of the even column */ + gint even_y = ((sw - 1 - y) & ~1); + + u = (s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset] + + s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]) / 2; + v = (s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset] + + s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]) / 2; + + d[y * dest_stride + x * bpp + u_offset] = u; + d[y * dest_stride + x * bpp + v_offset] = v; + d[y * dest_stride + x * bpp + y_offset] = + s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + y_offset]; + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[(sh - 1 - (x + 1)) * src_stride + (sw - 1 - y) * bpp + + y_offset]; + } + } + break; + case GST_VIDEO_FLIP_METHOD_IDENTITY: + g_assert_not_reached (); + break; + default: + g_assert_not_reached (); + break; + } +} + + static gboolean gst_video_flip_set_caps (GstBaseTransform * btrans, GstCaps * incaps, GstCaps * outcaps) @@ -624,6 +829,11 @@ gst_video_flip_set_caps (GstBaseTransform * btrans, GstCaps * incaps, case GST_VIDEO_FORMAT_Y444: vf->process = gst_video_flip_planar_yuv; break; + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_UYVY: + case GST_VIDEO_FORMAT_YVYU: + vf->process = gst_video_flip_y422; + break; case GST_VIDEO_FORMAT_AYUV: case GST_VIDEO_FORMAT_ARGB: case GST_VIDEO_FORMAT_ABGR: From 56edbd0fa3c6bdbfeed4cc29a3489f3b9223ce1e Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 15 Mar 2011 19:36:01 +0200 Subject: [PATCH 28/54] speexdec: silence warning message when appropriate If we did not know how many frames to expect, then we get an unexpected end of stream when trying to decode more frames that are there, if there are leftover bits to pad to the next byte --- ext/speex/gstspeexdec.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/ext/speex/gstspeexdec.c b/ext/speex/gstspeexdec.c index c866ef8fe6..0c8c3434ee 100644 --- a/ext/speex/gstspeexdec.c +++ b/ext/speex/gstspeexdec.c @@ -665,7 +665,8 @@ speex_dec_chain_parse_data (GstSpeexDec * dec, GstBuffer * buf, fpp = dec->header->frames_per_packet; bits = &dec->bits; - GST_DEBUG_OBJECT (dec, "received buffer of size %u, fpp %d", size, fpp); + GST_DEBUG_OBJECT (dec, "received buffer of size %u, fpp %d, %d bits", size, + fpp, speex_bits_remaining (bits)); } else { /* concealment data, pass NULL as the bits parameters */ GST_DEBUG_OBJECT (dec, "creating concealment data"); @@ -680,7 +681,8 @@ speex_dec_chain_parse_data (GstSpeexDec * dec, GstBuffer * buf, gint16 *out_data; gint ret; - GST_LOG_OBJECT (dec, "decoding frame %d/%d", i, fpp); + GST_LOG_OBJECT (dec, "decoding frame %d/%d, %d bits remaining", i, fpp, + bits ? speex_bits_remaining (bits) : -1); res = gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE, dec->frame_size * dec->header->nb_channels * 2, @@ -696,7 +698,12 @@ speex_dec_chain_parse_data (GstSpeexDec * dec, GstBuffer * buf, ret = speex_decode_int (dec->state, bits, out_data); if (ret == -1) { /* uh? end of stream */ - GST_WARNING_OBJECT (dec, "Unexpected end of stream found"); + if (fpp == 0 && speex_bits_remaining (bits) < 8) { + /* if we did not know how many frames to expect, then we get this + at the end if there are leftover bits to pad to the next byte */ + } else { + GST_WARNING_OBJECT (dec, "Unexpected end of stream found"); + } gst_buffer_unref (outbuf); outbuf = NULL; break; From a1a0186a62684520b6b49b628ed01007a7892084 Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Mon, 14 Mar 2011 19:14:07 -0400 Subject: [PATCH 29/54] videoflip: Fix buffer overflow bug for odd resolutions and Y422 colorspaces https://bugzilla.gnome.org/show_bug.cgi?id=644773 --- gst/videofilter/gstvideoflip.c | 84 +++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/gst/videofilter/gstvideoflip.c b/gst/videofilter/gstvideoflip.c index af01cc054f..a08d64f157 100644 --- a/gst/videofilter/gstvideoflip.c +++ b/gst/videofilter/gstvideoflip.c @@ -611,16 +611,22 @@ gst_video_flip_y422 (GstVideoFlip * videoflip, guint8 * dest, /* u/v must be calculated using the offset of the even column */ gint even_y = (y & ~1); - u = (s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset] + - s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]) / 2; - v = (s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset] + - s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]) / 2; + u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset]; + if (x + 1 < dw) + u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset] + + u) >> 1; + v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset]; + if (x + 1 < dw) + v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset] + + v) >> 1; + d[y * dest_stride + x * bpp + u_offset] = u; d[y * dest_stride + x * bpp + v_offset] = v; d[y * dest_stride + x * bpp + y_offset] = s[(sh - 1 - x) * src_stride + y * bpp + y_offset]; - d[y * dest_stride + (x + 1) * bpp + y_offset] = - s[(sh - 1 - (x + 1)) * src_stride + y * bpp + y_offset]; + if (x + 1 < dw) + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[(sh - 1 - (x + 1)) * src_stride + y * bpp + y_offset]; } } break; @@ -632,17 +638,20 @@ gst_video_flip_y422 (GstVideoFlip * videoflip, guint8 * dest, /* u/v must be calculated using the offset of the even column */ gint even_y = ((sw - 1 - y) & ~1); - u = (s[x * src_stride + even_y * bpp + u_offset] + - s[(x + 1) * src_stride + even_y * bpp + u_offset]) / 2; - v = (s[x * src_stride + even_y * bpp + v_offset] + - s[(x + 1) * src_stride + even_y * bpp + v_offset]) / 2; + u = s[x * src_stride + even_y * bpp + u_offset]; + if (x + 1 < dw) + u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1; + v = s[x * src_stride + even_y * bpp + v_offset]; + if (x + 1 < dw) + v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1; d[y * dest_stride + x * bpp + u_offset] = u; d[y * dest_stride + x * bpp + v_offset] = v; d[y * dest_stride + x * bpp + y_offset] = s[x * src_stride + (sw - 1 - y) * bpp + y_offset]; - d[y * dest_stride + (x + 1) * bpp + y_offset] = - s[(x + 1) * src_stride + (sw - 1 - y) * bpp + y_offset]; + if (x + 1 < dw) + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[(x + 1) * src_stride + (sw - 1 - y) * bpp + y_offset]; } } break; @@ -663,9 +672,10 @@ gst_video_flip_y422 (GstVideoFlip * videoflip, guint8 * dest, d[y * dest_stride + x * bpp + v_offset] = v; d[y * dest_stride + x * bpp + y_offset] = s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + y_offset]; - d[y * dest_stride + (x + 1) * bpp + y_offset] = - s[(sh - 1 - y) * src_stride + (sw - 1 - (x + 1)) * bpp + - y_offset]; + if (x + 1 < dw) + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[(sh - 1 - y) * src_stride + (sw - 1 - (x + 1)) * bpp + + y_offset]; } } break; @@ -686,8 +696,9 @@ gst_video_flip_y422 (GstVideoFlip * videoflip, guint8 * dest, d[y * dest_stride + x * bpp + v_offset] = v; d[y * dest_stride + x * bpp + y_offset] = s[y * src_stride + (sw - 1 - x) * bpp + y_offset]; - d[y * dest_stride + (x + 1) * bpp + y_offset] = - s[y * src_stride + (sw - 1 - (x + 1)) * bpp + y_offset]; + if (x + 1 < dw) + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[y * src_stride + (sw - 1 - (x + 1)) * bpp + y_offset]; } } break; @@ -708,8 +719,9 @@ gst_video_flip_y422 (GstVideoFlip * videoflip, guint8 * dest, d[y * dest_stride + x * bpp + v_offset] = v; d[y * dest_stride + x * bpp + y_offset] = s[(sh - 1 - y) * src_stride + x * bpp + y_offset]; - d[y * dest_stride + (x + 1) * bpp + y_offset] = - s[(sh - 1 - y) * src_stride + (x + 1) * bpp + y_offset]; + if (x + 1 < dw) + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[(sh - 1 - y) * src_stride + (x + 1) * bpp + y_offset]; } } break; @@ -721,17 +733,20 @@ gst_video_flip_y422 (GstVideoFlip * videoflip, guint8 * dest, /* u/v must be calculated using the offset of the even column */ gint even_y = (y & ~1); - u = (s[x * src_stride + even_y * bpp + u_offset] + - s[(x + 1) * src_stride + even_y * bpp + u_offset]) / 2; - v = (s[x * src_stride + even_y * bpp + v_offset] + - s[(x + 1) * src_stride + even_y * bpp + v_offset]) / 2; + u = s[x * src_stride + even_y * bpp + u_offset]; + if (x + 1 < dw) + u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1; + v = s[x * src_stride + even_y * bpp + v_offset]; + if (x + 1 < dw) + v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1; d[y * dest_stride + x * bpp + u_offset] = u; d[y * dest_stride + x * bpp + v_offset] = v; d[y * dest_stride + x * bpp + y_offset] = s[x * src_stride + y * bpp + y_offset]; - d[y * dest_stride + (x + 1) * bpp + y_offset] = - s[(x + 1) * src_stride + y * bpp + y_offset]; + if (x + 1 < dw) + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[(x + 1) * src_stride + y * bpp + y_offset]; } } break; @@ -743,18 +758,23 @@ gst_video_flip_y422 (GstVideoFlip * videoflip, guint8 * dest, /* u/v must be calculated using the offset of the even column */ gint even_y = ((sw - 1 - y) & ~1); - u = (s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset] + - s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]) / 2; - v = (s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset] + - s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]) / 2; + u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset]; + if (x + 1 < dw) + u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset] + + u) >> 1; + v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset]; + if (x + 1 < dw) + v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset] + + v) >> 1; d[y * dest_stride + x * bpp + u_offset] = u; d[y * dest_stride + x * bpp + v_offset] = v; d[y * dest_stride + x * bpp + y_offset] = s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + y_offset]; - d[y * dest_stride + (x + 1) * bpp + y_offset] = - s[(sh - 1 - (x + 1)) * src_stride + (sw - 1 - y) * bpp + - y_offset]; + if (x + 1 < dw) + d[y * dest_stride + (x + 1) * bpp + y_offset] = + s[(sh - 1 - (x + 1)) * src_stride + (sw - 1 - y) * bpp + + y_offset]; } } break; From 2a8103553d32644129b79293dbe7bd5d404d2691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 15 Mar 2011 20:19:48 +0000 Subject: [PATCH 30/54] tests: enable more formats in videofilter unit test, check more resolutions --- tests/check/elements/videofilter.c | 44 +++++++++++++++++------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/tests/check/elements/videofilter.c b/tests/check/elements/videofilter.c index 0bd148ab66..7389478c0e 100644 --- a/tests/check/elements/videofilter.c +++ b/tests/check/elements/videofilter.c @@ -36,6 +36,9 @@ GstPad *mysrcpad, *mysinkpad; #define VIDEO_CAPS_TEMPLATE_STRING \ GST_VIDEO_CAPS_YUV ("I420") ";" \ GST_VIDEO_CAPS_YUV ("AYUV") ";" \ + GST_VIDEO_CAPS_YUV ("YUY2") ";" \ + GST_VIDEO_CAPS_YUV ("UYVY") ";" \ + GST_VIDEO_CAPS_YUV ("YVYU") ";" \ GST_VIDEO_CAPS_xRGB static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", @@ -129,7 +132,14 @@ check_filter_caps (const gchar * name, GstCaps * caps, gint size, static void check_filter (const gchar * name, gint num_buffers, const gchar * prop, ...) { - gint i, n; + static const struct + { + const int width, height; + } resolutions[] = { { + 384, 288}, { + 385, 289}, { + 385, 385}}; + gint i, n, r; GstVideoFormat format; gint size; GstCaps *templ = gst_caps_from_string (VIDEO_CAPS_TEMPLATE_STRING); @@ -142,27 +152,23 @@ check_filter (const gchar * name, gint num_buffers, const gchar * prop, ...) GstCaps *caps = gst_caps_new_empty (); gst_caps_append_structure (caps, gst_structure_copy (s)); - gst_caps_set_simple (caps, "width", G_TYPE_INT, 384, "height", G_TYPE_INT, - 288, "framerate", GST_TYPE_FRACTION, 25, 1, NULL); - GST_DEBUG ("Testing with caps: %" GST_PTR_FORMAT, caps); - gst_video_format_parse_caps (caps, &format, NULL, NULL); - size = gst_video_format_get_size (format, 384, 288); - va_start (varargs, prop); - check_filter_caps (name, caps, size, num_buffers, prop, varargs); - va_end (varargs); + /* try various resolutions */ + for (r = 0; r < G_N_ELEMENTS (resolutions); ++r) { + caps = gst_caps_make_writable (caps); + gst_caps_set_simple (caps, "width", G_TYPE_INT, resolutions[r].width, + "height", G_TYPE_INT, resolutions[r].height, + "framerate", GST_TYPE_FRACTION, 25, 1, NULL); - /* and again with 'odd' width/height */ - caps = gst_caps_make_writable (caps); - gst_caps_set_simple (caps, "width", G_TYPE_INT, 385, "height", G_TYPE_INT, - 289, "framerate", GST_TYPE_FRACTION, 25, 1, NULL); + GST_DEBUG ("Testing with caps: %" GST_PTR_FORMAT, caps); + gst_video_format_parse_caps (caps, &format, NULL, NULL); + size = gst_video_format_get_size (format, resolutions[r].width, + resolutions[r].height); - GST_DEBUG ("Testing with caps: %" GST_PTR_FORMAT, caps); - gst_video_format_parse_caps (caps, &format, NULL, NULL); - size = gst_video_format_get_size (format, 385, 289); - va_start (varargs, prop); - check_filter_caps (name, caps, size, num_buffers, prop, varargs); - va_end (varargs); + va_start (varargs, prop); + check_filter_caps (name, caps, size, num_buffers, prop, varargs); + va_end (varargs); + } gst_caps_unref (caps); } From 52aa27f997f117c0e456596df96713e9901eb959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 16 Mar 2011 09:35:50 +0100 Subject: [PATCH 31/54] matroskademux: Use ARTIST Matroska tag instead of AUTHOR for GST_TAG_ARTIST AUTHOR only existed in an old version of the spec and ARTIST is the new replacement for this. We are still reading both to still be compatible with old files. Fixes bug #644875. --- gst/matroska/matroska-demux.c | 5 +++-- gst/matroska/matroska-ids.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 401554b435..67ff3f116a 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -2689,8 +2689,8 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, entry->pos + demux->ebml_segment_start); } - flush = !!(flags & GST_SEEK_FLAG_FLUSH); - keyunit = !!(flags & GST_SEEK_FLAG_KEY_UNIT); + flush = ! !(flags & GST_SEEK_FLAG_FLUSH); + keyunit = ! !(flags & GST_SEEK_FLAG_KEY_UNIT); if (flush) { GST_DEBUG_OBJECT (demux, "Starting flush"); @@ -3639,6 +3639,7 @@ gst_matroska_demux_parse_metadata_id_simple_tag (GstMatroskaDemux * demux, tag_conv[] = { { GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, { + GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, { GST_MATROSKA_TAG_ID_AUTHOR, GST_TAG_ARTIST}, { GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, { GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, { diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h index 3bb0610fe6..9027add1b3 100644 --- a/gst/matroska/matroska-ids.h +++ b/gst/matroska/matroska-ids.h @@ -395,6 +395,7 @@ #define GST_MATROSKA_TAG_ID_TITLE "TITLE" #define GST_MATROSKA_TAG_ID_AUTHOR "AUTHOR" +#define GST_MATROSKA_TAG_ID_ARTIST "ARTIST" #define GST_MATROSKA_TAG_ID_ALBUM "ALBUM" #define GST_MATROSKA_TAG_ID_COMMENTS "COMMENTS" #define GST_MATROSKA_TAG_ID_BITSPS "BITSPS" From 7db758164dade4d906754d5b750450769d59427b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 16 Mar 2011 09:37:58 +0100 Subject: [PATCH 32/54] matroskamux: Use ARTIST instead of AUTHOR for GST_TAG_ARTIST --- gst/matroska/matroska-mux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c index b94a434544..0c199c9344 100644 --- a/gst/matroska/matroska-mux.c +++ b/gst/matroska/matroska-mux.c @@ -2177,7 +2177,7 @@ gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag, tag_conv[] = { { GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, { - GST_MATROSKA_TAG_ID_AUTHOR, GST_TAG_ARTIST}, { + GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, { GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, { GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, { GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, { From 5b977c4fec1475cbbd697374cd4a82b3abc0ffd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 16 Mar 2011 09:38:43 +0100 Subject: [PATCH 33/54] matroska: Mark tag mapping tables as static const --- gst/matroska/matroska-demux.c | 2 +- gst/matroska/matroska-mux.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 67ff3f116a..aa714f6a0b 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -3631,7 +3631,7 @@ gst_matroska_demux_parse_metadata_id_simple_tag (GstMatroskaDemux * demux, GstEbmlRead * ebml, GstTagList ** p_taglist) { /* FIXME: check if there are more useful mappings */ - struct + static const struct { const gchar *matroska_tagname; const gchar *gstreamer_tagname; diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c index 0c199c9344..7dd9d55382 100644 --- a/gst/matroska/matroska-mux.c +++ b/gst/matroska/matroska-mux.c @@ -2169,7 +2169,7 @@ gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag, gpointer data) { /* TODO: more sensible tag mappings */ - struct + static const struct { const gchar *matroska_tagname; const gchar *gstreamer_tagname; From a430042f411aceee005a0b3035ca746d654b8b8a Mon Sep 17 00:00:00 2001 From: Robert Swain Date: Wed, 16 Mar 2011 10:43:47 +0100 Subject: [PATCH 34/54] jackaudiosink: Fix typo from 9544622674c0d0a3147a9b51145159b02eec68e9 --- ext/jack/gstjackaudiosink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/jack/gstjackaudiosink.c b/ext/jack/gstjackaudiosink.c index 0abcfe79fd..13f69b7365 100644 --- a/ext/jack/gstjackaudiosink.c +++ b/ext/jack/gstjackaudiosink.c @@ -609,7 +609,7 @@ gst_jack_ring_buffer_delay (GstRingBuffer * buf) if (range.max > res) res = range.max; #else - latency = jack_port_get_total_latency (client, src->ports[i]); + latency = jack_port_get_total_latency (client, sink->ports[i]); if (latency > res) res = latency; #endif From 0f5ff4a8f5930502c3e5d585ebf79b3b3cf79690 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 18 Mar 2011 19:34:57 +0100 Subject: [PATCH 35/54] autogen: wingo signed comment --- autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index 884e9fb680..1fcf9f2827 100755 --- a/autogen.sh +++ b/autogen.sh @@ -80,7 +80,7 @@ tool_run "$libtoolize" "--copy --force" tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS" tool_run "$autoheader" -# touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode -- wingo +# touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode echo timestamp > stamp-h.in 2> /dev/null tool_run "$autoconf" From 08daffdebe472ebe5536fecb4364c4c5b920cd0d Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 22 Mar 2011 12:53:22 +0100 Subject: [PATCH 36/54] configure.ac: redundant uses of AC_MSG_RESULT() cleaned the redundant uses of AC_MSG_RESULT() in configure.ac --- configure.ac | 2 -- 1 file changed, 2 deletions(-) diff --git a/configure.ac b/configure.ac index bd6cbb0625..4296ff4c49 100644 --- a/configure.ac +++ b/configure.ac @@ -927,7 +927,6 @@ AG_GST_CHECK_FEATURE(SOUP, [soup http client plugin (2.4)], souphttpsrc, [ ],[ PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.26, HAVE_SOUP="yes", [ HAVE_SOUP="no" - AC_MSG_RESULT(no) ]) ]) AC_SUBST(SOUP_CFLAGS) @@ -1004,7 +1003,6 @@ AG_GST_CHECK_FEATURE(WAVPACK, [wavpack plug-in], wavpack, [ AC_DEFINE(WAVPACK_OLD_API, 1, [old wavpack API]) ],[ HAVE_WAVPACK=no - AC_MSG_RESULT(no) ]) ]) AC_SUBST(WAVPACK_CFLAGS) From b02edfbfffbfd2bfb899e88e6d7c7ab2674c5767 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Tue, 22 Mar 2011 19:35:58 +0100 Subject: [PATCH 37/54] avimux: use running time for synchronization See bug #432612. --- gst/avi/gstavimux.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gst/avi/gstavimux.c b/gst/avi/gstavimux.c index d0d2f0ecc6..37f9291377 100644 --- a/gst/avi/gstavimux.c +++ b/gst/avi/gstavimux.c @@ -1916,6 +1916,11 @@ gst_avi_mux_do_buffer (GstAviMux * avimux, GstAviPad * avipad) guint flags; data = gst_collect_pads_pop (avimux->collect, avipad->collect); + /* arrange downstream running time */ + data = gst_buffer_make_metadata_writable (data); + GST_BUFFER_TIMESTAMP (data) = + gst_segment_to_running_time (&avipad->collect->segment, + GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (data)); /* Prepend a special buffer to the first one for some formats */ if (avipad->is_video) { @@ -2042,6 +2047,19 @@ gst_avi_mux_do_one_buffer (GstAviMux * avimux) time = GST_BUFFER_TIMESTAMP (buffer); gst_buffer_unref (buffer); + /* invalid should pass */ + if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) { + time = gst_segment_to_running_time (&avipad->collect->segment, + GST_FORMAT_TIME, time); + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) { + GST_DEBUG_OBJECT (avimux, "clipping buffer on pad %s outside segment", + GST_PAD_NAME (avipad->collect->pad)); + buffer = gst_collect_pads_pop (avimux->collect, avipad->collect); + gst_buffer_unref (buffer); + return GST_FLOW_OK; + } + } + delay = avipad->is_video ? GST_SECOND / 2 : 0; /* invalid timestamp buffers pass first, From dd19a7edad076535c917c3f5f3a6cda19804d6cf Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Tue, 22 Mar 2011 19:36:21 +0100 Subject: [PATCH 38/54] matroskamux: use running time for synchronization Fixes #432612. --- gst/matroska/matroska-mux.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c index 7dd9d55382..4b7fdaf7f5 100644 --- a/gst/matroska/matroska-mux.c +++ b/gst/matroska/matroska-mux.c @@ -2409,8 +2409,29 @@ gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped) collect_pad->buffer = gst_collect_pads_pop (mux->collect, (GstCollectData *) collect_pad); - if (collect_pad->buffer != NULL) + if (collect_pad->buffer != NULL) { + GstClockTime time; + *popped = TRUE; + /* convert to running time */ + time = GST_BUFFER_TIMESTAMP (collect_pad->buffer); + /* invalid should pass */ + if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) { + time = gst_segment_to_running_time (&collect_pad->collect.segment, + GST_FORMAT_TIME, time); + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) { + GST_DEBUG_OBJECT (mux, "clipping buffer on pad %s outside segment", + GST_PAD_NAME (collect_pad->collect.pad)); + gst_buffer_unref (collect_pad->buffer); + collect_pad->buffer = NULL; + return NULL; + } else { + collect_pad->buffer = + gst_buffer_make_metadata_writable (collect_pad->buffer); + GST_BUFFER_TIMESTAMP (collect_pad->buffer) = time; + } + } + } } /* if we have a buffer check if it is better then the current best one */ @@ -2772,7 +2793,7 @@ gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data) GstEbmlWrite *ebml = mux->ebml_write; GstMatroskaPad *best; gboolean popped; - GstFlowReturn ret; + GstFlowReturn ret = GST_FLOW_OK; GST_DEBUG_OBJECT (mux, "Collected pads"); @@ -2796,6 +2817,9 @@ gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data) /* if there is no best pad, we have reached EOS */ if (best == NULL) { + /* buffer popped, but none returned means it was clipped */ + if (popped) + break; GST_DEBUG_OBJECT (mux, "No best pad finishing..."); if (!mux->streamable) { gst_matroska_mux_finish (mux); From 87e1b06cacb6d2cf8d3ae45f559124c47471042a Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Tue, 22 Mar 2011 19:36:31 +0100 Subject: [PATCH 39/54] flvmux: use running time for synchronization Fixes #432612. --- gst/flv/gstflvmux.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/gst/flv/gstflvmux.c b/gst/flv/gstflvmux.c index 68a0df4fc7..c128d34132 100644 --- a/gst/flv/gstflvmux.c +++ b/gst/flv/gstflvmux.c @@ -1199,6 +1199,12 @@ gst_flv_mux_write_buffer (GstFlvMux * mux, GstFlvPad * cpad) gst_collect_pads_pop (mux->collect, (GstCollectData *) cpad); GstFlowReturn ret; + /* arrange downstream running time */ + buffer = gst_buffer_make_metadata_writable (buffer); + GST_BUFFER_TIMESTAMP (buffer) = + gst_segment_to_running_time (&cpad->collect.segment, + GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buffer)); + if (!mux->streamable) gst_flv_mux_update_index (mux, buffer, cpad); @@ -1437,6 +1443,15 @@ gst_flv_mux_collected (GstCollectPads * pads, gpointer user_data) break; } + time = gst_segment_to_running_time (&cpad->collect.segment, + GST_FORMAT_TIME, time); + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) { + GST_DEBUG_OBJECT (mux, "clipping buffer on pad %s outside segment", + GST_PAD_NAME (cpad->collect.pad)); + buffer = gst_collect_pads_pop (pads, (GstCollectData *) cpad); + gst_buffer_unref (buffer); + return GST_FLOW_OK; + } if (best == NULL || (GST_CLOCK_TIME_IS_VALID (best_time) && time < best_time)) { From 85ace6d413f2b0ea24af955dc28b499149b584b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 23 Mar 2011 16:34:16 +0100 Subject: [PATCH 40/54] speexdec: Get and use streamheader from the caps if possible This allows playback of streams where the streamheader buffers were dropped from the stream for some reason. --- ext/speex/gstspeexdec.c | 89 ++++++++++++++++++++++++++++++++++++----- ext/speex/gstspeexdec.h | 3 ++ 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/ext/speex/gstspeexdec.c b/ext/speex/gstspeexdec.c index 0c8c3434ee..46f774b8f9 100644 --- a/ext/speex/gstspeexdec.c +++ b/ext/speex/gstspeexdec.c @@ -86,6 +86,7 @@ static GstStateChangeReturn speex_dec_change_state (GstElement * element, static gboolean speex_dec_src_event (GstPad * pad, GstEvent * event); static gboolean speex_dec_src_query (GstPad * pad, GstQuery * query); static gboolean speex_dec_sink_query (GstPad * pad, GstQuery * query); +static gboolean speex_dec_sink_setcaps (GstPad * pad, GstCaps * caps); static const GstQueryType *speex_get_src_query_types (GstPad * pad); static const GstQueryType *speex_get_sink_query_types (GstPad * pad); static gboolean speex_dec_convert (GstPad * pad, @@ -100,6 +101,11 @@ static void gst_speex_dec_set_property (GObject * object, guint prop_id, static GstFlowReturn speex_dec_chain_parse_data (GstSpeexDec * dec, GstBuffer * buf, GstClockTime timestamp, GstClockTime duration); +static GstFlowReturn speex_dec_chain_parse_header (GstSpeexDec * dec, + GstBuffer * buf); +static GstFlowReturn speex_dec_chain_parse_comments (GstSpeexDec * dec, + GstBuffer * buf); + static void gst_speex_dec_base_init (gpointer g_class) { @@ -148,6 +154,9 @@ gst_speex_dec_reset (GstSpeexDec * dec) dec->header = NULL; speex_bits_destroy (&dec->bits); + gst_buffer_replace (&dec->streamheader, NULL); + gst_buffer_replace (&dec->vorbiscomment, NULL); + if (dec->stereo) { speex_stereo_state_destroy (dec->stereo); dec->stereo = NULL; @@ -172,6 +181,8 @@ gst_speex_dec_init (GstSpeexDec * dec, GstSpeexDecClass * g_class) GST_DEBUG_FUNCPTR (speex_get_sink_query_types)); gst_pad_set_query_function (dec->sinkpad, GST_DEBUG_FUNCPTR (speex_dec_sink_query)); + gst_pad_set_setcaps_function (dec->sinkpad, + GST_DEBUG_FUNCPTR (speex_dec_sink_setcaps)); gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad); dec->srcpad = @@ -190,6 +201,46 @@ gst_speex_dec_init (GstSpeexDec * dec, GstSpeexDecClass * g_class) gst_speex_dec_reset (dec); } +static gboolean +speex_dec_sink_setcaps (GstPad * pad, GstCaps * caps) +{ + GstSpeexDec *dec = GST_SPEEX_DEC (gst_pad_get_parent (pad)); + gboolean ret = TRUE; + GstStructure *s; + const GValue *streamheader; + + s = gst_caps_get_structure (caps, 0); + if ((streamheader = gst_structure_get_value (s, "streamheader")) && + G_VALUE_HOLDS (streamheader, GST_TYPE_ARRAY) && + gst_value_array_get_size (streamheader) >= 2) { + const GValue *header, *vorbiscomment; + GstBuffer *buf; + GstFlowReturn res = GST_FLOW_OK; + + header = gst_value_array_get_value (streamheader, 0); + if (header && G_VALUE_HOLDS (header, GST_TYPE_BUFFER)) { + buf = gst_value_get_buffer (header); + res = speex_dec_chain_parse_header (dec, buf); + if (res != GST_FLOW_OK) + goto done; + gst_buffer_replace (&dec->streamheader, buf); + } + + vorbiscomment = gst_value_array_get_value (streamheader, 1); + if (vorbiscomment && G_VALUE_HOLDS (vorbiscomment, GST_TYPE_BUFFER)) { + buf = gst_value_get_buffer (vorbiscomment); + res = speex_dec_chain_parse_comments (dec, buf); + if (res != GST_FLOW_OK) + goto done; + gst_buffer_replace (&dec->vorbiscomment, buf); + } + } + +done: + gst_object_unref (dec); + return ret; +} + static gboolean speex_dec_convert (GstPad * pad, GstFormat src_format, gint64 src_value, @@ -760,19 +811,37 @@ speex_dec_chain (GstPad * pad, GstBuffer * buf) dec = GST_SPEEX_DEC (gst_pad_get_parent (pad)); - switch (dec->packetno) { - case 0: - res = speex_dec_chain_parse_header (dec, buf); - break; - case 1: - res = speex_dec_chain_parse_comments (dec, buf); - break; - default: - { + /* If we have the streamheader and vorbiscomment from the caps already + * ignore them here */ + if (dec->streamheader && dec->vorbiscomment) { + if (GST_BUFFER_SIZE (dec->streamheader) == GST_BUFFER_SIZE (buf) + && memcmp (GST_BUFFER_DATA (dec->streamheader), GST_BUFFER_DATA (buf), + GST_BUFFER_SIZE (buf)) == 0) { + res = GST_FLOW_OK; + } else if (GST_BUFFER_SIZE (dec->vorbiscomment) == GST_BUFFER_SIZE (buf) + && memcmp (GST_BUFFER_DATA (dec->vorbiscomment), GST_BUFFER_DATA (buf), + GST_BUFFER_SIZE (buf)) == 0) { + res = GST_FLOW_OK; + } else { res = speex_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf), GST_BUFFER_DURATION (buf)); - break; + } + } else { + /* Otherwise fall back to packet counting and assume that the + * first two packets are the headers. */ + switch (dec->packetno) { + case 0: + res = speex_dec_chain_parse_header (dec, buf); + break; + case 1: + res = speex_dec_chain_parse_comments (dec, buf); + break; + default: + res = + speex_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf), + GST_BUFFER_DURATION (buf)); + break; } } diff --git a/ext/speex/gstspeexdec.h b/ext/speex/gstspeexdec.h index 6419a6ecf5..660d8053df 100644 --- a/ext/speex/gstspeexdec.h +++ b/ext/speex/gstspeexdec.h @@ -68,6 +68,9 @@ struct _GstSpeexDec { guint64 packetno; GstSegment segment; /* STREAM LOCK */ + + GstBuffer *streamheader; + GstBuffer *vorbiscomment; }; struct _GstSpeexDecClass { From 1979b04f464637c7937e34b4197bbdb0575dd83b Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Tue, 22 Mar 2011 16:26:45 +0200 Subject: [PATCH 41/54] spectrum: use local var for input_data function Avoid dereferencing the input_data from the instance from within an inner loop. --- gst/spectrum/gstspectrum.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index 0dbf37273f..135206c9d9 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -974,12 +974,14 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) input_pos = spectrum->input_pos; if (!spectrum->multi_channel) { + GstSpectrumInputDataMixed input_data_mixed = spectrum->input_data_mixed; + cd = &spectrum->channel_data[0]; input = cd->input; while (size >= width * channels) { /* Move the mixdown of current frame into our ringbuffer */ - input[input_pos] = spectrum->input_data_mixed (data, channels, max_value); + input[input_pos] = input_data_mixed (data, channels, max_value); data += width * channels; size -= width * channels; @@ -1035,13 +1037,14 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) } } else { guint c; + GstSpectrumInputData input_data = spectrum->input_data; while (size >= width * channels) { for (c = 0; c < channels; c++) { cd = &spectrum->channel_data[c]; input = cd->input; /* Move the current frames into our ringbuffers */ - input[input_pos] = spectrum->input_data (data, max_value); + input[input_pos] = input_data (data, max_value); data += width; } size -= width * channels; From 3b552ae6f81d134040c1969ee3a1323dbf82df77 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Tue, 22 Mar 2011 16:29:53 +0200 Subject: [PATCH 42/54] spectrum: simplify the have_interval calculation Move some of the conditions to the places where the dependent variables change. --- gst/spectrum/gstspectrum.c | 23 +++++++++++------------ gst/spectrum/gstspectrum.h | 1 + 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index 135206c9d9..cfd4032d98 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -953,6 +953,7 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) * interval is in ns */ spectrum->frames_per_interval = gst_util_uint64_scale (spectrum->interval, rate, GST_SECOND); + spectrum->frames_todo = spectrum->frames_per_interval; /* rounding error in ns, aggregated it in accumulated_error */ spectrum->error_per_interval = (spectrum->interval * rate) % GST_SECOND; if (spectrum->frames_per_interval == 0) @@ -988,12 +989,7 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) input_pos = (input_pos + 1) % nfft; spectrum->num_frames++; - have_full_interval = ( - (spectrum->accumulated_error < GST_SECOND - && spectrum->num_frames == spectrum->frames_per_interval) || - (spectrum->accumulated_error >= GST_SECOND - && spectrum->num_frames - 1 == spectrum->frames_per_interval) - ); + have_full_interval = (spectrum->num_frames == spectrum->frames_todo); /* If we have enough frames for an FFT or we have all frames required for * the interval and we haven't run a FFT, then run an FFT */ @@ -1015,6 +1011,10 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) else spectrum->accumulated_error += spectrum->error_per_interval; + spectrum->frames_todo = spectrum->frames_per_interval; + if (spectrum->accumulated_error >= spectrum->frame_time) + spectrum->frames_todo++; + if (spectrum->post_messages) { GstMessage *m; @@ -1051,12 +1051,7 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) input_pos = (input_pos + 1) % nfft; spectrum->num_frames++; - have_full_interval = ( - (spectrum->accumulated_error < GST_SECOND - && spectrum->num_frames == spectrum->frames_per_interval) || - (spectrum->accumulated_error >= GST_SECOND - && spectrum->num_frames - 1 == spectrum->frames_per_interval) - ); + have_full_interval = (spectrum->num_frames == spectrum->frames_todo); /* If we have enough frames for an FFT or we have all frames required for * the interval and we haven't run a FFT, then run an FFT */ @@ -1082,6 +1077,10 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) else spectrum->accumulated_error += spectrum->error_per_interval; + spectrum->frames_todo = spectrum->frames_per_interval; + if (spectrum->accumulated_error >= spectrum->frame_time) + spectrum->frames_todo++; + if (spectrum->post_messages) { GstMessage *m; diff --git a/gst/spectrum/gstspectrum.h b/gst/spectrum/gstspectrum.h index 60ebd503e9..b7e2be3c96 100644 --- a/gst/spectrum/gstspectrum.h +++ b/gst/spectrum/gstspectrum.h @@ -61,6 +61,7 @@ struct _GstSpectrum gboolean message_phase; guint64 interval; /* how many nanoseconds between emits */ guint64 frames_per_interval; /* how many frames per interval */ + guint64 frames_todo; guint bands; /* number of spectrum bands */ gint threshold; /* energy level treshold */ gboolean multi_channel; /* send separate channel results */ From 315347a8dcac5301263c45ce83975a706e53a366 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 24 Mar 2011 13:53:12 +0200 Subject: [PATCH 43/54] spectrum: fix broken code resulting for a wrong splitup of changes --- gst/spectrum/gstspectrum.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index cfd4032d98..272d9032c3 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -1012,7 +1012,7 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) spectrum->accumulated_error += spectrum->error_per_interval; spectrum->frames_todo = spectrum->frames_per_interval; - if (spectrum->accumulated_error >= spectrum->frame_time) + if (spectrum->accumulated_error >= GST_SECOND) spectrum->frames_todo++; if (spectrum->post_messages) { @@ -1078,7 +1078,7 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) spectrum->accumulated_error += spectrum->error_per_interval; spectrum->frames_todo = spectrum->frames_per_interval; - if (spectrum->accumulated_error >= spectrum->frame_time) + if (spectrum->accumulated_error >= GST_SECOND) spectrum->frames_todo++; if (spectrum->post_messages) { From f00af192c92fa64e7078b5a3adc89f0784e2d32e Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 24 Mar 2011 14:14:09 +0200 Subject: [PATCH 44/54] spectrum: fix the error accumulation and frames_todo handling Even though we wrap around the accumulated second, we still need to add the error in the same cycle. Increase the todo in the same conditional as afterwards the accumulated error will be below one second. --- gst/spectrum/gstspectrum.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index 272d9032c3..0bef4c15d7 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -1006,14 +1006,12 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) spectrum->num_frames, spectrum->frames_per_interval, GST_TIME_ARGS (spectrum->accumulated_error)); - if (spectrum->accumulated_error >= GST_SECOND) - spectrum->accumulated_error -= GST_SECOND; - else - spectrum->accumulated_error += spectrum->error_per_interval; - spectrum->frames_todo = spectrum->frames_per_interval; - if (spectrum->accumulated_error >= GST_SECOND) + if (spectrum->accumulated_error >= GST_SECOND) { + spectrum->accumulated_error -= GST_SECOND; spectrum->frames_todo++; + } + spectrum->accumulated_error += spectrum->error_per_interval; if (spectrum->post_messages) { GstMessage *m; @@ -1072,14 +1070,12 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) spectrum->num_frames, spectrum->frames_per_interval, GST_TIME_ARGS (spectrum->accumulated_error)); - if (spectrum->accumulated_error >= GST_SECOND) - spectrum->accumulated_error -= GST_SECOND; - else - spectrum->accumulated_error += spectrum->error_per_interval; - spectrum->frames_todo = spectrum->frames_per_interval; - if (spectrum->accumulated_error >= GST_SECOND) + if (spectrum->accumulated_error >= GST_SECOND) { + spectrum->accumulated_error -= GST_SECOND; spectrum->frames_todo++; + } + spectrum->accumulated_error += spectrum->error_per_interval; if (spectrum->post_messages) { GstMessage *m; From ea24767b948bdd529c1f60897f5b36c742f471e5 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 24 Mar 2011 18:49:19 +0200 Subject: [PATCH 45/54] Automatic update of common submodule From 6aec6b9 to 6aaa286 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 6aec6b9716..6aaa286970 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 6aec6b9716c184c60c4bc6a5916a2471cfa8c8cd +Subproject commit 6aaa286970e59ed89bd69544f2ee10551f377cb6 From 51f25f371b14f9f2cb67091aa5cde0374109ee9f Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 24 Mar 2011 23:47:33 +0200 Subject: [PATCH 46/54] jack: unbreak the build for jack2 users Jack2 (versions 1.X.X) does only have that API in svn. Limmit the use of the new API for jack1 versions. --- configure.ac | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4296ff4c49..245614974e 100644 --- a/configure.ac +++ b/configure.ac @@ -767,7 +767,8 @@ AG_GST_CHECK_FEATURE(JACK, Jack, jack, [ AC_SUBST(JACK_CFLAGS) AC_SUBST(JACK_LIBS) - AG_GST_PKG_CHECK_MODULES(JACK_0_120_2, jack >= 0.120.2) + dnl upcomming jack2 (1.9.7 will have the new api as well + AG_GST_PKG_CHECK_MODULES(JACK_0_120_2, jack >= 0.120.2 jack < 1.0) if test x$HAVE_JACK_0_120_2 = xyes; then AC_DEFINE(HAVE_JACK_0_120_2, 1, [defined if jack >= 0.120.2 is available]) fi From fb071dd89e16337b4545c6144d44813b09e4ed0d Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Fri, 25 Mar 2011 00:10:56 +0200 Subject: [PATCH 47/54] spectrum: refactor processing loop for block based operation Previously the chain function was working sample frame based. In each cycle it was checking if it is time to run a fft or if it is time to send a message. Now we changed the data transform functions to work on a block of data and calculate the max length until either {end-of-data, do-fft, do-msg}. This allows us also to avoid the duplicated code for the single and multi-channel case (as the transformers have the same signature now). --- gst/spectrum/gstspectrum.c | 592 ++++++++++++++++++++----------------- gst/spectrum/gstspectrum.h | 6 +- 2 files changed, 317 insertions(+), 281 deletions(-) diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index 0bef4c15d7..bc4fca45c5 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -1,6 +1,6 @@ /* GStreamer * Copyright (C) <1999> Erik Walthinsen - * <2006> Stefan Kost + * <2006,2011> Stefan Kost * <2007-2009> Sebastian Dröge * * This library is free software; you can redistribute it and/or @@ -484,189 +484,274 @@ gst_spectrum_stop (GstBaseTransform * trans) /* mixing data readers */ -static gfloat -input_data_mixed_float (const guint8 * data, guint channels, gfloat max_value) +static void +input_data_mixed_float (const guint8 * _in, gfloat * out, guint len, + guint channels, gfloat max_value, guint op, guint nfft) { - guint i; - gfloat v = 0.0; - gfloat *in = (gfloat *) data; + guint i, j, ip = 0; + gfloat v; + gfloat *in = (gfloat *) _in; - for (i = 0; i < channels; i++) - v += in[i]; - - return v / channels; -} - -static gfloat -input_data_mixed_double (const guint8 * data, guint channels, gfloat max_value) -{ - guint i; - gfloat v = 0.0; - gdouble *in = (gdouble *) data; - - for (i = 0; i < channels; i++) - v += in[i]; - - return v / channels; -} - -static gfloat -input_data_mixed_int32 (const guint8 * data, guint channels, gfloat max_value) -{ - guint i; - gfloat v = 0.0; - gint32 *in = (gint32 *) data; - - for (i = 0; i < channels; i++) - v += in[i] * 2 + 1; - - return v / channels; -} - -static gfloat -input_data_mixed_int32_max (const guint8 * data, guint channels, - gfloat max_value) -{ - guint i; - gfloat v = 0.0; - gint32 *in = (gint32 *) data; - - for (i = 0; i < channels; i++) - v += in[i] / max_value; - - return v / channels; -} - -static gfloat -input_data_mixed_int24 (const guint8 * data, guint channels, gfloat max_value) -{ - guint i; - gfloat v = 0.0; - - for (i = 0; i < channels; i++) { -#if G_BYTE_ORDER == G_BIG_ENDIAN - gint32 value = GST_READ_UINT24_BE (data); -#else - gint32 value = GST_READ_UINT24_LE (data); -#endif - if (value & 0x00800000) - value |= 0xff000000; - v += value * 2 + 1; + for (j = 0; j < len; j++) { + v = in[ip++]; + for (i = 1; i < channels; i++) + v += in[ip++]; + out[op] = v / channels; + op = (op + 1) % nfft; } - - return v / channels; } -static gfloat -input_data_mixed_int24_max (const guint8 * data, guint channels, - gfloat max_value) +static void +input_data_mixed_double (const guint8 * _in, gfloat * out, guint len, + guint channels, gfloat max_value, guint op, guint nfft) { - guint i; - gfloat v = 0.0; + guint i, j, ip = 0; + gfloat v; + gdouble *in = (gdouble *) _in; - for (i = 0; i < channels; i++) { -#if G_BYTE_ORDER == G_BIG_ENDIAN - gint32 value = GST_READ_UINT24_BE (data); -#else - gint32 value = GST_READ_UINT24_LE (data); -#endif - if (value & 0x00800000) - value |= 0xff000000; - v += value / max_value; + for (j = 0; j < len; j++) { + v = in[ip++]; + for (i = 1; i < channels; i++) + v += in[ip++]; + out[op] = v / channels; + op = (op + 1) % nfft; } - - return v / channels; } -static gfloat -input_data_mixed_int16 (const guint8 * data, guint channels, gfloat max_value) +static void +input_data_mixed_int32 (const guint8 * _in, gfloat * out, guint len, + guint channels, gfloat max_value, guint op, guint nfft) { - guint i; - gfloat v = 0.0; - gint16 *in = (gint16 *) data; + guint i, j, ip = 0; + gint32 *in = (gint32 *) _in; + gfloat v; - for (i = 0; i < channels; i++) - v += in[i] * 2 + 1; - - return v / channels; + for (j = 0; j < len; j++) { + v = in[ip++] * 2 + 1; + for (i = 1; i < channels; i++) + v += in[ip++] * 2 + 1; + out[op] = v / channels; + op = (op + 1) % nfft; + } } -static gfloat -input_data_mixed_int16_max (const guint8 * data, guint channels, - gfloat max_value) +static void +input_data_mixed_int32_max (const guint8 * _in, gfloat * out, guint len, + guint channels, gfloat max_value, guint op, guint nfft) { - guint i; + guint i, j, ip = 0; + gint32 *in = (gint32 *) _in; + gfloat v; + + for (j = 0; j < len; j++) { + v = in[ip++] / max_value; + for (i = 1; i < channels; i++) + v += in[ip++] / max_value; + out[op] = v / channels; + op = (op + 1) % nfft; + } +} + +static void +input_data_mixed_int24 (const guint8 * _in, gfloat * out, guint len, + guint channels, gfloat max_value, guint op, guint nfft) +{ + guint i, j; gfloat v = 0.0; - gint16 *in = (gint16 *) data; - for (i = 0; i < channels; i++) - v += in[i] / max_value; + for (j = 0; j < len; j++) { + for (i = 0; i < channels; i++) { +#if G_BYTE_ORDER == G_BIG_ENDIAN + gint32 value = GST_READ_UINT24_BE (_in); +#else + gint32 value = GST_READ_UINT24_LE (_in); +#endif + if (value & 0x00800000) + value |= 0xff000000; + v += value * 2 + 1; + _in += 3; + } + out[op] = v / channels; + op = (op + 1) % nfft; + } +} - return v / channels; +static void +input_data_mixed_int24_max (const guint8 * _in, gfloat * out, guint len, + guint channels, gfloat max_value, guint op, guint nfft) +{ + guint i, j; + gfloat v = 0.0; + + for (j = 0; j < len; j++) { + for (i = 0; i < channels; i++) { +#if G_BYTE_ORDER == G_BIG_ENDIAN + gint32 value = GST_READ_UINT24_BE (_in); +#else + gint32 value = GST_READ_UINT24_LE (_in); +#endif + if (value & 0x00800000) + value |= 0xff000000; + v += value / max_value; + _in += 3; + } + out[op] = v / channels; + op = (op + 1) % nfft; + } +} + +static void +input_data_mixed_int16 (const guint8 * _in, gfloat * out, guint len, + guint channels, gfloat max_value, guint op, guint nfft) +{ + guint i, j, ip = 0; + gint16 *in = (gint16 *) _in; + gfloat v; + + for (j = 0; j < len; j++) { + v = in[ip++] * 2 + 1; + for (i = 1; i < channels; i++) + v += in[ip++] * 2 + 1; + out[op] = v / channels; + op = (op + 1) % nfft; + } +} + +static void +input_data_mixed_int16_max (const guint8 * _in, gfloat * out, guint len, + guint channels, gfloat max_value, guint op, guint nfft) +{ + guint i, j, ip = 0; + gint16 *in = (gint16 *) _in; + gfloat v; + + for (j = 0; j < len; j++) { + v = in[ip++] / max_value; + for (i = 1; i < channels; i++) + v += in[ip++] / max_value; + out[op] = v / channels; + op = (op + 1) % nfft; + } } /* non mixing data readers */ -static gfloat -input_data_float (const guint8 * data, gfloat max_value) +static void +input_data_float (const guint8 * _in, gfloat * out, guint len, guint channels, + gfloat max_value, guint op, guint nfft) { - return ((gfloat *) data)[0]; + guint j, ip; + gfloat *in = (gfloat *) _in; + + for (j = 0, ip = 0; j < len; j++, ip += channels) { + out[op] = in[ip]; + op = (op + 1) % nfft; + } } -static gfloat -input_data_double (const guint8 * data, gfloat max_value) +static void +input_data_double (const guint8 * _in, gfloat * out, guint len, guint channels, + gfloat max_value, guint op, guint nfft) { - return (gfloat) ((gdouble *) data)[0]; + guint j, ip; + gdouble *in = (gdouble *) _in; + + for (j = 0, ip = 0; j < len; j++, ip += channels) { + out[op] = in[ip]; + op = (op + 1) % nfft; + } } -static gfloat -input_data_int32 (const guint8 * data, gfloat max_value) +static void +input_data_int32 (const guint8 * _in, gfloat * out, guint len, guint channels, + gfloat max_value, guint op, guint nfft) { - return ((gint32 *) data)[0] * 2 + 1; + guint j, ip; + gint32 *in = (gint32 *) _in; + + for (j = 0, ip = 0; j < len; j++, ip += channels) { + out[op] = in[ip] * 2 + 1; + op = (op + 1) % nfft; + } } -static gfloat -input_data_int32_max (const guint8 * data, gfloat max_value) +static void +input_data_int32_max (const guint8 * _in, gfloat * out, guint len, + guint channels, gfloat max_value, guint op, guint nfft) { - return ((gint32 *) data)[0] / max_value; + guint j, ip; + gint32 *in = (gint32 *) _in; + + for (j = 0, ip = 0; j < len; j++, ip += channels) { + out[op] = in[ip] / max_value; + op = (op + 1) % nfft; + } } -static gfloat -input_data_int24 (const guint8 * data, gfloat max_value) +static void +input_data_int24 (const guint8 * _in, gfloat * out, guint len, guint channels, + gfloat max_value, guint op, guint nfft) { + guint j; + + for (j = 0; j < len; j++) { #if G_BYTE_ORDER == G_BIG_ENDIAN - gint32 in = GST_READ_UINT24_BE (data); + gint32 v = GST_READ_UINT24_BE (_in); #else - gint32 in = GST_READ_UINT24_LE (data); + gint32 v = GST_READ_UINT24_LE (_in); #endif - if (in & 0x00800000) - in |= 0xff000000; - return in * 2 + 1; + if (v & 0x00800000) + v |= 0xff000000; + _in += 3 * channels; + out[op] = v * 2 + 1; + op = (op + 1) % nfft; + } } -static gfloat -input_data_int24_max (const guint8 * data, gfloat max_value) +static void +input_data_int24_max (const guint8 * _in, gfloat * out, guint len, + guint channels, gfloat max_value, guint op, guint nfft) { + guint j; + + for (j = 0; j < len; j++) { #if G_BYTE_ORDER == G_BIG_ENDIAN - gint32 in = GST_READ_UINT24_BE (data); + gint32 v = GST_READ_UINT24_BE (_in); #else - gint32 in = GST_READ_UINT24_LE (data); + gint32 v = GST_READ_UINT24_LE (_in); #endif - if (in & 0x00800000) - in |= 0xff000000; - return in / max_value; + if (v & 0x00800000) + v |= 0xff000000; + _in += 3 * channels; + out[op] = v / max_value; + op = (op + 1) % nfft; + } } -static gfloat -input_data_int16 (const guint8 * data, gfloat max_value) +static void +input_data_int16 (const guint8 * _in, gfloat * out, guint len, guint channels, + gfloat max_value, guint op, guint nfft) { - return ((gint16 *) data)[0] * 2 + 1; + guint j, ip; + gint16 *in = (gint16 *) _in; + + for (j = 0, ip = 0; j < len; j++, ip += channels) { + out[op] = in[ip] * 2 + 1; + op = (op + 1) % nfft; + } } -static gfloat -input_data_int16_max (const guint8 * data, gfloat max_value) +static void +input_data_int16_max (const guint8 * _in, gfloat * out, guint len, + guint channels, gfloat max_value, guint op, guint nfft) { - return ((gint16 *) data)[0] / max_value; + guint j, ip; + gint16 *in = (gint16 *) _in; + + for (j = 0, ip = 0; j < len; j++, ip += channels) { + out[op] = in[ip] / max_value; + op = (op + 1) % nfft; + } } static gboolean @@ -677,51 +762,46 @@ gst_spectrum_setup (GstAudioFilter * base, GstRingBufferSpec * format) gboolean is_float = (format->type == GST_BUFTYPE_FLOAT); /* max_value will be 0 when depth is 1, * interpret -1 and 0 as -1 and +1 if that's the case. */ - gfloat max_value = (1UL << (format->depth - 1)) - 1; - - spectrum->input_data_mixed = NULL; - spectrum->input_data = NULL; + guint max_value = (1UL << (format->depth - 1)) - 1; + gboolean multi_channel = spectrum->multi_channel; + GstSpectrumInputData input_data = NULL; if (is_float) { if (width == 4) { - spectrum->input_data_mixed = input_data_mixed_float; - spectrum->input_data = input_data_float; + input_data = multi_channel ? input_data_float : input_data_mixed_float; } else if (width == 8) { - spectrum->input_data_mixed = input_data_mixed_double; - spectrum->input_data = input_data_double; + input_data = multi_channel ? input_data_double : input_data_mixed_double; } else { g_assert_not_reached (); } } else { if (width == 4) { if (max_value) { - spectrum->input_data_mixed = input_data_mixed_int32_max; - spectrum->input_data = input_data_int32_max; + input_data = + multi_channel ? input_data_int32_max : input_data_mixed_int32_max; } else { - spectrum->input_data_mixed = input_data_mixed_int32; - spectrum->input_data = input_data_int32; + input_data = multi_channel ? input_data_int32 : input_data_mixed_int32; } } else if (width == 3) { if (max_value) { - spectrum->input_data_mixed = input_data_mixed_int24_max; - spectrum->input_data = input_data_int24_max; + input_data = + multi_channel ? input_data_int24_max : input_data_mixed_int24_max; } else { - spectrum->input_data_mixed = input_data_mixed_int24; - spectrum->input_data = input_data_int24; + input_data = multi_channel ? input_data_int24 : input_data_mixed_int24; } } else if (width == 2) { if (max_value) { - spectrum->input_data_mixed = input_data_mixed_int16_max; - spectrum->input_data = input_data_int16_max; + input_data = + multi_channel ? input_data_int16_max : input_data_mixed_int16_max; } else { - spectrum->input_data_mixed = input_data_mixed_int16; - spectrum->input_data = input_data_int16; + input_data = multi_channel ? input_data_int16 : input_data_mixed_int16; } } else { g_assert_not_reached (); } } + spectrum->input_data = input_data; gst_spectrum_reset_state (spectrum); return TRUE; } @@ -923,6 +1003,8 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) GstRingBufferSpec *format = &GST_AUDIO_FILTER (spectrum)->format; guint rate = format->rate; guint channels = format->channels; + guint output_channels = spectrum->multi_channel ? channels : 1; + guint c; guint width = format->width / 8; gfloat max_value = (1UL << (format->depth - 1)) - 1; guint bands = spectrum->bands; @@ -931,8 +1013,11 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) gfloat *input; const guint8 *data = GST_BUFFER_DATA (buffer); guint size = GST_BUFFER_SIZE (buffer); + guint frame_size = width * channels; + guint fft_todo, msg_todo, block_size; gboolean have_full_interval; GstSpectrumChannel *cd; + GstSpectrumInputData input_data; GST_LOG_OBJECT (spectrum, "input size: %d bytes", GST_BUFFER_SIZE (buffer)); @@ -954,7 +1039,8 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) spectrum->frames_per_interval = gst_util_uint64_scale (spectrum->interval, rate, GST_SECOND); spectrum->frames_todo = spectrum->frames_per_interval; - /* rounding error in ns, aggregated it in accumulated_error */ + /* rounding error for frames_per_interval in ns, + * aggregated it in accumulated_error */ spectrum->error_per_interval = (spectrum->interval * rate) % GST_SECOND; if (spectrum->frames_per_interval == 0) spectrum->frames_per_interval = 1; @@ -973,135 +1059,87 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) spectrum->message_ts = GST_BUFFER_TIMESTAMP (buffer); input_pos = spectrum->input_pos; + input_data = spectrum->input_data; - if (!spectrum->multi_channel) { - GstSpectrumInputDataMixed input_data_mixed = spectrum->input_data_mixed; + while (size >= frame_size) { + /* run input_data for a chunk of data */ + fft_todo = nfft - (spectrum->num_frames % nfft); + msg_todo = spectrum->frames_todo - spectrum->num_frames; + GST_LOG_OBJECT (spectrum, + "message frames todo: %u, fft frames todo: %u, input frames %u", + msg_todo, fft_todo, (size / frame_size)); + block_size = msg_todo; + if (block_size > (size / frame_size)) + block_size = (size / frame_size); + if (block_size > fft_todo) + block_size = fft_todo; - cd = &spectrum->channel_data[0]; - input = cd->input; - - while (size >= width * channels) { - /* Move the mixdown of current frame into our ringbuffer */ - input[input_pos] = input_data_mixed (data, channels, max_value); - - data += width * channels; - size -= width * channels; - input_pos = (input_pos + 1) % nfft; - spectrum->num_frames++; - - have_full_interval = (spectrum->num_frames == spectrum->frames_todo); - - /* If we have enough frames for an FFT or we have all frames required for - * the interval and we haven't run a FFT, then run an FFT */ - if ((spectrum->num_frames % nfft == 0) || - (have_full_interval && !spectrum->num_fft)) { - gst_spectrum_run_fft (spectrum, cd, input_pos); - spectrum->num_fft++; - } - - /* Do we have the FFTs for one interval? */ - if (have_full_interval) { - GST_DEBUG_OBJECT (spectrum, "nfft: %u frames: %" G_GUINT64_FORMAT - " fpi: %" G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft, - spectrum->num_frames, spectrum->frames_per_interval, - GST_TIME_ARGS (spectrum->accumulated_error)); - - spectrum->frames_todo = spectrum->frames_per_interval; - if (spectrum->accumulated_error >= GST_SECOND) { - spectrum->accumulated_error -= GST_SECOND; - spectrum->frames_todo++; - } - spectrum->accumulated_error += spectrum->error_per_interval; - - if (spectrum->post_messages) { - GstMessage *m; - - gst_spectrum_prepare_message_data (spectrum, cd); - - m = gst_spectrum_message_new (spectrum, spectrum->message_ts, - spectrum->interval); - - gst_element_post_message (GST_ELEMENT (spectrum), m); - } - - if (GST_CLOCK_TIME_IS_VALID (spectrum->message_ts)) - spectrum->message_ts += - gst_util_uint64_scale (spectrum->num_frames, GST_SECOND, rate); - - gst_spectrum_reset_message_data (spectrum, cd); - spectrum->num_frames = 0; - spectrum->num_fft = 0; - } + for (c = 0; c < output_channels; c++) { + cd = &spectrum->channel_data[c]; + input = cd->input; + /* Move the current frames into our ringbuffers */ + input_data (data + c * width, input, block_size, channels, max_value, + input_pos, nfft); } - } else { - guint c; - GstSpectrumInputData input_data = spectrum->input_data; + data += block_size * frame_size; + size -= block_size * frame_size; + input_pos = (input_pos + block_size) % nfft; + spectrum->num_frames += block_size; + + have_full_interval = (spectrum->num_frames == spectrum->frames_todo); + + GST_LOG_OBJECT (spectrum, "size: %u, do-fft = %d, do-message = %d", size, + (spectrum->num_frames % nfft == 0), have_full_interval); + + /* If we have enough frames for an FFT or we have all frames required for + * the interval and we haven't run a FFT, then run an FFT */ + if ((spectrum->num_frames % nfft == 0) || + (have_full_interval && !spectrum->num_fft)) { + for (c = 0; c < output_channels; c++) { + cd = &spectrum->channel_data[c]; + gst_spectrum_run_fft (spectrum, cd, input_pos); + } + spectrum->num_fft++; + } + + /* Do we have the FFTs for one interval? */ + if (have_full_interval) { + GST_DEBUG_OBJECT (spectrum, "nfft: %u frames: %" G_GUINT64_FORMAT + " fpi: %" G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft, + spectrum->num_frames, spectrum->frames_per_interval, + GST_TIME_ARGS (spectrum->accumulated_error)); + + spectrum->frames_todo = spectrum->frames_per_interval; + if (spectrum->accumulated_error >= GST_SECOND) { + spectrum->accumulated_error -= GST_SECOND; + spectrum->frames_todo++; + } + spectrum->accumulated_error += spectrum->error_per_interval; + + if (spectrum->post_messages) { + GstMessage *m; + + for (c = 0; c < output_channels; c++) { + cd = &spectrum->channel_data[c]; + gst_spectrum_prepare_message_data (spectrum, cd); + } + + m = gst_spectrum_message_new (spectrum, spectrum->message_ts, + spectrum->interval); + + gst_element_post_message (GST_ELEMENT (spectrum), m); + } + + if (GST_CLOCK_TIME_IS_VALID (spectrum->message_ts)) + spectrum->message_ts += + gst_util_uint64_scale (spectrum->num_frames, GST_SECOND, rate); - while (size >= width * channels) { for (c = 0; c < channels; c++) { cd = &spectrum->channel_data[c]; - input = cd->input; - /* Move the current frames into our ringbuffers */ - input[input_pos] = input_data (data, max_value); - data += width; - } - size -= width * channels; - input_pos = (input_pos + 1) % nfft; - spectrum->num_frames++; - - have_full_interval = (spectrum->num_frames == spectrum->frames_todo); - - /* If we have enough frames for an FFT or we have all frames required for - * the interval and we haven't run a FFT, then run an FFT */ - if ((spectrum->num_frames % nfft == 0) || - (have_full_interval && !spectrum->num_fft)) { - for (c = 0; c < channels; c++) { - cd = &spectrum->channel_data[c]; - gst_spectrum_run_fft (spectrum, cd, input_pos); - } - spectrum->num_fft++; - } - - /* Do we have the FFTs for one interval? */ - if (have_full_interval) { - - GST_DEBUG_OBJECT (spectrum, "nfft: %u frames: %" G_GUINT64_FORMAT - " fpi: %" G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft, - spectrum->num_frames, spectrum->frames_per_interval, - GST_TIME_ARGS (spectrum->accumulated_error)); - - spectrum->frames_todo = spectrum->frames_per_interval; - if (spectrum->accumulated_error >= GST_SECOND) { - spectrum->accumulated_error -= GST_SECOND; - spectrum->frames_todo++; - } - spectrum->accumulated_error += spectrum->error_per_interval; - - if (spectrum->post_messages) { - GstMessage *m; - - for (c = 0; c < channels; c++) { - cd = &spectrum->channel_data[c]; - gst_spectrum_prepare_message_data (spectrum, cd); - } - - m = gst_spectrum_message_new (spectrum, spectrum->message_ts, - spectrum->interval); - - gst_element_post_message (GST_ELEMENT (spectrum), m); - } - - if (GST_CLOCK_TIME_IS_VALID (spectrum->message_ts)) - spectrum->message_ts += - gst_util_uint64_scale (spectrum->num_frames, GST_SECOND, rate); - - for (c = 0; c < channels; c++) { - cd = &spectrum->channel_data[c]; - gst_spectrum_reset_message_data (spectrum, cd); - } - spectrum->num_frames = 0; - spectrum->num_fft = 0; + gst_spectrum_reset_message_data (spectrum, cd); } + spectrum->num_frames = 0; + spectrum->num_fft = 0; } } diff --git a/gst/spectrum/gstspectrum.h b/gst/spectrum/gstspectrum.h index b7e2be3c96..416072ffe8 100644 --- a/gst/spectrum/gstspectrum.h +++ b/gst/spectrum/gstspectrum.h @@ -37,9 +37,8 @@ typedef struct _GstSpectrum GstSpectrum; typedef struct _GstSpectrumClass GstSpectrumClass; typedef struct _GstSpectrumChannel GstSpectrumChannel; -typedef gfloat (*GstSpectrumInputDataMixed)(const guint8 * data, guint channels, - gfloat max_value); -typedef gfloat (*GstSpectrumInputData)(const guint8 * data, gfloat max_value); +typedef void (*GstSpectrumInputData)(const guint8 * in, gfloat * out, + guint len, guint channels, gfloat max_value, guint op, guint nfft); struct _GstSpectrumChannel { @@ -79,7 +78,6 @@ struct _GstSpectrum guint64 error_per_interval; guint64 accumulated_error; - GstSpectrumInputDataMixed input_data_mixed; GstSpectrumInputData input_data; }; From 06c81de08d31a937b22afa6d67811265adf0c958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 25 Mar 2011 09:06:16 +0100 Subject: [PATCH 48/54] Automatic update of common submodule From 6aaa286 to d8814b6 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 6aaa286970..d8814b6c7f 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 6aaa286970e59ed89bd69544f2ee10551f377cb6 +Subproject commit d8814b6c7fb8e037bd19bff6a2698f55ddb2b311 From f4577b64dfe6c5a28061ab1cb0c01433b837a0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 25 Mar 2011 09:31:03 +0100 Subject: [PATCH 49/54] Automatic update of common submodule From d8814b6 to b77e2bf --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index d8814b6c7f..b77e2bfbb7 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit d8814b6c7fb8e037bd19bff6a2698f55ddb2b311 +Subproject commit b77e2bfbb78e1093d39b7714572ed364e46df53c From ed77b14aa0eab9c662b0388f892e72c79f3d62c5 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Fri, 25 Mar 2011 12:53:43 +0200 Subject: [PATCH 50/54] cairo: fix the name of the *-marshall.list file to unbreak make distcheck --- ext/cairo/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/cairo/Makefile.am b/ext/cairo/Makefile.am index b9d97e6246..5a8d3be8f0 100644 --- a/ext/cairo/Makefile.am +++ b/ext/cairo/Makefile.am @@ -41,5 +41,5 @@ libgstcairo_la_LIBADD = \ libgstcairo_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstcairo_la_LIBTOOLFLAGS = --tag=disable-static -EXTRA_DIST = cairo-marshal.list +EXTRA_DIST = gstcairo-marshal.list From f267ccf4a2409d8257958b0142af4793f23f301d Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Fri, 25 Mar 2011 14:56:06 +0200 Subject: [PATCH 51/54] Automatic update of common submodule From b77e2bf to 193b717 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index b77e2bfbb7..193b7176e6 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit b77e2bfbb78e1093d39b7714572ed364e46df53c +Subproject commit 193b7176e61160d78a967884f1b20af76d1c7379 From 0a39cec7e3ab7f7527e9ce0eac7c4db13aca8e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 25 Mar 2011 22:22:43 +0100 Subject: [PATCH 52/54] Automatic update of common submodule From 193b717 to 1ccbe09 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 193b7176e6..1ccbe098d6 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 193b7176e61160d78a967884f1b20af76d1c7379 +Subproject commit 1ccbe098d6379612fcef09f4000da23585af980a From e7a63c34ac93a180d785b2cfc50b066fa8a7c882 Mon Sep 17 00:00:00 2001 From: Alexey Chernov <4ernov@gmail.com> Date: Sun, 27 Mar 2011 01:19:58 +0300 Subject: [PATCH 53/54] v4l2: new v4l2radio element to control analog radio devices https://bugzilla.gnome.org/show_bug.cgi?id=640118 --- docs/plugins/Makefile.am | 1 + .../gst-plugins-good-plugins-docs.sgml | 1 + .../gst-plugins-good-plugins-sections.txt | 14 + docs/plugins/inspect/plugin-video4linux2.xml | 9 +- sys/v4l2/Makefile.am | 2 + sys/v4l2/gstv4l2.c | 3 + sys/v4l2/gstv4l2radio.c | 633 ++++++++++++++++++ sys/v4l2/gstv4l2radio.h | 68 ++ 8 files changed, 730 insertions(+), 1 deletion(-) create mode 100644 sys/v4l2/gstv4l2radio.c create mode 100644 sys/v4l2/gstv4l2radio.h diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am index f620de147d..491034979a 100644 --- a/docs/plugins/Makefile.am +++ b/docs/plugins/Makefile.am @@ -229,6 +229,7 @@ EXTRA_HFILES = \ $(top_srcdir)/sys/osxvideo/osxvideosink.h \ $(top_srcdir)/sys/v4l2/gstv4l2src.h \ $(top_srcdir)/sys/v4l2/gstv4l2sink.h \ + $(top_srcdir)/sys/v4l2/gstv4l2radio.h \ $(top_srcdir)/sys/waveform/gstwaveformsink.h \ $(top_srcdir)/sys/ximage/gstximagesrc.h diff --git a/docs/plugins/gst-plugins-good-plugins-docs.sgml b/docs/plugins/gst-plugins-good-plugins-docs.sgml index 459a064c83..988bba3417 100644 --- a/docs/plugins/gst-plugins-good-plugins-docs.sgml +++ b/docs/plugins/gst-plugins-good-plugins-docs.sgml @@ -154,6 +154,7 @@ + diff --git a/docs/plugins/gst-plugins-good-plugins-sections.txt b/docs/plugins/gst-plugins-good-plugins-sections.txt index 6081c67633..b2e6de68cf 100644 --- a/docs/plugins/gst-plugins-good-plugins-sections.txt +++ b/docs/plugins/gst-plugins-good-plugins-sections.txt @@ -2048,6 +2048,20 @@ GST_IS_V4L2SINK_CLASS gst_v4l2sink_get_type +
+element-v4l2radio +v4l2radio +GstV4l2Radio + +GstV4l2RadioClass +GST_V4L2RADIO +GST_IS_V4L2RADIO +GST_TYPE_V4L2RADIO +GST_V4L2RADIO_CLASS +GST_IS_V4L2RADIO_CLASS +gst_v4l2radio_get_type +
+
element-waveformsink waveformsink diff --git a/docs/plugins/inspect/plugin-video4linux2.xml b/docs/plugins/inspect/plugin-video4linux2.xml index 5204cc02fa..8349f913d3 100644 --- a/docs/plugins/inspect/plugin-video4linux2.xml +++ b/docs/plugins/inspect/plugin-video4linux2.xml @@ -24,5 +24,12 @@ + + v4l2radio + Radio (video4linux2) Tuner + Tuner + Controls a Video4Linux2 radio device + Alexey Chernov <4ernov@gmail.com> + - \ No newline at end of file + diff --git a/sys/v4l2/Makefile.am b/sys/v4l2/Makefile.am index ab996a15a8..a7a99dea31 100644 --- a/sys/v4l2/Makefile.am +++ b/sys/v4l2/Makefile.am @@ -13,6 +13,7 @@ libgstvideo4linux2_la_SOURCES = gstv4l2.c \ gstv4l2object.c \ gstv4l2bufferpool.c \ gstv4l2src.c \ + gstv4l2radio.c \ gstv4l2tuner.c \ gstv4l2vidorient.c \ v4l2_calls.c \ @@ -51,6 +52,7 @@ noinst_HEADERS = \ gstv4l2object.h \ gstv4l2sink.h \ gstv4l2src.h \ + gstv4l2radio.h \ gstv4l2tuner.h \ gstv4l2vidorient.h \ gstv4l2xoverlay.h \ diff --git a/sys/v4l2/gstv4l2.c b/sys/v4l2/gstv4l2.c index 4a7056fd52..95f64db785 100644 --- a/sys/v4l2/gstv4l2.c +++ b/sys/v4l2/gstv4l2.c @@ -35,6 +35,7 @@ #ifdef HAVE_EXPERIMENTAL #include "gstv4l2sink.h" #endif +#include "gstv4l2radio.h" /* #include "gstv4l2jpegsrc.h" */ /* #include "gstv4l2mjpegsrc.h" */ /* #include "gstv4l2mjpegsink.h" */ @@ -58,6 +59,8 @@ plugin_init (GstPlugin * plugin) !gst_element_register (plugin, "v4l2sink", GST_RANK_NONE, GST_TYPE_V4L2SINK) || #endif + !gst_element_register (plugin, "v4l2radio", GST_RANK_NONE, + GST_TYPE_V4L2RADIO) || /* !gst_element_register (plugin, "v4l2jpegsrc", */ /* GST_RANK_NONE, GST_TYPE_V4L2JPEGSRC) || */ /* !gst_element_register (plugin, "v4l2mjpegsrc", */ diff --git a/sys/v4l2/gstv4l2radio.c b/sys/v4l2/gstv4l2radio.c new file mode 100644 index 0000000000..b1699d3814 --- /dev/null +++ b/sys/v4l2/gstv4l2radio.c @@ -0,0 +1,633 @@ +/* GStreamer v4l2 radio tuner element + * Copyright (C) 2010, 2011 Alexey Chernov <4ernov@gmail.com> + * + * gstv4l2radio.c - V4L2 radio tuner element + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:element-v4l2radio + * + * v4l2radio can be used to control radio device + * and to tune it to different radiostations. + * + * + * Example launch lines + * |[ + * gst-launch v4l2radio device=/dev/radio0 frequency=101200000 + * gst-launch alsasrc device=hw:1 ! audioconvert ! audioresample ! alsasink + * ]| + * First pipeline tunes the radio device /dev/radio0 to station 101.2 MHz, + * second pipeline connects digital audio out (hw:1) to default sound card. + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "gst/gst-i18n-plugin.h" + +#include "gstv4l2tuner.h" +#include "gstv4l2radio.h" +#include "v4l2_calls.h" + +GST_DEBUG_CATEGORY_STATIC (v4l2radio_debug); +#define GST_CAT_DEFAULT v4l2radio_debug + +#define DEFAULT_PROP_DEVICE "/dev/radio0" +#define MIN_FREQUENCY 87500000 +#define DEFAULT_FREQUENCY 100000000 +#define MAX_FREQUENCY 108000000 + +enum +{ + ARG_0, + ARG_DEVICE, + ARG_FREQUENCY +}; + +static gboolean +gst_v4l2radio_fill_channel_list (GstV4l2Radio * radio) +{ + int res; + struct v4l2_tuner vtun; + struct v4l2_capability vc; + GstV4l2TunerChannel *v4l2channel; + GstTunerChannel *channel; + + GstElement *e; + + GstV4l2Object *v4l2object; + + e = GST_ELEMENT (radio); + v4l2object = radio->v4l2object; + + GST_DEBUG_OBJECT (e, "getting audio enumeration"); + GST_V4L2_CHECK_OPEN (v4l2object); + + GST_DEBUG_OBJECT (e, " audio input"); + + memset (&vc, 0, sizeof (vc)); + + res = v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &vc); + if (res < 0) + goto caps_failed; + + if (!(vc.capabilities & V4L2_CAP_TUNER)) + goto not_a_tuner; + + /* getting audio input */ + memset (&vtun, 0, sizeof (vtun)); + vtun.index = 0; + + res = v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun); + if (res < 0) + goto tuner_failed; + + GST_LOG_OBJECT (e, " index: %d", vtun.index); + GST_LOG_OBJECT (e, " name: '%s'", vtun.name); + GST_LOG_OBJECT (e, " type: %016x", (guint) vtun.type); + GST_LOG_OBJECT (e, " caps: %016x", (guint) vtun.capability); + GST_LOG_OBJECT (e, " rlow: %016x", (guint) vtun.rangelow); + GST_LOG_OBJECT (e, " rhigh: %016x", (guint) vtun.rangehigh); + GST_LOG_OBJECT (e, " audmode: %016x", (guint) vtun.audmode); + + v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL); + channel = GST_TUNER_CHANNEL (v4l2channel); + channel->label = g_strdup ((const gchar *) vtun.name); + channel->flags = GST_TUNER_CHANNEL_FREQUENCY | GST_TUNER_CHANNEL_AUDIO; + v4l2channel->index = 0; + v4l2channel->tuner = 0; + + channel->freq_multiplicator = + 62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW) ? 1 : 1000); + channel->min_frequency = vtun.rangelow * channel->freq_multiplicator; + channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator; + channel->min_signal = 0; + channel->max_signal = 0xffff; + + v4l2object->channels = + g_list_prepend (v4l2object->channels, (gpointer) channel); + + v4l2object->channels = g_list_reverse (v4l2object->channels); + + GST_DEBUG_OBJECT (e, "done"); + return TRUE; + + /* ERRORS */ +tuner_failed: + { + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, + (_("Failed to get settings of tuner %d on device '%s'."), + vtun.index, v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +caps_failed: + { + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, + (_("Error getting capabilities for device '%s'."), + v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +not_a_tuner: + { + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, + (_("Device '%s' is not a tuner."), + v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + +static gboolean +gst_v4l2radio_get_input (GstV4l2Object * v4l2object, gint * input) +{ + GST_DEBUG_OBJECT (v4l2object->element, "trying to get radio input"); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (!v4l2object->channels) + goto input_failed; + + *input = 0; + + GST_DEBUG_OBJECT (v4l2object->element, "input: %d", 0); + + return TRUE; + + /* ERRORS */ +input_failed: + { + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to get radio input on device '%s'. "), + v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + +static gboolean +gst_v4l2radio_set_input (GstV4l2Object * v4l2object, gint input) +{ + GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (!v4l2object->channels) + goto input_failed; + + return TRUE; + + /* ERRORS */ +input_failed: + { + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to set input %d on device %s."), + input, v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + +static gboolean +gst_v4l2radio_set_mute_on (GstV4l2Radio * radio, gboolean on) +{ + gint res; + struct v4l2_control vctrl; + + GST_DEBUG_OBJECT (radio, "setting current tuner mute state: %d", on); + + if (!GST_V4L2_IS_OPEN (radio->v4l2object)) + return FALSE; + + memset (&vctrl, 0, sizeof (vctrl)); + vctrl.id = V4L2_CID_AUDIO_MUTE; + vctrl.value = on; + + GST_DEBUG_OBJECT (radio, "radio fd: %d", radio->v4l2object->video_fd); + + res = ioctl (radio->v4l2object->video_fd, VIDIOC_S_CTRL, &vctrl); + GST_DEBUG_OBJECT (radio, "mute state change result: %d", res); + if (res < 0) + goto freq_failed; + + return TRUE; + + /* ERRORS */ +freq_failed: + { + GST_ELEMENT_WARNING (radio, RESOURCE, SETTINGS, + (_("Failed to change mute state for device '%s'."), + radio->v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + +static gboolean +gst_v4l2radio_set_mute (GstV4l2Radio * radio) +{ + return gst_v4l2radio_set_mute_on (radio, TRUE); +} + +static gboolean +gst_v4l2radio_set_unmute (GstV4l2Radio * radio) +{ + return gst_v4l2radio_set_mute_on (radio, FALSE); +} + +GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2RadioClass, gst_v4l2radio); +GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Radio, gst_v4l2radio); + +static void gst_v4l2radio_uri_handler_init (gpointer g_iface, + gpointer iface_data); + +static gboolean +gst_v4l2radio_interface_supported (GstImplementsInterface * iface, + GType iface_type) +{ + if (iface_type == GST_TYPE_TUNER) + return TRUE; + else + return FALSE; +} + +static void +gst_v4l2radio_implements_interface_init (GstImplementsInterfaceClass * iface) +{ + iface->supported = gst_v4l2radio_interface_supported; +} + +static void +gst_v4l2radio_tuner_interface_reinit (GstTunerClass * iface) +{ + gst_v4l2radio_tuner_interface_init (iface); +} + +static void +gst_v4l2radio_interfaces (GType type) +{ + static const GInterfaceInfo urihandler_info = { + (GInterfaceInitFunc) gst_v4l2radio_uri_handler_init, + NULL, + NULL + }; + + static const GInterfaceInfo implements_interface_info = { + (GInterfaceInitFunc) gst_v4l2radio_implements_interface_init, + NULL, + NULL, + }; + + static const GInterfaceInfo propertyprobe_info = { + (GInterfaceInitFunc) gst_v4l2radio_property_probe_interface_init, + NULL, + NULL, + }; + + static const GInterfaceInfo tuner_interface_info = { + (GInterfaceInitFunc) gst_v4l2radio_tuner_interface_reinit, + NULL, + NULL, + }; + + g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info); + g_type_add_interface_static (type, + GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info); + + g_type_add_interface_static (type, GST_TYPE_TUNER, &tuner_interface_info); + + g_type_add_interface_static (type, + GST_TYPE_PROPERTY_PROBE, &propertyprobe_info); +} + +GST_BOILERPLATE_FULL (GstV4l2Radio, gst_v4l2radio, GstElement, GST_TYPE_ELEMENT, + gst_v4l2radio_interfaces); + +static void gst_v4l2radio_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_v4l2radio_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_v4l2radio_finalize (GstV4l2Radio * radio); +static void gst_v4l2radio_dispose (GObject * object); +static GstStateChangeReturn gst_v4l2radio_change_state (GstElement * element, + GstStateChange transition); + +static void +gst_v4l2radio_base_init (gpointer gclass) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (gclass); + GstV4l2RadioClass *gstv4l2radio_class = GST_V4L2RADIO_CLASS (gclass); + + GST_DEBUG_CATEGORY_INIT (v4l2radio_debug, "v4l2radio", 0, + "V4l2 radio element"); + + gstv4l2radio_class->v4l2_class_devices = NULL; + + gst_element_class_set_details_simple (gstelement_class, + "Radio (video4linux2) Tuner", + "Tuner", + "Controls a Video4Linux2 radio device", + "Alexey Chernov <4ernov@gmail.com>"); +} + +static void +gst_v4l2radio_class_init (GstV4l2RadioClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + gobject_class->set_property = gst_v4l2radio_set_property; + gobject_class->get_property = gst_v4l2radio_get_property; + + g_object_class_install_property (gobject_class, ARG_DEVICE, + g_param_spec_string ("device", "Radio device location", + "Video4Linux2 radio device location", + DEFAULT_PROP_DEVICE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, ARG_FREQUENCY, + g_param_spec_int ("frequency", "Station frequency", + "Station frequency in Hz", + MIN_FREQUENCY, MAX_FREQUENCY, DEFAULT_FREQUENCY, G_PARAM_READWRITE)); + + gobject_class->dispose = gst_v4l2radio_dispose; + gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2radio_finalize; + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_v4l2radio_change_state); + +} + +static void +gst_v4l2radio_init (GstV4l2Radio * filter, GstV4l2RadioClass * gclass) +{ + filter->v4l2object = gst_v4l2_object_new (GST_ELEMENT (filter), + V4L2_BUF_TYPE_VIDEO_CAPTURE, DEFAULT_PROP_DEVICE, + gst_v4l2radio_get_input, gst_v4l2radio_set_input, NULL); + + filter->v4l2object->frequency = DEFAULT_FREQUENCY; + filter->v4l2object->videodev = g_strdup (DEFAULT_PROP_DEVICE); +} + +static void +gst_v4l2radio_dispose (GObject * object) +{ + GstV4l2Radio *radio = GST_V4L2RADIO (object); + gst_v4l2_close (radio->v4l2object); + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_v4l2radio_finalize (GstV4l2Radio * radio) +{ + gst_v4l2_object_destroy (radio->v4l2object); + G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (radio)); +} + +static gboolean +gst_v4l2radio_open (GstV4l2Radio * radio) +{ + GstV4l2Object *v4l2object; + + v4l2object = radio->v4l2object; + if (gst_v4l2_open (v4l2object)) + return gst_v4l2radio_fill_channel_list (radio); + else + return FALSE; +} + +static void +gst_v4l2radio_set_defaults (GstV4l2Radio * radio) +{ + GstV4l2Object *v4l2object; + GstTunerChannel *channel = NULL; + GstTuner *tuner; + + v4l2object = radio->v4l2object; + + if (!GST_IS_TUNER (v4l2object->element)) + return; + + tuner = GST_TUNER (v4l2object->element); + + if (v4l2object->channel) + channel = gst_tuner_find_channel_by_name (tuner, v4l2object->channel); + if (channel) { + gst_tuner_set_channel (tuner, channel); + } else { + channel = + GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER + (v4l2object->element))); + if (channel) { + g_free (v4l2object->channel); + v4l2object->channel = g_strdup (channel->label); + gst_tuner_channel_changed (tuner, channel); + } + } + + if (channel + && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { + if (v4l2object->frequency != 0) { + gst_tuner_set_frequency (tuner, channel, v4l2object->frequency); + } else { + v4l2object->frequency = gst_tuner_get_frequency (tuner, channel); + if (v4l2object->frequency == 0) { + /* guess */ + gst_tuner_set_frequency (tuner, channel, MIN_FREQUENCY); + } else { + } + } + } +} + +static gboolean +gst_v4l2radio_start (GstV4l2Radio * radio) +{ + if (!gst_v4l2radio_open (radio)) + return FALSE; + + gst_v4l2radio_set_defaults (radio); + + return TRUE; +} + +static gboolean +gst_v4l2radio_stop (GstV4l2Radio * radio) +{ + if (!gst_v4l2_object_stop (radio->v4l2object)) + return FALSE; + + return TRUE; +} + +static GstStateChangeReturn +gst_v4l2radio_change_state (GstElement * element, GstStateChange transition) +{ + GstV4l2Radio *radio; + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + radio = GST_V4L2RADIO (element); + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + /*start radio */ + if (!gst_v4l2radio_start (radio)) + ret = GST_STATE_CHANGE_FAILURE; + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + /*unmute radio */ + if (!gst_v4l2radio_set_unmute (radio)) + ret = GST_STATE_CHANGE_FAILURE; + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + /*mute radio */ + if (!gst_v4l2radio_set_mute (radio)) + ret = GST_STATE_CHANGE_FAILURE; + break; + case GST_STATE_CHANGE_READY_TO_NULL: + /*stop radio */ + if (!gst_v4l2radio_stop (radio)) + ret = GST_STATE_CHANGE_FAILURE; + break; + default: + break; + } + + return ret; +} + +static void +gst_v4l2radio_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstV4l2Radio *radio = GST_V4L2RADIO (object); + gint frequency; + switch (prop_id) { + case ARG_DEVICE: + radio->v4l2object->videodev = + g_strdup ((gchar *) g_value_get_string (value)); + break; + case ARG_FREQUENCY: + frequency = g_value_get_int (value); + if (frequency >= MIN_FREQUENCY && frequency <= MAX_FREQUENCY) { + radio->v4l2object->frequency = frequency; + gst_v4l2_set_frequency (radio->v4l2object, 0, + radio->v4l2object->frequency); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_v4l2radio_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstV4l2Radio *radio = GST_V4L2RADIO (object); + + switch (prop_id) { + case ARG_DEVICE: + g_value_set_string (value, radio->v4l2object->videodev); + break; + case ARG_FREQUENCY: + if (gst_v4l2_get_frequency (radio->v4l2object, + 0, &(radio->v4l2object->frequency))) + g_value_set_int (value, radio->v4l2object->frequency); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/* GstURIHandler interface */ +static GstURIType +gst_v4l2radio_uri_get_type (void) +{ + return GST_URI_SRC; +} + +static gchar ** +gst_v4l2radio_uri_get_protocols (void) +{ + static gchar *protocols[] = { (char *) "radio", NULL }; + return protocols; +} + +static const gchar * +gst_v4l2radio_uri_get_uri (GstURIHandler * handler) +{ + GstV4l2Radio *radio = GST_V4L2RADIO (handler); + + if (radio->v4l2object->videodev != NULL) { + if (gst_v4l2_get_frequency (radio->v4l2object, + 0, &(radio->v4l2object->frequency))) { + gchar uri[20]; + gchar freq[6]; + g_ascii_formatd (freq, 6, "%4.1f", radio->v4l2object->frequency / 1e6); + g_snprintf (uri, sizeof (uri), "radio://%s", freq); + return g_intern_string (uri); + } + } + + return "radio://"; +} + +static gboolean +gst_v4l2radio_uri_set_uri (GstURIHandler * handler, const gchar * uri) +{ + GstV4l2Radio *radio = GST_V4L2RADIO (handler); + gdouble dfreq; + gint ifreq; + const gchar *freq; + gchar *end; + + if (strcmp (uri, "radio://") != 0) { + freq = uri + 8; + + dfreq = g_ascii_strtod (freq, &end); + + if (errno || strlen (end)) + goto uri_failed; + + ifreq = dfreq * 1e6; + g_object_set (radio, "frequency", ifreq, NULL); + + } else + goto uri_failed; + + return TRUE; + +uri_failed: + return FALSE; +} + +static void +gst_v4l2radio_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_v4l2radio_uri_get_type; + iface->get_protocols = gst_v4l2radio_uri_get_protocols; + iface->get_uri = gst_v4l2radio_uri_get_uri; + iface->set_uri = gst_v4l2radio_uri_set_uri; +} diff --git a/sys/v4l2/gstv4l2radio.h b/sys/v4l2/gstv4l2radio.h new file mode 100644 index 0000000000..f1c99a277f --- /dev/null +++ b/sys/v4l2/gstv4l2radio.h @@ -0,0 +1,68 @@ +/* GStreamer v4l2 radio tuner element + * Copyright (C) 2010, 2011 Alexey Chernov <4ernov@gmail.com> + * + * gstv4l2radio.h - V4L2 radio tuner element + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_V4L2RADIO_H__ +#define __GST_V4L2RADIO_H__ + +#include "gstv4l2object.h" + +G_BEGIN_DECLS + +#define GST_TYPE_V4L2RADIO \ + (gst_v4l2radio_get_type()) +#define GST_V4L2RADIO(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2RADIO,GstV4l2Radio)) +#define GST_V4L2RADIO_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2RADIO,GstV4l2RadioClass)) +#define GST_IS_V4L2RADIO(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2RADIO)) +#define GST_IS_V4L2RADIO_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2RADIO)) + +typedef struct _GstV4l2Radio GstV4l2Radio; +typedef struct _GstV4l2RadioClass GstV4l2RadioClass; + +/** + * GstV4l2Radio: + * @v4l2object: private #GstV4l2Object + * + * Opaque video4linux2 radio tuner element + */ +struct _GstV4l2Radio +{ + GstElement element; + + /*< private >*/ + GstV4l2Object * v4l2object; +}; + +struct _GstV4l2RadioClass +{ + GstElementClass parent_class; + + GList *v4l2_class_devices; +}; + +GType gst_v4l2radio_get_type (void); + +G_END_DECLS + +#endif /* __GST_V4L2RADIO_H__ */ From 9c5a12c11ff971bf93b3275b7b6a3fcc25cff8f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Urba=C5=84ski?= Date: Sun, 27 Mar 2011 21:39:50 +0200 Subject: [PATCH 54/54] flvdemux: Do not build an index if upstream is not seekable An index is not useful if upstream cannot handle seeks and building it for infinite files, for instance FLV streams, results in a memory leak. --- gst/flv/gstflvdemux.c | 43 +++++++++++++++++++++++++++++++++++++++++++ gst/flv/gstflvdemux.h | 1 + 2 files changed, 44 insertions(+) diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c index 87ebf0e869..79f83bc2b8 100644 --- a/gst/flv/gstflvdemux.c +++ b/gst/flv/gstflvdemux.c @@ -103,6 +103,10 @@ gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts, "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT, keyframe, GST_TIME_ARGS (ts), pos); + /* if upstream is not seekable there is no point in building an index */ + if (!demux->upstream_seekable) + return; + /* entry may already have been added before, avoid adding indefinitely */ entry = gst_index_get_assoc_entry (demux->index, demux->index_id, GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos); @@ -186,6 +190,41 @@ gst_flv_demux_query_types (GstPad * pad) return query_types; } +static void +gst_flv_demux_check_seekability (GstFlvDemux * demux) +{ + GstQuery *query; + gint64 start = -1, stop = -1; + + demux->upstream_seekable = FALSE; + + query = gst_query_new_seeking (GST_FORMAT_BYTES); + if (!gst_pad_peer_query (demux->sinkpad, query)) { + GST_DEBUG_OBJECT (demux, "seeking query failed"); + return; + } + + gst_query_parse_seeking (query, NULL, &demux->upstream_seekable, + &start, &stop); + + /* try harder to query upstream size if we didn't get it the first time */ + if (demux->upstream_seekable && stop == -1) { + GstFormat fmt = GST_FORMAT_BYTES; + + GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop"); + gst_pad_query_peer_duration (demux->sinkpad, &fmt, &stop); + } + + /* if upstream doesn't know the size, it's likely that it's not seekable in + * practice even if it technically may be seekable */ + if (demux->upstream_seekable && (start != 0 || stop <= start)) { + GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable"); + demux->upstream_seekable = FALSE; + } + + GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable); +} + static void parse_flv_demux_parse_date_string (GDate * date, const gchar * s) { @@ -1491,6 +1530,9 @@ gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer) } } + /* do a one-time seekability check */ + gst_flv_demux_check_seekability (demux); + /* We don't care about the rest */ demux->need_header = FALSE; @@ -1544,6 +1586,7 @@ gst_flv_demux_cleanup (GstFlvDemux * demux) demux->got_par = FALSE; demux->indexed = FALSE; + demux->upstream_seekable = FALSE; demux->file_size = 0; demux->index_max_pos = 0; diff --git a/gst/flv/gstflvdemux.h b/gst/flv/gstflvdemux.h index dadff9428e..10ff306a2b 100644 --- a/gst/flv/gstflvdemux.h +++ b/gst/flv/gstflvdemux.h @@ -123,6 +123,7 @@ struct _GstFlvDemux gboolean seeking; gboolean building_index; gboolean indexed; /* TRUE if index is completely built */ + gboolean upstream_seekable; /* TRUE if upstream is seekable */ gint64 file_size; GstEvent *seek_event; gint64 seek_time;