X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmodules%2Favformat%2Ffilter_avcolour_space.c;h=cce62c5ea2021e62b11db5f93290c1c2136c54f2;hb=4fd6c14958ac5bd739c8d2b66b86cbf99ae68c23;hp=d3a0d5439ccf341f8bbc63ff7147b220a7f470e4;hpb=605ec97c8e8064731abf007ec0255ebf52a0f5d8;p=mlt diff --git a/src/modules/avformat/filter_avcolour_space.c b/src/modules/avformat/filter_avcolour_space.c index d3a0d543..cce62c5e 100644 --- a/src/modules/avformat/filter_avcolour_space.c +++ b/src/modules/avformat/filter_avcolour_space.c @@ -1,6 +1,6 @@ /* * filter_avcolour_space.c -- Colour space filter - * Copyright (C) 2004-2005 Ushodaya Enterprises Limited + * Copyright (C) 2004-2014 Ushodaya Enterprises Limited * Author: Charles Yates * * This library is free software; you can redistribute it and/or @@ -22,16 +22,11 @@ #include #include #include +#include // ffmpeg Header files -#include -#ifdef SWSCALE -#include -#endif - -#if LIBAVUTIL_VERSION_INT < (50<<16) -#define PIX_FMT_YUYV422 PIX_FMT_YUV422 -#endif +#include +#include #include #include @@ -65,52 +60,69 @@ static int convert_mlt_to_av_cs( mlt_image_format format ) case mlt_image_yuv420p: value = PIX_FMT_YUV420P; break; - case mlt_image_none: - mlt_log_error( NULL, "[filter avcolor_space] Invalid format\n" ); + default: + mlt_log_error( NULL, "[filter avcolor_space] Invalid format %s\n", + mlt_image_format_name( format ) ); break; } return value; } -static void set_luma_transfer( struct SwsContext *context, int colorspace, int no_scale ) +static int set_luma_transfer( struct SwsContext *context, int src_colorspace, int dst_colorspace, int full_range ) { - int *coefficients; - int range; - int brightness, contrast, saturation; + const int *src_coefficients = sws_getCoefficients( SWS_CS_DEFAULT ); + const int *dst_coefficients = sws_getCoefficients( SWS_CS_DEFAULT ); + int brightness = 0; + int contrast = 1 << 16; + int saturation = 1 << 16; - if ( sws_getColorspaceDetails( context, &coefficients, &range, &coefficients, &range, - &brightness, &contrast, &saturation ) != -1 ) + switch ( src_colorspace ) { - // Don't change these from defaults unless explicitly told to. - if ( no_scale ) - range = 1; - switch ( colorspace ) - { - case 170: - case 470: - case 601: - case 624: - coefficients = sws_getCoefficients( SWS_CS_ITU601 ); - break; - case 240: - coefficients = sws_getCoefficients( SWS_CS_SMPTE240M ); - break; - case 709: - coefficients = sws_getCoefficients( SWS_CS_ITU709 ); - break; - } - sws_setColorspaceDetails( context, coefficients, range, coefficients, range, - brightness, contrast, saturation ); + case 170: + case 470: + case 601: + case 624: + src_coefficients = sws_getCoefficients( SWS_CS_ITU601 ); + break; + case 240: + src_coefficients = sws_getCoefficients( SWS_CS_SMPTE240M ); + break; + case 709: + src_coefficients = sws_getCoefficients( SWS_CS_ITU709 ); + break; + default: + break; } + switch ( dst_colorspace ) + { + case 170: + case 470: + case 601: + case 624: + src_coefficients = sws_getCoefficients( SWS_CS_ITU601 ); + break; + case 240: + src_coefficients = sws_getCoefficients( SWS_CS_SMPTE240M ); + break; + case 709: + src_coefficients = sws_getCoefficients( SWS_CS_ITU709 ); + break; + default: + break; + } + return sws_setColorspaceDetails( context, src_coefficients, full_range, dst_coefficients, full_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 colorspace, int no_scale ) +// returns set_lumage_transfer result +static int av_convert_image( uint8_t *out, uint8_t *in, int out_fmt, int in_fmt, + int width, int height, int src_colorspace, int dst_colorspace, int use_full_range ) { AVPicture input; AVPicture output; - int flags = SWS_BILINEAR | SWS_ACCURATE_RND; + int flags = SWS_BICUBIC | SWS_ACCURATE_RND; + int error = -1; if ( out_fmt == PIX_FMT_YUYV422 ) flags |= SWS_FULL_CHR_H_INP; @@ -122,19 +134,24 @@ static void av_convert_image( uint8_t *out, uint8_t *in, int out_fmt, int in_fmt #ifdef USE_SSE flags |= SWS_CPU_CAPS_MMX2; #endif + if ( out_fmt == PIX_FMT_YUV420P && use_full_range ) + out_fmt = PIX_FMT_YUVJ420P; avpicture_fill( &input, in, in_fmt, width, height ); avpicture_fill( &output, out, out_fmt, width, height ); -#ifdef SWSCALE struct SwsContext *context = sws_getContext( width, height, in_fmt, width, height, out_fmt, flags, NULL, NULL, NULL); - set_luma_transfer( context, colorspace, no_scale ); - sws_scale( context, input.data, input.linesize, 0, height, - output.data, output.linesize); - sws_freeContext( context ); -#else - img_convert( &output, out_fmt, &input, in_fmt, width, height ); -#endif + if ( context ) + { + // libswscale wants the RGB colorspace to be SWS_CS_DEFAULT, which is = SWS_CS_ITU601. + if ( out_fmt == PIX_FMT_RGB24 || out_fmt == PIX_FMT_RGBA ) + dst_colorspace = 601; + error = set_luma_transfer( context, src_colorspace, dst_colorspace, use_full_range ); + sws_scale( context, (const uint8_t* const*) input.data, input.linesize, 0, height, + output.data, output.linesize); + sws_freeContext( context ); + } + return error; } /** Do it :-). @@ -149,13 +166,19 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo if ( *format != output_format ) { - mlt_log_debug( NULL, "[filter avcolor_space] %s -> %s @ %dx%d\n", + mlt_profile profile = mlt_service_profile( + MLT_PRODUCER_SERVICE( mlt_frame_get_original_producer( frame ) ) ); + int colorspace = mlt_properties_get_int( properties, "colorspace" ); + int force_full_luma = 0; + + mlt_log_debug( NULL, "[filter avcolor_space] %s -> %s @ %dx%d space %d->%d\n", mlt_image_format_name( *format ), mlt_image_format_name( output_format ), - width, height ); + width, height, colorspace, profile->colorspace ); int in_fmt = convert_mlt_to_av_cs( *format ); int out_fmt = convert_mlt_to_av_cs( output_format ); - int size = avpicture_get_size( out_fmt, width, height ); + int size = FFMAX( avpicture_get_size( out_fmt, width, height ), + mlt_image_format_size( output_format, width, height, NULL ) ); uint8_t *output = mlt_pool_alloc( size ); if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) @@ -183,24 +206,30 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo } while ( --n > 0 ); } - mlt_properties_set_data( properties, "alpha", alpha, len, mlt_pool_release, NULL ); - frame->get_alpha_mask = NULL; + mlt_frame_set_alpha( frame, alpha, len, mlt_pool_release ); } } // Update the output - int colorspace = mlt_properties_get_int( properties, "colorspace" ); - 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 ) ) + if ( *format == mlt_image_yuv422 && mlt_properties_get( properties, "force_full_luma" ) + && ( output_format == mlt_image_rgb24 || output_format == mlt_image_rgb24a ) ) + { + // By removing the frame property we only permit the luma to skip scaling once. + // Thereafter, we let swscale scale the luma range as it pleases since it seems + // we do not have control over the RGB to YUV conversion. + force_full_luma = mlt_properties_get_int( properties, "force_full_luma" ); + mlt_properties_set( properties, "force_full_luma", NULL ); + } + if ( !av_convert_image( output, *image, out_fmt, in_fmt, width, height, + colorspace, profile->colorspace, force_full_luma ) ) { - no_scale_luma = 1; - mlt_properties_set( properties, "skip_luma_scale", NULL ); + // The new colorspace is only valid if destination is YUV. + if ( output_format == mlt_image_yuv422 || output_format == mlt_image_yuv420p ) + mlt_properties_set_int( properties, "colorspace", profile->colorspace ); } - av_convert_image( output, *image, out_fmt, in_fmt, width, height, colorspace, no_scale_luma ); *image = output; *format = output_format; - mlt_properties_set_data( properties, "image", output, size, mlt_pool_release, NULL ); + mlt_frame_set_image( frame, output, size, mlt_pool_release ); mlt_properties_set_int( properties, "format", output_format ); if ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl ) @@ -236,6 +265,8 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo return error; } +/* TODO: Enable this to force colorspace conversion. Cost is heavy due to RGB conversions. */ +#if 0 static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; @@ -246,11 +277,13 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format error = mlt_frame_get_image( frame, image, format, width, height, writable ); + int frame_colorspace = mlt_properties_get_int( properties, "colorspace" ); + if ( !error && *format == mlt_image_yuv422 && profile->colorspace > 0 && - mlt_properties_get_int( properties, "colorspace" ) != profile->colorspace ) + frame_colorspace > 0 && frame_colorspace != profile->colorspace ) { mlt_log_debug( NULL, "[filter avcolor_space] colorspace %d -> %d\n", - mlt_properties_get_int( properties, "colorspace" ), profile->colorspace ); + frame_colorspace, profile->colorspace ); // Convert to RGB using frame's colorspace error = convert_image( frame, image, &format_from, format_to ); @@ -269,15 +302,27 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format return error; } +#endif /** Filter processing. */ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { - frame->convert_image = convert_image; - mlt_frame_push_get_image( frame, mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) ); - mlt_frame_push_get_image( frame, get_image ); + // Set a default colorspace on the frame if not yet set by the producer. + // The producer may still change it during get_image. + // This way we do not have to modify each producer to set a valid colorspace. + mlt_properties properties = MLT_FRAME_PROPERTIES(frame); + if ( mlt_properties_get_int( properties, "colorspace" ) <= 0 ) + mlt_properties_set_int( properties, "colorspace", mlt_service_profile( MLT_FILTER_SERVICE(filter) )->colorspace ); + + if ( !frame->convert_image ) + frame->convert_image = convert_image; + +// Not working yet - see comment for get_image() above. +// mlt_frame_push_service( frame, mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) ); +// mlt_frame_push_get_image( frame, get_image ); + return frame; } @@ -286,25 +331,22 @@ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) mlt_filter filter_avcolour_space_init( void *arg ) { -#ifdef SWSCALE -#if (LIBSWSCALE_VERSION_INT >= ((0<<16)+(7<<8)+2)) // Test to see if swscale accepts the arg as resolution if ( arg ) { - int width = (int) arg; - struct SwsContext *context = sws_getContext( width, width, PIX_FMT_RGB32, 64, 64, PIX_FMT_RGB32, SWS_BILINEAR, NULL, NULL, NULL); - if ( context ) - sws_freeContext( context ); - else - return NULL; - } -#else - return NULL; -#endif -#endif - mlt_filter this = mlt_filter_new( ); - if ( this != NULL ) - this->process = filter_process; - return this; + int *width = (int*) arg; + if ( *width > 0 ) + { + struct SwsContext *context = sws_getContext( *width, *width, PIX_FMT_RGB32, 64, 64, PIX_FMT_RGB32, SWS_BILINEAR, NULL, NULL, NULL); + if ( context ) + sws_freeContext( context ); + else + return NULL; + } + } + mlt_filter filter = mlt_filter_new( ); + if ( filter != NULL ) + filter->process = filter_process; + return filter; }