[FFmpeg-cvslog] avfilter/vf_scale: fix 4:1:0 interlaced chroma pos

Niklas Haas git at videolan.org
Fri Aug 16 12:44:51 EEST 2024


ffmpeg | branch: master | Niklas Haas <git at haasn.dev> | Thu Jul  4 16:28:50 2024 +0200| [c8bc6fabd79ee19df93f2486b8a6ebeedb7cd27e] | committer: Niklas Haas

avfilter/vf_scale: fix 4:1:0 interlaced chroma pos

The current logic hard-coded a check for v_sub == 1. We can extend this
logic slightly to cover the case of interlaced 4:1:0 (which has v_sub ==
2).

Here is a diagram explaining this scenario (with center-siting):

a   a   a   a   a   a   a   a

b   b   b   b   b   b   b   b
      X               X
a   a   a   a   a   a   a   a

b   b   b   b   b   b   b   b

a   a   a   a   a   a   a   a

b   b   b   b   b   b   b   b
      Y               Y
a   a   a   a   a   a   a   a

b   b   b   b   b   b   b   b

a = even luma rows
b = odd luma rows
X = even chroma sample
Y = odd chroma sample

In progressive mode, the chroma samples sit at (384, 384) respectively.

Relative to the 8x4 grid of even luma samples (a), the X sample sits at:
  h_chr_pos = 384
  v_chr_pos = 192

Relative to the 8x4 grid of odd luma samples (b), the Y sample sits at:
  h_chr_pos = 384
  v_chr_pos = 576

The new code calculates the correct values in all circumstances.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=c8bc6fabd79ee19df93f2486b8a6ebeedb7cd27e
---

 libavfilter/vf_scale.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index ea77bac1c3..afa159914b 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -643,9 +643,19 @@ static void calc_chroma_pos(int *h_pos_out, int *v_pos_out, int chroma_loc,
         v_pos = v_pos_override;
 
     /* Fix vertical chroma position for interlaced frames */
-    if (v_sub == 1 && index > 0) {
-        v_pos += 256 * (index == 2); /* offset by one luma row for odd rows */
-        v_pos >>= 1; /* double luma row distance */
+    if (v_sub && index > 0) {
+        /* When vertically subsampling, chroma samples are effectively only
+         * placed next to even rows. To access them from the odd field, we need
+         * to account for this shift by offsetting the distance of one luma row.
+         *
+         * For 4x vertical subsampling (v_sub == 2), they are only placed
+         * next to every *other* even row, so we need to shift by three luma
+         * rows to get to the chroma sample. */
+        if (index == 2)
+            v_pos += (256 << v_sub) - 256;
+
+        /* Luma row distance is doubled for fields, so halve offsets */
+        v_pos >>= 1;
     }
 
     /* Explicitly strip chroma offsets when not subsampling, because it



More information about the ffmpeg-cvslog mailing list