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