summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Staples <staples255@gmail.com>2017-05-26 15:19:00 +0000
committerVíctor Manuel Jáquez Leal <vjaquez@igalia.com>2017-07-10 19:30:46 +0200
commit66d26da39f42ed1670705cfb80d8f93105655a00 (patch)
treeac3ce6ab69fb1acbef631663902fcdf222b7bf44
parent11f461fb106326a771666dde9ee842a8ce43a0a3 (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.c73
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;