From ed9a20ebe4a89de119ea97bdccf688ece8c6648c Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Fri, 15 Apr 2016 16:10:21 +0200 Subject: [PATCH] h264: split reading the ref list modifications and actually building the ref list This will allow postponing the reference list construction (and by consequence some other functions, like frame_start) until the whole slice header has been parsed. --- libavcodec/h264.h | 6 ++ libavcodec/h264_refs.c | 197 ++++++++++++++++++++++------------------ libavcodec/h264_slice.c | 3 + 3 files changed, 118 insertions(+), 88 deletions(-) diff --git a/libavcodec/h264.h b/libavcodec/h264.h index 034507d3cd..b4e5f3ace7 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -391,6 +391,11 @@ typedef struct H264SliceContext { H264Ref ref_list[2][48]; /**< 0..15: frame refs, 16..47: mbaff field refs. * Reordered version of default_ref_list * according to picture reordering in slice header */ + struct { + uint8_t op; + uint8_t val; + } ref_modifications[2][32]; + int nb_ref_modifications[2]; const uint8_t *intra_pcm_ptr; int16_t *dc_val_base; @@ -657,6 +662,7 @@ int ff_h264_get_slice_type(const H264SliceContext *sl); int ff_h264_alloc_tables(H264Context *h); int ff_h264_decode_ref_pic_list_reordering(const H264Context *h, H264SliceContext *sl); +int ff_h264_build_ref_list(const H264Context *h, H264SliceContext *sl); void ff_h264_remove_all_refs(H264Context *h); /** diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c index b4dfbbcfcd..ce3806c311 100644 --- a/libavcodec/h264_refs.c +++ b/libavcodec/h264_refs.c @@ -252,7 +252,7 @@ static void h264_fill_mbaff_ref_list(H264SliceContext *sl) } } -int ff_h264_decode_ref_pic_list_reordering(const H264Context *h, H264SliceContext *sl) +int ff_h264_build_ref_list(const H264Context *h, H264SliceContext *sl) { int list, index, pic_structure; @@ -262,102 +262,88 @@ int ff_h264_decode_ref_pic_list_reordering(const H264Context *h, H264SliceContex h264_initialise_ref_list(h, sl); for (list = 0; list < sl->list_count; list++) { - if (get_bits1(&sl->gb)) { // ref_pic_list_modification_flag_l[01] - int pred = h->curr_pic_num; + int pred = h->curr_pic_num; - for (index = 0; ; index++) { - unsigned int modification_of_pic_nums_idc = get_ue_golomb_31(&sl->gb); - unsigned int pic_id; - int i; - H264Picture *ref = NULL; + for (index = 0; index < sl->nb_ref_modifications[list]; index++) { + unsigned int modification_of_pic_nums_idc = sl->ref_modifications[list][index].op; + unsigned int val = sl->ref_modifications[list][index].val; + unsigned int pic_id; + int i; + H264Picture *ref = NULL; - if (modification_of_pic_nums_idc == 3) - break; + switch (modification_of_pic_nums_idc) { + case 0: + case 1: { + const unsigned int abs_diff_pic_num = val + 1; + int frame_num; - if (index >= sl->ref_count[list]) { - av_log(h->avctx, AV_LOG_ERROR, "reference count overflow\n"); - return -1; - } - - switch (modification_of_pic_nums_idc) { - case 0: - case 1: { - const unsigned int abs_diff_pic_num = get_ue_golomb(&sl->gb) + 1; - int frame_num; - - if (abs_diff_pic_num > h->max_pic_num) { - av_log(h->avctx, AV_LOG_ERROR, - "abs_diff_pic_num overflow\n"); - return AVERROR_INVALIDDATA; - } - - if (modification_of_pic_nums_idc == 0) - pred -= abs_diff_pic_num; - else - pred += abs_diff_pic_num; - pred &= h->max_pic_num - 1; - - frame_num = pic_num_extract(h, pred, &pic_structure); - - for (i = h->short_ref_count - 1; i >= 0; i--) { - ref = h->short_ref[i]; - assert(ref->reference); - assert(!ref->long_ref); - if (ref->frame_num == frame_num && - (ref->reference & pic_structure)) - break; - } - if (i >= 0) - ref->pic_id = pred; - break; - } - case 2: { - int long_idx; - pic_id = get_ue_golomb(&sl->gb); // long_term_pic_idx - - long_idx = pic_num_extract(h, pic_id, &pic_structure); - - if (long_idx > 31) { - av_log(h->avctx, AV_LOG_ERROR, - "long_term_pic_idx overflow\n"); - return AVERROR_INVALIDDATA; - } - ref = h->long_ref[long_idx]; - assert(!(ref && !ref->reference)); - if (ref && (ref->reference & pic_structure)) { - ref->pic_id = pic_id; - assert(ref->long_ref); - i = 0; - } else { - i = -1; - } - break; - } - default: + if (abs_diff_pic_num > h->max_pic_num) { av_log(h->avctx, AV_LOG_ERROR, - "illegal modification_of_pic_nums_idc %u\n", - modification_of_pic_nums_idc); + "abs_diff_pic_num overflow\n"); return AVERROR_INVALIDDATA; } - if (i < 0) { + if (modification_of_pic_nums_idc == 0) + pred -= abs_diff_pic_num; + else + pred += abs_diff_pic_num; + pred &= h->max_pic_num - 1; + + frame_num = pic_num_extract(h, pred, &pic_structure); + + for (i = h->short_ref_count - 1; i >= 0; i--) { + ref = h->short_ref[i]; + assert(ref->reference); + assert(!ref->long_ref); + if (ref->frame_num == frame_num && + (ref->reference & pic_structure)) + break; + } + if (i >= 0) + ref->pic_id = pred; + break; + } + case 2: { + int long_idx; + pic_id = val; // long_term_pic_idx + + long_idx = pic_num_extract(h, pic_id, &pic_structure); + + if (long_idx > 31) { av_log(h->avctx, AV_LOG_ERROR, - "reference picture missing during reorder\n"); - memset(&sl->ref_list[list][index], 0, sizeof(sl->ref_list[0][0])); // FIXME + "long_term_pic_idx overflow\n"); + return AVERROR_INVALIDDATA; + } + ref = h->long_ref[long_idx]; + assert(!(ref && !ref->reference)); + if (ref && (ref->reference & pic_structure)) { + ref->pic_id = pic_id; + assert(ref->long_ref); + i = 0; } else { - for (i = index; i + 1 < sl->ref_count[list]; i++) { - if (sl->ref_list[list][i].parent && - ref->long_ref == sl->ref_list[list][i].parent->long_ref && - ref->pic_id == sl->ref_list[list][i].pic_id) - break; - } - for (; i > index; i--) { - sl->ref_list[list][i] = sl->ref_list[list][i - 1]; - } - ref_from_h264pic(&sl->ref_list[list][index], ref); - if (FIELD_PICTURE(h)) { - pic_as_field(&sl->ref_list[list][index], pic_structure); - } + i = -1; + } + break; + } + } + + if (i < 0) { + av_log(h->avctx, AV_LOG_ERROR, + "reference picture missing during reorder\n"); + memset(&sl->ref_list[list][index], 0, sizeof(sl->ref_list[0][0])); // FIXME + } else { + for (i = index; i + 1 < sl->ref_count[list]; i++) { + if (sl->ref_list[list][i].parent && + ref->long_ref == sl->ref_list[list][i].parent->long_ref && + ref->pic_id == sl->ref_list[list][i].pic_id) + break; + } + for (; i > index; i--) { + sl->ref_list[list][i] = sl->ref_list[list][i - 1]; + } + ref_from_h264pic(&sl->ref_list[list][index], ref); + if (FIELD_PICTURE(h)) { + pic_as_field(&sl->ref_list[list][index], pic_structure); } } } @@ -380,6 +366,41 @@ int ff_h264_decode_ref_pic_list_reordering(const H264Context *h, H264SliceContex return 0; } +int ff_h264_decode_ref_pic_list_reordering(const H264Context *h, H264SliceContext *sl) +{ + int list, index; + + sl->nb_ref_modifications[0] = 0; + sl->nb_ref_modifications[1] = 0; + + for (list = 0; list < sl->list_count; list++) { + if (!get_bits1(&sl->gb)) // ref_pic_list_modification_flag_l[01] + continue; + + for (index = 0; ; index++) { + unsigned int op = get_ue_golomb_31(&sl->gb); + + if (op == 3) + break; + + if (index >= sl->ref_count[list]) { + av_log(h->avctx, AV_LOG_ERROR, "reference count overflow\n"); + return AVERROR_INVALIDDATA; + } else if (op > 2) { + av_log(h->avctx, AV_LOG_ERROR, + "illegal modification_of_pic_nums_idc %u\n", + op); + return AVERROR_INVALIDDATA; + } + sl->ref_modifications[list][index].val = get_ue_golomb(&sl->gb); + sl->ref_modifications[list][index].op = op; + sl->nb_ref_modifications[list]++; + } + } + + return 0; +} + /** * Mark a picture as no longer needed for reference. The refmask * argument allows unreferencing of individual fields or the whole frame. diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 031f8cc7d8..b84514c653 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -1347,6 +1347,9 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl) sl->ref_count[1] = sl->ref_count[0] = 0; return ret; } + ret = ff_h264_build_ref_list(h, sl); + if (ret < 0) + return ret; } if ((pps->weighted_pred && sl->slice_type_nos == AV_PICTURE_TYPE_P) ||