From 92fa187d11943a1a3f5387ea0b8b5f5fbabd6ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 14 Jan 2015 16:01:07 +0100 Subject: [PATCH] decklinkvideosink: Don't schedule too late frames in prepare() Otherwise we will overflow the internal buffer of the hardware with useless frames and run into an error. This is necessary until this bug in basesink is fixed: https://bugzilla.gnome.org/show_bug.cgi?id=742916 --- sys/decklink/gstdecklinkvideosink.cpp | 67 +++++++++++++++++++++------ sys/decklink/gstdecklinkvideosink.h | 1 + 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/sys/decklink/gstdecklinkvideosink.cpp b/sys/decklink/gstdecklinkvideosink.cpp index 69f8f3a698..d9b77ef27c 100644 --- a/sys/decklink/gstdecklinkvideosink.cpp +++ b/sys/decklink/gstdecklinkvideosink.cpp @@ -272,6 +272,7 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer) GstClockTime timestamp, duration; GstClockTime running_time, running_time_duration; gint i; + GstClock *clock; GST_DEBUG_OBJECT (self, "Preparing buffer %p", buffer); @@ -280,6 +281,57 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer) return GST_FLOW_ERROR; } + timestamp = GST_BUFFER_TIMESTAMP (buffer); + duration = GST_BUFFER_DURATION (buffer); + if (duration == GST_CLOCK_TIME_NONE) { + duration = + gst_util_uint64_scale_int (GST_SECOND, self->info.fps_d, + self->info.fps_n); + } + running_time = + gst_segment_to_running_time (&GST_BASE_SINK_CAST (self)->segment, + GST_FORMAT_TIME, timestamp); + running_time_duration = + gst_segment_to_running_time (&GST_BASE_SINK_CAST (self)->segment, + GST_FORMAT_TIME, timestamp + duration) - running_time; + + // FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=742916 + // We need to drop late buffers here immediately instead of + // potentially overflowing the internal queue of the hardware + clock = gst_element_get_clock (GST_ELEMENT_CAST (self)); + if (clock) { + GstClockTime clock_running_time, latency; + + clock_running_time = gst_element_get_base_time (GST_ELEMENT_CAST (self)); + if (clock_running_time != GST_CLOCK_TIME_NONE) { + clock_running_time = gst_clock_get_time (clock) - clock_running_time; + latency = gst_base_sink_get_latency (GST_BASE_SINK_CAST (self)); + + if (clock_running_time > running_time + running_time_duration + latency) { + GST_DEBUG_OBJECT (self, + "Late buffer: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT, + GST_TIME_ARGS (clock_running_time), + GST_TIME_ARGS (running_time + running_time_duration)); + + if (self->last_render_time == GST_CLOCK_TIME_NONE + || (self->last_render_time < clock_running_time + && clock_running_time - self->last_render_time >= GST_SECOND)) { + GST_DEBUG_OBJECT (self, + "Rendering frame nonetheless because we had none for more than 1s"); + running_time = clock_running_time; + running_time_duration = 0; + } else { + GST_WARNING_OBJECT (self, "Dropping frame"); + gst_object_unref (clock); + return GST_FLOW_OK; + } + } + } + + gst_object_unref (clock); + } + self->last_render_time = running_time; + ret = self->output->output->CreateVideoFrame (self->info.width, self->info.height, self->info.stride[0], bmdFormat8BitYUV, bmdFrameFlagDefault, &frame); @@ -304,20 +356,6 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer) } gst_video_frame_unmap (&vframe); - timestamp = GST_BUFFER_TIMESTAMP (buffer); - duration = GST_BUFFER_DURATION (buffer); - if (duration == GST_CLOCK_TIME_NONE) { - duration = - gst_util_uint64_scale_int (GST_SECOND, self->info.fps_d, - self->info.fps_n); - } - running_time = - gst_segment_to_running_time (&GST_BASE_SINK_CAST (self)->segment, - GST_FORMAT_TIME, timestamp); - running_time_duration = - gst_segment_to_running_time (&GST_BASE_SINK_CAST (self)->segment, - GST_FORMAT_TIME, timestamp + duration) - running_time; - convert_to_internal_clock (self, &running_time, &running_time_duration); GST_LOG_OBJECT (self, "Scheduling video frame %p at %" GST_TIME_FORMAT @@ -507,6 +545,7 @@ gst_decklink_video_sink_change_state (GstElement * element, gst_element_post_message (element, gst_message_new_clock_provide (GST_OBJECT_CAST (element), self->output->clock, TRUE)); + self->last_render_time = GST_CLOCK_TIME_NONE; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING:{ GstClock *clock, *audio_clock; diff --git a/sys/decklink/gstdecklinkvideosink.h b/sys/decklink/gstdecklinkvideosink.h index 16b2fbb3fe..04d5c972e0 100644 --- a/sys/decklink/gstdecklinkvideosink.h +++ b/sys/decklink/gstdecklinkvideosink.h @@ -56,6 +56,7 @@ struct _GstDecklinkVideoSink GstClockTime internal_base_time; GstClockTime external_base_time; + GstClockTime last_render_time; GstDecklinkOutput *output; };