Fix transform plugin 90-degree rotations on I422.
authorSam Hocevar <sam@zoy.org>
Mon, 7 Apr 2008 14:47:49 +0000 (16:47 +0200)
committerSam Hocevar <sam@zoy.org>
Mon, 7 Apr 2008 14:51:51 +0000 (16:51 +0200)
I422 is a planar chroma with non-square pixels. It requires some pixel
play when rotating the image at a 90-degree angle. For other transformations
we just fall back to the original function.

modules/video_filter/filter_picture.h
modules/video_filter/transform.c

index 9806903..73ef0d5 100644 (file)
@@ -21,7 +21,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-#define CASE_PLANAR_YUV                     \
+/* FIXME: do all of these really have square pixels? */
+#define CASE_PLANAR_YUV_SQUARE              \
         case VLC_FOURCC('I','4','2','0'):   \
         case VLC_FOURCC('I','Y','U','V'):   \
         case VLC_FOURCC('J','4','2','0'):   \
         case VLC_FOURCC('I','4','1','1'):   \
         case VLC_FOURCC('I','4','1','0'):   \
         case VLC_FOURCC('Y','V','U','9'):   \
-        case VLC_FOURCC('I','4','2','2'):   \
-        case VLC_FOURCC('J','4','2','2'):   \
         case VLC_FOURCC('I','4','4','4'):   \
         case VLC_FOURCC('J','4','4','4'):   \
         case VLC_FOURCC('Y','U','V','A'):
 
+#define CASE_PLANAR_YUV_NONSQUARE           \
+        case VLC_FOURCC('I','4','2','2'):   \
+        case VLC_FOURCC('J','4','2','2'):
+
+#define CASE_PLANAR_YUV                     \
+        CASE_PLANAR_YUV_SQUARE              \
+        CASE_PLANAR_YUV_NONSQUARE           \
+
 #define CASE_PACKED_YUV_422                 \
         case VLC_FOURCC('U','Y','V','Y'):   \
         case VLC_FOURCC('U','Y','N','V'):   \
index b658ffe..e837745 100644 (file)
@@ -52,6 +52,7 @@ static void End       ( vout_thread_t * );
 static void Render    ( vout_thread_t *, picture_t * );
 
 static void FilterPlanar( vout_thread_t *, const picture_t *, picture_t * );
+static void FilterI422( vout_thread_t *, const picture_t *, picture_t * );
 static void FilterYUYV( vout_thread_t *, const picture_t *, picture_t * );
 
 static int  SendEvents( vlc_object_t *, char const *,
@@ -145,11 +146,16 @@ static int Create( vlc_object_t *p_this )
 
     switch( p_vout->fmt_in.i_chroma )
     {
-        CASE_PLANAR_YUV
+        CASE_PLANAR_YUV_SQUARE
         case VLC_FOURCC('G','R','E','Y'):
             p_vout->p_sys->pf_filter = FilterPlanar;
             break;
 
+        case VLC_FOURCC('I','4','2','2'):
+        case VLC_FOURCC('J','4','2','2'):
+            p_vout->p_sys->pf_filter = FilterI422;
+            break;
+
         CASE_PACKED_YUV_422
             p_vout->p_sys->pf_filter = FilterYUYV;
             break;
@@ -551,6 +557,156 @@ static void FilterPlanar( vout_thread_t *p_vout,
     }
 }
 
+static void FilterI422( vout_thread_t *p_vout,
+                        const picture_t *p_pic, picture_t *p_outpic )
+{
+    int i_index;
+    switch( p_vout->p_sys->i_mode )
+    {
+        case TRANSFORM_MODE_180:
+        case TRANSFORM_MODE_HFLIP:
+        case TRANSFORM_MODE_VFLIP:
+            /* Fall back on the default implementation */
+            FilterPlanar( p_vout, p_pic, p_outpic );
+            return;
+
+        case TRANSFORM_MODE_90:
+            for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
+            {
+                int i_pitch = p_pic->p[i_index].i_pitch;
+
+                uint8_t *p_in = p_pic->p[i_index].p_pixels;
+
+                uint8_t *p_out = p_outpic->p[i_index].p_pixels;
+                uint8_t *p_out_end = p_out +
+                    p_outpic->p[i_index].i_visible_lines *
+                    p_outpic->p[i_index].i_pitch;
+
+                if( i_index == 0 )
+                {
+                    for( ; p_out < p_out_end ; )
+                    {
+                        uint8_t *p_line_end;
+
+                        p_out_end -= p_outpic->p[i_index].i_pitch
+                                      - p_outpic->p[i_index].i_visible_pitch;
+                        p_line_end = p_in + p_pic->p[i_index].i_visible_lines *
+                            i_pitch;
+
+                        for( ; p_in < p_line_end ; )
+                        {
+                            p_line_end -= i_pitch;
+                            *(--p_out_end) = *p_line_end;
+                        }
+
+                        p_in++;
+                    }
+                }
+                else /* i_index == 1 or 2 */
+                {
+                    for( ; p_out < p_out_end ; )
+                    {
+                        uint8_t *p_line_end, *p_out_end2;
+
+                        p_out_end -= p_outpic->p[i_index].i_pitch
+                                      - p_outpic->p[i_index].i_visible_pitch;
+                        p_out_end2 = p_out_end - p_outpic->p[i_index].i_pitch;
+                        p_line_end = p_in + p_pic->p[i_index].i_visible_lines *
+                            i_pitch;
+
+                        for( ; p_in < p_line_end ; )
+                        {
+                            uint8_t p1, p2;
+
+                            p_line_end -= i_pitch;
+                            p1 = *p_line_end;
+                            p_line_end -= i_pitch;
+                            p2 = *p_line_end;
+
+                            /* Trick for (x+y)/2 without overflow, based on
+                             *   x + y == (x ^ y) + 2 * (x & y) */
+                            *(--p_out_end) = (p1 & p2) + ((p1 ^ p2) / 2);
+                            *(--p_out_end2) = (p1 & p2) + ((p1 ^ p2) / 2);
+                        }
+
+                        p_out_end = p_out_end2;
+                        p_in++;
+                    }
+                }
+            }
+            break;
+
+        case TRANSFORM_MODE_270:
+            for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
+            {
+                int i_pitch = p_pic->p[i_index].i_pitch;
+
+                uint8_t *p_in = p_pic->p[i_index].p_pixels;
+
+                uint8_t *p_out = p_outpic->p[i_index].p_pixels;
+                uint8_t *p_out_end = p_out +
+                    p_outpic->p[i_index].i_visible_lines *
+                    p_outpic->p[i_index].i_pitch;
+
+                if( i_index == 0 )
+                {
+                    for( ; p_out < p_out_end ; )
+                    {
+                        uint8_t *p_in_end;
+
+                        p_in_end = p_in + p_pic->p[i_index].i_visible_lines *
+                            i_pitch;
+
+                        for( ; p_in < p_in_end ; )
+                        {
+                            p_in_end -= i_pitch;
+                            *p_out++ = *p_in_end;
+                        }
+
+                        p_out += p_outpic->p[i_index].i_pitch
+                                  - p_outpic->p[i_index].i_visible_pitch;
+                        p_in++;
+                    }
+                }
+                else /* i_index == 1 or 2 */
+                {
+                    for( ; p_out < p_out_end ; )
+                    {
+                        uint8_t *p_in_end, *p_out2;
+
+                        p_in_end = p_in + p_pic->p[i_index].i_visible_lines *
+                            i_pitch;
+                        p_out2 = p_out + p_outpic->p[i_index].i_pitch;
+
+                        for( ; p_in < p_in_end ; )
+                        {
+                            uint8_t p1, p2;
+
+                            p_in_end -= i_pitch;
+                            p1 = *p_in_end;
+                            p_in_end -= i_pitch;
+                            p2 = *p_in_end;
+
+                            /* Trick for (x+y)/2 without overflow, based on
+                             *   x + y == (x ^ y) + 2 * (x & y) */
+                            *p_out++ = (p1 & p2) + ((p1 ^ p2) / 2);
+                            *p_out2++ = (p1 & p2) + ((p1 ^ p2) / 2);
+                        }
+
+                        p_out2 += p_outpic->p[i_index].i_pitch
+                                   - p_outpic->p[i_index].i_visible_pitch;
+                        p_out = p_out2;
+                        p_in++;
+                    }
+                }
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
 static void FilterYUYV( vout_thread_t *p_vout,
                         const picture_t *p_pic, picture_t *p_outpic )
 {
@@ -562,6 +718,11 @@ static void FilterYUYV( vout_thread_t *p_vout,
 
     switch( p_vout->p_sys->i_mode )
     {
+        case TRANSFORM_MODE_HFLIP:
+            /* Fall back on the default implementation */
+            FilterPlanar( p_vout, p_pic, p_outpic );
+            return;
+
         case TRANSFORM_MODE_90:
             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
             {
@@ -684,25 +845,6 @@ static void FilterYUYV( vout_thread_t *p_vout,
             }
             break;
 
-        case TRANSFORM_MODE_HFLIP:
-            for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
-            {
-                uint8_t *p_in = p_pic->p[i_index].p_pixels;
-                uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
-                                            * p_pic->p[i_index].i_pitch;
-
-                uint8_t *p_out = p_outpic->p[i_index].p_pixels;
-
-                for( ; p_in < p_in_end ; )
-                {
-                    p_in_end -= p_pic->p[i_index].i_pitch;
-                    p_vout->p_libvlc->pf_memcpy( p_out, p_in_end,
-                                           p_pic->p[i_index].i_visible_pitch );
-                    p_out += p_pic->p[i_index].i_pitch;
-                }
-            }
-            break;
-
         case TRANSFORM_MODE_VFLIP:
             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
             {