From dfd46b588bfe5bbb668376ede16ef7337e510213 Mon Sep 17 00:00:00 2001 From: Damiano Galassi Date: Mon, 7 Nov 2016 11:46:40 +0100 Subject: Select the appropriate coefficients for yuv<->rgb conversions. --- libhb/cropscale.c | 3 +- libhb/decavcodec.c | 135 +++++++++++++++++++++++++++----------------------- libhb/hb.c | 32 ++++++++++-- libhb/hbffmpeg.h | 4 +- libhb/qsv_filter_pp.c | 4 +- libhb/rendersub.c | 2 +- 6 files changed, 110 insertions(+), 70 deletions(-) (limited to 'libhb') diff --git a/libhb/cropscale.c b/libhb/cropscale.c index 33fc156f7..0ee653ce0 100644 --- a/libhb/cropscale.c +++ b/libhb/cropscale.c @@ -194,7 +194,8 @@ static hb_buffer_t* crop_scale( hb_filter_private_t * pv, hb_buffer_t * in ) in->f.width - (pv->crop[2] + pv->crop[3]), in->f.height - (pv->crop[0] + pv->crop[1]), in->f.fmt, out->f.width, out->f.height, - out->f.fmt, SWS_LANCZOS|SWS_ACCURATE_RND); + out->f.fmt, SWS_LANCZOS|SWS_ACCURATE_RND, + hb_ff_get_colorspace(pv->job->title->color_matrix)); pv->width_in = in->f.width; pv->height_in = in->f.height; pv->pix_fmt = in->f.fmt; diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index 3f66b83d4..e021880b6 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -53,6 +53,10 @@ static void decavcodecClose( hb_work_object_t * ); static int decavcodecaInfo( hb_work_object_t *, hb_work_info_t * ); static int decavcodecaBSInfo( hb_work_object_t *, const hb_buffer_t *, hb_work_info_t * ); +static int get_color_prim(int color_primaries, hb_geometry_t geometry, hb_rational_t rate); +static int get_color_transfer(int color_trc); +static int get_color_matrix(int colorspace, hb_geometry_t geometry); + hb_work_object_t hb_decavcodeca = { .id = WORK_DECAVCODEC, @@ -863,11 +867,16 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv ) { if (pv->sws_context != NULL) sws_freeContext(pv->sws_context); + + hb_geometry_t geometry = {context->width, context->height}; + int color_matrix = get_color_matrix(context->colorspace, geometry); + pv->sws_context = hb_sws_get_context(context->width, context->height, context->pix_fmt, w, h, AV_PIX_FMT_YUV420P, - SWS_LANCZOS|SWS_ACCURATE_RND); + SWS_LANCZOS|SWS_ACCURATE_RND, + hb_ff_get_colorspace(color_matrix)); pv->sws_width = context->width; pv->sws_height = context->height; pv->sws_pix_fmt = context->pix_fmt; @@ -1676,103 +1685,107 @@ static void compute_frame_duration( hb_work_private_t *pv ) } } -static int decavcodecvInfo( hb_work_object_t *w, hb_work_info_t *info ) +static int get_color_prim(int color_primaries, hb_geometry_t geometry, hb_rational_t rate) { - hb_work_private_t *pv = w->private_data; - - int clock_min, clock_max, clock; - hb_video_framerate_get_limits(&clock_min, &clock_max, &clock); - - memset( info, 0, sizeof(*info) ); - - if (pv->context == NULL) - return 0; - - info->bitrate = pv->context->bit_rate; - // HandBrake's video pipeline uses yuv420 color. This means all - // dimensions must be even. So we must adjust the dimensions - // of incoming video if not even. - info->geometry.width = pv->context->width & ~1; - info->geometry.height = pv->context->height & ~1; - - info->geometry.par.num = pv->context->sample_aspect_ratio.num; - info->geometry.par.den = pv->context->sample_aspect_ratio.den; - - compute_frame_duration( pv ); - info->rate.num = clock; - info->rate.den = pv->duration * (clock / 90000.); - - info->profile = pv->context->profile; - info->level = pv->context->level; - info->name = pv->context->codec->name; - - switch( pv->context->color_primaries ) + switch (color_primaries) { case AVCOL_PRI_BT709: - info->color_prim = HB_COLR_PRI_BT709; - break; + return HB_COLR_PRI_BT709; case AVCOL_PRI_BT470BG: - info->color_prim = HB_COLR_PRI_EBUTECH; - break; + return HB_COLR_PRI_EBUTECH; case AVCOL_PRI_BT470M: case AVCOL_PRI_SMPTE170M: case AVCOL_PRI_SMPTE240M: - info->color_prim = HB_COLR_PRI_SMPTEC; - break; + return HB_COLR_PRI_SMPTEC; default: { - if ((info->geometry.width >= 1280 || info->geometry.height >= 720)|| - (info->geometry.width > 720 && info->geometry.height > 576 )) + if ((geometry.width >= 1280 || geometry.height >= 720)|| + (geometry.width > 720 && geometry.height > 576 )) // ITU BT.709 HD content - info->color_prim = HB_COLR_PRI_BT709; - else if( info->rate.den == 1080000 ) + return HB_COLR_PRI_BT709; + else if (rate.den == 1080000) // ITU BT.601 DVD or SD TV content (PAL) - info->color_prim = HB_COLR_PRI_EBUTECH; + return HB_COLR_PRI_EBUTECH; else // ITU BT.601 DVD or SD TV content (NTSC) - info->color_prim = HB_COLR_PRI_SMPTEC; - break; + return HB_COLR_PRI_SMPTEC; } } +} - switch( pv->context->color_trc ) +static int get_color_transfer(int color_trc) +{ + switch (color_trc) { case AVCOL_TRC_SMPTE240M: - info->color_transfer = HB_COLR_TRA_SMPTE240M; - break; + return HB_COLR_TRA_SMPTE240M; default: // ITU BT.601, BT.709, anything else - info->color_transfer = HB_COLR_TRA_BT709; - break; + return HB_COLR_TRA_BT709; } +} - switch( pv->context->colorspace ) +static int get_color_matrix(int colorspace, hb_geometry_t geometry) +{ + switch (colorspace) { case AVCOL_SPC_BT709: - info->color_matrix = HB_COLR_MAT_BT709; - break; + return HB_COLR_MAT_BT709; case AVCOL_SPC_FCC: case AVCOL_SPC_BT470BG: case AVCOL_SPC_SMPTE170M: case AVCOL_SPC_RGB: // libswscale rgb2yuv - info->color_matrix = HB_COLR_MAT_SMPTE170M; - break; + return HB_COLR_MAT_SMPTE170M; case AVCOL_SPC_SMPTE240M: - info->color_matrix = HB_COLR_MAT_SMPTE240M; - break; + return HB_COLR_MAT_SMPTE240M; default: { - if ((info->geometry.width >= 1280 || info->geometry.height >= 720)|| - (info->geometry.width > 720 && info->geometry.height > 576 )) + if ((geometry.width >= 1280 || geometry.height >= 720)|| + (geometry.width > 720 && geometry.height > 576 )) // ITU BT.709 HD content - info->color_matrix = HB_COLR_MAT_BT709; + return HB_COLR_MAT_BT709; else // ITU BT.601 DVD or SD TV content (PAL) // ITU BT.601 DVD or SD TV content (NTSC) - info->color_matrix = HB_COLR_MAT_SMPTE170M; - break; + return HB_COLR_MAT_SMPTE170M; } } +} + + +static int decavcodecvInfo( hb_work_object_t *w, hb_work_info_t *info ) +{ + hb_work_private_t *pv = w->private_data; + + int clock_min, clock_max, clock; + hb_video_framerate_get_limits(&clock_min, &clock_max, &clock); + + memset( info, 0, sizeof(*info) ); + + if (pv->context == NULL) + return 0; + + info->bitrate = pv->context->bit_rate; + // HandBrake's video pipeline uses yuv420 color. This means all + // dimensions must be even. So we must adjust the dimensions + // of incoming video if not even. + info->geometry.width = pv->context->width & ~1; + info->geometry.height = pv->context->height & ~1; + + info->geometry.par.num = pv->context->sample_aspect_ratio.num; + info->geometry.par.den = pv->context->sample_aspect_ratio.den; + + compute_frame_duration( pv ); + info->rate.num = clock; + info->rate.den = pv->duration * (clock / 90000.); + + info->profile = pv->context->profile; + info->level = pv->context->level; + info->name = pv->context->codec->name; + + info->color_prim = get_color_prim(pv->context->color_primaries, info->geometry, info->rate); + info->color_transfer = get_color_transfer(pv->context->color_trc); + info->color_matrix = get_color_matrix(pv->context->colorspace, info->geometry); info->video_decode_support = HB_DECODE_SUPPORT_SW; switch (pv->context->codec_id) diff --git a/libhb/hb.c b/libhb/hb.c index 05af04953..cbca91b4d 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -206,10 +206,32 @@ static int handle_jpeg(enum AVPixelFormat *format) } } +int hb_ff_get_colorspace(int color_matrix) +{ + int color_space = SWS_CS_DEFAULT; + + switch (color_matrix) + { + case HB_COLR_MAT_SMPTE170M: + color_space = SWS_CS_ITU601; + break; + case HB_COLR_MAT_SMPTE240M: + color_space = SWS_CS_SMPTE240M; + break; + case HB_COLR_MAT_BT709: + color_space = SWS_CS_ITU709; + break; + default: + break; + } + + return color_space; +} + struct SwsContext* hb_sws_get_context(int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, - int flags) + int flags, int colorspace) { struct SwsContext * ctx; @@ -235,9 +257,9 @@ hb_sws_get_context(int srcW, int srcH, enum AVPixelFormat srcFormat, av_opt_set_int(ctx, "sws_flags", flags, 0); sws_setColorspaceDetails( ctx, - sws_getCoefficients( SWS_CS_DEFAULT ), // src colorspace + sws_getCoefficients( colorspace ), // src colorspace srcRange, // src range 0 = MPG, 1 = JPG - sws_getCoefficients( SWS_CS_DEFAULT ), // dst colorspace + sws_getCoefficients( colorspace ), // dst colorspace dstRange, // dst range 0 = MPG, 1 = JPG 0, // brightness 1 << 16, // contrast @@ -806,11 +828,13 @@ hb_image_t* hb_get_preview2(hb_handle_t * h, int title_idx, int picture, geo->crop[0], geo->crop[2] ); } + int colorspace = hb_ff_get_colorspace(title->color_matrix); + // Get scaling context context = hb_sws_get_context( title->geometry.width - (geo->crop[2] + geo->crop[3]), title->geometry.height - (geo->crop[0] + geo->crop[1]), - AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_RGB32, swsflags); + AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_RGB32, swsflags, colorspace); if (context == NULL) { diff --git a/libhb/hbffmpeg.h b/libhb/hbffmpeg.h index 5efd4244b..63bee5402 100644 --- a/libhb/hbffmpeg.h +++ b/libhb/hbffmpeg.h @@ -29,7 +29,9 @@ const char* const* hb_av_preset_get_names(int encoder); uint64_t hb_ff_mixdown_xlat(int hb_mixdown, int *downmix_mode); void hb_ff_set_sample_fmt(AVCodecContext *, AVCodec *, enum AVSampleFormat); +int hb_ff_get_colorspace(int color_matrix); + struct SwsContext* hb_sws_get_context(int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, - int flags); + int flags, int colorspace); diff --git a/libhb/qsv_filter_pp.c b/libhb/qsv_filter_pp.c index 55aa30357..7850d3b9a 100644 --- a/libhb/qsv_filter_pp.c +++ b/libhb/qsv_filter_pp.c @@ -288,13 +288,13 @@ static int hb_qsv_filter_pre_init( hb_filter_object_t * filter, AV_PIX_FMT_NV12, pv->job->title->geometry.width, pv->job->title->geometry.height, AV_PIX_FMT_YUV420P, - SWS_LANCZOS|SWS_ACCURATE_RND); + SWS_LANCZOS|SWS_ACCURATE_RND, SWS_CS_DEFAULT); pv->sws_context_to_nv12 = hb_sws_get_context( pv->job->title->geometry.width, pv->job->title->geometry.height, AV_PIX_FMT_YUV420P, pv->job->title->geometry.width, pv->job->title->geometry.height, AV_PIX_FMT_NV12, - SWS_LANCZOS|SWS_ACCURATE_RND); + SWS_LANCZOS|SWS_ACCURATE_RND, SWS_CS_DEFAULT); return 0; } int pre_process_frame(hb_buffer_t *in, av_qsv_context* qsv, hb_filter_private_t * pv ){ diff --git a/libhb/rendersub.c b/libhb/rendersub.c index 4ecb726d8..6ebfffcb5 100644 --- a/libhb/rendersub.c +++ b/libhb/rendersub.c @@ -240,7 +240,7 @@ static hb_buffer_t * ScaleSubtitle(hb_filter_private_t *pv, pv->sws = hb_sws_get_context( sub->f.width, sub->f.height, sub->f.fmt, scaled->f.width, scaled->f.height, sub->f.fmt, - SWS_LANCZOS|SWS_ACCURATE_RND); + SWS_LANCZOS|SWS_ACCURATE_RND, SWS_CS_DEFAULT); pv->sws_width = width; pv->sws_height = height; } -- cgit v1.2.3