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