/* GstBaseTransform vmethod implementations */ static GstFlowReturn gst_audio_echo_transform_ip (GstBaseTransform * base, GstBuffer * buf) { GstAudioEcho *self = GST_AUDIO_ECHO (base); guint num_samples; GstClockTime timestamp, stream_time; GstMapInfo map; g_mutex_lock (&self->lock); timestamp = GST_BUFFER_TIMESTAMP (buf); stream_time = gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp); GST_DEBUG_OBJECT (self, "sync to %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); if (GST_CLOCK_TIME_IS_VALID (stream_time)) gst_object_sync_values (GST_OBJECT (self), stream_time); if (self->buffer == NULL) { guint bpf, rate; bpf = GST_AUDIO_FILTER_BPF (self); rate = GST_AUDIO_FILTER_RATE (self); self->delay_frames = MAX (gst_util_uint64_scale (self->delay, rate, GST_SECOND), 1); self->buffer_size_frames = MAX (gst_util_uint64_scale (self->max_delay, rate, GST_SECOND), 1); self->buffer_size = self->buffer_size_frames * bpf; self->buffer = g_try_malloc0 (self->buffer_size); self->buffer_pos = 0; if (self->buffer == NULL) { g_mutex_unlock (&self->lock); GST_ERROR_OBJECT (self, "Failed to allocate %u bytes", self->buffer_size); return GST_FLOW_ERROR; } } gst_buffer_map (buf, &map, GST_MAP_READWRITE); num_samples = map.size / GST_AUDIO_FILTER_BPS (self); self->process (self, map.data, num_samples); gst_buffer_unmap (buf, &map); g_mutex_unlock (&self->lock); return GST_FLOW_OK; }
static GstFlowReturn gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer) { GstSpectrum *spectrum = GST_SPECTRUM (trans); guint rate = GST_AUDIO_FILTER_RATE (spectrum); guint channels = GST_AUDIO_FILTER_CHANNELS (spectrum); guint bps = GST_AUDIO_FILTER_BPS (spectrum); guint bpf = GST_AUDIO_FILTER_BPF (spectrum); guint output_channels = spectrum->multi_channel ? channels : 1; guint c; gfloat max_value = (1UL << ((bps << 3) - 1)) - 1; guint bands = spectrum->bands; guint nfft = 2 * bands - 2; guint input_pos; gfloat *input; GstMapInfo map; const guint8 *data; gsize size; guint fft_todo, msg_todo, block_size; gboolean have_full_interval; GstSpectrumChannel *cd; GstSpectrumInputData input_data; g_mutex_lock (&spectrum->lock); gst_buffer_map (buffer, &map, GST_MAP_READ); data = map.data; size = map.size; GST_LOG_OBJECT (spectrum, "input size: %" G_GSIZE_FORMAT " bytes", size); if (GST_BUFFER_IS_DISCONT (buffer)) { GST_DEBUG_OBJECT (spectrum, "Discontinuity detected -- flushing"); gst_spectrum_flush (spectrum); } /* 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->channel_data == NULL) { GST_DEBUG_OBJECT (spectrum, "allocating for bands %u", bands); 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); spectrum->frames_todo = spectrum->frames_per_interval; /* 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; 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); } if (spectrum->num_frames == 0) spectrum->message_ts = GST_BUFFER_TIMESTAMP (buffer); input_pos = spectrum->input_pos; input_data = spectrum->input_data; while (size >= bpf) { /* 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 %" G_GSIZE_FORMAT, msg_todo, fft_todo, (size / bpf)); block_size = msg_todo; if (block_size > (size / bpf)) block_size = (size / bpf); if (block_size > fft_todo) block_size = fft_todo; 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 * bps, input, block_size, channels, max_value, input_pos, nfft); } data += block_size * bpf; size -= block_size * bpf; 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: %" G_GSIZE_FORMAT ", 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); for (c = 0; c < output_channels; c++) { cd = &spectrum->channel_data[c]; gst_spectrum_reset_message_data (spectrum, cd); } spectrum->num_frames = 0; spectrum->num_fft = 0; } } spectrum->input_pos = input_pos; gst_buffer_unmap (buffer, &map); g_mutex_unlock (&spectrum->lock); g_assert (size == 0); return GST_FLOW_OK; }