Copy a neighbouring frame/field from the list as error resilience
measure since the decoder assumes frame data pointers of known reference
to be valid.

Prevents stale references in ref_list in the fuzzed sample
bipbop234.ts_s20118 caused by not refreshing the ref lists when required
due to slice decoding errors.

fix
---
 libavcodec/h264_refs.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 62 insertions(+), 1 deletion(-)

diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c
index 0b88587..d6b1979 100644
--- a/libavcodec/h264_refs.c
+++ b/libavcodec/h264_refs.c
@@ -333,6 +333,65 @@ void ff_h264_fill_mbaff_ref_list(H264Context *h){
     }
 }
 
+static inline int pics_are_equal(Picture *p1, Picture *p2)
+{
+    return p1->frame_num == p2->frame_num && p1->poc == p2->poc;
+}
+
+static void drop_unreferenced_copies(H264Context *h, Picture *pic)
+{
+    int i, j, l, max_ref;
+
+    for (l = 0; l <= 1; l++) {
+        for (i = 0; i < 32; i++) {
+            Picture *ref = &h->default_ref_list[l][i];
+            if (pics_are_equal(pic, ref)) {
+                av_log(h->s.avctx, AV_LOG_DEBUG, "unreferene pic %d %d %p -"
+                       " %d %d %p at %d in default_ref_list[%d]\n",
+                       pic->frame_num, pic->poc, pic->f.data[0],
+                       ref->frame_num, ref->poc, ref->f.data[0], i, l);
+                if (i > 0)
+                    h->default_ref_list[l][i] = h->default_ref_list[l][i - 1];
+                else
+                    h->default_ref_list[l][i] = h->default_ref_list[l][i + 1];
+            }
+        }
+
+        max_ref = pic->mbaff ? 16 : 32;
+        for (i = 0; i < max_ref; i++) {
+            Picture *ref = &h->ref_list[l][i];
+            if (pics_are_equal(pic, ref)) {
+                av_log(h->s.avctx, AV_LOG_DEBUG, "unreferene pic %d %d %p -"
+                       " %d %d %p at %d in ref_list[%d]\n",
+                       pic->frame_num, pic->poc, pic->f.data[0],
+                       ref->frame_num, ref->poc, ref->f.data[0], i, l);
+                if (i > 0)
+                    h->ref_list[l][i] = h->ref_list[l][i - 1];
+                else
+                    h->ref_list[l][i] = h->ref_list[l][i + 1];
+            }
+        }
+
+        if (!pic->mbaff)
+            continue;
+
+        // check mbaff field references
+        for (i = 16; i < 48; i++) {
+            Picture *ref = &h->ref_list[l][i];
+            if (pics_are_equal(pic, ref)) {
+                av_log(h->s.avctx, AV_LOG_DEBUG, "unreferene field %d %d %p -"
+                       " %d %d %p at %d in ref_list[%d]\n",
+                       pic->frame_num, pic->poc, pic->f.data[0],
+                       ref->frame_num, ref->poc, ref->f.data[0], i, l);
+                if (i > 17)
+                    h->ref_list[l][i] = h->ref_list[l][i - 2];
+                else
+                    h->ref_list[l][i] = h->ref_list[l][i + 2];
+            }
+        }
+    }
+}
+
 /**
  * Mark a picture as no longer needed for reference. The refmask
  * argument allows unreferencing of individual fields or the whole frame.
@@ -354,8 +413,10 @@ static inline int unreference_pic(H264Context *h, Picture 
*pic, int refmask){
                 pic->f.reference = DELAYED_PIC_REF;
                 break;
             }
-        return 1;
     }
+    /* check if we have a copy of pic on a ref_list and clear it */
+    drop_unreferenced_copies(h, pic);
+    return 1;
 }
 
 /**
-- 
1.7.12.4

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

Reply via email to