>From fa5e5646a5d2564aa9d1b8e0fa0f6ccb47644380 Mon Sep 17 00:00:00 2001
From: Grigori Goronzy <greg@blackbox>
Date: Sat, 17 Jul 2010 19:12:59 +0200
Subject: [PATCH] blend: subsample chroma correctly when blending rgba to yv12

Use average of 2x2 RGBA pixel block for chroma. Fixes #3009.
---
 modules/video_filter/blend.c |   47 +++++++++++++++++++++++++++++++++---------
 1 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/modules/video_filter/blend.c b/modules/video_filter/blend.c
index 530be44..80f88c1 100644
--- a/modules/video_filter/blend.c
+++ b/modules/video_filter/blend.c
@@ -1232,13 +1232,13 @@ static void BlendRGBAI420( filter_t *p_filter,
               p_filter->fmt_out.video.i_x_offset +
               p_dst->p[Y_PLANE].i_pitch *
               ( i_y_offset + p_filter->fmt_out.video.i_y_offset );
-    p_dst_u = p_dst->p[U_PLANE].p_pixels + i_x_offset/2 +
-              p_filter->fmt_out.video.i_x_offset/2 +
-              ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
+    p_dst_u = p_dst->p[U_PLANE].p_pixels + (i_x_offset +
+              p_filter->fmt_out.video.i_x_offset + 1) / 2 +
+              ( i_y_offset + p_filter->fmt_out.video.i_y_offset + 1) / 2 *
               p_dst->p[U_PLANE].i_pitch;
-    p_dst_v = p_dst->p[V_PLANE].p_pixels + i_x_offset/2 +
-              p_filter->fmt_out.video.i_x_offset/2 +
-              ( i_y_offset + p_filter->fmt_out.video.i_y_offset ) / 2 *
+    p_dst_v = p_dst->p[V_PLANE].p_pixels + (i_x_offset +
+              p_filter->fmt_out.video.i_x_offset + 1) / 2 +
+              ( i_y_offset + p_filter->fmt_out.video.i_y_offset + 1) / 2 *
               p_dst->p[V_PLANE].i_pitch;
 
     i_src_pix_pitch = p_src_pic->p->i_pixel_pitch;
@@ -1251,10 +1251,11 @@ static void BlendRGBAI420( filter_t *p_filter,
     /* Draw until we reach the bottom of the subtitle */
     for( i_y = 0; i_y < i_height; i_y++,
          p_dst_y += i_dst_pitch,
-         p_dst_u += b_even_scanline ? i_dst_pitch/2 : 0,
-         p_dst_v += b_even_scanline ? i_dst_pitch/2 : 0,
+         p_dst_u += b_even_scanline ? p_dst->p[U_PLANE].i_pitch : 0,
+         p_dst_v += b_even_scanline ? p_dst->p[V_PLANE].i_pitch : 0,
          p_src += i_src_pitch )
     {
+        bool b_even_col = i_x_offset % 2;
         b_even_scanline = !b_even_scanline;
 
         /* Draw until we reach the end of the line */
@@ -1264,16 +1265,42 @@ static void BlendRGBAI420( filter_t *p_filter,
             const int G = p_src[i_x * i_src_pix_pitch + 1];
             const int B = p_src[i_x * i_src_pix_pitch + 2];
 
+            b_even_col = !b_even_col;
+
             i_trans = vlc_alpha( p_src[i_x * i_src_pix_pitch + 3], i_alpha );
             if( !i_trans )
                 continue;
 
             /* Blending */
             rgb_to_yuv( &y, &u, &v, R, G, B );
-
             p_dst_y[i_x] = vlc_blend( y, p_dst_y[i_x], i_trans );
-            if( b_even_scanline && i_x % 2 == 0 )
+
+            /* Blend u/v planes */
+            if( b_even_scanline && b_even_col && i_x < (i_width - 1) && i_y < (i_height - 1) )
             {
+                /* Average RGBA of 2x2 pixel block */
+                const int R = p_src[i_x * i_src_pix_pitch + 0]
+                    + p_src[(i_x + 1) * i_src_pix_pitch + 0]
+                    + p_src[i_x * i_src_pix_pitch + i_src_pitch + 0]
+                    + p_src[(i_x + 1) * i_src_pix_pitch + i_src_pitch + 0];
+                const int G = p_src[i_x * i_src_pix_pitch + 1]
+                    + p_src[(i_x + 1) * i_src_pix_pitch + 1]
+                    + p_src[(i_x) * i_src_pix_pitch + i_src_pitch + 1]
+                    + p_src[(i_x + 1) * i_src_pix_pitch + i_src_pitch + 1];
+                const int B = p_src[i_x * i_src_pix_pitch + 2]
+                    + p_src[(i_x + 1) * i_src_pix_pitch + 2]
+                    + p_src[(i_x) * i_src_pix_pitch + i_src_pitch + 2]
+                    + p_src[(i_x + 1) * i_src_pix_pitch + i_src_pitch + 2];
+                const int A = p_src[i_x * i_src_pix_pitch + 3]
+                    + p_src[(i_x + 1) * i_src_pix_pitch + 3]
+                    + p_src[(i_x) * i_src_pix_pitch + i_src_pitch + 3]
+                    + p_src[(i_x + 1) * i_src_pix_pitch + i_src_pitch + 3];
+
+                /* Convert */
+                rgb_to_yuv( &y, &u, &v, R >> 2, G >> 2, B >> 2 );
+                i_trans = vlc_alpha( A >> 2, i_alpha );
+
+                /* Blending */
                 p_dst_u[i_x/2] = vlc_blend( u, p_dst_u[i_x/2], i_trans );
                 p_dst_v[i_x/2] = vlc_blend( v, p_dst_v[i_x/2], i_trans );
             }
-- 
1.6.3.2

