Current code is excessively complicated and hard to read. Use the same
logic as in the HEVC decoder, augmented with detection of insufficient
delay.
---
 libavcodec/h264_picture.c |   2 +-
 libavcodec/h264_refs.c    |  18 +----
 libavcodec/h264_slice.c   | 185 ++++++++++++++++------------------------------
 libavcodec/h264dec.c      |  61 +++++----------
 libavcodec/h264dec.h      |  17 +++--
 5 files changed, 96 insertions(+), 187 deletions(-)

diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c
index 24ba79d..5b483fd 100644
--- a/libavcodec/h264_picture.c
+++ b/libavcodec/h264_picture.c
@@ -107,8 +107,8 @@ int ff_h264_ref_picture(H264Context *h, H264Picture *dst, 
H264Picture *src)
 
     dst->poc           = src->poc;
     dst->frame_num     = src->frame_num;
-    dst->mmco_reset    = src->mmco_reset;
     dst->pic_id        = src->pic_id;
+    dst->sequence      = src->sequence;
     dst->long_ref      = src->long_ref;
     dst->mbaff         = src->mbaff;
     dst->field_picture = src->field_picture;
diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c
index b4dc49c..af1b854 100644
--- a/libavcodec/h264_refs.c
+++ b/libavcodec/h264_refs.c
@@ -415,17 +415,8 @@ int 
ff_h264_decode_ref_pic_list_reordering(H264SliceContext *sl, void *logctx)
  */
 static inline int unreference_pic(H264Context *h, H264Picture *pic, int 
refmask)
 {
-    int i;
-    if (pic->reference &= refmask) {
-        return 0;
-    } else {
-        for(i = 0; h->delayed_pic[i]; i++)
-            if(pic == h->delayed_pic[i]){
-                pic->reference = DELAYED_PIC_REF;
-                break;
-            }
-        return 1;
-    }
+    pic->reference &= refmask | DELAYED_PIC_REF;
+    return !(pic->reference & ~DELAYED_PIC_REF);
 }
 
 /**
@@ -657,8 +648,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h)
                 remove_long(h, j, 0);
             }
             h->poc.frame_num = h->cur_pic_ptr->frame_num = 0;
-            h->mmco_reset = 1;
-            h->cur_pic_ptr->mmco_reset = 1;
+            h->seq_decode++;
             break;
         default: assert(0);
         }
@@ -673,7 +663,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h)
          */
         if (h->short_ref_count && h->short_ref[0] == h->cur_pic_ptr) {
             /* Just mark the second field valid */
-            h->cur_pic_ptr->reference = PICT_FRAME;
+            h->cur_pic_ptr->reference |= PICT_FRAME;
         } else if (h->cur_pic_ptr->long_ref) {
             av_log(h->avctx, AV_LOG_ERROR, "illegal short term reference "
                                            "assignment for second field "
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index aa6d951..869f352 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -385,6 +385,9 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
     h->picture_structure    = h1->picture_structure;
     h->mb_aff_frame         = h1->mb_aff_frame;
     h->droppable            = h1->droppable;
+    h->seq_decode           = h1->seq_decode;
+    h->seq_output           = h1->seq_output;
+    h->last_output_poc      = h1->last_output_poc;
 
     for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) {
         ff_h264_unref_picture(h, &h->DPB[i]);
@@ -413,22 +416,15 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
 
     memcpy(h->short_ref,   h1->short_ref,   sizeof(h->short_ref));
     memcpy(h->long_ref,    h1->long_ref,    sizeof(h->long_ref));
-    memcpy(h->delayed_pic, h1->delayed_pic, sizeof(h->delayed_pic));
-    memcpy(h->last_pocs,   h1->last_pocs,   sizeof(h->last_pocs));
-
-    h->next_outputed_poc = h1->next_outputed_poc;
 
     memcpy(h->mmco, h1->mmco, sizeof(h->mmco));
     h->nb_mmco         = h1->nb_mmco;
-    h->mmco_reset      = h1->mmco_reset;
     h->explicit_ref_marking = h1->explicit_ref_marking;
     h->long_ref_count  = h1->long_ref_count;
     h->short_ref_count = h1->short_ref_count;
 
     copy_picture_range(h->short_ref, h1->short_ref, 32, h, h1);
     copy_picture_range(h->long_ref, h1->long_ref, 32, h, h1);
-    copy_picture_range(h->delayed_pic, h1->delayed_pic,
-                       MAX_DELAYED_PIC_COUNT + 2, h, h1);
 
     if (!h->cur_pic_ptr)
         return 0;
@@ -458,7 +454,8 @@ static int h264_frame_start(H264Context *h)
         return ret;
 
     pic = h->cur_pic_ptr;
-    pic->reference              = h->droppable ? 0 : h->picture_structure;
+    pic->reference              = (h->droppable ? 0 : h->picture_structure) |
+                                  DELAYED_PIC_REF;
     pic->f->coded_picture_number = h->coded_picture_number++;
     pic->field_picture          = h->picture_structure != PICT_FRAME;
     pic->frame_num               = h->poc.frame_num;
@@ -468,7 +465,6 @@ static int h264_frame_start(H264Context *h)
      * See decode_nal_units().
      */
     pic->f->key_frame = 0;
-    pic->mmco_reset  = 0;
     pic->recovered   = 0;
 
     pic->f->pict_type = h->slice_ctx[0].slice_type;
@@ -497,18 +493,16 @@ static int h264_frame_start(H264Context *h)
     memset(h->slice_table, -1,
            (h->mb_height * h->mb_stride - 1) * sizeof(*h->slice_table));
 
-    /* We mark the current picture as non-reference after allocating it, so
-     * that if we break out due to an error it can be released automatically
-     * in the next ff_mpv_frame_start().
-     */
-    h->cur_pic_ptr->reference = 0;
-
     h->cur_pic_ptr->field_poc[0] = h->cur_pic_ptr->field_poc[1] = INT_MAX;
 
     h->postpone_filter = 0;
 
     h->mb_aff_frame = h->ps.sps->mb_aff && (h->picture_structure == 
PICT_FRAME);
 
+    if (h->picture_idr)
+        h->seq_decode++;
+    h->cur_pic_ptr->sequence = h->seq_decode;
+
     assert(h->cur_pic_ptr->long_ref == 0);
 
     return 0;
@@ -1147,104 +1141,67 @@ static int h264_export_frame_props(H264Context *h)
     return 0;
 }
 
-static int h264_select_output_frame(H264Context *h)
+int ff_h264_select_output_frame(H264Context *h, int flush)
 {
-    const SPS *sps = h->ps.sps;
-    H264Picture *out = h->cur_pic_ptr;
-    H264Picture *cur = h->cur_pic_ptr;
-    int i, pics, out_of_order, out_idx;
-    int invalid = 0, cnt = 0;
-    int ret;
+    int i, ret;
 
-    if (sps->bitstream_restriction_flag ||
-        h->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
-        h->avctx->has_b_frames = FFMAX(h->avctx->has_b_frames, 
sps->num_reorder_frames);
-    }
-
-    pics = 0;
-    while (h->delayed_pic[pics])
-        pics++;
-
-    assert(pics <= MAX_DELAYED_PIC_COUNT);
-
-    h->delayed_pic[pics++] = cur;
-    if (cur->reference == 0)
-        cur->reference = DELAYED_PIC_REF;
-
-    /* Frame reordering. This code takes pictures from coding order and sorts
-     * them by their incremental POC value into display order. It supports POC
-     * gaps, MMCO reset codes and random resets.
-     * A "display group" can start either with a IDR frame (f.key_frame = 1),
-     * and/or can be closed down with a MMCO reset code. In sequences where
-     * there is no delay, we can't detect that (since the frame was already
-     * output to the user), so we also set h->mmco_reset to detect the MMCO
-     * reset code.
-     * FIXME: if we detect insufficient delays (as per h->avctx->has_b_frames),
-     * we increase the delay between input and output. All frames affected by
-     * the lag (e.g. those that should have been output before another frame
-     * that we already returned to the user) will be dropped. This is a bug
-     * that we will fix later. */
-    for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++) {
-        cnt     += out->poc < h->last_pocs[i];
-        invalid += out->poc == INT_MIN;
-    }
-    if (!h->mmco_reset && !cur->f->key_frame &&
-        cnt + invalid == MAX_DELAYED_PIC_COUNT && cnt > 0) {
-        h->mmco_reset = 2;
-        if (pics > 1)
-            h->delayed_pic[pics - 2]->mmco_reset = 2;
-    }
-    if (h->mmco_reset || cur->f->key_frame) {
-        for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++)
-            h->last_pocs[i] = INT_MIN;
-        cnt     = 0;
-        invalid = MAX_DELAYED_PIC_COUNT;
-    }
-    out     = h->delayed_pic[0];
-    out_idx = 0;
-    for (i = 1; i < MAX_DELAYED_PIC_COUNT &&
-                h->delayed_pic[i] &&
-                !h->delayed_pic[i - 1]->mmco_reset &&
-                !h->delayed_pic[i]->f->key_frame;
-         i++)
-        if (h->delayed_pic[i]->poc < out->poc) {
-            out     = h->delayed_pic[i];
-            out_idx = i;
-        }
-    if (h->avctx->has_b_frames == 0 &&
-        (h->delayed_pic[0]->f->key_frame || h->mmco_reset))
-        h->next_outputed_poc = INT_MIN;
-    out_of_order = !out->f->key_frame && !h->mmco_reset &&
-                   (out->poc < h->next_outputed_poc);
-
-    if (sps->bitstream_restriction_flag &&
-        h->avctx->has_b_frames >= sps->num_reorder_frames) {
-    } else if (out_of_order && pics - 1 == h->avctx->has_b_frames &&
-               h->avctx->has_b_frames < MAX_DELAYED_PIC_COUNT) {
-        if (invalid + cnt < MAX_DELAYED_PIC_COUNT) {
-            h->avctx->has_b_frames = FFMAX(h->avctx->has_b_frames, cnt);
+    if (!flush) {
+        const SPS *sps = h->ps.sps;
+        if (sps->bitstream_restriction_flag ||
+            h->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
+            h->avctx->has_b_frames = FFMAX(h->avctx->has_b_frames, 
sps->num_reorder_frames);
         }
-    } else if (!h->avctx->has_b_frames &&
-               ((h->next_outputed_poc != INT_MIN &&
-                 out->poc > h->next_outputed_poc + 2) ||
-                cur->f->pict_type == AV_PICTURE_TYPE_B)) {
-        h->avctx->has_b_frames++;
     }
 
-    if (pics > h->avctx->has_b_frames) {
+    while (1) {
+        H264Picture *out;
+        int nb_output = 0;
+        int min_poc   = INT_MAX;
+        int min_idx;
+
+        for (i = 0; i < FF_ARRAY_ELEMS(h->DPB); i++) {
+            H264Picture *frame = &h->DPB[i];
+            if (frame->reference & DELAYED_PIC_REF &&
+                frame->sequence == h->seq_output) {
+                nb_output++;
+                if (frame->poc < min_poc) {
+                    min_poc = frame->poc;
+                    min_idx = i;
+                }
+            }
+        }
+
+        /* wait for more frames before output */
+        if (!flush && h->seq_output == h->seq_decode &&
+            nb_output <= h->avctx->has_b_frames)
+            return 0;
+
+        if (!nb_output) {
+            if (h->seq_output == h->seq_decode)
+                break;
+
+            h->seq_output++;
+            h->last_output_poc = INT_MIN;
+            continue;
+        }
+
+        out             = &h->DPB[min_idx];
         out->reference &= ~DELAYED_PIC_REF;
-        for (i = out_idx; h->delayed_pic[i]; i++)
-            h->delayed_pic[i] = h->delayed_pic[i + 1];
-    }
-    memmove(h->last_pocs, &h->last_pocs[1],
-            sizeof(*h->last_pocs) * (MAX_DELAYED_PIC_COUNT - 1));
-    h->last_pocs[MAX_DELAYED_PIC_COUNT - 1] = cur->poc;
-    if (!out_of_order && pics > h->avctx->has_b_frames) {
+
+        if (out->poc <= h->last_output_poc) {
+            av_log(h->avctx, AV_LOG_WARNING, "Insufficient delay signalled "
+                   "in the bitstream, some frames will be lost.\n");
+            h->avctx->has_b_frames++;
+            h->last_output_poc = out->poc;
+            continue;
+        }
+
         av_frame_unref(h->output_frame);
         ret = av_frame_ref(h->output_frame, out->f);
         if (ret < 0)
             return ret;
 
+        h->last_output_poc = out->poc;
         if (out->recovered) {
             // We have reached an recovery point and all frames after it in
             // display order are "recovered".
@@ -1259,23 +1216,7 @@ static int h264_select_output_frame(H264Context *h)
                 h->output_frame->flags |= AV_FRAME_FLAG_CORRUPT;
         }
 
-        if (out->mmco_reset) {
-            if (out_idx > 0) {
-                h->next_outputed_poc                    = out->poc;
-                h->delayed_pic[out_idx - 1]->mmco_reset = out->mmco_reset;
-            } else {
-                h->next_outputed_poc = INT_MIN;
-            }
-        } else {
-            if (out_idx == 0 && pics > 1 && h->delayed_pic[0]->f->key_frame) {
-                h->next_outputed_poc = INT_MIN;
-            } else {
-                h->next_outputed_poc = out->poc;
-            }
-        }
-        h->mmco_reset = 0;
-    } else {
-        av_log(h->avctx, AV_LOG_DEBUG, "no picture\n");
+        break;
     }
 
     return 0;
@@ -1458,6 +1399,8 @@ static int h264_field_start(H264Context *h, const 
H264SliceContext *sl,
         h->first_field = FIELD_PICTURE(h);
     }
 
+    h->picture_idr = nal->type == H264_NAL_IDR_SLICE;
+
     if (!FIELD_PICTURE(h) || h->first_field) {
         if (h264_frame_start(h) < 0) {
             h->first_field = 0;
@@ -1474,8 +1417,6 @@ static int h264_field_start(H264Context *h, const 
H264SliceContext *sl,
     h->nb_mmco = sl->nb_mmco;
     h->explicit_ref_marking = sl->explicit_ref_marking;
 
-    h->picture_idr = nal->type == H264_NAL_IDR_SLICE;
-
     if (h->sei.recovery_point.recovery_frame_cnt >= 0 && h->recovery_frame < 
0) {
         h->recovery_frame = (h->poc.frame_num + 
h->sei.recovery_point.recovery_frame_cnt) &
                             ((1 << h->ps.sps->log2_max_frame_num) - 1);
@@ -1502,7 +1443,7 @@ static int h264_field_start(H264Context *h, const 
H264SliceContext *sl,
         if (ret < 0)
             return ret;
 
-        ret = h264_select_output_frame(h);
+        ret = ff_h264_select_output_frame(h, 0);
         if (ret < 0)
             return ret;
     }
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index 771520b..b92795d 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -295,10 +295,6 @@ static int h264_init_context(AVCodecContext *avctx, 
H264Context *h)
     h->recovery_frame        = -1;
     h->frame_recovered       = 0;
 
-    h->next_outputed_poc = INT_MIN;
-    for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++)
-        h->last_pocs[i] = INT_MIN;
-
     ff_h264_sei_uninit(&h->sei);
 
     avctx->chroma_sample_location = AVCHROMA_LOC_LEFT;
@@ -424,10 +420,7 @@ static void idr(H264Context *h)
 /* forget old pics after a seek */
 void ff_h264_flush_change(H264Context *h)
 {
-    int i;
-    for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++)
-        h->last_pocs[i] = INT_MIN;
-    h->next_outputed_poc = INT_MIN;
+    h->seq_decode++;
     h->prev_interlaced_frame = 1;
     idr(h);
     if (h->cur_pic_ptr)
@@ -444,10 +437,12 @@ static void flush_dpb(AVCodecContext *avctx)
     H264Context *h = avctx->priv_data;
     int i;
 
-    memset(h->delayed_pic, 0, sizeof(h->delayed_pic));
-
     ff_h264_flush_change(h);
 
+    h->seq_decode      = 0;
+    h->seq_output      = 0;
+    h->last_output_poc = INT_MIN;
+
     for (i = 0; i < H264_MAX_PICTURE_COUNT; i++)
         ff_h264_unref_picture(h, &h->DPB[i]);
     h->cur_pic_ptr = NULL;
@@ -475,6 +470,8 @@ static int get_last_needed_nal(H264Context *h)
         switch (nal->type) {
         case H264_NAL_SPS:
         case H264_NAL_PPS:
+        case H264_NAL_END_SEQUENCE:
+        case H264_NAL_END_STREAM:
             nals_needed = i;
             break;
         case H264_NAL_DPA:
@@ -597,9 +594,11 @@ static int decode_nal_units(H264Context *h, const uint8_t 
*buf, int buf_size)
             if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))
                 goto end;
             break;
-        case H264_NAL_AUD:
-        case H264_NAL_END_SEQUENCE:
         case H264_NAL_END_STREAM:
+        case H264_NAL_END_SEQUENCE:
+            h->seq_decode++;
+            break;
+        case H264_NAL_AUD:
         case H264_NAL_FILLER_DATA:
         case H264_NAL_SPS_EXT:
         case H264_NAL_AUXILIARY_SLICE:
@@ -659,37 +658,16 @@ static int h264_decode_frame(AVCodecContext *avctx, void 
*data,
     h->nb_slice_ctx_queued = 0;
 
     /* end of stream, output what is still in the buffers */
-out:
     if (buf_size == 0) {
-        H264Picture *out;
-        int i, out_idx;
-
-        h->cur_pic_ptr = NULL;
-
-        // FIXME factorize this with the output code below
-        out     = h->delayed_pic[0];
-        out_idx = 0;
-        for (i = 1;
-             h->delayed_pic[i] &&
-             !h->delayed_pic[i]->f->key_frame &&
-             !h->delayed_pic[i]->mmco_reset;
-             i++)
-            if (h->delayed_pic[i]->poc < out->poc) {
-                out     = h->delayed_pic[i];
-                out_idx = i;
-            }
-
-        for (i = out_idx; h->delayed_pic[i]; i++)
-            h->delayed_pic[i] = h->delayed_pic[i + 1];
+        ret = ff_h264_select_output_frame(h, 1);
+        if (ret < 0)
+            return ret;
 
-        if (out) {
-            ret = av_frame_ref(pict, out->f);
-            if (ret < 0)
-                return ret;
+        if (h->output_frame->buf[0]) {
+            av_frame_move_ref(pict, h->output_frame);
             *got_frame = 1;
         }
-
-        return buf_index;
+        return 0;
     }
 
     new_extradata_size = 0;
@@ -707,11 +685,6 @@ out:
     if (buf_index < 0)
         return AVERROR_INVALIDDATA;
 
-    if (!h->cur_pic_ptr && h->nal_unit_type == H264_NAL_END_SEQUENCE) {
-        buf_size = 0;
-        goto out;
-    }
-
     if (!(avctx->flags2 & AV_CODEC_FLAG2_CHUNKS) && !h->cur_pic_ptr) {
         if (avctx->skip_frame >= AVDISCARD_NONREF)
             return 0;
diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h
index fc7beeb..db6ce03 100644
--- a/libavcodec/h264dec.h
+++ b/libavcodec/h264dec.h
@@ -146,8 +146,6 @@ typedef struct H264Picture {
     int field_poc[2];       ///< top/bottom POC
     int poc;                ///< frame POC
     int frame_num;          ///< frame_num (raw frame_num from slice header)
-    int mmco_reset;         /**< MMCO_RESET set this 1. Reordering code must
-                                 not mix pictures before and after MMCO_RESET. 
*/
     int pic_id;             /**< pic_num (short -> no wrap version of pic_num,
                                  pic_num & max_pic_num; long -> long_pic_num) 
*/
     int long_ref;           ///< 1->long term reference 0->short term reference
@@ -158,6 +156,12 @@ typedef struct H264Picture {
 
     int reference;
     int recovered;          ///< picture at IDR or recovery point + recovery 
count
+
+    /**
+     * A counter that increases for each new video sequence, so that old frames
+     * are output first after a POC reset
+     */
+    unsigned int sequence;
 } H264Picture;
 
 typedef struct H264Ref {
@@ -453,16 +457,12 @@ typedef struct H264Context {
 
     H264Picture *short_ref[32];
     H264Picture *long_ref[32];
-    H264Picture *delayed_pic[MAX_DELAYED_PIC_COUNT + 2]; // FIXME size?
-    int last_pocs[MAX_DELAYED_PIC_COUNT];
-    int next_outputed_poc;
 
     /**
      * memory management control operations buffer.
      */
     MMCO mmco[MAX_MMCO_COUNT];
     int  nb_mmco;
-    int mmco_reset;
     int explicit_ref_marking;
 
     int long_ref_count;     ///< number of actual long term references
@@ -525,6 +525,9 @@ typedef struct H264Context {
     int height_from_caller;
 
     AVFrame *output_frame;
+    unsigned int seq_decode;
+    unsigned int seq_output;
+    int          last_output_poc;
 
     int enable_er;
 
@@ -804,6 +807,8 @@ int ff_h264_field_end(H264Context *h, H264SliceContext *sl, 
int in_setup);
 int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src);
 void ff_h264_unref_picture(H264Context *h, H264Picture *pic);
 
+int ff_h264_select_output_frame(H264Context *h, int flush);
+
 int ff_h264_slice_context_init(H264Context *h, H264SliceContext *sl);
 
 void ff_h264_draw_horiz_band(const H264Context *h, H264SliceContext *sl, int 
y, int height);
-- 
2.0.0

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to