diff options
author | Sebastian Dröge <sebastian@centricular.com> | 2020-10-19 18:23:25 +0300 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2020-10-19 22:04:55 +0300 |
commit | d885cc0f1ad68b60f54ac533e3ef252ff52e9853 (patch) | |
tree | 94439d35870e89c335983eabbcfd767e1235f719 /sys | |
parent | bcb3428ed06e59945dc1c6034f6e68c0e9d3a964 (diff) |
v4l2codec: Garbage collect old frames if they accumulate because of codec bugs
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/778>
Diffstat (limited to 'sys')
-rw-r--r-- | sys/v4l2/gstv4l2videodec.c | 36 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2videoenc.c | 35 |
2 files changed, 70 insertions, 1 deletions
diff --git a/sys/v4l2/gstv4l2videodec.c b/sys/v4l2/gstv4l2videodec.c index 4f0ff30c2..89ad3e817 100644 --- a/sys/v4l2/gstv4l2videodec.c +++ b/sys/v4l2/gstv4l2videodec.c @@ -472,6 +472,22 @@ gst_v4l2_video_dec_drain (GstVideoDecoder * decoder) return GST_FLOW_OK; } +static gboolean +check_system_frame_number_too_old (guint32 current, guint32 old) +{ + guint32 absdiff = current > old ? current - old : old - current; + + /* More than 100 frames in the past, or current wrapped around */ + if (absdiff > 100) { + /* Wraparound and difference is actually smaller than 100 */ + if (absdiff > G_MAXUINT32 - 100) + return FALSE; + return TRUE; + } + + return FALSE; +} + static void gst_v4l2_video_dec_loop (GstVideoDecoder * decoder) { @@ -517,11 +533,29 @@ gst_v4l2_video_dec_loop (GstVideoDecoder * decoder) GST_LOG_OBJECT (decoder, "Got buffer for frame number %u", (guint32) (GST_BUFFER_TIMESTAMP (buffer) / GST_SECOND)); - /* FIXME: Add garbage collection for the frames */ frame = gst_video_decoder_get_frame (decoder, GST_BUFFER_TIMESTAMP (buffer) / GST_SECOND); if (frame) { + GstVideoCodecFrame *oldest_frame; + gboolean warned = FALSE; + + /* Garbage collect old frames in case of codec bugs */ + while ((oldest_frame = gst_video_decoder_get_oldest_frame (decoder)) && + check_system_frame_number_too_old (frame->system_frame_number, + oldest_frame->system_frame_number)) { + gst_video_decoder_drop_frame (decoder, oldest_frame); + oldest_frame = NULL; + + if (!warned) { + g_warning ("%s: Too old frames, bug in decoder -- please file a bug", + GST_ELEMENT_NAME (decoder)); + warned = TRUE; + } + } + if (oldest_frame) + gst_video_codec_frame_unref (oldest_frame); + frame->output_buffer = buffer; buffer = NULL; ret = gst_video_decoder_finish_frame (decoder, frame); diff --git a/sys/v4l2/gstv4l2videoenc.c b/sys/v4l2/gstv4l2videoenc.c index 193d1f723..117d1400a 100644 --- a/sys/v4l2/gstv4l2videoenc.c +++ b/sys/v4l2/gstv4l2videoenc.c @@ -612,6 +612,22 @@ not_negotiated: return FALSE; } +static gboolean +check_system_frame_number_too_old (guint32 current, guint32 old) +{ + guint32 absdiff = current > old ? current - old : old - current; + + /* More than 100 frames in the past, or current wrapped around */ + if (absdiff > 100) { + /* Wraparound and difference is actually smaller than 100 */ + if (absdiff > G_MAXUINT32 - 100) + return FALSE; + return TRUE; + } + + return FALSE; +} + static void gst_v4l2_video_enc_loop (GstVideoEncoder * encoder) { @@ -650,6 +666,25 @@ gst_v4l2_video_enc_loop (GstVideoEncoder * encoder) GST_BUFFER_TIMESTAMP (buffer) / GST_SECOND); if (frame) { + GstVideoCodecFrame *oldest_frame; + gboolean warned = FALSE; + + /* Garbage collect old frames in case of codec bugs */ + while ((oldest_frame = gst_video_encoder_get_oldest_frame (encoder)) && + check_system_frame_number_too_old (frame->system_frame_number, + oldest_frame->system_frame_number)) { + gst_video_encoder_finish_frame (encoder, oldest_frame); + oldest_frame = NULL; + + if (!warned) { + g_warning ("%s: Too old frames, bug in encoder -- please file a bug", + GST_ELEMENT_NAME (encoder)); + warned = TRUE; + } + } + if (oldest_frame) + gst_video_codec_frame_unref (oldest_frame); + /* At this point, the delta unit buffer flag is already correctly set by * gst_v4l2_buffer_pool_process. Since gst_video_encoder_finish_frame * will overwrite it from GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame), |