]> git.sesse.net Git - mlt/commitdiff
Add input YUV colorspace (601 vs 709) handling.
authorDan Dennedy <dan@dennedy.org>
Tue, 24 Aug 2010 08:49:22 +0000 (01:49 -0700)
committerDan Dennedy <dan@dennedy.org>
Sun, 26 Sep 2010 22:20:15 +0000 (15:20 -0700)
Still need to work on the output side including normalization and
setting the encoder.

src/framework/mlt_profile.h
src/modules/avformat/filter_avcolour_space.c
src/modules/avformat/producer_avformat.c

index bd673a131379192317431dc846bf7fc0f6c39301..2ac6799c297d917ec3359374802e4de4048f0ab9 100644 (file)
@@ -42,7 +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;
+       int colorspace;         /**< the Y'CbCr colorspace standard: =601 for ITU-R 601, =709 for ITU-R 709, or =240 for SMPTE240M */
 };
 
 extern mlt_profile mlt_profile_init( const char *name );
index d908987c98e2f3ebb374d4789ccb4629ab0a905e..e5c4b3993c1a41b1ce6b599511e3c404dee47608 100644 (file)
@@ -72,7 +72,7 @@ static int convert_mlt_to_av_cs( mlt_image_format format )
        return value;
 }
 
-static void set_luma_transfer( struct SwsContext *context, int is_709, int no_scale )
+static void set_luma_transfer( struct SwsContext *context, int yuv_std, int no_scale )
 {
        int *coefficients;
        int range;
@@ -84,15 +84,17 @@ static void set_luma_transfer( struct SwsContext *context, int is_709, int no_sc
                // Don't change these from defaults unless explicitly told to.
                if ( no_scale )
                        range = 1;
-               if ( is_709 )
+               if ( yuv_std == 709 )
                        coefficients = sws_getCoefficients( SWS_CS_ITU709 );
+               else if ( yuv_std == 240 )
+                       coefficients = sws_getCoefficients( SWS_CS_SMPTE240M );
                sws_setColorspaceDetails( context, coefficients, range, coefficients, range,
                        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 no_scale )
+       int width, int height, int yuv_std, int no_scale )
 {
        AVPicture input;
        AVPicture output;
@@ -114,7 +116,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, no_scale );
+       set_luma_transfer( context, yuv_std, no_scale );
        sws_scale( context, input.data, input.linesize, 0, height,
                output.data, output.linesize);
        sws_freeContext( context );
@@ -175,7 +177,7 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo
                }
 
                // Update the output
-               int is_709 = output_format == mlt_image_yuv422 && width * height > 750000;
+               int yuv_std = mlt_properties_get_int( properties, "yuv_std" );
                int no_scale_luma = 0;
                if ( *format == mlt_image_yuv422 && mlt_properties_get_int( properties, "skip_luma_scale" )
                         && ( output_format == mlt_image_rgb24 || output_format == mlt_image_rgb24a ) )
@@ -183,7 +185,7 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo
                        no_scale_luma = 1;
                        mlt_properties_set( properties, "skip_luma_scale", NULL );
                }
-               av_convert_image( output, *image, out_fmt, in_fmt, width, height, is_709, no_scale_luma );
+               av_convert_image( output, *image, out_fmt, in_fmt, width, height, yuv_std, no_scale_luma );
                *image = output;
                *format = output_format;
                mlt_properties_set_data( properties, "image", output, size, mlt_pool_release, NULL );
index 72daaf4e23f0d83bdf33e82a9bf84a4b67804c47..77f4aba6e6ba7234f0dc8f8e6e6fb54f4027d2c9 100644 (file)
@@ -95,6 +95,7 @@ struct producer_avformat_s
        unsigned int invalid_pts_counter;
        double resample_factor;
        mlt_cache image_cache;
+       int yuv_std;
 #ifdef VDPAU
        struct
        {
@@ -281,6 +282,8 @@ static mlt_properties find_default_streams( mlt_properties meta_media, AVFormatC
                                mlt_properties_set( meta_media, key, avcodec_get_pix_fmt_name( codec_context->pix_fmt ) );
                                snprintf( key, sizeof(key), "meta.media.%d.codec.sample_aspect_ratio", i );
                                mlt_properties_set_double( meta_media, key, av_q2d( codec_context->sample_aspect_ratio ) );
+                               snprintf( key, sizeof(key), "meta.media.%d.codec.colorspace", i );
+                               mlt_properties_set_int( meta_media, key, codec_context->colorspace );
                                break;
                        case CODEC_TYPE_AUDIO:
                                if ( *audio_index < 0 )
@@ -689,8 +692,7 @@ static void get_audio_streams_info( producer_avformat this )
        this->resample_factor = 1.0;
 }
 
-#ifdef SWSCALE
-static void set_luma_transfer( struct SwsContext *context, int is_709, int no_scale )
+static void set_luma_transfer( struct SwsContext *context, int yuv_std, int no_scale )
 {
        int *coefficients;
        int range;
@@ -702,18 +704,19 @@ static void set_luma_transfer( struct SwsContext *context, int is_709, int no_sc
                // Don't change these from defaults unless explicitly told to.
                if ( no_scale )
                        range = 1;
-               if ( is_709 )
+               if ( yuv_std == 709 )
                        coefficients = sws_getCoefficients( SWS_CS_ITU709 );
+               else if ( yuv_std == 240 )
+                       coefficients = sws_getCoefficients( SWS_CS_SMPTE240M );
                sws_setColorspaceDetails( context, coefficients, range, coefficients, range,
                        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 )
+static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt,
+       mlt_image_format *format, int width, int height, int yuv_std )
 {
 #ifdef SWSCALE
-       int is_709 = *format == mlt_image_yuv422 && width * height > 750000;
        int luma = 0;
        int flags = SWS_BILINEAR | SWS_ACCURATE_RND;
 
@@ -731,7 +734,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 );
+               set_luma_transfer( context, yuv_std, luma );
                sws_scale( context, frame->data, frame->linesize, 0, height,
                        output.data, output.linesize);
                sws_freeContext( context );
@@ -747,7 +750,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 );
+               set_luma_transfer( context, yuv_std, luma );
                sws_scale( context, frame->data, frame->linesize, 0, height,
                        output.data, output.linesize);
                sws_freeContext( context );
@@ -759,7 +762,7 @@ static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt,
                AVPicture output;
                avpicture_fill( &output, buffer, PIX_FMT_RGB24, width, height );
                luma = 1;
-               set_luma_transfer( context, is_709, luma );
+               set_luma_transfer( context, yuv_std, luma );
                sws_scale( context, frame->data, frame->linesize, 0, height,
                        output.data, output.linesize);
                sws_freeContext( context );
@@ -771,7 +774,7 @@ static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt,
                AVPicture output;
                avpicture_fill( &output, buffer, PIX_FMT_RGBA, width, height );
                luma = 1;
-               set_luma_transfer( context, is_709, luma );
+               set_luma_transfer( context, yuv_std, luma );
                sws_scale( context, frame->data, frame->linesize, 0, height,
                        output.data, output.linesize);
                sws_freeContext( context );
@@ -782,8 +785,7 @@ 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 );
+               set_luma_transfer( context, yuv_std, luma );
                sws_scale( context, frame->data, frame->linesize, 0, height,
                        output.data, output.linesize);
                sws_freeContext( context );
@@ -1079,11 +1081,13 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
                                picture.linesize[0] = codec_context->width;
                                picture.linesize[1] = codec_context->width / 2;
                                picture.linesize[2] = codec_context->width / 2;
-                               convert_image( (AVFrame*) &picture, *buffer, PIX_FMT_YUV420P, format, *width, *height );
+                               convert_image( (AVFrame*) &picture, *buffer,
+                                       PIX_FMT_YUV420P, format, *width, *height, this->yuv_std );
                        }
                        else
 #endif
-                       convert_image( this->av_frame, *buffer, codec_context->pix_fmt, format, *width, *height );
+                       convert_image( this->av_frame, *buffer, codec_context->pix_fmt,
+                               format, *width, *height, this->yuv_std );
                }
                else
                        mlt_frame_get_image( frame, buffer, format, width, height, writable );
@@ -1265,7 +1269,8 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
                                                        VdpStatus status = vdp_surface_get_bits( render->surface, dest_format, planes, pitches );
                                                        if ( status == VDP_STATUS_OK )
                                                        {
-                                                               convert_image( (AVFrame*) &picture, *buffer, PIX_FMT_YUV420P, format, *width, *height );
+                                                               convert_image( (AVFrame*) &picture, *buffer, PIX_FMT_YUV420P,
+                                                                       format, *width, *height, this->yuv_std );
                                                        }
                                                        else
                                                        {
@@ -1281,7 +1286,8 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
                                        }
                                        else
 #endif
-                                       convert_image( this->av_frame, *buffer, codec_context->pix_fmt, format, *width, *height );
+                                       convert_image( this->av_frame, *buffer, codec_context->pix_fmt,
+                                               format, *width, *height, this->yuv_std );
                                        this->top_field_first |= this->av_frame->top_field_first;
                                        this->current_position = int_position;
                                        this->got_picture = 1;
@@ -1445,6 +1451,30 @@ static int video_codec_init( producer_avformat this, int index, mlt_properties p
                        mlt_properties_set_double( properties, "source_fps", source_fps );
                else
                        mlt_properties_set_double( properties, "source_fps", mlt_producer_get_fps( this->parent ) );
+
+               // Set the YUV colorspace from override or detect
+               this->yuv_std = mlt_properties_get_int( properties, "force_yuv_std" );
+               if ( ! this->yuv_std )
+               {
+                       switch ( this->video_codec->colorspace )
+                       {
+                       case AVCOL_SPC_BT709:
+                               this->yuv_std = 709;
+                               break;
+                       case AVCOL_SPC_BT470BG:
+                       case AVCOL_SPC_SMPTE170M:
+                               this->yuv_std = 601;
+                               break;
+                       case AVCOL_SPC_SMPTE240M:
+                               this->yuv_std = 240;
+                               break;
+                       default:
+                               this->yuv_std = this->video_codec->width * this->video_codec->height > 750000 ? 709 : 601;
+                               break;
+                       }
+               }
+               // Let apps get chosen colorspace
+               mlt_properties_set_int( properties, "yuv_std", this->yuv_std );
        }
        return this->video_codec && this->video_index > -1;
 }
@@ -1535,6 +1565,7 @@ static void producer_set_up_video( producer_avformat this, mlt_frame frame )
                mlt_properties_set_int( frame_properties, "real_width", this->video_codec->width );
                mlt_properties_set_int( frame_properties, "real_height", this->video_codec->height );
                mlt_properties_set_double( frame_properties, "aspect_ratio", aspect_ratio );
+               mlt_properties_set_int( frame_properties, "yuv_std", this->yuv_std );
 
                // Workaround 1088 encodings missing cropping info.
                if ( this->video_codec->height == 1088 && mlt_profile_dar( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ) == 16.0/9.0 )