mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
decklinkaudiosink: Throttle reading from the ringbuffer
The driver has an internal buffer of unspecified and unconfigurable size, and it will pull data from our ring buffer as fast as it can until that is full. Unfortunately that means that we pull silence from the ringbuffer unless its size is by conincidence larger than the driver's internal ringbuffer. The good news is that it's not required to completely fill the buffer for proper playback. So we now throttle reading from the ringbuffer whenever the driver has buffered more than half of our ringbuffer size by waiting on the clock for the amount of time until it has buffered less than that again.
This commit is contained in:
parent
a6bcd09b6c
commit
4de7fdfa3a
1 changed files with 60 additions and 0 deletions
|
@ -54,6 +54,9 @@ struct _GstDecklinkAudioSinkRingBuffer
|
||||||
|
|
||||||
GstDecklinkOutput *output;
|
GstDecklinkOutput *output;
|
||||||
GstDecklinkAudioSink *sink;
|
GstDecklinkAudioSink *sink;
|
||||||
|
|
||||||
|
GMutex clock_id_lock;
|
||||||
|
GstClockID clock_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstDecklinkAudioSinkRingBufferClass
|
struct _GstDecklinkAudioSinkRingBufferClass
|
||||||
|
@ -122,6 +125,7 @@ static void
|
||||||
static void
|
static void
|
||||||
gst_decklink_audio_sink_ringbuffer_init (GstDecklinkAudioSinkRingBuffer * self)
|
gst_decklink_audio_sink_ringbuffer_init (GstDecklinkAudioSinkRingBuffer * self)
|
||||||
{
|
{
|
||||||
|
g_mutex_init (&self->clock_id_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -132,6 +136,7 @@ gst_decklink_audio_sink_ringbuffer_finalize (GObject * object)
|
||||||
|
|
||||||
gst_object_unref (self->sink);
|
gst_object_unref (self->sink);
|
||||||
self->sink = NULL;
|
self->sink = NULL;
|
||||||
|
g_mutex_clear (&self->clock_id_lock);
|
||||||
|
|
||||||
G_OBJECT_CLASS (ringbuffer_parent_class)->finalize (object);
|
G_OBJECT_CLASS (ringbuffer_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
@ -193,10 +198,60 @@ public:
|
||||||
gint bpf;
|
gint bpf;
|
||||||
guint written, written_sum;
|
guint written, written_sum;
|
||||||
HRESULT res;
|
HRESULT res;
|
||||||
|
const GstAudioRingBufferSpec *spec =
|
||||||
|
&GST_AUDIO_RING_BUFFER_CAST (m_ringbuffer)->spec;
|
||||||
|
guint delay, max_delay;
|
||||||
|
|
||||||
GST_LOG_OBJECT (m_ringbuffer->sink, "Writing audio samples (preroll: %d)",
|
GST_LOG_OBJECT (m_ringbuffer->sink, "Writing audio samples (preroll: %d)",
|
||||||
preroll);
|
preroll);
|
||||||
|
|
||||||
|
delay =
|
||||||
|
gst_audio_ring_buffer_delay (GST_AUDIO_RING_BUFFER_CAST (m_ringbuffer));
|
||||||
|
max_delay = MAX ((spec->segtotal * spec->segsize) / 2, spec->segsize);
|
||||||
|
max_delay /= GST_AUDIO_INFO_BPF (&spec->info);
|
||||||
|
if (delay > max_delay) {
|
||||||
|
GstClock *clock =
|
||||||
|
gst_element_get_clock (GST_ELEMENT_CAST (m_ringbuffer->sink));
|
||||||
|
GstClockTime wait_time;
|
||||||
|
GstClockID clock_id;
|
||||||
|
GstClockReturn clock_ret;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (m_ringbuffer->sink, "Delay %u > max delay %u", delay,
|
||||||
|
max_delay);
|
||||||
|
|
||||||
|
wait_time =
|
||||||
|
gst_util_uint64_scale (delay - max_delay, GST_SECOND,
|
||||||
|
GST_AUDIO_INFO_RATE (&spec->info));
|
||||||
|
GST_DEBUG_OBJECT (m_ringbuffer->sink, "Waiting for %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (wait_time));
|
||||||
|
wait_time += gst_clock_get_time (clock);
|
||||||
|
|
||||||
|
g_mutex_lock (&m_ringbuffer->clock_id_lock);
|
||||||
|
if (!GST_AUDIO_RING_BUFFER_CAST (m_ringbuffer)->acquired) {
|
||||||
|
GST_DEBUG_OBJECT (m_ringbuffer->sink,
|
||||||
|
"Ringbuffer not acquired anymore");
|
||||||
|
g_mutex_unlock (&m_ringbuffer->clock_id_lock);
|
||||||
|
gst_object_unref (clock);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
clock_id = gst_clock_new_single_shot_id (clock, wait_time);
|
||||||
|
m_ringbuffer->clock_id = clock_id;
|
||||||
|
g_mutex_unlock (&m_ringbuffer->clock_id_lock);
|
||||||
|
gst_object_unref (clock);
|
||||||
|
|
||||||
|
clock_ret = gst_clock_id_wait (clock_id, NULL);
|
||||||
|
|
||||||
|
g_mutex_lock (&m_ringbuffer->clock_id_lock);
|
||||||
|
gst_clock_id_unref (clock_id);
|
||||||
|
m_ringbuffer->clock_id = NULL;
|
||||||
|
g_mutex_unlock (&m_ringbuffer->clock_id_lock);
|
||||||
|
|
||||||
|
if (clock_ret == GST_CLOCK_UNSCHEDULED) {
|
||||||
|
GST_DEBUG_OBJECT (m_ringbuffer->sink, "Flushing");
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!gst_audio_ring_buffer_prepare_read (GST_AUDIO_RING_BUFFER_CAST
|
if (!gst_audio_ring_buffer_prepare_read (GST_AUDIO_RING_BUFFER_CAST
|
||||||
(m_ringbuffer), &seg, &ptr, &len)) {
|
(m_ringbuffer), &seg, &ptr, &len)) {
|
||||||
GST_WARNING_OBJECT (m_ringbuffer->sink, "No segment available");
|
GST_WARNING_OBJECT (m_ringbuffer->sink, "No segment available");
|
||||||
|
@ -392,6 +447,11 @@ gst_decklink_audio_sink_ringbuffer_release (GstAudioRingBuffer * rb)
|
||||||
GST_DEBUG_OBJECT (self->sink, "Release");
|
GST_DEBUG_OBJECT (self->sink, "Release");
|
||||||
|
|
||||||
if (self->output) {
|
if (self->output) {
|
||||||
|
g_mutex_lock (&self->clock_id_lock);
|
||||||
|
if (self->clock_id)
|
||||||
|
gst_clock_id_unschedule (self->clock_id);
|
||||||
|
g_mutex_unlock (&self->clock_id_lock);
|
||||||
|
|
||||||
g_mutex_lock (&self->output->lock);
|
g_mutex_lock (&self->output->lock);
|
||||||
self->output->audio_enabled = FALSE;
|
self->output->audio_enabled = FALSE;
|
||||||
if (self->output->start_scheduled_playback)
|
if (self->output->start_scheduled_playback)
|
||||||
|
|
Loading…
Reference in a new issue