h264: split reading the ref list modifications and actually building the ref list
authorAnton Khirnov <anton@khirnov.net>
Fri, 15 Apr 2016 14:10:21 +0000 (16:10 +0200)
committerAnton Khirnov <anton@khirnov.net>
Sun, 12 Jun 2016 18:27:52 +0000 (20:27 +0200)
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
libavcodec/h264_refs.c
libavcodec/h264_slice.c

index 034507d..b4e5f3a 100644 (file)
@@ -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);
 
 /**
index b4dfbbc..ce3806c 100644 (file)
@@ -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.
index 031f8cc..b84514c 100644 (file)
@@ -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) ||