diff mbox series

[FFmpeg-devel] avcodec/mss2: calculate draw region and revise split position

Message ID 812f50e814dbd8cd8d854da6ccd5a5d6477551ba.1666256242.git.pross@xvid.org
State Accepted
Commit 31162eb9490e51a526ff0f78a57303a4d6433aba
Headers show
Series [FFmpeg-devel] avcodec/mss2: calculate draw region and revise split position | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Peter Ross Oct. 20, 2022, 8:59 a.m. UTC
for videos with wmv9 rectangles, the region drawn by ff_mss12_decode_rect
may be less than the entire video area. the wmv9 rectangles are used to
calculate the ff_mss12_decode_rect draw region.

Fixes tickets #3255 and #4043
---

(will also fix identation as seperate commit on push)

 libavcodec/mss2.c | 70 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 66 insertions(+), 4 deletions(-)

Comments

Peter Ross Oct. 24, 2022, 8:56 a.m. UTC | #1
On Thu, Oct 20, 2022 at 07:59:25PM +1100, Peter Ross wrote:
> for videos with wmv9 rectangles, the region drawn by ff_mss12_decode_rect
> may be less than the entire video area. the wmv9 rectangles are used to
> calculate the ff_mss12_decode_rect draw region.
> 
> Fixes tickets #3255 and #4043
> ---
> 
> (will also fix identation as seperate commit on push)
> 
>  libavcodec/mss2.c | 70 ++++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 66 insertions(+), 4 deletions(-)

will push in a couple of days

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
Anton Khirnov Oct. 25, 2022, 8:47 a.m. UTC | #2
Quoting Peter Ross (2022-10-20 10:59:25)
> for videos with wmv9 rectangles, the region drawn by ff_mss12_decode_rect
> may be less than the entire video area. the wmv9 rectangles are used to
> calculate the ff_mss12_decode_rect draw region.
> 
> Fixes tickets #3255 and #4043

Would be nice to have a test.
diff mbox series

Patch

diff --git a/libavcodec/mss2.c b/libavcodec/mss2.c
index d8a30019f7..69494d8c44 100644
--- a/libavcodec/mss2.c
+++ b/libavcodec/mss2.c
@@ -468,6 +468,39 @@  struct Rectangle {
     int coded, x, y, w, h;
 };
 
+struct Rectangle2 {
+    int left, right, top, bottom;
+};
+
+static void calc_draw_region(struct Rectangle2 * draw, const struct Rectangle2 * rect)
+{
+#define COMPARE(top, bottom, left, right)  \
+    if (rect->top <= draw->top && rect->bottom >= draw->bottom) { \
+        if (rect->left <= draw->left && rect->right >= draw->left) \
+            draw->left = FFMIN(rect->right, draw->right); \
+        \
+        if (rect->right >= draw->right) { \
+            if (rect->left >= draw->left) { \
+                if (rect->left < draw->right) \
+                    draw->right = rect->left; \
+            } else { \
+                draw->right = draw->left; \
+            } \
+        } \
+    }
+
+    COMPARE(top, bottom, left, right)
+    COMPARE(left, right, top, bottom)
+}
+
+static int calc_split_position(int split_position, const struct Rectangle2 * rect, int height)
+{
+    if (rect->top || rect->bottom != height)
+        split_position = rect->top + split_position * (rect->bottom - rect->top) / height;
+
+    return av_clip(split_position, rect->top + 1, rect->bottom - 1);
+}
+
 #define MAX_WMV9_RECTANGLES 20
 #define ARITH2_PADDING 2
 
@@ -485,6 +518,7 @@  static int mss2_decode_frame(AVCodecContext *avctx, AVFrame *frame,
     int keyframe, has_wmv9, has_mv, is_rle, is_555, ret;
 
     struct Rectangle wmv9rects[MAX_WMV9_RECTANGLES], *r;
+    struct Rectangle2 draw;
     int used_rects = 0, i, implicit_rect = 0, av_uninit(wmv9_mask);
 
     if ((ret = init_get_bits8(&gb, buf, buf_size)) < 0)
@@ -671,11 +705,32 @@  static int mss2_decode_frame(AVCodecContext *avctx, AVFrame *frame,
             bytestream2_init(&gB, buf, buf_size + ARITH2_PADDING);
             arith2_init(&acoder, &gB);
             c->keyframe = keyframe;
-            if (c->corrupted = ff_mss12_decode_rect(&ctx->sc[0], &acoder, 0, 0,
-                                                    avctx->width,
-                                                    ctx->split_position))
+
+            draw.left = 0;
+            draw.top = 0;
+            draw.right = avctx->width;
+            draw.bottom = avctx->height;
+            if (wmv9_mask == -1) {
+                for (i = 0; i < used_rects; i++) {
+                    struct Rectangle2 r;
+                    r.left   = wmv9rects[i].x;
+                    r.top    = wmv9rects[i].y;
+                    r.right  = r.left + wmv9rects[i].w;
+                    r.bottom = r.top + wmv9rects[i].h;
+                    calc_draw_region(&draw, &r);
+                }
+            }
+
+            if (draw.left >= avctx->width || draw.right > avctx->width ||
+                draw.top >= avctx->height || draw.bottom > avctx->height)
                 return AVERROR_INVALIDDATA;
 
+            if (c->slice_split && draw.bottom - draw.top >= 10) {
+                ctx->split_position = calc_split_position(ctx->split_position, &draw, avctx->height);
+            if (c->corrupted = ff_mss12_decode_rect(&ctx->sc[0], &acoder, 0, draw.top,
+                                                    avctx->width,
+                                                    ctx->split_position - draw.top))
+                return AVERROR_INVALIDDATA;
             buf      += arith2_get_consumed_bytes(&acoder);
             buf_size -= arith2_get_consumed_bytes(&acoder);
             if (c->slice_split) {
@@ -686,7 +741,14 @@  static int mss2_decode_frame(AVCodecContext *avctx, AVFrame *frame,
                 if (c->corrupted = ff_mss12_decode_rect(&ctx->sc[1], &acoder, 0,
                                                         ctx->split_position,
                                                         avctx->width,
-                                                        avctx->height - ctx->split_position))
+                                                        draw.bottom - ctx->split_position))
+                    return AVERROR_INVALIDDATA;
+                buf      += arith2_get_consumed_bytes(&acoder);
+                buf_size -= arith2_get_consumed_bytes(&acoder);
+            }
+            } else {
+                if (c->corrupted = ff_mss12_decode_rect(&ctx->sc[0], &acoder, draw.left, draw.top,
+                                                        draw.right - draw.left, draw.bottom - draw.top))
                     return AVERROR_INVALIDDATA;
 
                 buf      += arith2_get_consumed_bytes(&acoder);