[vlc-devel] [PATCH] adjust: add 10-bit support (Fixes #9600)

Tristan Matthews tmatth at videolan.org
Tue May 5 16:53:43 CEST 2015


---
 modules/video_filter/adjust.c         | 153 ++++++++++++++++++++++++----------
 modules/video_filter/adjust_sat_hue.c | 124 +++++++++++++++++++++++----
 modules/video_filter/adjust_sat_hue.h |  12 +++
 3 files changed, 233 insertions(+), 56 deletions(-)

diff --git a/modules/video_filter/adjust.c b/modules/video_filter/adjust.c
index 620f36e..9573f72 100644
--- a/modules/video_filter/adjust.c
+++ b/modules/video_filter/adjust.c
@@ -45,6 +45,12 @@
 #   define M_PI 3.14159265358979323846
 #endif
 
+#define CASE_PLANAR_YUV10                   \
+        case VLC_CODEC_I420_10L:            \
+        case VLC_CODEC_I420_10B:            \
+        case VLC_CODEC_I444_10L:            \
+        case VLC_CODEC_I444_10B:
+
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -173,6 +179,13 @@ static int Create( vlc_object_t *p_this )
             p_sys->pf_process_sat_hue = planar_sat_hue_C;
             break;
 
+        CASE_PLANAR_YUV10
+            /* Planar YUV 10-bit */
+            p_filter->pf_video_filter = FilterPlanar;
+            p_sys->pf_process_sat_hue_clip = planar_sat_hue_clip_C_10bpp;
+            p_sys->pf_process_sat_hue = planar_sat_hue_C_10bpp;
+            break;
+
         CASE_PACKED_YUV_422
             /* Packed YUV 4:2:2 */
             p_filter->pf_video_filter = FilterPacked;
@@ -223,12 +236,11 @@ static void Destroy( vlc_object_t *p_this )
  *****************************************************************************/
 static picture_t *FilterPlanar( filter_t *p_filter, picture_t *p_pic )
 {
-    int pi_luma[256];
-    int pi_gamma[256];
+    /* The full range will only be used for 10-bit */
+    int pi_luma[1024];
+    int pi_gamma[1024];
 
     picture_t *p_outpic;
-    uint8_t *p_in, *p_in_end, *p_line_end;
-    uint8_t *p_out;
 
     filter_sys_t *p_sys = p_filter->p_sys;
 
@@ -241,12 +253,28 @@ static picture_t *FilterPlanar( filter_t *p_filter, picture_t *p_pic )
         return NULL;
     }
 
+    bool b_10bpp;
+    switch( p_filter->fmt_in.video.i_chroma )
+    {
+        CASE_PLANAR_YUV10
+            b_10bpp = true;
+            break;
+        default:
+            b_10bpp = false;
+    }
+
+    const float f_range = b_10bpp ? 1024.f : 256.f;
+    const float f_max = f_range - 1.f;
+    const int i_max = f_max;
+    const int i_range = f_range;
+    const unsigned i_mid = i_range >> 1;
+
     /* Get variables */
     vlc_mutex_lock( &p_sys->lock );
-    int32_t i_cont = lroundf( p_sys->f_contrast * 255.f );
-    int32_t i_lum = lroundf( (p_sys->f_brightness - 1.f) * 255.f );
+    int32_t i_cont = lroundf( p_sys->f_contrast * f_max );
+    int32_t i_lum = lroundf( (p_sys->f_brightness - 1.f) * f_max );
     float f_hue = p_sys->f_hue * (float)(M_PI / 180.);
-    int i_sat = (int)( p_sys->f_saturation * 256.f );
+    int i_sat = (int)( p_sys->f_saturation * f_range );
     float f_gamma = 1.f / p_sys->f_gamma;
     bool b_thres = p_sys->b_brightness_threshold;
     vlc_mutex_unlock( &p_sys->lock );
@@ -259,18 +287,18 @@ static picture_t *FilterPlanar( filter_t *p_filter, picture_t *p_pic )
 
         /* Contrast is a fast but kludged function, so I put this gap to be
          * cleaner :) */
-        i_lum += 128 - i_cont / 2;
+        i_lum += i_mid - i_cont / 2;
 
         /* Fill the gamma lookup table */
-        for( unsigned i = 0 ; i < 256 ; i++ )
+        for( int i = 0 ; i < i_range; i++ )
         {
-            pi_gamma[ i ] = clip_uint8_vlc( powf(i / 255.f, f_gamma) * 255.f);
+            pi_gamma[ i ] = VLC_CLIP( powf(i / f_max, f_gamma) * f_max, 0, i_max );
         }
 
         /* Fill the luma lookup table */
-        for( unsigned i = 0 ; i < 256 ; i++ )
+        for( int i = 0 ; i < i_range; i++ )
         {
-            pi_luma[ i ] = pi_gamma[clip_uint8_vlc( i_lum + i_cont * i / 256)];
+            pi_luma[ i ] = pi_gamma[VLC_CLIP( ( i_lum + i_cont * i / i_range), 0, i_max )];
         }
     }
     else
@@ -279,9 +307,9 @@ static picture_t *FilterPlanar( filter_t *p_filter, picture_t *p_pic )
          * We get luma as threshold value: the higher it is, the darker is
          * the image. Should I reverse this?
          */
-        for( int i = 0 ; i < 256 ; i++ )
+        for( int i = 0 ; i < i_range; i++ )
         {
-            pi_luma[ i ] = (i < i_lum) ? 0 : 255;
+            pi_luma[ i ] = (i < i_lum) ? 0 : i_max;
         }
 
         /*
@@ -293,50 +321,91 @@ static picture_t *FilterPlanar( filter_t *p_filter, picture_t *p_pic )
     /*
      * Do the Y plane
      */
-
-    p_in = p_pic->p[Y_PLANE].p_pixels;
-    p_in_end = p_in + p_pic->p[Y_PLANE].i_visible_lines
-                      * p_pic->p[Y_PLANE].i_pitch - 8;
-
-    p_out = p_outpic->p[Y_PLANE].p_pixels;
-
-    for( ; p_in < p_in_end ; )
+    if ( b_10bpp )
     {
-        p_line_end = p_in + p_pic->p[Y_PLANE].i_visible_pitch - 8;
+        uint16_t *p_in, *p_in_end, *p_line_end;
+        uint16_t *p_out;
+        p_in = (uint16_t *) p_pic->p[Y_PLANE].p_pixels;
+        p_in_end = p_in + p_pic->p[Y_PLANE].i_visible_lines
+            * (p_pic->p[Y_PLANE].i_pitch >> 1) - 8;
 
-        for( ; p_in < p_line_end ; )
+        p_out = (uint16_t *) p_outpic->p[Y_PLANE].p_pixels;
+
+        for( ; p_in < p_in_end ; )
         {
-            /* Do 8 pixels at a time */
-            *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
-            *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
-            *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
-            *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
+            p_line_end = p_in + (p_pic->p[Y_PLANE].i_visible_pitch >> 1) - 8;
+
+            for( ; p_in < p_line_end ; )
+            {
+                /* Do 8 pixels at a time */
+                *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
+                *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
+                *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
+                *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
+            }
+
+            p_line_end += 8;
+
+            for( ; p_in < p_line_end ; )
+            {
+                *p_out++ = pi_luma[ *p_in++ ];
+            }
+
+            p_in += (p_pic->p[Y_PLANE].i_pitch >> 1)
+                  - (p_pic->p[Y_PLANE].i_visible_pitch >> 1);
+            p_out += (p_outpic->p[Y_PLANE].i_pitch >> 1)
+                   - (p_outpic->p[Y_PLANE].i_visible_pitch >> 1);
         }
+    }
+    else
+    {
+        uint8_t *p_in, *p_in_end, *p_line_end;
+        uint8_t *p_out;
+        p_in = p_pic->p[Y_PLANE].p_pixels;
+        p_in_end = p_in + p_pic->p[Y_PLANE].i_visible_lines
+                 * p_pic->p[Y_PLANE].i_pitch - 8;
 
-        p_line_end += 8;
+        p_out = p_outpic->p[Y_PLANE].p_pixels;
 
-        for( ; p_in < p_line_end ; )
+        for( ; p_in < p_in_end ; )
         {
-            *p_out++ = pi_luma[ *p_in++ ];
+            p_line_end = p_in + p_pic->p[Y_PLANE].i_visible_pitch - 8;
+
+            for( ; p_in < p_line_end ; )
+            {
+                /* Do 8 pixels at a time */
+                *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
+                *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
+                *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
+                *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
+            }
+
+            p_line_end += 8;
+
+            for( ; p_in < p_line_end ; )
+            {
+                *p_out++ = pi_luma[ *p_in++ ];
+            }
+
+            p_in += p_pic->p[Y_PLANE].i_pitch
+                  - p_pic->p[Y_PLANE].i_visible_pitch;
+            p_out += p_outpic->p[Y_PLANE].i_pitch
+                   - p_outpic->p[Y_PLANE].i_visible_pitch;
         }
-
-        p_in += p_pic->p[Y_PLANE].i_pitch
-              - p_pic->p[Y_PLANE].i_visible_pitch;
-        p_out += p_outpic->p[Y_PLANE].i_pitch
-               - p_outpic->p[Y_PLANE].i_visible_pitch;
     }
 
     /*
      * Do the U and V planes
      */
 
-    int i_sin = sinf(f_hue) * 256.f;
-    int i_cos = cosf(f_hue) * 256.f;
+    int i_sin = sinf(f_hue) * f_max;
+    int i_cos = cosf(f_hue) * f_max;
 
-    int i_x = ( cosf(f_hue) + sinf(f_hue) ) * 32768.f;
-    int i_y = ( cosf(f_hue) - sinf(f_hue) ) * 32768.f;
+    /* pow(2, (bpp * 2) - 1) */
+    int i_x = ( cosf(f_hue) + sinf(f_hue) ) * f_range * i_mid;
+    int i_y = ( cosf(f_hue) - sinf(f_hue) ) * f_range * i_mid;
 
-    if ( i_sat > 256 )
+    if ( i_sat > i_range )
     {
         /* Currently no errors are implemented in the function, if any are added
          * check them here */
diff --git a/modules/video_filter/adjust_sat_hue.c b/modules/video_filter/adjust_sat_hue.c
index ab7b826..9d52297 100644
--- a/modules/video_filter/adjust_sat_hue.c
+++ b/modules/video_filter/adjust_sat_hue.c
@@ -30,19 +30,23 @@
 #include "filter_picture.h"
 #include "adjust_sat_hue.h"
 
-#define PLANAR_WRITE_UV_CLIP() \
+#define I_RANGE( i_bpp ) (1 << i_bpp)
+#define I_MAX( i_bpp ) (I_RANGE( i_bpp ) - 1)
+#define I_MID( i_bpp ) (I_RANGE( i_bpp ) >> 1)
+
+#define PLANAR_WRITE_UV_CLIP( i_bpp ) \
     i_u = *p_in++ ; i_v = *p_in_v++ ; \
-    *p_out++ = clip_uint8_vlc( (( ((i_u * i_cos + i_v * i_sin - i_x) >> 8) \
-                           * i_sat) >> 8) + 128); \
-    *p_out_v++ = clip_uint8_vlc( (( ((i_v * i_cos - i_u * i_sin - i_y) >> 8) \
-                           * i_sat) >> 8) + 128)
+    *p_out++ = VLC_CLIP( (( ((i_u * i_cos + i_v * i_sin - i_x) >> i_bpp) \
+                     * i_sat) >> i_bpp) + I_MID( i_bpp ), 0, I_MAX( i_bpp ) ); \
+    *p_out_v++ = VLC_CLIP( (( ((i_v * i_cos - i_u * i_sin - i_y) >> i_bpp) \
+                       * i_sat) >> i_bpp) + I_MID( i_bpp ), 0, I_MAX( i_bpp ) )
 
-#define PLANAR_WRITE_UV() \
+#define PLANAR_WRITE_UV( i_bpp ) \
     i_u = *p_in++ ; i_v = *p_in_v++ ; \
-    *p_out++ = (( ((i_u * i_cos + i_v * i_sin - i_x) >> 8) \
-                       * i_sat) >> 8) + 128; \
-    *p_out_v++ = (( ((i_v * i_cos - i_u * i_sin - i_y) >> 8) \
-                       * i_sat) >> 8) + 128
+    *p_out++ = (( ((i_u * i_cos + i_v * i_sin - i_x) >> i_bpp) \
+                       * i_sat) >> i_bpp) + I_MID( i_bpp ); \
+    *p_out_v++ = (( ((i_v * i_cos - i_u * i_sin - i_y) >> i_bpp) \
+                       * i_sat) >> i_bpp) + I_MID( i_bpp )
 
 #define PACKED_WRITE_UV_CLIP() \
     i_u = *p_in; p_in += 4; i_v = *p_in_v; p_in_v += 4; \
@@ -93,14 +97,14 @@ int planar_sat_hue_clip_C( picture_t * p_pic, picture_t * p_outpic, int i_sin, i
         for( ; p_in < p_line_end ; )
         {
             /* Do 8 pixels at a time */
-            ADJUST_8_TIMES( PLANAR_WRITE_UV_CLIP() );
+            ADJUST_8_TIMES( PLANAR_WRITE_UV_CLIP( 8 ) );
         }
 
         p_line_end += 8;
 
         for( ; p_in < p_line_end ; )
         {
-            PLANAR_WRITE_UV_CLIP();
+            PLANAR_WRITE_UV_CLIP( 8 );
         }
 
         p_in += p_pic->p[U_PLANE].i_pitch
@@ -139,14 +143,14 @@ int planar_sat_hue_C( picture_t * p_pic, picture_t * p_outpic, int i_sin, int i_
         for( ; p_in < p_line_end ; )
         {
             /* Do 8 pixels at a time */
-            ADJUST_8_TIMES( PLANAR_WRITE_UV() );
+            ADJUST_8_TIMES( PLANAR_WRITE_UV( 8 ) );
         }
 
         p_line_end += 8;
 
         for( ; p_in < p_line_end ; )
         {
-            PLANAR_WRITE_UV();
+            PLANAR_WRITE_UV( 8 );
         }
 
         p_in += p_pic->p[U_PLANE].i_pitch
@@ -162,6 +166,98 @@ int planar_sat_hue_C( picture_t * p_pic, picture_t * p_outpic, int i_sin, int i_
     return VLC_SUCCESS;
 }
 
+int planar_sat_hue_clip_C_10bpp( picture_t * p_pic, picture_t * p_outpic, int i_sin, int i_cos,
+                         int i_sat, int i_x, int i_y )
+{
+    uint16_t *p_in, *p_in_v, *p_in_end, *p_line_end;
+    uint16_t *p_out, *p_out_v;
+
+    p_in = (uint16_t *) p_pic->p[U_PLANE].p_pixels;
+    p_in_v = (uint16_t *) p_pic->p[V_PLANE].p_pixels;
+    p_in_end = p_in + p_pic->p[U_PLANE].i_visible_lines
+               * (p_pic->p[U_PLANE].i_pitch >> 1) - 8;
+
+    p_out = (uint16_t *) p_outpic->p[U_PLANE].p_pixels;
+    p_out_v = (uint16_t *) p_outpic->p[V_PLANE].p_pixels;
+
+    uint16_t i_u, i_v;
+
+    for( ; p_in < p_in_end ; )
+    {
+        p_line_end = p_in + (p_pic->p[U_PLANE].i_visible_pitch >> 1) - 8;
+
+        for( ; p_in < p_line_end ; )
+        {
+            /* Do 8 pixels at a time */
+            ADJUST_8_TIMES( PLANAR_WRITE_UV_CLIP( 10 ) );
+        }
+
+        p_line_end += 8;
+
+        for( ; p_in < p_line_end ; )
+        {
+            PLANAR_WRITE_UV_CLIP( 10 );
+        }
+
+        p_in += (p_pic->p[U_PLANE].i_pitch >> 1)
+                - (p_pic->p[U_PLANE].i_visible_pitch >> 1);
+        p_in_v += (p_pic->p[V_PLANE].i_pitch >> 1)
+                - (p_pic->p[V_PLANE].i_visible_pitch >> 1);
+        p_out += (p_outpic->p[U_PLANE].i_pitch >> 1)
+                - (p_outpic->p[U_PLANE].i_visible_pitch >> 1);
+        p_out_v += (p_outpic->p[V_PLANE].i_pitch >> 1)
+                    - (p_outpic->p[V_PLANE].i_visible_pitch >> 1);
+    }
+
+    return VLC_SUCCESS;
+}
+
+int planar_sat_hue_C_10bpp( picture_t * p_pic, picture_t * p_outpic, int i_sin, int i_cos,
+                            int i_sat, int i_x, int i_y )
+{
+    uint16_t *p_in, *p_in_v, *p_in_end, *p_line_end;
+    uint16_t *p_out, *p_out_v;
+
+    p_in = (uint16_t *) p_pic->p[U_PLANE].p_pixels;
+    p_in_v = (uint16_t *) p_pic->p[V_PLANE].p_pixels;
+    p_in_end = (uint16_t *) p_in + p_pic->p[U_PLANE].i_visible_lines
+                      * (p_pic->p[U_PLANE].i_pitch >> 1) - 8;
+
+    p_out = (uint16_t *) p_outpic->p[U_PLANE].p_pixels;
+    p_out_v = (uint16_t *) p_outpic->p[V_PLANE].p_pixels;
+
+    uint16_t i_u, i_v;
+
+    for( ; p_in < p_in_end ; )
+    {
+        p_line_end = p_in + (p_pic->p[U_PLANE].i_visible_pitch >> 1) - 8;
+
+        for( ; p_in < p_line_end ; )
+        {
+            /* Do 8 pixels at a time */
+            ADJUST_8_TIMES( PLANAR_WRITE_UV( 10 ) );
+        }
+
+        p_line_end += 8;
+
+        for( ; p_in < p_line_end ; )
+        {
+            PLANAR_WRITE_UV( 10 );
+        }
+
+        p_in += (p_pic->p[U_PLANE].i_pitch >> 1)
+              - (p_pic->p[U_PLANE].i_visible_pitch >> 1);
+        p_in_v += (p_pic->p[V_PLANE].i_pitch >> 1)
+                - (p_pic->p[V_PLANE].i_visible_pitch >> 1);
+        p_out += (p_outpic->p[U_PLANE].i_pitch >> 1)
+               - (p_outpic->p[U_PLANE].i_visible_pitch >> 1);
+        p_out_v += (p_outpic->p[V_PLANE].i_pitch >> 1)
+                 - (p_outpic->p[V_PLANE].i_visible_pitch >> 1);
+    }
+
+    return VLC_SUCCESS;
+}
+
 int packed_sat_hue_clip_C( picture_t * p_pic, picture_t * p_outpic, int i_sin, int i_cos,
                          int i_sat, int i_x, int i_y )
 {
diff --git a/modules/video_filter/adjust_sat_hue.h b/modules/video_filter/adjust_sat_hue.h
index f4dcd66..f4514d4 100644
--- a/modules/video_filter/adjust_sat_hue.h
+++ b/modules/video_filter/adjust_sat_hue.h
@@ -49,6 +49,18 @@ int planar_sat_hue_clip_C( picture_t * p_pic, picture_t * p_outpic,
  */
 int planar_sat_hue_C( picture_t * p_pic, picture_t * p_outpic,
                       int i_sin, int i_cos, int i_sat, int i_x, int i_y );
+/**
+ * Basic C compiler generated function for 10-bit planar format, i_sat > 1024
+ */
+int planar_sat_hue_clip_C_10bpp( picture_t * p_pic, picture_t * p_outpic,
+        int i_sin, int i_cos, int i_sat, int i_x, int i_y );
+
+/**
+ * Basic C compiler generated function for 10-bit planar format, i_sat <= 1024
+ */
+int planar_sat_hue_C_10bpp( picture_t * p_pic, picture_t * p_outpic,
+        int i_sin, int i_cos, int i_sat, int i_x, int i_y );
+
 
 /**
  * Basic C compiler generated function for packed format, i_sat > 256
-- 
2.1.0




More information about the vlc-devel mailing list