h264: make sure the slices do not overlap during slice threading
authorAnton Khirnov <anton@khirnov.net>
Wed, 6 May 2015 09:12:55 +0000 (11:12 +0200)
committerAnton Khirnov <anton@khirnov.net>
Sat, 27 Jun 2015 14:43:22 +0000 (16:43 +0200)
Based on a patch by Michael Niedermayer <michaelni@gmx.at>.
CC: libav-stable@libav.org
Found-by: Kieran Kunhya <kierank@obe.tv>
libavcodec/h264.h
libavcodec/h264_slice.c

index 12172ac..624a761 100644 (file)
@@ -374,6 +374,8 @@ typedef struct H264SliceContext {
     int mb_xy;
     int resync_mb_x;
     int resync_mb_y;
+    // index of the first MB of the next slice
+    int next_slice_idx;
     int mb_skip_run;
     int is_complex;
 
index 4e8ee4f..93f0704 100644 (file)
@@ -2080,8 +2080,15 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
 
         for (;;) {
             // START_TIMER
-            int ret = ff_h264_decode_mb_cabac(h, sl);
-            int eos;
+            int ret, eos;
+
+            if (sl->mb_x + sl->mb_y * h->mb_width >= sl->next_slice_idx) {
+                av_log(h->avctx, AV_LOG_ERROR, "Slice overlaps with next at %d\n",
+                       sl->next_slice_idx);
+                return AVERROR_INVALIDDATA;
+            }
+
+            ret = ff_h264_decode_mb_cabac(h, sl);
             // STOP_TIMER("decode_mb_cabac")
 
             if (ret >= 0)
@@ -2141,7 +2148,15 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
         }
     } else {
         for (;;) {
-            int ret = ff_h264_decode_mb_cavlc(h, sl);
+            int ret;
+
+            if (sl->mb_x + sl->mb_y * h->mb_width >= sl->next_slice_idx) {
+                av_log(h->avctx, AV_LOG_ERROR, "Slice overlaps with next at %d\n",
+                       sl->next_slice_idx);
+                return AVERROR_INVALIDDATA;
+            }
+
+            ret = ff_h264_decode_mb_cavlc(h, sl);
 
             if (ret >= 0)
                 ff_h264_hl_decode_mb(h, sl);
@@ -2224,18 +2239,37 @@ int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count)
 {
     AVCodecContext *const avctx = h->avctx;
     H264SliceContext *sl;
-    int i;
+    int i, j;
 
     if (h->avctx->hwaccel)
         return 0;
     if (context_count == 1) {
-        int ret = decode_slice(avctx, &h->slice_ctx[0]);
+        int ret;
+
+        h->slice_ctx[0].next_slice_idx = h->mb_width * h->mb_height;
+
+        ret = decode_slice(avctx, &h->slice_ctx[0]);
         h->mb_y = h->slice_ctx[0].mb_y;
         return ret;
     } else {
-        for (i = 1; i < context_count; i++) {
+        for (i = 0; i < context_count; i++) {
+            int next_slice_idx = h->mb_width * h->mb_height;
+            int slice_idx;
+
             sl                 = &h->slice_ctx[i];
             sl->er.error_count = 0;
+
+            /* make sure none of those slices overlap */
+            slice_idx = sl->mb_y * h->mb_width + sl->mb_x;
+            for (j = 0; j < context_count; j++) {
+                H264SliceContext *sl2 = &h->slice_ctx[j];
+                int        slice_idx2 = sl2->mb_y * h->mb_width + sl2->mb_x;
+
+                if (i == j || slice_idx2 < slice_idx)
+                    continue;
+                next_slice_idx = FFMIN(next_slice_idx, slice_idx2);
+            }
+            sl->next_slice_idx = next_slice_idx;
         }
 
         avctx->execute(avctx, decode_slice, h->slice_ctx,