Add support for color-range. In decoder, export (eventually) into vpx_image_t.range field. In encoder, use oxcf->color_range to set it (same way as for color_space). See issue 1059. Change-Id: Ieabbb2a785fa58cc4044bd54eee66f328f3906ce
diff --git a/test/vp9_encoder_parms_get_to_decoder.cc b/test/vp9_encoder_parms_get_to_decoder.cc index 1ceff1e..901605d 100644 --- a/test/vp9_encoder_parms_get_to_decoder.cc +++ b/test/vp9_encoder_parms_get_to_decoder.cc
@@ -40,15 +40,16 @@ int32_t lossless; int32_t error_resilient; int32_t frame_parallel; + int32_t color_range; vpx_color_space_t cs; // TODO(JBB): quantizers / bitrate }; const EncodeParameters kVP9EncodeParameterSet[] = { - {0, 0, 0, 1, 0, VPX_CS_BT_601}, - {0, 0, 0, 0, 0, VPX_CS_BT_709}, - {0, 0, 1, 0, 0, VPX_CS_BT_2020}, - {0, 2, 0, 0, 1, VPX_CS_UNKNOWN}, + {0, 0, 0, 1, 0, 0, VPX_CS_BT_601}, + {0, 0, 0, 0, 0, 1, VPX_CS_BT_709}, + {0, 0, 1, 0, 0, 1, VPX_CS_BT_2020}, + {0, 2, 0, 0, 1, 0, VPX_CS_UNKNOWN}, // TODO(JBB): Test profiles (requires more work). }; @@ -76,6 +77,7 @@ ::libvpx_test::Encoder *encoder) { if (video->frame() == 1) { encoder->Control(VP9E_SET_COLOR_SPACE, encode_parms.cs); + encoder->Control(VP9E_SET_COLOR_RANGE, encode_parms.color_range); encoder->Control(VP9E_SET_LOSSLESS, encode_parms.lossless); encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, encode_parms.frame_parallel); @@ -114,6 +116,7 @@ EXPECT_EQ(encode_parms.frame_parallel, common->frame_parallel_decoding_mode); } + EXPECT_EQ(encode_parms.color_range, common->color_range); EXPECT_EQ(encode_parms.cs, common->color_space); EXPECT_EQ(encode_parms.tile_cols, common->log2_tile_cols); EXPECT_EQ(encode_parms.tile_rows, common->log2_tile_rows);
diff --git a/vp10/common/onyxc_int.h b/vp10/common/onyxc_int.h index b88aa7d..eeaadc6 100644 --- a/vp10/common/onyxc_int.h +++ b/vp10/common/onyxc_int.h
@@ -129,6 +129,7 @@ typedef struct VP10Common { struct vpx_internal_error_info error; vpx_color_space_t color_space; + int color_range; int width; int height; int display_width;
diff --git a/vp10/decoder/decodeframe.c b/vp10/decoder/decodeframe.c index e31cf72..b4c8841 100644 --- a/vp10/decoder/decodeframe.c +++ b/vp10/decoder/decodeframe.c
@@ -1228,6 +1228,7 @@ pool->frame_bufs[cm->new_fb_idx].buf.subsampling_y = cm->subsampling_y; pool->frame_bufs[cm->new_fb_idx].buf.bit_depth = (unsigned int)cm->bit_depth; pool->frame_bufs[cm->new_fb_idx].buf.color_space = cm->color_space; + pool->frame_bufs[cm->new_fb_idx].buf.color_range = cm->color_range; } static INLINE int valid_ref_frame_img_fmt(vpx_bit_depth_t ref_bit_depth, @@ -1309,6 +1310,7 @@ pool->frame_bufs[cm->new_fb_idx].buf.subsampling_y = cm->subsampling_y; pool->frame_bufs[cm->new_fb_idx].buf.bit_depth = (unsigned int)cm->bit_depth; pool->frame_bufs[cm->new_fb_idx].buf.color_space = cm->color_space; + pool->frame_bufs[cm->new_fb_idx].buf.color_range = cm->color_range; } static void setup_tile_info(VP10_COMMON *cm, struct vpx_read_bit_buffer *rb) { @@ -1749,7 +1751,8 @@ } cm->color_space = vpx_rb_read_literal(rb, 3); if (cm->color_space != VPX_CS_SRGB) { - vpx_rb_read_bit(rb); // [16,235] (including xvycc) vs [0,255] range + // [16,235] (including xvycc) vs [0,255] range + cm->color_range = vpx_rb_read_bit(rb); if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) { cm->subsampling_x = vpx_rb_read_bit(rb); cm->subsampling_y = vpx_rb_read_bit(rb); @@ -1893,6 +1896,7 @@ // specifies that the default color format should be YUV 4:2:0 in this // case (normative). cm->color_space = VPX_CS_BT_601; + cm->color_range = 0; cm->subsampling_y = cm->subsampling_x = 1; cm->bit_depth = VPX_BITS_8; #if CONFIG_VP9_HIGHBITDEPTH @@ -1943,6 +1947,7 @@ get_frame_new_buffer(cm)->bit_depth = cm->bit_depth; #endif get_frame_new_buffer(cm)->color_space = cm->color_space; + get_frame_new_buffer(cm)->color_range = cm->color_range; if (pbi->need_resync) { vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME,
diff --git a/vp10/encoder/bitstream.c b/vp10/encoder/bitstream.c index eb5a867..8d84a85 100644 --- a/vp10/encoder/bitstream.c +++ b/vp10/encoder/bitstream.c
@@ -1055,7 +1055,8 @@ } vpx_wb_write_literal(wb, cm->color_space, 3); if (cm->color_space != VPX_CS_SRGB) { - vpx_wb_write_bit(wb, 0); // 0: [16, 235] (i.e. xvYCC), 1: [0, 255] + // 0: [16, 235] (i.e. xvYCC), 1: [0, 255] + vpx_wb_write_bit(wb, cm->color_range); if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) { assert(cm->subsampling_x != 1 || cm->subsampling_y != 1); vpx_wb_write_bit(wb, cm->subsampling_x);
diff --git a/vp10/encoder/encoder.c b/vp10/encoder/encoder.c index 58c6423..08ce944 100644 --- a/vp10/encoder/encoder.c +++ b/vp10/encoder/encoder.c
@@ -735,6 +735,7 @@ cm->use_highbitdepth = oxcf->use_highbitdepth; #endif cm->color_space = oxcf->color_space; + cm->color_range = oxcf->color_range; cm->width = oxcf->width; cm->height = oxcf->height; @@ -1406,6 +1407,7 @@ cm->profile = oxcf->profile; cm->bit_depth = oxcf->bit_depth; cm->color_space = oxcf->color_space; + cm->color_range = oxcf->color_range; if (cm->profile <= PROFILE_1) assert(cm->bit_depth == VPX_BITS_8); @@ -3624,6 +3626,7 @@ cm->frame_to_show = get_frame_new_buffer(cm); cm->frame_to_show->color_space = cm->color_space; + cm->frame_to_show->color_range = cm->color_range; // Pick the loop filter level for the frame. loopfilter_frame(cpi, cm);
diff --git a/vp10/encoder/encoder.h b/vp10/encoder/encoder.h index d0beac4..8ab1efa 100644 --- a/vp10/encoder/encoder.h +++ b/vp10/encoder/encoder.h
@@ -228,6 +228,7 @@ int use_highbitdepth; #endif vpx_color_space_t color_space; + int color_range; } VP10EncoderConfig; static INLINE int is_lossless_requested(const VP10EncoderConfig *cfg) {
diff --git a/vp10/vp10_cx_iface.c b/vp10/vp10_cx_iface.c index ec89aae..2cb309d 100644 --- a/vp10/vp10_cx_iface.c +++ b/vp10/vp10_cx_iface.c
@@ -45,6 +45,7 @@ vpx_bit_depth_t bit_depth; vp9e_tune_content content; vpx_color_space_t color_space; + int color_range; }; static struct vp10_extracfg default_extra_cfg = { @@ -71,6 +72,7 @@ VPX_BITS_8, // Bit depth VP9E_CONTENT_DEFAULT, // content VPX_CS_UNKNOWN, // color space + 0, // color range }; struct vpx_codec_alg_priv { @@ -255,6 +257,7 @@ ERROR("Codec bit-depth 8 not supported in profile > 1"); } RANGE_CHECK(extra_cfg, color_space, VPX_CS_UNKNOWN, VPX_CS_SRGB); + RANGE_CHECK(extra_cfg, color_range, 0, 1); return VPX_CODEC_OK; } @@ -398,6 +401,7 @@ #endif oxcf->color_space = extra_cfg->color_space; + oxcf->color_range = extra_cfg->color_range; oxcf->arnr_max_frames = extra_cfg->arnr_max_frames; oxcf->arnr_strength = extra_cfg->arnr_strength; oxcf->min_gf_interval = extra_cfg->min_gf_interval; @@ -1221,6 +1225,13 @@ return update_extra_cfg(ctx, &extra_cfg); } +static vpx_codec_err_t ctrl_set_color_range(vpx_codec_alg_priv_t *ctx, + va_list args) { + struct vp10_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.color_range = CAST(VP9E_SET_COLOR_RANGE, args); + return update_extra_cfg(ctx, &extra_cfg); +} + static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { {VP8_COPY_REFERENCE, ctrl_copy_reference}, {VP8E_UPD_ENTROPY, ctrl_update_entropy}, @@ -1254,6 +1265,7 @@ {VP9E_REGISTER_CX_CALLBACK, ctrl_register_cx_callback}, {VP9E_SET_TUNE_CONTENT, ctrl_set_tune_content}, {VP9E_SET_COLOR_SPACE, ctrl_set_color_space}, + {VP9E_SET_COLOR_RANGE, ctrl_set_color_range}, {VP9E_SET_NOISE_SENSITIVITY, ctrl_set_noise_sensitivity}, {VP9E_SET_MIN_GF_INTERVAL, ctrl_set_min_gf_interval}, {VP9E_SET_MAX_GF_INTERVAL, ctrl_set_max_gf_interval},
diff --git a/vp10/vp10_iface_common.h b/vp10/vp10_iface_common.h index 8e1bfc2..7987d18 100644 --- a/vp10/vp10_iface_common.h +++ b/vp10/vp10_iface_common.h
@@ -37,6 +37,7 @@ } } img->cs = yv12->color_space; + img->range = yv12->color_range; img->bit_depth = 8; img->w = yv12->y_stride; img->h = ALIGN_POWER_OF_TWO(yv12->y_height + 2 * VP9_ENC_BORDER_IN_PIXELS, 3); @@ -96,6 +97,7 @@ yv12->y_stride = img->stride[VPX_PLANE_Y]; yv12->uv_stride = img->stride[VPX_PLANE_U]; yv12->color_space = img->cs; + yv12->color_range = img->range; #if CONFIG_VP9_HIGHBITDEPTH if (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h index c373c02..5d8eb90 100644 --- a/vp9/common/vp9_onyxc_int.h +++ b/vp9/common/vp9_onyxc_int.h
@@ -112,6 +112,7 @@ typedef struct VP9Common { struct vpx_internal_error_info error; vpx_color_space_t color_space; + int color_range; int width; int height; int display_width;
diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c index 18b8c70..004d343 100644 --- a/vp9/decoder/vp9_decodeframe.c +++ b/vp9/decoder/vp9_decodeframe.c
@@ -1256,6 +1256,7 @@ pool->frame_bufs[cm->new_fb_idx].buf.subsampling_y = cm->subsampling_y; pool->frame_bufs[cm->new_fb_idx].buf.bit_depth = (unsigned int)cm->bit_depth; pool->frame_bufs[cm->new_fb_idx].buf.color_space = cm->color_space; + pool->frame_bufs[cm->new_fb_idx].buf.color_range = cm->color_range; } static INLINE int valid_ref_frame_img_fmt(vpx_bit_depth_t ref_bit_depth, @@ -1337,6 +1338,7 @@ pool->frame_bufs[cm->new_fb_idx].buf.subsampling_y = cm->subsampling_y; pool->frame_bufs[cm->new_fb_idx].buf.bit_depth = (unsigned int)cm->bit_depth; pool->frame_bufs[cm->new_fb_idx].buf.color_space = cm->color_space; + pool->frame_bufs[cm->new_fb_idx].buf.color_range = cm->color_range; } static void setup_tile_info(VP9_COMMON *cm, struct vpx_read_bit_buffer *rb) { @@ -1774,7 +1776,8 @@ } cm->color_space = vpx_rb_read_literal(rb, 3); if (cm->color_space != VPX_CS_SRGB) { - vpx_rb_read_bit(rb); // [16,235] (including xvycc) vs [0,255] range + // [16,235] (including xvycc) vs [0,255] range + cm->color_range = vpx_rb_read_bit(rb); if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) { cm->subsampling_x = vpx_rb_read_bit(rb); cm->subsampling_y = vpx_rb_read_bit(rb); @@ -1788,6 +1791,7 @@ cm->subsampling_y = cm->subsampling_x = 1; } } else { + cm->color_range = 1; if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) { // Note if colorspace is SRGB then 4:4:4 chroma sampling is assumed. // 4:2:2 or 4:4:0 chroma sampling is not allowed. @@ -1893,6 +1897,7 @@ // specifies that the default color format should be YUV 4:2:0 in this // case (normative). cm->color_space = VPX_CS_BT_601; + cm->color_range = 0; cm->subsampling_y = cm->subsampling_x = 1; cm->bit_depth = VPX_BITS_8; #if CONFIG_VP9_HIGHBITDEPTH @@ -1943,6 +1948,7 @@ get_frame_new_buffer(cm)->bit_depth = cm->bit_depth; #endif get_frame_new_buffer(cm)->color_space = cm->color_space; + get_frame_new_buffer(cm)->color_range = cm->color_range; if (pbi->need_resync) { vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME,
diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 71715f0..01cced0 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c
@@ -1060,7 +1060,8 @@ } vpx_wb_write_literal(wb, cm->color_space, 3); if (cm->color_space != VPX_CS_SRGB) { - vpx_wb_write_bit(wb, 0); // 0: [16, 235] (i.e. xvYCC), 1: [0, 255] + // 0: [16, 235] (i.e. xvYCC), 1: [0, 255] + vpx_wb_write_bit(wb, cm->color_range); if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) { assert(cm->subsampling_x != 1 || cm->subsampling_y != 1); vpx_wb_write_bit(wb, cm->subsampling_x);
diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 60c6cec..91e92ff 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c
@@ -775,6 +775,7 @@ cm->use_highbitdepth = oxcf->use_highbitdepth; #endif cm->color_space = oxcf->color_space; + cm->color_range = oxcf->color_range; cm->width = oxcf->width; cm->height = oxcf->height; @@ -1462,6 +1463,7 @@ cm->profile = oxcf->profile; cm->bit_depth = oxcf->bit_depth; cm->color_space = oxcf->color_space; + cm->color_range = oxcf->color_range; if (cm->profile <= PROFILE_1) assert(cm->bit_depth == VPX_BITS_8); @@ -3817,6 +3819,7 @@ cm->frame_to_show = get_frame_new_buffer(cm); cm->frame_to_show->color_space = cm->color_space; + cm->frame_to_show->color_range = cm->color_range; // Pick the loop filter level for the frame. loopfilter_frame(cpi, cm);
diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index c3a9839..b50f2fb 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h
@@ -238,6 +238,7 @@ int use_highbitdepth; #endif vpx_color_space_t color_space; + int color_range; VP9E_TEMPORAL_LAYERING_MODE temporal_layering_mode; } VP9EncoderConfig;
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index f155b9a..fd65ed9 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c
@@ -45,6 +45,7 @@ vpx_bit_depth_t bit_depth; vp9e_tune_content content; vpx_color_space_t color_space; + int color_range; }; static struct vp9_extracfg default_extra_cfg = { @@ -71,6 +72,7 @@ VPX_BITS_8, // Bit depth VP9E_CONTENT_DEFAULT, // content VPX_CS_UNKNOWN, // color space + 0, // color range }; struct vpx_codec_alg_priv { @@ -321,6 +323,7 @@ ERROR("Codec bit-depth 8 not supported in profile > 1"); } RANGE_CHECK(extra_cfg, color_space, VPX_CS_UNKNOWN, VPX_CS_SRGB); + RANGE_CHECK(extra_cfg, color_range, 0, 2); return VPX_CODEC_OK; } @@ -465,6 +468,7 @@ #endif oxcf->color_space = extra_cfg->color_space; + oxcf->color_range = extra_cfg->color_range; oxcf->arnr_max_frames = extra_cfg->arnr_max_frames; oxcf->arnr_strength = extra_cfg->arnr_strength; oxcf->min_gf_interval = extra_cfg->min_gf_interval; @@ -1436,6 +1440,13 @@ return update_extra_cfg(ctx, &extra_cfg); } +static vpx_codec_err_t ctrl_set_color_range(vpx_codec_alg_priv_t *ctx, + va_list args) { + struct vp9_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.color_range = CAST(VP9E_SET_COLOR_RANGE, args); + return update_extra_cfg(ctx, &extra_cfg); +} + static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { {VP8_COPY_REFERENCE, ctrl_copy_reference}, {VP8E_UPD_ENTROPY, ctrl_update_entropy}, @@ -1472,6 +1483,7 @@ {VP9E_SET_SVC_LAYER_ID, ctrl_set_svc_layer_id}, {VP9E_SET_TUNE_CONTENT, ctrl_set_tune_content}, {VP9E_SET_COLOR_SPACE, ctrl_set_color_space}, + {VP9E_SET_COLOR_RANGE, ctrl_set_color_range}, {VP9E_SET_NOISE_SENSITIVITY, ctrl_set_noise_sensitivity}, {VP9E_SET_MIN_GF_INTERVAL, ctrl_set_min_gf_interval}, {VP9E_SET_MAX_GF_INTERVAL, ctrl_set_max_gf_interval},
diff --git a/vp9/vp9_iface_common.h b/vp9/vp9_iface_common.h index da7ae0e..7d514ba 100644 --- a/vp9/vp9_iface_common.h +++ b/vp9/vp9_iface_common.h
@@ -37,6 +37,7 @@ } } img->cs = yv12->color_space; + img->range = yv12->color_range; img->bit_depth = 8; img->w = yv12->y_stride; img->h = ALIGN_POWER_OF_TWO(yv12->y_height + 2 * VP9_ENC_BORDER_IN_PIXELS, 3); @@ -96,6 +97,7 @@ yv12->y_stride = img->stride[VPX_PLANE_Y]; yv12->uv_stride = img->stride[VPX_PLANE_U]; yv12->color_space = img->cs; + yv12->color_range = img->range; #if CONFIG_VP9_HIGHBITDEPTH if (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h index 31120df..b7d85d8 100644 --- a/vpx/vp8cx.h +++ b/vpx/vp8cx.h
@@ -547,6 +547,15 @@ * Supported in codecs: VP9 */ VP9E_GET_ACTIVEMAP, + + /*!\brief Codec control function to set color range bit. + * \note Valid ranges: 0..1, default is 0 + * 0 = Limited range (16..235 or HBD equivalent) + * 1 = Full range (0..255 or HBD equivalent) + * + * Supported in codecs: VP9 + */ + VP9E_SET_COLOR_RANGE, }; /*!\brief vpx 1-D scaling mode @@ -757,6 +766,13 @@ #define VPX_CTRL_VP9E_SET_MAX_GF_INTERVAL VPX_CTRL_USE_TYPE(VP9E_GET_ACTIVEMAP, vpx_active_map_t *) + +/*!\brief + * + * TODO(rbultje) : add support of the control in ffmpeg + */ +#define VPX_CTRL_VP9E_SET_COLOR_RANGE +VPX_CTRL_USE_TYPE(VP9E_SET_COLOR_RANGE, int) /*! @} - end defgroup vp8_encoder */ #ifdef __cplusplus } // extern "C"
diff --git a/vpx/vpx_image.h b/vpx/vpx_image.h index c06d351..be93147 100644 --- a/vpx/vpx_image.h +++ b/vpx/vpx_image.h
@@ -82,6 +82,7 @@ typedef struct vpx_image { vpx_img_fmt_t fmt; /**< Image Format */ vpx_color_space_t cs; /**< Color Space */ + int range; /**< Limited (0) vs. Full-range (1) sample data */ /* Image storage dimensions */ unsigned int w; /**< Stored image width */
diff --git a/vpx_scale/yv12config.h b/vpx_scale/yv12config.h index fd5d54b..2e12ace 100644 --- a/vpx_scale/yv12config.h +++ b/vpx_scale/yv12config.h
@@ -56,6 +56,7 @@ int subsampling_y; unsigned int bit_depth; vpx_color_space_t color_space; + int color_range; int corrupted; int flags;