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";
}
*buffer = NULL;
break;
case mlt_image_rgb24:
+ case mlt_image_rgb24_full:
size *= 3;
size += *width * 3;
*buffer = mlt_pool_alloc( size );
memset( *buffer, 255, size );
break;
case mlt_image_rgb24a:
+ case mlt_image_rgb24a_full:
case mlt_image_opengl:
size *= 4;
size += *width * 4;
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 );
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;
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:
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;
#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 );
}
// 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 );
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:
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
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 );
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 );
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 );
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 );
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 );
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 ) );
}
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 ) );
}
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;