Index: source/libvpx/vpxenc.c |
=================================================================== |
--- source/libvpx/vpxenc.c (revision 291857) |
+++ source/libvpx/vpxenc.c (working copy) |
@@ -200,6 +200,10 @@ |
ARG_DEF(NULL, "experimental-bitstream", 0, |
"Allow experimental bitstream features."); |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+static const arg_def_t test16bitinternalarg = ARG_DEF( |
+ NULL, "test-16bit-internal", 0, "Force use of 16 bit internal buffer"); |
+#endif |
static const arg_def_t *main_args[] = { |
&debugmode, |
@@ -248,6 +252,9 @@ |
#endif |
&timebase, &framerate, |
&error_resilient, |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ &test16bitinternalarg, |
+#endif |
&lag_in_frames, NULL |
}; |
@@ -321,7 +328,7 @@ |
static const arg_def_t noise_sens = ARG_DEF(NULL, "noise-sensitivity", 1, |
"Noise sensitivity (frames to blur)"); |
static const arg_def_t sharpness = ARG_DEF(NULL, "sharpness", 1, |
- "Filter sharpness (0-7)"); |
+ "Loop filter sharpness (0..7)"); |
static const arg_def_t static_thresh = ARG_DEF(NULL, "static-thresh", 1, |
"Motion detection threshold"); |
static const arg_def_t cpu_used = ARG_DEF(NULL, "cpu-used", 1, |
@@ -329,11 +336,11 @@ |
static const arg_def_t auto_altref = ARG_DEF(NULL, "auto-alt-ref", 1, |
"Enable automatic alt reference frames"); |
static const arg_def_t arnr_maxframes = ARG_DEF(NULL, "arnr-maxframes", 1, |
- "AltRef Max Frames"); |
+ "AltRef max frames (0..15)"); |
static const arg_def_t arnr_strength = ARG_DEF(NULL, "arnr-strength", 1, |
- "AltRef Strength"); |
+ "AltRef filter strength (0..6)"); |
static const arg_def_t arnr_type = ARG_DEF(NULL, "arnr-type", 1, |
- "AltRef Type"); |
+ "AltRef type"); |
static const struct arg_enum_list tuning_enum[] = { |
{"psnr", VP8_TUNE_PSNR}, |
{"ssim", VP8_TUNE_SSIM}, |
@@ -378,9 +385,26 @@ |
"Adaptive quantization mode (0: off (default), 1: variance 2: complexity, " |
"3: cyclic refresh)"); |
static const arg_def_t frame_periodic_boost = ARG_DEF( |
- NULL, "frame_boost", 1, |
+ NULL, "frame-boost", 1, |
"Enable frame periodic boost (0: off (default), 1: on)"); |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+static const struct arg_enum_list bitdepth_enum[] = { |
+ {"8", VPX_BITS_8}, |
+ {"10", VPX_BITS_10}, |
+ {"12", VPX_BITS_12}, |
+ {NULL, 0} |
+}; |
+ |
+static const arg_def_t bitdeptharg = ARG_DEF_ENUM("b", "bit-depth", 1, |
+ "Bit depth for codec " |
+ "(8 for version <=1, " |
+ "10 or 12 for version 2)", |
+ bitdepth_enum); |
+static const arg_def_t inbitdeptharg = ARG_DEF(NULL, "input-bit-depth", 1, |
+ "Bit depth of input"); |
+#endif |
+ |
static const struct arg_enum_list tune_content_enum[] = { |
{"default", VP9E_CONTENT_DEFAULT}, |
{"screen", VP9E_CONTENT_SCREEN}, |
@@ -395,6 +419,9 @@ |
&tile_cols, &tile_rows, &arnr_maxframes, &arnr_strength, &arnr_type, |
&tune_ssim, &cq_level, &max_intra_rate_pct, &lossless, |
&frame_parallel_decoding, &aq_mode, &frame_periodic_boost, &tune_content, |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ &bitdeptharg, &inbitdeptharg, |
+#endif |
NULL |
}; |
static const int vp9_arg_ctrl_map[] = { |
@@ -450,6 +477,102 @@ |
} |
#define mmin(a, b) ((a) < (b) ? (a) : (b)) |
+ |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+static void find_mismatch_high(const vpx_image_t *const img1, |
+ const vpx_image_t *const img2, |
+ int yloc[4], int uloc[4], int vloc[4]) { |
+ uint16_t *plane1, *plane2; |
+ uint32_t stride1, stride2; |
+ const uint32_t bsize = 64; |
+ const uint32_t bsizey = bsize >> img1->y_chroma_shift; |
+ const uint32_t bsizex = bsize >> img1->x_chroma_shift; |
+ const uint32_t c_w = |
+ (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift; |
+ const uint32_t c_h = |
+ (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift; |
+ int match = 1; |
+ uint32_t i, j; |
+ yloc[0] = yloc[1] = yloc[2] = yloc[3] = -1; |
+ plane1 = (uint16_t*)img1->planes[VPX_PLANE_Y]; |
+ plane2 = (uint16_t*)img2->planes[VPX_PLANE_Y]; |
+ stride1 = img1->stride[VPX_PLANE_Y]/2; |
+ stride2 = img2->stride[VPX_PLANE_Y]/2; |
+ for (i = 0, match = 1; match && i < img1->d_h; i += bsize) { |
+ for (j = 0; match && j < img1->d_w; j += bsize) { |
+ int k, l; |
+ const int si = mmin(i + bsize, img1->d_h) - i; |
+ const int sj = mmin(j + bsize, img1->d_w) - j; |
+ for (k = 0; match && k < si; ++k) { |
+ for (l = 0; match && l < sj; ++l) { |
+ if (*(plane1 + (i + k) * stride1 + j + l) != |
+ *(plane2 + (i + k) * stride2 + j + l)) { |
+ yloc[0] = i + k; |
+ yloc[1] = j + l; |
+ yloc[2] = *(plane1 + (i + k) * stride1 + j + l); |
+ yloc[3] = *(plane2 + (i + k) * stride2 + j + l); |
+ match = 0; |
+ break; |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ uloc[0] = uloc[1] = uloc[2] = uloc[3] = -1; |
+ plane1 = (uint16_t*)img1->planes[VPX_PLANE_U]; |
+ plane2 = (uint16_t*)img2->planes[VPX_PLANE_U]; |
+ stride1 = img1->stride[VPX_PLANE_U]/2; |
+ stride2 = img2->stride[VPX_PLANE_U]/2; |
+ for (i = 0, match = 1; match && i < c_h; i += bsizey) { |
+ for (j = 0; match && j < c_w; j += bsizex) { |
+ int k, l; |
+ const int si = mmin(i + bsizey, c_h - i); |
+ const int sj = mmin(j + bsizex, c_w - j); |
+ for (k = 0; match && k < si; ++k) { |
+ for (l = 0; match && l < sj; ++l) { |
+ if (*(plane1 + (i + k) * stride1 + j + l) != |
+ *(plane2 + (i + k) * stride2 + j + l)) { |
+ uloc[0] = i + k; |
+ uloc[1] = j + l; |
+ uloc[2] = *(plane1 + (i + k) * stride1 + j + l); |
+ uloc[3] = *(plane2 + (i + k) * stride2 + j + l); |
+ match = 0; |
+ break; |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ vloc[0] = vloc[1] = vloc[2] = vloc[3] = -1; |
+ plane1 = (uint16_t*)img1->planes[VPX_PLANE_V]; |
+ plane2 = (uint16_t*)img2->planes[VPX_PLANE_V]; |
+ stride1 = img1->stride[VPX_PLANE_V]/2; |
+ stride2 = img2->stride[VPX_PLANE_V]/2; |
+ for (i = 0, match = 1; match && i < c_h; i += bsizey) { |
+ for (j = 0; match && j < c_w; j += bsizex) { |
+ int k, l; |
+ const int si = mmin(i + bsizey, c_h - i); |
+ const int sj = mmin(j + bsizex, c_w - j); |
+ for (k = 0; match && k < si; ++k) { |
+ for (l = 0; match && l < sj; ++l) { |
+ if (*(plane1 + (i + k) * stride1 + j + l) != |
+ *(plane2 + (i + k) * stride2 + j + l)) { |
+ vloc[0] = i + k; |
+ vloc[1] = j + l; |
+ vloc[2] = *(plane1 + (i + k) * stride1 + j + l); |
+ vloc[3] = *(plane2 + (i + k) * stride2 + j + l); |
+ match = 0; |
+ break; |
+ } |
+ } |
+ } |
+ } |
+ } |
+} |
+#endif |
+ |
static void find_mismatch(const vpx_image_t *const img1, |
const vpx_image_t *const img2, |
int yloc[4], int uloc[4], int vloc[4]) { |
@@ -542,7 +665,8 @@ |
static int compare_img(const vpx_image_t *const img1, |
const vpx_image_t *const img2) { |
- const uint32_t c_w = |
+ uint32_t l_w = img1->d_w; |
+ uint32_t c_w = |
(img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift; |
const uint32_t c_h = |
(img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift; |
@@ -552,11 +676,17 @@ |
match &= (img1->fmt == img2->fmt); |
match &= (img1->d_w == img2->d_w); |
match &= (img1->d_h == img2->d_h); |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ if (img1->fmt & VPX_IMG_FMT_HIGHBITDEPTH) { |
+ l_w *= 2; |
+ c_w *= 2; |
+ } |
+#endif |
for (i = 0; i < img1->d_h; ++i) |
match &= (memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y], |
img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y], |
- img1->d_w) == 0); |
+ l_w) == 0); |
for (i = 0; i < c_h; ++i) |
match &= (memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U], |
@@ -601,6 +731,10 @@ |
int arg_ctrl_cnt; |
int write_webm; |
int have_kf_max_dist; |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ // whether to use 16bit internal buffers |
+ int use_16bit_internal; |
+#endif |
}; |
@@ -740,8 +874,9 @@ |
#if CONFIG_VP9_ENCODER |
// Make default VP9 passes = 2 until there is a better quality 1-pass |
// encoder |
- global->passes = (strcmp(global->codec->name, "vp9") == 0 && |
- global->deadline != VPX_DL_REALTIME) ? 2 : 1; |
+ if (global->codec != NULL && global->codec->name != NULL) |
+ global->passes = (strcmp(global->codec->name, "vp9") == 0 && |
+ global->deadline != VPX_DL_REALTIME) ? 2 : 1; |
#else |
global->passes = 1; |
#endif |
@@ -809,8 +944,10 @@ |
struct stream_state *stream; |
stream = calloc(1, sizeof(*stream)); |
- if (!stream) |
+ if (stream == NULL) { |
fatal("Failed to allocate new stream."); |
+ } |
+ |
if (prev) { |
memcpy(stream, prev, sizeof(*stream)); |
stream->index++; |
@@ -870,6 +1007,9 @@ |
static const int *ctrl_args_map = NULL; |
struct stream_config *config = &stream->config; |
int eos_mark_found = 0; |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ int test_16bit_internal = 0; |
+#endif |
// Handle codec specific options |
if (0) { |
@@ -918,6 +1058,12 @@ |
config->cfg.g_w = arg_parse_uint(&arg); |
} else if (arg_match(&arg, &height, argi)) { |
config->cfg.g_h = arg_parse_uint(&arg); |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ } else if (arg_match(&arg, &bitdeptharg, argi)) { |
+ config->cfg.g_bit_depth = arg_parse_enum_or_int(&arg); |
+ } else if (arg_match(&arg, &inbitdeptharg, argi)) { |
+ config->cfg.g_input_bit_depth = arg_parse_uint(&arg); |
+#endif |
#if CONFIG_WEBM_IO |
} else if (arg_match(&arg, &stereo_mode, argi)) { |
config->stereo_fmt = arg_parse_enum_or_int(&arg); |
@@ -985,6 +1131,12 @@ |
config->have_kf_max_dist = 1; |
} else if (arg_match(&arg, &kf_disabled, argi)) { |
config->cfg.kf_mode = VPX_KF_DISABLED; |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ } else if (arg_match(&arg, &test16bitinternalarg, argi)) { |
+ if (strcmp(global->codec->name, "vp9") == 0) { |
+ test_16bit_internal = 1; |
+ } |
+#endif |
} else { |
int i, match = 0; |
for (i = 0; ctrl_args[i]; i++) { |
@@ -996,12 +1148,13 @@ |
* instance of this control. |
*/ |
for (j = 0; j < config->arg_ctrl_cnt; j++) |
- if (config->arg_ctrls[j][0] == ctrl_args_map[i]) |
+ if (ctrl_args_map != NULL && |
+ config->arg_ctrls[j][0] == ctrl_args_map[i]) |
break; |
/* Update/insert */ |
assert(j < (int)ARG_CTRL_CNT_MAX); |
- if (j < (int)ARG_CTRL_CNT_MAX) { |
+ if (ctrl_args_map != NULL && j < (int)ARG_CTRL_CNT_MAX) { |
config->arg_ctrls[j][0] = ctrl_args_map[i]; |
config->arg_ctrls[j][1] = arg_parse_enum_or_int(&arg); |
if (j == config->arg_ctrl_cnt) |
@@ -1014,6 +1167,12 @@ |
argj++; |
} |
} |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ if (strcmp(global->codec->name, "vp9") == 0) { |
+ config->use_16bit_internal = test_16bit_internal | |
+ (config->cfg.g_profile > 1); |
+ } |
+#endif |
return eos_mark_found; |
} |
@@ -1041,6 +1200,14 @@ |
experimental_bitstream.long_name); |
} |
+ // Check that the codec bit depth is greater than the input bit depth. |
+ if (stream->config.cfg.g_input_bit_depth > |
+ (unsigned int)stream->config.cfg.g_bit_depth) { |
+ fatal("Stream %d: codec bit depth (%d) less than input bit depth (%d)", |
+ stream->index, (int)stream->config.cfg.g_bit_depth, |
+ stream->config.cfg.g_input_bit_depth); |
+ } |
+ |
for (streami = stream; streami; streami = streami->next) { |
/* All streams require output files */ |
if (!streami->config.out_fn) |
@@ -1149,6 +1316,8 @@ |
SHOW(g_profile); |
SHOW(g_w); |
SHOW(g_h); |
+ SHOW(g_bit_depth); |
+ SHOW(g_input_bit_depth); |
SHOW(g_timebase.num); |
SHOW(g_timebase.den); |
SHOW(g_error_resilient); |
@@ -1281,6 +1450,9 @@ |
flags |= global->show_psnr ? VPX_CODEC_USE_PSNR : 0; |
flags |= global->out_part ? VPX_CODEC_USE_OUTPUT_PARTITION : 0; |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ flags |= stream->config.use_16bit_internal ? VPX_CODEC_USE_HIGHBITDEPTH : 0; |
+#endif |
/* Construct Encoder Context */ |
vpx_codec_enc_init(&stream->encoder, global->codec->codec_interface(), |
@@ -1326,6 +1498,46 @@ |
/ cfg->g_timebase.num / global->framerate.num; |
/* Scale if necessary */ |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ if (img) { |
+ if ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) && |
+ (img->d_w != cfg->g_w || img->d_h != cfg->g_h)) { |
+ if (img->fmt != VPX_IMG_FMT_I42016) { |
+ fprintf(stderr, "%s can only scale 4:2:0 inputs\n", exec_name); |
+ exit(EXIT_FAILURE); |
+ } |
+#if CONFIG_LIBYUV |
+ if (!stream->img) { |
+ stream->img = vpx_img_alloc(NULL, VPX_IMG_FMT_I42016, |
+ cfg->g_w, cfg->g_h, 16); |
+ } |
+ I420Scale_16((uint16*)img->planes[VPX_PLANE_Y], |
+ img->stride[VPX_PLANE_Y]/2, |
+ (uint16*)img->planes[VPX_PLANE_U], |
+ img->stride[VPX_PLANE_U]/2, |
+ (uint16*)img->planes[VPX_PLANE_V], |
+ img->stride[VPX_PLANE_V]/2, |
+ img->d_w, img->d_h, |
+ (uint16*)stream->img->planes[VPX_PLANE_Y], |
+ stream->img->stride[VPX_PLANE_Y]/2, |
+ (uint16*)stream->img->planes[VPX_PLANE_U], |
+ stream->img->stride[VPX_PLANE_U]/2, |
+ (uint16*)stream->img->planes[VPX_PLANE_V], |
+ stream->img->stride[VPX_PLANE_V]/2, |
+ stream->img->d_w, stream->img->d_h, |
+ kFilterBox); |
+ img = stream->img; |
+#else |
+ stream->encoder.err = 1; |
+ ctx_exit_on_error(&stream->encoder, |
+ "Stream %d: Failed to encode frame.\n" |
+ "Scaling disabled in this configuration. \n" |
+ "To enable, configure with --enable-libyuv\n", |
+ stream->index); |
+#endif |
+ } |
+ } |
+#endif |
if (img && (img->d_w != cfg->g_w || img->d_h != cfg->g_h)) { |
if (img->fmt != VPX_IMG_FMT_I420 && img->fmt != VPX_IMG_FMT_YV12) { |
fprintf(stderr, "%s can only scale 4:2:0 8bpp inputs\n", exec_name); |
@@ -1504,7 +1716,132 @@ |
return (float)(usec > 0 ? frames * 1000000.0 / (float)usec : 0); |
} |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+static void high_img_upshift(vpx_image_t *dst, vpx_image_t *src, |
+ int input_shift) { |
+ // Note the offset is 1 less than half |
+ const int offset = input_shift > 0 ? (1 << (input_shift - 1)) - 1 : 0; |
+ int plane; |
+ if (dst->w != src->w || dst->h != src->h || |
+ dst->x_chroma_shift != src->x_chroma_shift || |
+ dst->y_chroma_shift != src->y_chroma_shift || |
+ dst->fmt != src->fmt || input_shift < 0) { |
+ fatal("Unsupported image conversion"); |
+ } |
+ switch (src->fmt) { |
+ case VPX_IMG_FMT_I42016: |
+ case VPX_IMG_FMT_I42216: |
+ case VPX_IMG_FMT_I44416: |
+ break; |
+ default: |
+ fatal("Unsupported image conversion"); |
+ break; |
+ } |
+ for (plane = 0; plane < 3; plane++) { |
+ int w = src->w; |
+ int h = src->h; |
+ int x, y; |
+ if (plane) { |
+ w >>= src->x_chroma_shift; |
+ h >>= src->y_chroma_shift; |
+ } |
+ for (y = 0; y < h; y++) { |
+ uint16_t *p_src = (uint16_t *)(src->planes[plane] + |
+ y * src->stride[plane]); |
+ uint16_t *p_dst = (uint16_t *)(dst->planes[plane] + |
+ y * dst->stride[plane]); |
+ for (x = 0; x < w; x++) |
+ *p_dst++ = (*p_src++ << input_shift) + offset; |
+ } |
+ } |
+} |
+static void low_img_upshift(vpx_image_t *dst, vpx_image_t *src, |
+ int input_shift) { |
+ // Note the offset is 1 less than half |
+ const int offset = input_shift > 0 ? (1 << (input_shift - 1)) - 1 : 0; |
+ int plane; |
+ if (dst->w != src->w || dst->h != src->h || |
+ dst->x_chroma_shift != src->x_chroma_shift || |
+ dst->y_chroma_shift != src->y_chroma_shift || |
+ dst->fmt != src->fmt + VPX_IMG_FMT_HIGHBITDEPTH || |
+ input_shift < 0) { |
+ fatal("Unsupported image conversion"); |
+ } |
+ switch (src->fmt) { |
+ case VPX_IMG_FMT_I420: |
+ case VPX_IMG_FMT_I422: |
+ case VPX_IMG_FMT_I444: |
+ break; |
+ default: |
+ fatal("Unsupported image conversion"); |
+ break; |
+ } |
+ for (plane = 0; plane < 3; plane++) { |
+ int w = src->w; |
+ int h = src->h; |
+ int x, y; |
+ if (plane) { |
+ w >>= src->x_chroma_shift; |
+ h >>= src->y_chroma_shift; |
+ } |
+ for (y = 0; y < h; y++) { |
+ uint8_t *p_src = src->planes[plane] + y * src->stride[plane]; |
+ uint16_t *p_dst = (uint16_t *)(dst->planes[plane] + |
+ y * dst->stride[plane]); |
+ for (x = 0; x < w; x++) { |
+ *p_dst++ = (*p_src++ << input_shift) + offset; |
+ } |
+ } |
+ } |
+} |
+ |
+static void img_upshift(vpx_image_t *dst, vpx_image_t *src, |
+ int input_shift) { |
+ if (src->fmt & VPX_IMG_FMT_HIGHBITDEPTH) { |
+ high_img_upshift(dst, src, input_shift); |
+ } else { |
+ low_img_upshift(dst, src, input_shift); |
+ } |
+} |
+ |
+static void img_cast_16_to_8(vpx_image_t *dst, vpx_image_t *src) { |
+ int plane; |
+ if (dst->fmt + VPX_IMG_FMT_HIGHBITDEPTH != src->fmt || |
+ dst->d_w != src->d_w || dst->d_h != src->d_h || |
+ dst->x_chroma_shift != src->x_chroma_shift || |
+ dst->y_chroma_shift != src->y_chroma_shift) { |
+ fatal("Unsupported image conversion"); |
+ } |
+ switch (dst->fmt) { |
+ case VPX_IMG_FMT_I420: |
+ case VPX_IMG_FMT_I422: |
+ case VPX_IMG_FMT_I444: |
+ break; |
+ default: |
+ fatal("Unsupported image conversion"); |
+ break; |
+ } |
+ for (plane = 0; plane < 3; plane++) { |
+ int w = src->d_w; |
+ int h = src->d_h; |
+ int x, y; |
+ if (plane) { |
+ w >>= src->x_chroma_shift; |
+ h >>= src->y_chroma_shift; |
+ } |
+ for (y = 0; y < h; y++) { |
+ uint16_t *p_src = (uint16_t *)(src->planes[plane] + |
+ y * src->stride[plane]); |
+ uint8_t *p_dst = dst->planes[plane] + y * dst->stride[plane]; |
+ for (x = 0; x < w; x++) { |
+ *p_dst++ = *p_src++; |
+ } |
+ } |
+ } |
+} |
+#endif |
+ |
static void test_decode(struct stream_state *stream, |
enum TestDecodeFatality fatal, |
const VpxInterface *codec) { |
@@ -1530,20 +1867,44 @@ |
vpx_codec_control(&stream->encoder, VP8_COPY_REFERENCE, &ref_enc); |
vpx_codec_control(&stream->decoder, VP8_COPY_REFERENCE, &ref_dec); |
} else { |
- struct vp9_ref_frame ref; |
+ struct vp9_ref_frame ref_enc, ref_dec; |
- ref.idx = 0; |
- vpx_codec_control(&stream->encoder, VP9_GET_REFERENCE, &ref); |
- enc_img = ref.img; |
- vpx_codec_control(&stream->decoder, VP9_GET_REFERENCE, &ref); |
- dec_img = ref.img; |
+ ref_enc.idx = 0; |
+ ref_dec.idx = 0; |
+ vpx_codec_control(&stream->encoder, VP9_GET_REFERENCE, &ref_enc); |
+ enc_img = ref_enc.img; |
+ vpx_codec_control(&stream->decoder, VP9_GET_REFERENCE, &ref_dec); |
+ dec_img = ref_dec.img; |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ if ((enc_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH) != |
+ (dec_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH)) { |
+ if (enc_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH) { |
+ vpx_img_alloc(&enc_img, enc_img.fmt - VPX_IMG_FMT_HIGHBITDEPTH, |
+ enc_img.d_w, enc_img.d_h, 16); |
+ img_cast_16_to_8(&enc_img, &ref_enc.img); |
+ } |
+ if (dec_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH) { |
+ vpx_img_alloc(&dec_img, dec_img.fmt - VPX_IMG_FMT_HIGHBITDEPTH, |
+ dec_img.d_w, dec_img.d_h, 16); |
+ img_cast_16_to_8(&dec_img, &ref_dec.img); |
+ } |
+ } |
+#endif |
} |
ctx_exit_on_error(&stream->encoder, "Failed to get encoder reference frame"); |
ctx_exit_on_error(&stream->decoder, "Failed to get decoder reference frame"); |
if (!compare_img(&enc_img, &dec_img)) { |
int y[4], u[4], v[4]; |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ if (enc_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH) { |
+ find_mismatch_high(&enc_img, &dec_img, y, u, v); |
+ } else { |
+ find_mismatch(&enc_img, &dec_img, y, u, v); |
+ } |
+#else |
find_mismatch(&enc_img, &dec_img, y, u, v); |
+#endif |
stream->decoder.err = 1; |
warn_or_exit_on_error(&stream->decoder, fatal == TEST_DECODE_FATAL, |
"Stream %d: Encode/decode mismatch on frame %d at" |
@@ -1585,6 +1946,12 @@ |
int main(int argc, const char **argv_) { |
int pass; |
vpx_image_t raw; |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ vpx_image_t raw_shift; |
+ int allocated_raw_shift = 0; |
+ int use_16bit_internal = 0; |
+ int input_shift = 0; |
+#endif |
int frame_avail, got_data; |
struct VpxInputContext input; |
@@ -1686,6 +2053,27 @@ |
if (!input.width || !input.height) |
fatal("Specify stream dimensions with --width (-w) " |
" and --height (-h)"); |
+ |
+ /* If input file does not specify bit-depth but input-bit-depth parameter |
+ * exists, assume that to be the input bit-depth. However, if the |
+ * input-bit-depth paramter does not exist, assume the input bit-depth |
+ * to be the same as the codec bit-depth. |
+ */ |
+ if (!input.bit_depth) { |
+ FOREACH_STREAM({ |
+ if (stream->config.cfg.g_input_bit_depth) |
+ input.bit_depth = stream->config.cfg.g_input_bit_depth; |
+ else |
+ input.bit_depth = stream->config.cfg.g_input_bit_depth = |
+ (int)stream->config.cfg.g_bit_depth; |
+ }); |
+ if (input.bit_depth > 8) input.fmt |= VPX_IMG_FMT_HIGHBITDEPTH; |
+ } else { |
+ FOREACH_STREAM({ |
+ stream->config.cfg.g_input_bit_depth = input.bit_depth; |
+ }); |
+ } |
+ |
FOREACH_STREAM(set_stream_dimensions(stream, input.width, input.height)); |
FOREACH_STREAM(validate_stream_config(stream, &global)); |
@@ -1739,6 +2127,25 @@ |
FOREACH_STREAM(open_output_file(stream, &global)); |
FOREACH_STREAM(initialize_encoder(stream, &global)); |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ if (strcmp(global.codec->name, "vp9") == 0) { |
+ // Check to see if at least one stream uses 16 bit internal. |
+ // Currently assume that the bit_depths for all streams using |
+ // highbitdepth are the same. |
+ FOREACH_STREAM({ |
+ if (stream->config.use_16bit_internal) { |
+ use_16bit_internal = 1; |
+ } |
+ if (stream->config.cfg.g_profile == 0) { |
+ input_shift = 0; |
+ } else { |
+ input_shift = (int)stream->config.cfg.g_bit_depth - |
+ stream->config.cfg.g_input_bit_depth; |
+ } |
+ }); |
+ } |
+#endif |
+ |
frame_avail = 1; |
got_data = 0; |
@@ -1776,10 +2183,45 @@ |
frame_avail = 0; |
if (frames_in > global.skip_frames) { |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ vpx_image_t *frame_to_encode; |
+ if (input_shift || (use_16bit_internal && input.bit_depth == 8)) { |
+ assert(use_16bit_internal); |
+ // Input bit depth and stream bit depth do not match, so up |
+ // shift frame to stream bit depth |
+ if (!allocated_raw_shift) { |
+ vpx_img_alloc(&raw_shift, raw.fmt | VPX_IMG_FMT_HIGHBITDEPTH, |
+ input.width, input.height, 32); |
+ allocated_raw_shift = 1; |
+ } |
+ img_upshift(&raw_shift, &raw, input_shift); |
+ frame_to_encode = &raw_shift; |
+ } else { |
+ frame_to_encode = &raw; |
+ } |
vpx_usec_timer_start(&timer); |
+ if (use_16bit_internal) { |
+ assert(frame_to_encode->fmt & VPX_IMG_FMT_HIGHBITDEPTH); |
+ FOREACH_STREAM({ |
+ if (stream->config.use_16bit_internal) |
+ encode_frame(stream, &global, |
+ frame_avail ? frame_to_encode : NULL, |
+ frames_in); |
+ else |
+ assert(0); |
+ }); |
+ } else { |
+ assert((frame_to_encode->fmt & VPX_IMG_FMT_HIGHBITDEPTH) == 0); |
+ FOREACH_STREAM(encode_frame(stream, &global, |
+ frame_avail ? frame_to_encode : NULL, |
+ frames_in)); |
+ } |
+#else |
+ vpx_usec_timer_start(&timer); |
FOREACH_STREAM(encode_frame(stream, &global, |
frame_avail ? &raw : NULL, |
frames_in)); |
+#endif |
vpx_usec_timer_mark(&timer); |
cx_time += vpx_usec_timer_elapsed(&timer); |
@@ -1788,7 +2230,8 @@ |
got_data = 0; |
FOREACH_STREAM(get_cx_data(stream, &global, &got_data)); |
- if (!got_data && input.length && !streams->frames_out) { |
+ if (!got_data && input.length && streams != NULL && |
+ !streams->frames_out) { |
lagged_count = global.limit ? seen_frames : ftello(input.file); |
} else if (input.length) { |
int64_t remaining; |
@@ -1896,6 +2339,10 @@ |
}); |
#endif |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ if (allocated_raw_shift) |
+ vpx_img_free(&raw_shift); |
+#endif |
vpx_img_free(&raw); |
free(argv); |
free(streams); |