Merge "Add protection for codec interface name change."
diff --git a/test/tools_common.sh b/test/tools_common.sh
index 27785c3..34c1516 100755
--- a/test/tools_common.sh
+++ b/test/tools_common.sh
@@ -401,6 +401,7 @@
VP9_IVF_FILE="${LIBVPX_TEST_DATA_PATH}/vp90-2-09-subpixel-00.ivf"
VP9_WEBM_FILE="${LIBVPX_TEST_DATA_PATH}/vp90-2-00-quantizer-00.webm"
+VP9_FPM_WEBM_FILE="${LIBVPX_TEST_DATA_PATH}/vp90-2-07-frame_parallel-1.webm"
YUV_RAW_INPUT="${LIBVPX_TEST_DATA_PATH}/hantro_collage_w352h288.yuv"
YUV_RAW_INPUT_WIDTH=352
diff --git a/test/vpxdec.sh b/test/vpxdec.sh
index f92acbd..d73a447 100755
--- a/test/vpxdec.sh
+++ b/test/vpxdec.sh
@@ -16,7 +16,8 @@
# Environment check: Make sure input is available.
vpxdec_verify_environment() {
- if [ ! -e "${VP8_IVF_FILE}" ] || [ ! -e "${VP9_WEBM_FILE}" ]; then
+ if [ ! -e "${VP8_IVF_FILE}" ] || [ ! -e "${VP9_WEBM_FILE}" ] || \
+ [ ! -e "${VP9_FPM_WEBM_FILE}" ] ; then
elog "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH."
return 1
fi
@@ -78,8 +79,20 @@
fi
}
+vpxdec_vp9_webm_frame_parallel() {
+ if [ "$(vpxdec_can_decode_vp9)" = "yes" ] && \
+ [ "$(webm_io_available)" = "yes" ]; then
+ for threads in 2 3 4 5 6 7 8; do
+ vpxdec "${VP9_FPM_WEBM_FILE}" --summary --noblit --threads=$threads \
+ --frame-parallel
+ done
+ fi
+
+}
+
vpxdec_tests="vpxdec_vp8_ivf
vpxdec_vp8_ivf_pipe_input
- vpxdec_vp9_webm"
+ vpxdec_vp9_webm
+ vpxdec_vp9_webm_frame_parallel"
run_tests vpxdec_verify_environment "${vpxdec_tests}"
diff --git a/usage.dox b/usage.dox
index 6bfca3b..8823520 100644
--- a/usage.dox
+++ b/usage.dox
@@ -12,13 +12,13 @@
- \ref usage_init
- \ref usage_errors
- Fore more information on decoder and encoder specific usage, see the
+ For more information on decoder and encoder specific usage, see the
following pages:
\if decoder
- - \subpage usage_decode
+ \li \subpage usage_decode
\endif
- \if decoder
- - \subpage usage_encode
+ \if encoder
+ \li \subpage usage_encode
\endif
\section usage_types Important Data Types
@@ -81,12 +81,12 @@
The available initialization methods are:
\if encoder
- - #vpx_codec_enc_init (calls vpx_codec_enc_init_ver())
- - #vpx_codec_enc_init_multi (calls vpx_codec_enc_init_multi_ver())
- .
+ \li #vpx_codec_enc_init (calls vpx_codec_enc_init_ver())
+ \li #vpx_codec_enc_init_multi (calls vpx_codec_enc_init_multi_ver())
\endif
- \if decoder - #vpx_codec_dec_init (calls vpx_codec_dec_init_ver()) \endif
-
+ \if decoder
+ \li #vpx_codec_dec_init (calls vpx_codec_dec_init_ver())
+ \endif
\section usage_errors Error Handling
diff --git a/usage_cx.dox b/usage_cx.dox
index 62f3e45..92b0d34 100644
--- a/usage_cx.dox
+++ b/usage_cx.dox
@@ -1,4 +1,4 @@
-/*! \page usage_encode Encode
+/*! \page usage_encode Encoding
The vpx_codec_encode() function is at the core of the encode loop. It
processes raw images passed by the application, producing packets of
diff --git a/vp9/encoder/vp9_avg.c b/vp9/encoder/vp9_avg.c
index 90d113c..dc5cfe2 100644
--- a/vp9/encoder/vp9_avg.c
+++ b/vp9/encoder/vp9_avg.c
@@ -46,10 +46,9 @@
int16_t vp9_int_pro_col_c(uint8_t const *ref, const int width) {
int idx;
int16_t sum = 0;
- const int norm_factor = MAX(8, width >> 1);
for (idx = 0; idx < width; ++idx)
sum += ref[idx];
- return sum / norm_factor;
+ return sum;
}
int vp9_vector_var_c(int16_t const *ref, int16_t const *src,
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index 1344b5b..ac9de21 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -44,12 +44,6 @@
#include "vp9/encoder/vp9_segmentation.h"
#include "vp9/encoder/vp9_tokenize.h"
-#define GF_ZEROMV_ZBIN_BOOST 0
-#define LF_ZEROMV_ZBIN_BOOST 0
-#define MV_ZBIN_BOOST 0
-#define SPLIT_MV_ZBIN_BOOST 0
-#define INTRA_ZBIN_BOOST 0
-
static void encode_superblock(VP9_COMP *cpi, ThreadData * td,
TOKENEXTRA **t, int output_enabled,
int mi_row, int mi_col, BLOCK_SIZE bsize,
@@ -406,7 +400,7 @@
int mi_col,
int64_t threshold,
BLOCK_SIZE bsize_min,
- int segment_id) {
+ int force_split) {
VP9_COMMON * const cm = &cpi->common;
variance_node vt;
const int block_width = num_8x8_blocks_wide_lookup[bsize];
@@ -415,8 +409,7 @@
assert(block_height == block_width);
tree_to_node(data, bsize, &vt);
- // No 64x64 blocks on segments other than base (un-boosted) segment.
- if (cyclic_refresh_segment_id_boosted(segment_id) && bsize == BLOCK_64X64)
+ if (force_split)
return 0;
// For bsize=bsize_min (16x16/8x8 for 8x8/4x4 downsampling), select if
@@ -432,7 +425,9 @@
}
return 0;
} else if (bsize > bsize_min) {
- get_variance(&vt.part_variances->none);
+ // Variance is already computed for 32x32 blocks to set the force_split.
+ if (bsize != BLOCK_32X32)
+ get_variance(&vt.part_variances->none);
// For key frame or low_res: for bsize above 32X32 or very high variance,
// take split.
if (cm->frame_type == KEY_FRAME &&
@@ -486,32 +481,34 @@
return;
} else {
VP9_COMMON *const cm = &cpi->common;
- const VP9EncoderConfig *const oxcf = &cpi->oxcf;
const int is_key_frame = (cm->frame_type == KEY_FRAME);
- const int use_4x4_partition = is_key_frame;
- const int low_res = (cm->width <= 352 && cm->height <= 288);
const int threshold_multiplier = is_key_frame ? 80 : 4;
const int64_t threshold_base = (int64_t)(threshold_multiplier *
vp9_convert_qindex_to_q(q, cm->bit_depth));
- cpi->vbp_threshold = threshold_base;
- cpi->vbp_threshold_bsize_min = threshold_base << oxcf->speed;
- cpi->vbp_threshold_bsize_max = threshold_base;
- if (is_key_frame) {
- cpi->vbp_threshold = threshold_base >> 2;
- cpi->vbp_threshold_bsize_min = threshold_base << 2;
- } else if (low_res) {
- cpi->vbp_threshold_bsize_min = threshold_base << 3;
- cpi->vbp_threshold_bsize_max = threshold_base >> 2;
- }
// TODO(marpan): Allow 4x4 partitions for inter-frames.
// use_4x4_partition = (variance4x4downsample[i2 + j] == 1);
// If 4x4 partition is not used, then 8x8 partition will be selected
// if variance of 16x16 block is very high, so use larger threshold
// for 16x16 (threshold_bsize_min) in that case.
- cpi->vbp_threshold_16x16 = (use_4x4_partition) ?
- cpi->vbp_threshold : cpi->vbp_threshold_bsize_min;
- cpi->vbp_bsize_min = (use_4x4_partition) ? BLOCK_8X8 : BLOCK_16X16;
+ if (is_key_frame) {
+ cpi->vbp_threshold = threshold_base >> 2;
+ cpi->vbp_threshold_bsize_max = threshold_base;
+ cpi->vbp_threshold_bsize_min = threshold_base << 2;
+ cpi->vbp_threshold_16x16 = cpi->vbp_threshold;
+ cpi->vbp_bsize_min = BLOCK_8X8;
+ } else {
+ cpi->vbp_threshold = threshold_base;
+ if (cm->width <= 352 && cm->height <= 288) {
+ cpi->vbp_threshold_bsize_max = threshold_base >> 2;
+ cpi->vbp_threshold_bsize_min = threshold_base << 3;
+ } else {
+ cpi->vbp_threshold_bsize_max = threshold_base;
+ cpi->vbp_threshold_bsize_min = threshold_base << cpi->oxcf.speed;
+ }
+ cpi->vbp_threshold_16x16 = cpi->vbp_threshold_bsize_min;
+ cpi->vbp_bsize_min = BLOCK_16X16;
+ }
}
}
@@ -526,6 +523,7 @@
int i, j, k, m;
v64x64 vt;
v16x16 vt2[16];
+ int force_split[5];
uint8_t *s;
const uint8_t *d;
int sp;
@@ -643,12 +641,15 @@
#endif // CONFIG_VP9_HIGHBITDEPTH
}
+ // Index for force_split: 0 for 64x64, 1-4 for 32x32 blocks,
+ force_split[0] = 0;
// Fill in the entire tree of 8x8 (or 4x4 under some conditions) variances
// for splits.
for (i = 0; i < 4; i++) {
const int x32_idx = ((i & 1) << 5);
const int y32_idx = ((i >> 1) << 5);
const int i2 = i << 2;
+ force_split[i + 1] = 0;
for (j = 0; j < 4; j++) {
const int x16_idx = x32_idx + ((j & 1) << 4);
const int y16_idx = y32_idx + ((j >> 1) << 4);
@@ -735,6 +736,11 @@
}
}
+ // No 64x64 blocks on segments other than base (un-boosted) segment,
+ // so force split.
+ if (cyclic_refresh_segment_id_boosted(segment_id))
+ force_split[0] = 1;
+
// Fill the rest of the variance tree by summing split partition values.
for (i = 0; i < 4; i++) {
const int i2 = i << 2;
@@ -742,22 +748,29 @@
if (variance4x4downsample[i2 + j] == 1) {
v16x16 *vtemp = (!is_key_frame) ? &vt2[i2 + j] :
&vt.split[i].split[j];
- for (m = 0; m < 4; m++) {
+ for (m = 0; m < 4; m++)
fill_variance_tree(&vtemp->split[m], BLOCK_8X8);
- }
fill_variance_tree(vtemp, BLOCK_16X16);
}
}
fill_variance_tree(&vt.split[i], BLOCK_32X32);
+ // If variance of this 32x32 block is above the threshold, force the block
+ // to split. This also forces a split on the upper (64x64) level.
+ get_variance(&vt.split[i].part_variances.none);
+ if (vt.split[i].part_variances.none.variance > cpi->vbp_threshold) {
+ force_split[i + 1] = 1;
+ force_split[0] = 1;
+ }
}
- fill_variance_tree(&vt, BLOCK_64X64);
+ if (!force_split[0])
+ fill_variance_tree(&vt, BLOCK_64X64);
// Now go through the entire structure, splitting every block size until
// we get to one that's got a variance lower than our threshold.
if ( mi_col + 8 > cm->mi_cols || mi_row + 8 > cm->mi_rows ||
!set_vt_partitioning(cpi, xd, &vt, BLOCK_64X64, mi_row, mi_col,
cpi->vbp_threshold_bsize_max, BLOCK_16X16,
- segment_id)) {
+ force_split[0])) {
for (i = 0; i < 4; ++i) {
const int x32_idx = ((i & 1) << 2);
const int y32_idx = ((i >> 1) << 2);
@@ -765,7 +778,7 @@
if (!set_vt_partitioning(cpi, xd, &vt.split[i], BLOCK_32X32,
(mi_row + y32_idx), (mi_col + x32_idx),
cpi->vbp_threshold,
- BLOCK_16X16, segment_id)) {
+ BLOCK_16X16, force_split[i + 1])) {
for (j = 0; j < 4; ++j) {
const int x16_idx = ((j & 1) << 1);
const int y16_idx = ((j >> 1) << 1);
@@ -779,7 +792,7 @@
mi_row + y32_idx + y16_idx,
mi_col + x32_idx + x16_idx,
cpi->vbp_threshold_16x16,
- cpi->vbp_bsize_min, segment_id)) {
+ cpi->vbp_bsize_min, 0)) {
for (k = 0; k < 4; ++k) {
const int x8_idx = (k & 1);
const int y8_idx = (k >> 1);
@@ -789,7 +802,7 @@
mi_row + y32_idx + y16_idx + y8_idx,
mi_col + x32_idx + x16_idx + x8_idx,
cpi->vbp_threshold_bsize_min,
- BLOCK_8X8, segment_id)) {
+ BLOCK_8X8, 0)) {
set_block_size(cpi, xd,
(mi_row + y32_idx + y16_idx + y8_idx),
(mi_col + x32_idx + x16_idx + x8_idx),
diff --git a/vp9/encoder/vp9_mcomp.c b/vp9/encoder/vp9_mcomp.c
index 88c5ca0..9602eb5 100644
--- a/vp9/encoder/vp9_mcomp.c
+++ b/vp9/encoder/vp9_mcomp.c
@@ -1805,6 +1805,7 @@
MV *tmp_mv = &xd->mi[0].src_mi->mbmi.mv[0].as_mv;
unsigned int best_sad, tmp_sad, this_sad[4];
MV this_mv;
+ const int norm_factor = 3 + (bw >> 5);
#if CONFIG_VP9_HIGHBITDEPTH
tmp_mv->row = 0;
@@ -1822,7 +1823,7 @@
ref_buf = xd->plane[0].pre[0].buf - (bh >> 1) * ref_stride;
for (idx = 0; idx < search_height; ++idx) {
- vbuf[idx] = vp9_int_pro_col(ref_buf, bw);
+ vbuf[idx] = vp9_int_pro_col(ref_buf, bw) >> norm_factor;
ref_buf += ref_stride;
}
@@ -1834,7 +1835,7 @@
src_buf = x->plane[0].src.buf;
for (idx = 0; idx < bh; ++idx) {
- src_vbuf[idx] = vp9_int_pro_col(src_buf, bw);
+ src_vbuf[idx] = vp9_int_pro_col(src_buf, bw) >> norm_factor;
src_buf += src_stride;
}
diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c
index 5bc9fca..7c1a930 100644
--- a/vp9/encoder/vp9_pickmode.c
+++ b/vp9/encoder/vp9_pickmode.c
@@ -615,9 +615,9 @@
static const REF_MODE ref_mode_set[RT_INTER_MODES] = {
{LAST_FRAME, ZEROMV},
{LAST_FRAME, NEARESTMV},
+ {GOLDEN_FRAME, ZEROMV},
{LAST_FRAME, NEARMV},
{LAST_FRAME, NEWMV},
- {GOLDEN_FRAME, ZEROMV},
{GOLDEN_FRAME, NEARESTMV},
{GOLDEN_FRAME, NEARMV},
{GOLDEN_FRAME, NEWMV}
@@ -755,8 +755,6 @@
vp9_find_best_ref_mvs(xd, cm->allow_high_precision_mv, candidates,
&frame_mv[NEARESTMV][ref_frame],
&frame_mv[NEARMV][ref_frame]);
- clamp_mv2(&frame_mv[NEARESTMV][ref_frame].as_mv, xd);
- clamp_mv2(&frame_mv[NEARMV][ref_frame].as_mv, xd);
if (!vp9_is_scaled(sf) && bsize >= BLOCK_8X8)
vp9_mv_pred(cpi, x, yv12_mb[ref_frame][0].buf, yv12->y_stride,
@@ -803,9 +801,6 @@
continue;
if (this_mode == NEWMV) {
- if (cpi->sf.partition_search_type != VAR_BASED_PARTITION
- && best_rdc.rdcost < (int64_t) (1 << num_pels_log2_lookup[bsize]))
- continue;
if (ref_frame > LAST_FRAME) {
int tmp_sad;
int dis, cost_list[5];
@@ -840,8 +835,9 @@
}
}
- if (this_mode != NEARESTMV && frame_mv[this_mode][ref_frame].as_int ==
- frame_mv[NEARESTMV][ref_frame].as_int)
+ if (this_mode != NEARESTMV &&
+ frame_mv[this_mode][ref_frame].as_int ==
+ frame_mv[NEARESTMV][ref_frame].as_int)
continue;
mbmi->mode = this_mode;
@@ -905,11 +901,11 @@
free_pred_buffer(current_pred);
mbmi->interp_filter = best_filter;
- mbmi->tx_size = pf_tx_size[mbmi->interp_filter];
- this_rdc.rate = pf_rate[mbmi->interp_filter];
- this_rdc.dist = pf_dist[mbmi->interp_filter];
- var_y = pf_var[mbmi->interp_filter];
- sse_y = pf_sse[mbmi->interp_filter];
+ mbmi->tx_size = pf_tx_size[best_filter];
+ this_rdc.rate = pf_rate[best_filter];
+ this_rdc.dist = pf_dist[best_filter];
+ var_y = pf_var[best_filter];
+ sse_y = pf_sse[best_filter];
x->skip_txfm[0] = skip_txfm;
} else {
mbmi->interp_filter = (filter_ref == SWITCHABLE) ? EIGHTTAP : filter_ref;
diff --git a/vp9/encoder/x86/vp9_avg_intrin_sse2.c b/vp9/encoder/x86/vp9_avg_intrin_sse2.c
index 618b5f7..4e80b255e 100644
--- a/vp9/encoder/x86/vp9_avg_intrin_sse2.c
+++ b/vp9/encoder/x86/vp9_avg_intrin_sse2.c
@@ -112,7 +112,6 @@
__m128i s0 = _mm_sad_epu8(src_line, zero);
__m128i s1;
int i;
- const int norm_factor = 3 + (width >> 5);
for (i = 16; i < width; i += 16) {
ref += 16;
@@ -124,7 +123,7 @@
s1 = _mm_srli_si128(s0, 8);
s0 = _mm_adds_epu16(s0, s1);
- return _mm_extract_epi16(s0, 0) >> norm_factor;
+ return _mm_extract_epi16(s0, 0);
}
int vp9_vector_var_sse2(int16_t const *ref, int16_t const *src,
diff --git a/vpxdec.c b/vpxdec.c
index 59c982d..62a5e93 100644
--- a/vpxdec.c
+++ b/vpxdec.c
@@ -75,6 +75,8 @@
"o", "output", 1, "Output file name pattern (see below)");
static const arg_def_t threadsarg = ARG_DEF(
"t", "threads", 1, "Max threads to use");
+static const arg_def_t frameparallelarg = ARG_DEF(
+ NULL, "frame-parallel", 0, "Frame parallel decode");
static const arg_def_t verbosearg = ARG_DEF(
"v", "verbose", 0, "Show version string");
static const arg_def_t error_concealment = ARG_DEF(
@@ -95,7 +97,7 @@
static const arg_def_t *all_args[] = {
&codecarg, &use_yv12, &use_i420, &flipuvarg, &rawvideo, &noblitarg,
&progressarg, &limitarg, &skiparg, &postprocarg, &summaryarg, &outputfile,
- &threadsarg, &verbosearg, &scalearg, &fb_arg,
+ &threadsarg, &frameparallelarg, &verbosearg, &scalearg, &fb_arg,
&md5arg, &error_concealment, &continuearg,
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
&outbitdeptharg,
@@ -542,7 +544,7 @@
size_t bytes_in_buffer = 0, buffer_size = 0;
FILE *infile;
int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0;
- int do_md5 = 0, progress = 0;
+ int do_md5 = 0, progress = 0, frame_parallel = 0;
int stop_after = 0, postproc = 0, summary = 0, quiet = 1;
int arg_skip = 0;
int ec_enabled = 0;
@@ -575,7 +577,7 @@
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
vpx_image_t *img_shifted = NULL;
#endif
- int frame_avail, got_data;
+ int frame_avail, got_data, flush_decoder = 0;
int num_external_frame_buffers = 0;
struct ExternalFrameBufferList ext_fb_list = {0, NULL};
@@ -642,6 +644,10 @@
summary = 1;
else if (arg_match(&arg, &threadsarg, argi))
cfg.threads = arg_parse_uint(&arg);
+#if CONFIG_VP9_DECODER
+ else if (arg_match(&arg, &frameparallelarg, argi))
+ frame_parallel = 1;
+#endif
else if (arg_match(&arg, &verbosearg, argi))
quiet = 0;
else if (arg_match(&arg, &scalearg, argi))
@@ -794,7 +800,8 @@
interface = get_vpx_decoder_by_index(0);
dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) |
- (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0);
+ (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0) |
+ (frame_parallel ? VPX_CODEC_USE_FRAME_THREADING : 0);
if (vpx_codec_dec_init(&decoder, interface->codec_interface(),
&cfg, dec_flags)) {
fprintf(stderr, "Failed to initialize decoder: %s\n",
@@ -892,11 +899,22 @@
vpx_usec_timer_mark(&timer);
dx_time += vpx_usec_timer_elapsed(&timer);
+ } else {
+ flush_decoder = 1;
}
+ } else {
+ flush_decoder = 1;
}
vpx_usec_timer_start(&timer);
+ if (flush_decoder) {
+ // Flush the decoder in frame parallel decode.
+ if (vpx_codec_decode(&decoder, NULL, 0, NULL, 0)) {
+ warn("Failed to flush decoder: %s", vpx_codec_error(&decoder));
+ }
+ }
+
got_data = 0;
if ((img = vpx_codec_get_frame(&decoder, &iter))) {
++frame_out;
@@ -906,7 +924,8 @@
vpx_usec_timer_mark(&timer);
dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);
- if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) {
+ if (!frame_parallel &&
+ vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) {
warn("Failed VP8_GET_FRAME_CORRUPTED: %s", vpx_codec_error(&decoder));
if (!keep_going)
goto fail;