diff options
author | Anton Khirnov <anton@khirnov.net> | 2016-04-15 16:10:21 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2016-06-12 20:27:52 +0200 |
commit | ed9a20ebe4a89de119ea97bdccf688ece8c6648c (patch) | |
tree | 8d6a939b9a337674255314e3e53ca3c5afda2557 /libavcodec | |
parent | fa57059079190242517701120cfdccad93c866da (diff) | |
download | ffmpeg-ed9a20ebe4a89de119ea97bdccf688ece8c6648c.tar.gz |
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.
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/h264.h | 6 | ||||
-rw-r--r-- | libavcodec/h264_refs.c | 197 | ||||
-rw-r--r-- | 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; - - 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; - - if (modification_of_pic_nums_idc == 3) - break; - - if (index >= sl->ref_count[list]) { - av_log(h->avctx, AV_LOG_ERROR, "reference count overflow\n"); - return -1; + int pred = h->curr_pic_num; + + 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; + + switch (modification_of_pic_nums_idc) { + case 0: + case 1: { + const unsigned int abs_diff_pic_num = val + 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; } - 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; + 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; } - case 2: { - int long_idx; - pic_id = get_ue_golomb(&sl->gb); // long_term_pic_idx + 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); + 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 (long_idx > 31) { av_log(h->avctx, AV_LOG_ERROR, - "illegal modification_of_pic_nums_idc %u\n", - modification_of_pic_nums_idc); + "long_term_pic_idx overflow\n"); return AVERROR_INVALIDDATA; } - - 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 + 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) || |