From 66d26da39f42ed1670705cfb80d8f93105655a00 Mon Sep 17 00:00:00 2001 From: Matt Staples Date: Fri, 26 May 2017 15:19:00 +0000 Subject: [PATCH] libs: decoder: h264: push frames as soon as possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Push frames downstream as soon as possible instead of waiting until they are ejected from the DPB. This patch makes the decoder not comply with the H.264 specification, but it is required for some video cameras. https://bugzilla.gnome.org/show_bug.cgi?id=762509 Signed-off-by: Víctor Manuel Jáquez Leal --- gst-libs/gst/vaapi/gstvaapidecoder_h264.c | 73 +++++++++++++++++++++-- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_h264.c b/gst-libs/gst/vaapi/gstvaapidecoder_h264.c index 18df327da9..e971f75012 100644 --- a/gst-libs/gst/vaapi/gstvaapidecoder_h264.c +++ b/gst-libs/gst/vaapi/gstvaapidecoder_h264.c @@ -800,17 +800,31 @@ dpb_find_nearest_prev_poc (GstVaapiDecoderH264 * decoder, /* Finds the picture with the lowest POC that needs to be output */ static gint -dpb_find_lowest_poc (GstVaapiDecoderH264 * decoder, - GstVaapiPictureH264 * picture, GstVaapiPictureH264 ** found_picture_ptr) +dpb_find_lowest_poc_for_output (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstVaapiPictureH264 ** found_picture_ptr, + gboolean * can_be_output) { GstVaapiDecoderH264Private *const priv = &decoder->priv; GstVaapiPictureH264 *found_picture = NULL; - guint i, j, found_index = -1; + guint i, j, found_index = -1, found_poc = -1; + gboolean is_first = TRUE; + gint last_output_poc = -1; for (i = 0; i < priv->dpb_count; i++) { GstVaapiFrameStore *const fs = priv->dpb[i]; - if (!fs->output_needed) + if (!fs->output_needed) { + /* find the maximum poc of any previously output frames that are + * still held in the DPB. */ + if (can_be_output != NULL) { + for (j = 0; j < fs->num_buffers; j++) { + if (is_first || fs->buffers[j]->base.poc > last_output_poc) { + is_first = FALSE; + last_output_poc = fs->buffers[j]->base.poc; + } + } + } continue; + } if (picture && picture->base.view_id != fs->view_id) continue; for (j = 0; j < fs->num_buffers; j++) { @@ -820,7 +834,27 @@ dpb_find_lowest_poc (GstVaapiDecoderH264 * decoder, if (!found_picture || found_picture->base.poc > pic->base.poc || (found_picture->base.poc == pic->base.poc && found_picture->base.voc > pic->base.voc)) - found_picture = pic, found_index = i; + found_picture = pic, found_index = i, found_poc = pic->base.poc; + } + } + + if (can_be_output != NULL) { + /* found_picture can be output if it's the first frame in the DPB, + * or if there's no gap between it and the most recently output + * frame. */ + *can_be_output = FALSE; + if (found_picture && + gst_vaapi_frame_store_is_complete (priv->dpb[found_index])) { + if (is_first) { + *can_be_output = TRUE; + } else if (((int) (found_poc)) > ((int) (last_output_poc))) { + *can_be_output = (found_poc - last_output_poc) <= 2; + } else { + /* A frame with a higher poc has already been sent. No choice + * now but to drop this frame */ + GST_WARNING ("dropping out-of-sequence frame"); + priv->dpb[found_index]->output_needed = FALSE; + } } } @@ -829,6 +863,16 @@ dpb_find_lowest_poc (GstVaapiDecoderH264 * decoder, return found_index; } +/* Finds the picture with the lowest POC that needs to be output */ +static gint +dpb_find_lowest_poc (GstVaapiDecoderH264 * decoder, + GstVaapiPictureH264 * picture, GstVaapiPictureH264 ** found_picture_ptr) +{ + return dpb_find_lowest_poc_for_output (decoder, picture, found_picture_ptr, + NULL); +} + + /* Finds the picture with the lowest VOC that needs to be output */ static gint dpb_find_lowest_voc (GstVaapiDecoderH264 * decoder, @@ -908,6 +952,22 @@ dpb_bump (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture) return success; } +static void +dpb_output_ready_frames (GstVaapiDecoderH264 * decoder) +{ + GstVaapiDecoderH264Private *const priv = &decoder->priv; + gboolean can_output = FALSE; + gint found_index; + + while (TRUE) { + found_index = dpb_find_lowest_poc_for_output (decoder, + priv->current_picture, NULL, &can_output); + if (found_index < 0 || !can_output) + break; + dpb_output (decoder, priv->dpb[found_index]); + } +} + static void dpb_clear (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture) { @@ -1662,6 +1722,9 @@ decode_current_picture (GstVaapiDecoderH264 * decoder) goto error; if (!dpb_add (decoder, picture)) goto error; + + if (priv->force_low_latency) + dpb_output_ready_frames (decoder); gst_vaapi_picture_replace (&priv->current_picture, NULL); return GST_VAAPI_DECODER_STATUS_SUCCESS;