diff options
author | Matt Staples <staples255@gmail.com> | 2017-05-26 15:19:00 +0000 |
---|---|---|
committer | Víctor Manuel Jáquez Leal <vjaquez@igalia.com> | 2017-07-10 19:30:46 +0200 |
commit | 66d26da39f42ed1670705cfb80d8f93105655a00 (patch) | |
tree | ac3ce6ab69fb1acbef631663902fcdf222b7bf44 | |
parent | 11f461fb106326a771666dde9ee842a8ce43a0a3 (diff) |
libs: decoder: h264: push frames as soon as possible
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 <vjaquez@igalia.com>
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapidecoder_h264.c | 73 |
1 files changed, 68 insertions, 5 deletions
diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_h264.c b/gst-libs/gst/vaapi/gstvaapidecoder_h264.c index 18df327d..e971f750 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, @@ -909,6 +953,22 @@ dpb_bump (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture) } 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) { GstVaapiDecoderH264Private *const priv = &decoder->priv; @@ -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; |