]> git.sesse.net Git - mlt/commitdiff
Improve colorspace handling (work in progress)
authorDan Dennedy <dan@dennedy.org>
Tue, 24 Aug 2010 06:32:40 +0000 (23:32 -0700)
committerDan Dennedy <dan@dennedy.org>
Sun, 26 Sep 2010 22:20:15 +0000 (15:20 -0700)
Trying to add support for non-scaling luma between YCbCr and RGB
conversions as well as support for ITU Rec. 709 luma conversion for HD
formats.

src/framework/mlt_frame.c
src/framework/mlt_profile.h
src/framework/mlt_types.h
src/modules/avformat/filter_avcolour_space.c
src/modules/avformat/filter_swscale.c
src/modules/avformat/producer_avformat.c
src/modules/gtk2/producer_pixbuf.c
src/modules/qimage/producer_qimage.c
src/modules/sdl/producer_sdl_image.c

index 1a49e74ac1d5094b958d04c31b9325833586b95e..2053cc847c7bc6675ae8cb41caaf1bdaa22b1253 100644 (file)
@@ -351,6 +351,9 @@ const char * mlt_image_format_name( mlt_image_format format )
                case mlt_image_yuv422:  return "yuv422";
                case mlt_image_yuv420p: return "yuv420p";
                case mlt_image_opengl:  return "opengl";
+               case mlt_image_rgb24_full:  return "rgb24_full";
+               case mlt_image_rgb24a_full: return "rgb24a_full";
+               case mlt_image_yuv422_709:  return "yuv422_709";
        }
        return "invalid";
 }
@@ -455,6 +458,7 @@ int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *for
                                *buffer = NULL;
                                break;
                        case mlt_image_rgb24:
+                       case mlt_image_rgb24_full:
                                size *= 3;
                                size += *width * 3;
                                *buffer = mlt_pool_alloc( size );
@@ -462,6 +466,7 @@ int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *for
                                        memset( *buffer, 255, size );
                                break;
                        case mlt_image_rgb24a:
+                       case mlt_image_rgb24a_full:
                        case mlt_image_opengl:
                                size *= 4;
                                size += *width * 4;
index 6245640e58dea8ed192383895873a4c1abf2994a..bd673a131379192317431dc846bf7fc0f6c39301 100644 (file)
@@ -42,6 +42,7 @@ struct mlt_profile_s
        int sample_aspect_den;  /**< the denominator of the pixel aspect ratio */
        int display_aspect_num; /**< the numerator of the image aspect ratio in case it can not be simply derived (e.g. ITU-R 601) */
        int display_aspect_den; /**< the denominator of the image aspect ratio in case it can not be simply derived (e.g. ITU-R 601) */
+       int luma_function;
 };
 
 extern mlt_profile mlt_profile_init( const char *name );
index 05c7bf5c95e839b9c317ae70543bdcfb5a964c30..b549f4c859c3db7872f78e6fe3ffa8ff7aeb2e12 100644 (file)
@@ -40,7 +40,10 @@ typedef enum
        mlt_image_rgb24a,  /**< 8-bit RGB with alpha channel */
        mlt_image_yuv422,  /**< 8-bit YUV 4:2:2 packed */
        mlt_image_yuv420p, /**< 8-bit YUV 4:2:0 planar */
-       mlt_image_opengl   /**< suitable for OpenGL texture */
+       mlt_image_opengl,  /**< suitable for OpenGL texture */
+       mlt_image_rgb24_full,  /**< 8-bit RGB */
+       mlt_image_rgb24a_full, /**< 8-bit RGB with alpha channel */
+       mlt_image_yuv422_709,  /**< 8-bit YUV 4:2:2 packed */
 }
 mlt_image_format;
 
index aed9b9714744948d78bf75087593552d3a7acb71..c1f6b203f365c7a4c0c28574fb1778b9cde1ab1e 100644 (file)
@@ -52,13 +52,16 @@ static int convert_mlt_to_av_cs( mlt_image_format format )
        switch( format )
        {
                case mlt_image_rgb24:
+               case mlt_image_rgb24_full:
                        value = PIX_FMT_RGB24;
                        break;
                case mlt_image_rgb24a:
                case mlt_image_opengl:
+               case mlt_image_rgb24a_full:
                        value = PIX_FMT_RGBA;
                        break;
                case mlt_image_yuv422:
+               case mlt_image_yuv422_709:
                        value = PIX_FMT_YUYV422;
                        break;
                case mlt_image_yuv420p:
@@ -72,7 +75,48 @@ static int convert_mlt_to_av_cs( mlt_image_format format )
        return value;
 }
 
-static void av_convert_image( uint8_t *out, uint8_t *in, int out_fmt, int in_fmt, int width, int height )
+enum luma_scale {
+       LUMA_SCALE_AUTO = 0,
+       LUMA_SCALE_NONE,
+       LUMA_SCALE_OUT,
+       LUMA_SCALE_IN
+};
+
+static void set_luma_transfer( struct SwsContext *context, int is_709, enum luma_scale scale )
+{
+       int *coefficients;
+       int range_in, range_out;
+       int brightness, contrast, saturation;
+
+       if ( sws_getColorspaceDetails( context, &coefficients, &range_in, &coefficients, &range_out,
+                       &brightness, &contrast, &saturation ) != -1 )
+       {
+               // Don't change these from defaults unless explicitly told to.
+               switch ( scale )
+               {
+               case LUMA_SCALE_NONE:
+                       range_in = range_out = 1;
+                       break;
+               case LUMA_SCALE_OUT:
+                       range_in = 0;
+                       range_out = 1;
+                       break;
+               case LUMA_SCALE_IN:
+                       range_in = 1;
+                       range_out = 0;
+                       break;
+               default:
+                       break;
+               }
+               if ( is_709 )
+                       coefficients = sws_getCoefficients( SWS_CS_ITU709 );
+               sws_setColorspaceDetails( context, coefficients, range_in, coefficients, range_out,
+                       brightness, contrast, saturation );
+       }
+}
+
+static void av_convert_image( uint8_t *out, uint8_t *in, int out_fmt, int in_fmt,
+       int width, int height, int is_709, int is_full )
 {
        AVPicture input;
        AVPicture output;
@@ -94,6 +138,7 @@ static void av_convert_image( uint8_t *out, uint8_t *in, int out_fmt, int in_fmt
 #ifdef SWSCALE
        struct SwsContext *context = sws_getContext( width, height, in_fmt,
                width, height, out_fmt, flags, NULL, NULL, NULL);
+       set_luma_transfer( context, is_709, is_full );
        sws_scale( context, input.data, input.linesize, 0, height,
                output.data, output.linesize);
        sws_freeContext( context );
@@ -154,7 +199,9 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo
                }
 
                // Update the output
-               av_convert_image( output, *image, out_fmt, in_fmt, width, height );
+               int is_709 = output_format == mlt_image_yuv422 && width * height > 750000;
+               enum luma_scale luma = LUMA_SCALE_AUTO;
+               av_convert_image( output, *image, out_fmt, in_fmt, width, height, is_709, luma );
                *image = output;
                *format = output_format;
                mlt_properties_set_data( properties, "image", output, size, mlt_pool_release, NULL );
index a82b5e7ccd5d1338040e0ea9af4cc973a4029178..5afc17713332282a64ec314983ce18c63324bd05 100644 (file)
@@ -43,13 +43,16 @@ static inline int convert_mlt_to_av_cs( mlt_image_format format )
        switch( format )
        {
                case mlt_image_rgb24:
+               case mlt_image_rgb24_full:
                        value = PIX_FMT_RGB24;
                        break;
                case mlt_image_rgb24a:
+               case mlt_image_rgb24a_full:
                case mlt_image_opengl:
                        value = PIX_FMT_RGB32;
                        break;
                case mlt_image_yuv422:
+               case mlt_image_yuv422_709:
                        value = PIX_FMT_YUYV422;
                        break;
                case mlt_image_yuv420p:
index b7a8ed462afe3aaa8b37d8f1492557639831c26a..a17e833f026d742f085fa36fd34c5ac029e68b5c 100644 (file)
@@ -689,9 +689,53 @@ static void get_audio_streams_info( producer_avformat this )
        this->resample_factor = 1.0;
 }
 
+#ifdef SWSCALE
+enum luma_scale {
+       LUMA_SCALE_AUTO = 0,
+       LUMA_SCALE_NONE,
+       LUMA_SCALE_OUT,
+       LUMA_SCALE_IN
+};
+
+static void set_luma_transfer( struct SwsContext *context, int is_709, enum luma_scale scale )
+{
+       int *coefficients;
+       int range_in, range_out;
+       int brightness, contrast, saturation;
+
+       if ( sws_getColorspaceDetails( context, &coefficients, &range_in, &coefficients, &range_out,
+                       &brightness, &contrast, &saturation ) != -1 )
+       {
+               // Don't change these from defaults unless explicitly told to.
+               switch ( scale )
+               {
+               case LUMA_SCALE_NONE:
+                       range_in = range_out = 1;
+                       break;
+               case LUMA_SCALE_OUT:
+                       range_in = 0;
+                       range_out = 1;
+                       break;
+               case LUMA_SCALE_IN:
+                       range_in = 1;
+                       range_out = 0;
+                       break;
+               default:
+                       break;
+               }
+               if ( is_709 )
+                       coefficients = sws_getCoefficients( SWS_CS_ITU709 );
+               sws_setColorspaceDetails( context, coefficients, range_in, coefficients, range_out,
+                       brightness, contrast, saturation );
+       }
+}
+#endif
+
 static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt, mlt_image_format *format, int width, int height )
 {
 #ifdef SWSCALE
+       int is_709 = *format == mlt_image_yuv422 && width * height > 750000;
+       enum luma_scale luma = LUMA_SCALE_AUTO;
        int flags = SWS_BILINEAR | SWS_ACCURATE_RND;
 
 #ifdef USE_MMX
@@ -708,6 +752,7 @@ static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt,
                        width, height, PIX_FMT_RGBA, flags, NULL, NULL, NULL);
                AVPicture output;
                avpicture_fill( &output, buffer, PIX_FMT_RGBA, width, height );
+               set_luma_transfer( context, is_709, luma );
                sws_scale( context, frame->data, frame->linesize, 0, height,
                        output.data, output.linesize);
                sws_freeContext( context );
@@ -723,6 +768,7 @@ static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt,
                output.linesize[0] = width;
                output.linesize[1] = width >> 1;
                output.linesize[2] = width >> 1;
+               set_luma_transfer( context, is_709, luma );
                sws_scale( context, frame->data, frame->linesize, 0, height,
                        output.data, output.linesize);
                sws_freeContext( context );
@@ -733,6 +779,7 @@ static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt,
                        width, height, PIX_FMT_RGB24, flags | SWS_FULL_CHR_H_INT, NULL, NULL, NULL);
                AVPicture output;
                avpicture_fill( &output, buffer, PIX_FMT_RGB24, width, height );
+               set_luma_transfer( context, is_709, luma );
                sws_scale( context, frame->data, frame->linesize, 0, height,
                        output.data, output.linesize);
                sws_freeContext( context );
@@ -743,6 +790,7 @@ static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt,
                        width, height, PIX_FMT_RGBA, flags | SWS_FULL_CHR_H_INT, NULL, NULL, NULL);
                AVPicture output;
                avpicture_fill( &output, buffer, PIX_FMT_RGBA, width, height );
+               set_luma_transfer( context, is_709, luma );
                sws_scale( context, frame->data, frame->linesize, 0, height,
                        output.data, output.linesize);
                sws_freeContext( context );
@@ -753,6 +801,8 @@ static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt,
                        width, height, PIX_FMT_YUYV422, flags | SWS_FULL_CHR_H_INP, NULL, NULL, NULL);
                AVPicture output;
                avpicture_fill( &output, buffer, PIX_FMT_YUYV422, width, height );
+               is_709 = width * height > 750000;
+               set_luma_transfer( context, is_709, luma );
                sws_scale( context, frame->data, frame->linesize, 0, height,
                        output.data, output.linesize);
                sws_freeContext( context );
index c99d711e0bcc4708189a4496bd76c2ac6fd0d1ec..fc44b902c4c5677c46f66d033f6653512459def1 100644 (file)
@@ -480,7 +480,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
                mlt_properties_set_data( properties, "image", image_copy, image_size, mlt_pool_release, NULL );
                // We're going to pass the copy on
                *buffer = image_copy;
-               *format = this->alpha ? mlt_image_rgb24a : mlt_image_rgb24;
+               *format = this->alpha ? mlt_image_rgb24a_full : mlt_image_rgb24_full;
                mlt_log_debug( MLT_PRODUCER_SERVICE( &this->parent ), "%dx%d (%s)\n",
                        this->width, this->height, mlt_image_format_name( *format ) );
        }
index 66d0833395da078b38c4226f0b4a3e844931fa1e..218691abda7ce64dd73b564aa8c9c00844d156f4 100644 (file)
@@ -202,7 +202,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
                mlt_properties_set_data( properties, "image", image_copy, image_size, mlt_pool_release, NULL );
                // We're going to pass the copy on
                *buffer = image_copy;
-               *format = this->has_alpha ? mlt_image_rgb24a : mlt_image_rgb24;
+               *format = this->has_alpha ? mlt_image_rgb24a_full : mlt_image_rgb24_full;
                mlt_log_debug( MLT_PRODUCER_SERVICE( &this->parent ), "%dx%d (%s)\n", 
                        this->current_width, this->current_height, mlt_image_format_name( *format ) );
        }
index 0d6246643488e79289e86df0cf250976e3471e2b..2355f6533ef88631bd13bd9a33faad0ceed198f5 100644 (file)
@@ -60,13 +60,13 @@ static int producer_get_image( mlt_frame frame, uint8_t **image, mlt_image_forma
        switch( surface->format->BitsPerPixel )
        {
                case 32:
-                       *format = mlt_image_rgb24a;
+                       *format = mlt_image_rgb24a_full;
                        image_size = *width * *height * 4;
                        *image = mlt_pool_alloc( image_size );
                        memcpy( *image, surface->pixels, image_size );
                        break;
                case 24:
-                       *format = mlt_image_rgb24;
+                       *format = mlt_image_rgb24_full;
                        *image = mlt_pool_alloc( image_size );
                        memcpy( *image, surface->pixels, image_size );
                        break;