Skip to content

Commit

Permalink
Improve colorspace conversion.
Browse files Browse the repository at this point in the history
Choose sws flags based on what conversion is being done.
  • Loading branch information
bmatherly committed Dec 31, 2019
1 parent e36e84d commit 5578529
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 8 deletions.
58 changes: 57 additions & 1 deletion src/modules/avformat/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,65 @@
#include "common.h"

#include <libavutil/channel_layout.h>
#include <libavutil/pixdesc.h>
#include <libavutil/samplefmt.h>

int mlt_default_sws_flags = SWS_BICUBIC | SWS_FULL_CHR_H_INP | SWS_FULL_CHR_H_INT | SWS_ACCURATE_RND;
int get_sws_flags(int srcwidth, int srcheight, int srcformat, int dstwidth, int dstheight, int dstformat)
{
// Use default flags unless there is a reason to use something different.
int flags = SWS_BICUBIC | SWS_FULL_CHR_H_INP | SWS_FULL_CHR_H_INT | SWS_ACCURATE_RND;

if( srcwidth != dstwidth || srcheight != dstheight )
{
// Any resolution change should use default flags
return flags;
}

const AVPixFmtDescriptor* srcDesc = av_pix_fmt_desc_get(srcformat);
const AVPixFmtDescriptor* dstDesc = av_pix_fmt_desc_get(dstformat);

if( !srcDesc || !dstDesc )
{
return flags;
}

if( (srcDesc->flags & AV_PIX_FMT_FLAG_RGB) != 0 &&
(dstDesc->flags & AV_PIX_FMT_FLAG_RGB) == 0)
{
// RGB -> YUV
flags = SWS_BICUBIC;
flags |= SWS_ACCURATE_RND; // Can improve precision by one bit
flags |= SWS_FULL_CHR_H_INT; // Avoids luma reduction. Causes chroma bleeding when used with SWS_BICUBIC
}
else if( (srcDesc->flags & AV_PIX_FMT_FLAG_RGB) == 0 &&
(dstDesc->flags & AV_PIX_FMT_FLAG_RGB) != 0)
{
// YUV -> RGB
// Going from lower sampling to full sampling - so pick the closest sample without interpolation
flags = SWS_POINT;
flags |= SWS_ACCURATE_RND; // Can improve precision by one bit
flags |= SWS_FULL_CHR_H_INT; // Avoids luma reduction. Does not cause chroma bleeding when used with SWS_POINT
}
else if( (srcDesc->flags & AV_PIX_FMT_FLAG_RGB) == 0 &&
(dstDesc->flags & AV_PIX_FMT_FLAG_RGB) == 0)
{
// YUV -> YUV
if( srcDesc->log2_chroma_w == dstDesc->log2_chroma_w &&
srcDesc->log2_chroma_h == dstDesc->log2_chroma_h )
{
// No chroma subsampling conversion. No interpolation required
flags = SWS_POINT;
flags |= SWS_ACCURATE_RND; // Can improve precision by one bit
}
else
{
// Chroma will be interpolated. Bilinear is suitable.
flags = SWS_FAST_BILINEAR | SWS_ACCURATE_RND;
}
}

return flags;
}

int mlt_to_av_sample_format( mlt_audio_format format )
{
Expand Down
2 changes: 1 addition & 1 deletion src/modules/avformat/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ mlt_channel_layout av_channel_layout_to_mlt( int64_t layout );
mlt_channel_layout mlt_get_channel_layout_or_default( const char* name, int channels );
int mlt_set_luma_transfer( struct SwsContext *context, int src_colorspace,
int dst_colorspace, int src_full_range, int dst_full_range );
extern int mlt_default_sws_flags;
int get_sws_flags(int srcwidth, int srcheight, int srcformat, int dstwidth, int dstheight, int dstformat);

#endif // COMMON_H
5 changes: 3 additions & 2 deletions src/modules/avformat/consumer_avformat.c
Original file line number Diff line number Diff line change
Expand Up @@ -1925,8 +1925,9 @@ static void *consumer_thread( void *arg )
mlt_image_format_planes( img_fmt, width, height, image, video_avframe.data, video_avframe.linesize );

// Do the colour space conversion
int flags = mlt_default_sws_flags;
struct SwsContext *context = sws_getContext( width, height, pick_pix_fmt( img_fmt ),
int srcfmt = pick_pix_fmt( img_fmt );
int flags = get_sws_flags( width, height, srcfmt, width, height, pix_fmt);
struct SwsContext *context = sws_getContext( width, height, srcfmt,
width, height, pix_fmt, flags, NULL, NULL, NULL);
int src_colorspace = mlt_properties_get_int( frame_properties, "colorspace" );
int src_full_range = mlt_properties_get_int( frame_properties, "full_luma" );
Expand Down
2 changes: 1 addition & 1 deletion src/modules/avformat/filter_avcolour_space.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static int av_convert_image( uint8_t *out, uint8_t *in, int out_fmt, int in_fmt,
int in_stride[4];
uint8_t *out_data[4];
int out_stride[4];
int flags = mlt_default_sws_flags;
int flags = get_sws_flags( width, height, in_fmt, width, height, out_fmt);
int error = -1;

if ( in_fmt == AV_PIX_FMT_YUV422P16LE )
Expand Down
12 changes: 9 additions & 3 deletions src/modules/avformat/producer_avformat.c
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,6 @@ static int sliced_h_pix_fmt_conv_proc( int id, int idx, int jobs, void* cookie )
static int convert_image( producer_avformat self, AVFrame *frame, uint8_t *buffer, int pix_fmt,
mlt_image_format *format, int width, int height, uint8_t **alpha )
{
int flags = mlt_default_sws_flags;
mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( self->parent ) );
int result = self->yuv_colorspace;

Expand Down Expand Up @@ -1368,11 +1367,14 @@ static int convert_image( producer_avformat self, AVFrame *frame, uint8_t *buffe
// Thankfully, there is not much other use of yuv420p except consumer
// avformat with no filters and explicitly requested.
#if defined(FFUDIV)
int flags = get_sws_flags(width, height, src_pix_fmt, width, height, AV_PIX_FMT_YUV420P);
struct SwsContext *context = sws_getContext(width, height, src_pix_fmt,
width, height, AV_PIX_FMT_YUV420P, flags, NULL, NULL, NULL);
#else
int dst_pix_fmt = self->full_luma ? AV_PIX_FMT_YUVJ420P : AV_PIX_FMT_YUV420P;
int flags = get_sws_flags(width, height, pix_fmt, width, height, dxt_pix_fmt);
struct SwsContext *context = sws_getContext( width, height, pix_fmt,
width, height, self->full_luma ? AV_PIX_FMT_YUVJ420P : AV_PIX_FMT_YUV420P,
width, height, dxt_pix_fmt,
flags, NULL, NULL, NULL);
#endif

Expand All @@ -1392,6 +1394,7 @@ static int convert_image( producer_avformat self, AVFrame *frame, uint8_t *buffe
}
else if ( *format == mlt_image_rgb24 )
{
int flags = get_sws_flags(width, height, src_pix_fmt, width, height, AV_PIX_FMT_RGB24);
struct SwsContext *context = sws_getContext( width, height, src_pix_fmt,
width, height, AV_PIX_FMT_RGB24, flags, NULL, NULL, NULL);
uint8_t *out_data[4];
Expand All @@ -1405,6 +1408,7 @@ static int convert_image( producer_avformat self, AVFrame *frame, uint8_t *buffe
}
else if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl )
{
int flags = get_sws_flags(width, height, src_pix_fmt, width, height, AV_PIX_FMT_RGBA);
struct SwsContext *context = sws_getContext( width, height, src_pix_fmt,
width, height, AV_PIX_FMT_RGBA, flags, NULL, NULL, NULL);
uint8_t *out_data[4];
Expand All @@ -1422,7 +1426,6 @@ static int convert_image( producer_avformat self, AVFrame *frame, uint8_t *buffe
int i, c;
struct sliced_pix_fmt_conv_t ctx =
{
.flags = flags,
.width = width,
.height = height,
.frame = frame,
Expand All @@ -1435,6 +1438,7 @@ static int convert_image( producer_avformat self, AVFrame *frame, uint8_t *buffe
ctx.src_format = (self->full_luma && src_pix_fmt == AV_PIX_FMT_YUV422P) ? AV_PIX_FMT_YUVJ422P : src_pix_fmt;
ctx.src_desc = av_pix_fmt_desc_get( ctx.src_format );
ctx.dst_desc = av_pix_fmt_desc_get( ctx.dst_format );
ctx.flags = get_sws_flags(width, height, ctx.src_format, width, height, ctx.dst_format);

av_image_fill_arrays(ctx.out_data, ctx.out_stride, buffer, ctx.dst_format, width, height, IMAGE_ALIGN);

Expand Down Expand Up @@ -1465,9 +1469,11 @@ static int convert_image( producer_avformat self, AVFrame *frame, uint8_t *buffe
#else
{
#if defined(FFUDIV)
int flags = get_sws_flags(width, height, src_pix_fmt, width, height, AV_PIX_FMT_YUYV422);
struct SwsContext *context = sws_getContext( width, height, src_pix_fmt,
width, height, AV_PIX_FMT_YUYV422, flags, NULL, NULL, NULL);
#else
int flags = get_sws_flags(width, height, pix_fmt, width, height, AV_PIX_FMT_YUYV422);
struct SwsContext *context = sws_getContext( width, height, pix_fmt,
width, height, AV_PIX_FMT_YUYV422, flags, NULL, NULL, NULL);
#endif
Expand Down

0 comments on commit 5578529

Please sign in to comment.