diff mbox series

[FFmpeg-devel,3/3] avcodec/ffv1: Implement new slice tiling

Message ID 20241001203126.1656651-3-michael@niedermayer.cc
State New
Headers show
Series [FFmpeg-devel,1/3] avcodec/ffv1enc: Correct error message about unsupported version | 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

Michael Niedermayer Oct. 1, 2024, 8:31 p.m. UTC
This fixes corner cases (requires version 4 or a spec update)

Fixes: Ticket5548

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavcodec/ffv1.c    | 21 +++++++++++++++++----
 libavcodec/ffv1.h    |  1 +
 libavcodec/ffv1dec.c |  8 ++++----
 libavcodec/ffv1enc.c |  2 +-
 4 files changed, 23 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/libavcodec/ffv1.c b/libavcodec/ffv1.c
index 2b8564c2f56..6c953e860f8 100644
--- a/libavcodec/ffv1.c
+++ b/libavcodec/ffv1.c
@@ -126,6 +126,19 @@  int ff_need_new_slices(int width, int num_h_slices, int chroma_shift) {
     return width % mpw && (width - i) % mpw == 0;
 }
 
+int ff_slice_coord(const FFV1Context *f, int width, int sx, int num_h_slices, int chroma_shift) {
+    int mpw = 1<<chroma_shift;
+    int awidth = FFALIGN(width, mpw);
+
+    if (f->version < 4 || f->version == 4 && f->micro_version < 3)
+        return width * sx / num_h_slices;
+
+    sx = (2LL * awidth * sx + num_h_slices * mpw) / (2 * num_h_slices * mpw) * mpw;
+    if (sx == awidth)
+        sx = width;
+    return sx;
+}
+
 av_cold int ff_ffv1_init_slice_contexts(FFV1Context *f)
 {
     int max_slice_count = f->num_h_slices * f->num_v_slices;
@@ -142,10 +155,10 @@  av_cold int ff_ffv1_init_slice_contexts(FFV1Context *f)
         FFV1SliceContext *sc = &f->slices[i];
         int sx          = i % f->num_h_slices;
         int sy          = i / f->num_h_slices;
-        int sxs         = f->avctx->width  *  sx      / f->num_h_slices;
-        int sxe         = f->avctx->width  * (sx + 1) / f->num_h_slices;
-        int sys         = f->avctx->height *  sy      / f->num_v_slices;
-        int sye         = f->avctx->height * (sy + 1) / f->num_v_slices;
+        int sxs         = ff_slice_coord(f, f->avctx->width , sx    , f->num_h_slices, f->chroma_h_shift);
+        int sxe         = ff_slice_coord(f, f->avctx->width , sx + 1, f->num_h_slices, f->chroma_h_shift);
+        int sys         = ff_slice_coord(f, f->avctx->height, sy   ,  f->num_v_slices, f->chroma_v_shift);
+        int sye         = ff_slice_coord(f, f->avctx->height, sy + 1, f->num_v_slices, f->chroma_v_shift);
 
         sc->slice_width  = sxe - sxs;
         sc->slice_height = sye - sys;
diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h
index e19c0df0142..10f46c80ee1 100644
--- a/libavcodec/ffv1.h
+++ b/libavcodec/ffv1.h
@@ -172,6 +172,7 @@  int ff_ffv1_allocate_initial_states(FFV1Context *f);
 void ff_ffv1_clear_slice_state(const FFV1Context *f, FFV1SliceContext *sc);
 int ff_ffv1_close(AVCodecContext *avctx);
 int ff_need_new_slices(int width, int num_h_slices, int chroma_shift);
+int ff_slice_coord(const FFV1Context *f, int width, int sx, int num_h_slices, int chroma_shift);
 
 static av_always_inline int fold(int diff, int bits)
 {
diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c
index 0afdeabd915..da31b863da5 100644
--- a/libavcodec/ffv1dec.c
+++ b/libavcodec/ffv1dec.c
@@ -187,10 +187,10 @@  static int decode_slice_header(const FFV1Context *f,
     if (sx > f->num_h_slices - sw || sy > f->num_v_slices - sh)
         return AVERROR_INVALIDDATA;
 
-    sc->slice_x      =  sx       * (int64_t)f->width  / f->num_h_slices;
-    sc->slice_y      =  sy       * (int64_t)f->height / f->num_v_slices;
-    sc->slice_width  = (sx + sw) * (int64_t)f->width  / f->num_h_slices - sc->slice_x;
-    sc->slice_height = (sy + sh) * (int64_t)f->height / f->num_v_slices - sc->slice_y;
+    sc->slice_x      =  ff_slice_coord(f, f->width , sx     , f->num_h_slices, f->chroma_h_shift);
+    sc->slice_y      =  ff_slice_coord(f, f->height, sy     , f->num_v_slices, f->chroma_v_shift);
+    sc->slice_width  =  ff_slice_coord(f, f->width , sx + sw, f->num_h_slices, f->chroma_h_shift) - sc->slice_x;
+    sc->slice_height =  ff_slice_coord(f, f->height, sy + sh, f->num_v_slices, f->chroma_v_shift) - sc->slice_y;
 
     av_assert0((unsigned)sc->slice_width  <= f->width &&
                 (unsigned)sc->slice_height <= f->height);
diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index 56af7dc4274..8b23e73c841 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -416,7 +416,7 @@  static int write_extradata(FFV1Context *f)
         if (f->version == 3) {
             f->micro_version = 4;
         } else if (f->version == 4)
-            f->micro_version = 2;
+            f->micro_version = 3;
         put_symbol(&c, state, f->micro_version, 0);
     }