diff options
62 files changed, 890 insertions, 1014 deletions
@@ -46,6 +46,9 @@ Advanced options: ${toggle_realtime_only} enable this option while building for real-time encoding ${toggle_onthefly_bitpacking} enable on-the-fly bitpacking in real-time encoding ${toggle_error_concealment} enable this option to get a decoder which is able to conceal losses + ${toggle_coefficient_range_checking} + enable decoder to check if intermediate + transform coefficients are in valid range ${toggle_runtime_cpu_detect} runtime cpu detection ${toggle_shared} shared library support ${toggle_static} static library support @@ -327,6 +330,7 @@ CONFIG_LIST=" encode_perf_tests multi_res_encoding temporal_denoising + coefficient_range_checking experimental size_limit ${EXPERIMENT_LIST} @@ -384,6 +388,7 @@ CMDLINE_SELECT=" encode_perf_tests multi_res_encoding temporal_denoising + coefficient_range_checking experimental " diff --git a/test/decode_test_driver.cc b/test/decode_test_driver.cc index 3e4ef0ad1..99610ebc5 100644 --- a/test/decode_test_driver.cc +++ b/test/decode_test_driver.cc @@ -67,24 +67,33 @@ void DecoderTest::RunLoop(CompressedVideoSource *video, const vpx_codec_dec_cfg_t &dec_cfg) { Decoder* const decoder = codec_->CreateDecoder(dec_cfg, 0); ASSERT_TRUE(decoder != NULL); + bool end_of_file = false; // Decode frames. - for (video->Begin(); !::testing::Test::HasFailure() && video->cxdata(); + for (video->Begin(); !::testing::Test::HasFailure() && !end_of_file; video->Next()) { PreDecodeFrameHook(*video, decoder); vpx_codec_stream_info_t stream_info; stream_info.sz = sizeof(stream_info); - const vpx_codec_err_t res_peek = decoder->PeekStream(video->cxdata(), - video->frame_size(), - &stream_info); - HandlePeekResult(decoder, video, res_peek); - ASSERT_FALSE(::testing::Test::HasFailure()); - - vpx_codec_err_t res_dec = decoder->DecodeFrame(video->cxdata(), - video->frame_size()); - if (!HandleDecodeResult(res_dec, *video, decoder)) - break; + + if (video->cxdata() != NULL) { + const vpx_codec_err_t res_peek = decoder->PeekStream(video->cxdata(), + video->frame_size(), + &stream_info); + HandlePeekResult(decoder, video, res_peek); + ASSERT_FALSE(::testing::Test::HasFailure()); + + vpx_codec_err_t res_dec = decoder->DecodeFrame(video->cxdata(), + video->frame_size()); + if (!HandleDecodeResult(res_dec, *video, decoder)) + break; + } else { + // Signal end of the file to the decoder. + const vpx_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0); + ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError(); + end_of_file = true; + } DxDataIterator dec_iter = decoder->GetDxData(); const vpx_image_t *img = NULL; diff --git a/test/sad_test.cc b/test/sad_test.cc index f07a98921..e63770bd4 100644 --- a/test/sad_test.cc +++ b/test/sad_test.cc @@ -640,19 +640,9 @@ INSTANTIATE_TEST_CASE_P(SSE3, SADTest, ::testing::Values( #if HAVE_AVX2 #if CONFIG_VP9_ENCODER -// TODO(jzern): these prototypes can be removed after the avx2 versions are -// reenabled in vp9_rtcd_defs.pl. -extern "C" { -void vp9_sad32x32x4d_avx2(const uint8_t *src_ptr, int src_stride, - const uint8_t *const ref_ptr[], int ref_stride, - unsigned int *sad_array); -void vp9_sad64x64x4d_avx2(const uint8_t *src_ptr, int src_stride, - const uint8_t *const ref_ptr[], int ref_stride, - unsigned int *sad_array); -} const SadMxNx4Func sad_64x64x4d_avx2 = vp9_sad64x64x4d_avx2; const SadMxNx4Func sad_32x32x4d_avx2 = vp9_sad32x32x4d_avx2; -INSTANTIATE_TEST_CASE_P(DISABLED_AVX2, SADx4Test, ::testing::Values( +INSTANTIATE_TEST_CASE_P(AVX2, SADx4Test, ::testing::Values( make_tuple(32, 32, sad_32x32x4d_avx2), make_tuple(64, 64, sad_64x64x4d_avx2))); #endif // CONFIG_VP9_ENCODER diff --git a/test/tools_common.sh b/test/tools_common.sh index e98beadf8..0bfefba46 100755 --- a/test/tools_common.sh +++ b/test/tools_common.sh @@ -182,65 +182,6 @@ webm_io_available() { [ "$(vpx_config_option_enabled CONFIG_WEBM_IO)" = "yes" ] && echo yes } -# Echoes yes to stdout when vpxenc exists according to vpx_tool_available(). -vpxenc_available() { - [ -n $(vpx_tool_available vpxenc) ] && echo yes -} - -# Wrapper function for running vpxenc. Positional parameters are interpreted as -# follows: -# 1 - codec name -# 2 - input width -# 3 - input height -# 4 - number of frames to encode -# 5 - path to input file -# 6 - path to output file -# Note: The output file path must end in .ivf to output an IVF file. -# 7 - extra flags -# Note: Extra flags currently supports a special case: when set to "-" -# input is piped to vpxenc via cat. -vpxenc() { - local encoder="${LIBVPX_BIN_PATH}/vpxenc${VPX_TEST_EXE_SUFFIX}" - local codec="${1}" - local width=${2} - local height=${3} - local frames=${4} - local input=${5} - local output="${VPX_TEST_OUTPUT_DIR}/${6}" - local extra_flags=${7} - - # Because --ivf must be within the command line to get IVF from vpxenc. - if echo "${output}" | egrep -q 'ivf$'; then - use_ivf=--ivf - else - unset use_ivf - fi - - if [ "${extra_flags}" = "-" ]; then - pipe_input=yes - extra_flags=${8} - else - unset pipe_input - fi - - if [ -z "${pipe_input}" ]; then - eval "${VPX_TEST_PREFIX}" "${encoder}" --codec=${codec} --width=${width} \ - --height=${height} --limit=${frames} ${use_ivf} ${extra_flags} \ - --output="${output}" "${input}" ${devnull} - else - cat "${input}" \ - | eval "${VPX_TEST_PREFIX}" "${encoder}" --codec=${codec} \ - --width=${width} --height=${height} --limit=${frames} ${use_ivf} \ - ${extra_flags} --output="${output}" - ${devnull} - fi - - if [ ! -e "${output}" ]; then - # Return non-zero exit status: output file doesn't exist, so something - # definitely went wrong. - return 1 - fi -} - # Filters strings from positional parameter one using the filter specified by # positional parameter two. Filter behavior depends on the presence of a third # positional parameter. When parameter three is present, strings that match the diff --git a/test/variance_test.cc b/test/variance_test.cc index 40b7df630..7d8118235 100644 --- a/test/variance_test.cc +++ b/test/variance_test.cc @@ -707,24 +707,7 @@ INSTANTIATE_TEST_CASE_P( #endif #if HAVE_AVX2 -// TODO(jzern): these prototypes can be removed after the avx2 versions are -// reenabled in vp9_rtcd_defs.pl. -extern "C" { -unsigned int vp9_sub_pixel_variance32x32_avx2( - const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, - const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); -unsigned int vp9_sub_pixel_variance64x64_avx2( - const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, - const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); -unsigned int vp9_sub_pixel_avg_variance32x32_avx2( - const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, - const uint8_t *ref_ptr, int ref_stride, unsigned int *sse, - const uint8_t *second_pred); -unsigned int vp9_sub_pixel_avg_variance64x64_avx2( - const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, - const uint8_t *ref_ptr, int ref_stride, unsigned int *sse, - const uint8_t *second_pred); -} + const vp9_variance_fn_t variance16x16_avx2 = vp9_variance16x16_avx2; const vp9_variance_fn_t variance32x16_avx2 = vp9_variance32x16_avx2; const vp9_variance_fn_t variance32x32_avx2 = vp9_variance32x32_avx2; @@ -743,7 +726,7 @@ const vp9_subpixvariance_fn_t subpel_variance32x32_avx2 = const vp9_subpixvariance_fn_t subpel_variance64x64_avx2 = vp9_sub_pixel_variance64x64_avx2; INSTANTIATE_TEST_CASE_P( - DISABLED_AVX2, VP9SubpelVarianceTest, + AVX2, VP9SubpelVarianceTest, ::testing::Values(make_tuple(5, 5, subpel_variance32x32_avx2), make_tuple(6, 6, subpel_variance64x64_avx2))); @@ -752,7 +735,7 @@ const vp9_subp_avg_variance_fn_t subpel_avg_variance32x32_avx2 = const vp9_subp_avg_variance_fn_t subpel_avg_variance64x64_avx2 = vp9_sub_pixel_avg_variance64x64_avx2; INSTANTIATE_TEST_CASE_P( - DISABLED_AVX2, VP9SubpelAvgVarianceTest, + AVX2, VP9SubpelAvgVarianceTest, ::testing::Values(make_tuple(5, 5, subpel_avg_variance32x32_avx2), make_tuple(6, 6, subpel_avg_variance64x64_avx2))); #endif // HAVE_AVX2 diff --git a/test/vp9_spatial_svc_encoder.sh b/test/vp9_spatial_svc_encoder.sh index 7a964a920..6dd5f171b 100755 --- a/test/vp9_spatial_svc_encoder.sh +++ b/test/vp9_spatial_svc_encoder.sh @@ -47,43 +47,9 @@ vp9_spatial_svc_encoder() { [ -e "${output_file}" ] || return 1 } -# Each mode is run with layer count 1-$vp9_ssvc_test_layers. +# Each test is run with layer count 1-$vp9_ssvc_test_layers. vp9_ssvc_test_layers=5 -DISABLED_vp9_spatial_svc_mode_i() { - if [ "$(vp9_encode_available)" = "yes" ]; then - local readonly test_name="DISABLED_vp9_spatial_svc_mode_i" - for layers in $(seq 1 ${vp9_ssvc_test_layers}); do - vp9_spatial_svc_encoder "${test_name}" -m i -l ${layers} - done - fi -} - -DISABLED_vp9_spatial_svc_mode_altip() { - if [ "$(vp9_encode_available)" = "yes" ]; then - local readonly test_name="DISABLED_vp9_spatial_svc_mode_altip" - for layers in $(seq 1 ${vp9_ssvc_test_layers}); do - vp9_spatial_svc_encoder "${test_name}" -m "alt-ip" -l ${layers} - done - fi -} - -DISABLED_vp9_spatial_svc_mode_ip() { - if [ "$(vp9_encode_available)" = "yes" ]; then - local readonly test_name="DISABLED_vp9_spatial_svc_mode_ip" - vp9_spatial_svc_encoder "${test_name}" -m ip -l 1 - fi -} - -DISABLED_vp9_spatial_svc_mode_gf() { - if [ "$(vp9_encode_available)" = "yes" ]; then - local readonly test_name="DISABLED_vp9_spatial_svc_mode_gf" - for layers in $(seq 1 ${vp9_ssvc_test_layers}); do - vp9_spatial_svc_encoder "${test_name}" -m gf -l ${layers} - done - fi -} - vp9_spatial_svc() { if [ "$(vp9_encode_available)" = "yes" ]; then local readonly test_name="vp9_spatial_svc" diff --git a/test/vpxenc.sh b/test/vpxenc.sh index f08c04878..6e9ad3564 100755 --- a/test/vpxenc.sh +++ b/test/vpxenc.sh @@ -15,7 +15,7 @@ ## . $(dirname $0)/tools_common.sh -TEST_FRAMES=10 +readonly TEST_FRAMES=10 # Environment check: Make sure input is available. vpxenc_verify_environment() { @@ -39,55 +39,170 @@ vpxenc_can_encode_vp9() { fi } +# Echoes yes to stdout when vpxenc exists according to vpx_tool_available(). +vpxenc_available() { + [ -n "$(vpx_tool_available vpxenc)" ] && echo yes +} + +# Wrapper function for running vpxenc with pipe input. Requires that +# LIBVPX_BIN_PATH points to the directory containing vpxenc. $1 is used as the +# input file path and shifted away. All remaining parameters are passed through +# to vpxenc. +vpxenc_pipe() { + local readonly encoder="${LIBVPX_BIN_PATH}/vpxenc${VPX_TEST_EXE_SUFFIX}" + local readonly input="$1" + shift + cat "${input}" | eval "${VPX_TEST_PREFIX}" "${encoder}" - "$@" ${devnull} +} + +# Wrapper function for running vpxenc. Requires that LIBVPX_BIN_PATH points to +# the directory containing vpxenc. $1 one is used as the input file path and +# shifted away. All remaining parameters are passed through to vpxenc. +vpxenc() { + local readonly encoder="${LIBVPX_BIN_PATH}/vpxenc${VPX_TEST_EXE_SUFFIX}" + local readonly input="${1}" + shift + eval "${VPX_TEST_PREFIX}" "${encoder}" "$input" "$@" ${devnull} +} + vpxenc_vp8_ivf() { if [ "$(vpxenc_can_encode_vp8)" = "yes" ]; then - vpxenc vp8 ${YUV_RAW_INPUT_WIDTH} ${YUV_RAW_INPUT_HEIGHT} ${TEST_FRAMES} \ - "${YUV_RAW_INPUT}" vp8.ivf + local readonly output="${VPX_TEST_OUTPUT_DIR}/vp8.ivf" + vpxenc --codec=vp8 \ + --width="${YUV_RAW_INPUT_WIDTH}" \ + --height="${YUV_RAW_INPUT_HEIGHT}" \ + --limit="${TEST_FRAMES}" \ + --ivf \ + --output="${output}" \ + "${YUV_RAW_INPUT}" + + if [ ! -e "${output}" ]; then + elog "Output file does not exist." + return 1 + fi fi } -vpxenc_vp8_ivf_pipe_input() { +vpxenc_vp8_ivf_piped_input() { if [ "$(vpxenc_can_encode_vp8)" = "yes" ]; then - vpxenc vp8 ${YUV_RAW_INPUT_WIDTH} ${YUV_RAW_INPUT_HEIGHT} ${TEST_FRAMES} \ - "${YUV_RAW_INPUT}" vp8.ivf - + local readonly output="${VPX_TEST_OUTPUT_DIR}/vp8_piped_input.ivf" + cat "${YUV_RAW_INPUT}" \ + | vpxenc --codec=vp8 \ + --width="${YUV_RAW_INPUT_WIDTH}" \ + --height="${YUV_RAW_INPUT_HEIGHT}" \ + --limit="${TEST_FRAMES}" \ + --ivf \ + --output="${output}" \ + - + + if [ ! -e "${output}" ]; then + elog "Output file does not exist." + return 1 + fi fi } vpxenc_vp8_webm() { - if [ "$(vpxenc_can_encode_vp8)" = "yes" ] && - [ "$(webm_io_available)" = "yes" ] ; then - vpxenc vp8 ${YUV_RAW_INPUT_WIDTH} ${YUV_RAW_INPUT_HEIGHT} ${TEST_FRAMES} \ - "${YUV_RAW_INPUT}" vp8.webm + if [ "$(vpxenc_can_encode_vp8)" = "yes" ] && \ + [ "$(webm_io_available)" = "yes" ]; then + local readonly output="${VPX_TEST_OUTPUT_DIR}/vp8.webm" + vpxenc --codec=vp8 \ + --width="${YUV_RAW_INPUT_WIDTH}" \ + --height="${YUV_RAW_INPUT_HEIGHT}" \ + --limit="${TEST_FRAMES}" \ + --output="${output}" \ + "${YUV_RAW_INPUT}" + + if [ ! -e "${output}" ]; then + elog "Output file does not exist." + return 1 + fi fi } vpxenc_vp9_ivf() { if [ "$(vpxenc_can_encode_vp9)" = "yes" ]; then - vpxenc vp9 ${YUV_RAW_INPUT_WIDTH} ${YUV_RAW_INPUT_HEIGHT} ${TEST_FRAMES} \ - "${YUV_RAW_INPUT}" vp9.ivf + local readonly output="${VPX_TEST_OUTPUT_DIR}/vp9.ivf" + vpxenc --codec=vp9 \ + --width="${YUV_RAW_INPUT_WIDTH}" \ + --height="${YUV_RAW_INPUT_HEIGHT}" \ + --limit="${TEST_FRAMES}" \ + --ivf \ + --output="${output}" \ + "${YUV_RAW_INPUT}" + + if [ ! -e "${output}" ]; then + elog "Output file does not exist." + return 1 + fi fi } vpxenc_vp9_webm() { - if [ "$(vpxenc_can_encode_vp9)" = "yes" ] && - [ "$(webm_io_available)" = "yes" ] ; then - vpxenc vp9 ${YUV_RAW_INPUT_WIDTH} ${YUV_RAW_INPUT_HEIGHT} ${TEST_FRAMES} \ - "${YUV_RAW_INPUT}" vp9.webm + if [ "$(vpxenc_can_encode_vp9)" = "yes" ] && \ + [ "$(webm_io_available)" = "yes" ]; then + local readonly output="${VPX_TEST_OUTPUT_DIR}/vp9.webm" + vpxenc --codec=vp9 \ + --width="${YUV_RAW_INPUT_WIDTH}" \ + --height="${YUV_RAW_INPUT_HEIGHT}" \ + --limit="${TEST_FRAMES}" \ + --output="${output}" \ + "${YUV_RAW_INPUT}" + + if [ ! -e "${output}" ]; then + elog "Output file does not exist." + return 1 + fi + fi +} + +vpxenc_vp9_ivf_lossless() { + if [ "$(vpxenc_can_encode_vp9)" = "yes" ]; then + local readonly output="${VPX_TEST_OUTPUT_DIR}/vp9_lossless.ivf" + vpxenc --codec=vp9 \ + --width="${YUV_RAW_INPUT_WIDTH}" \ + --height="${YUV_RAW_INPUT_HEIGHT}" \ + --limit="${TEST_FRAMES}" \ + --ivf \ + --output="${output}" \ + --lossless=1 \ + --test-decode=fatal \ + "${YUV_RAW_INPUT}" + + if [ ! -e "${output}" ]; then + elog "Output file does not exist." + return 1 + fi fi } -DISABLED_vpxenc_vp9_ivf_lossless() { +vpxenc_vp9_ivf_minq0_maxq0() { if [ "$(vpxenc_can_encode_vp9)" = "yes" ]; then - vpxenc vp9 ${YUV_RAW_INPUT_WIDTH} ${YUV_RAW_INPUT_HEIGHT} ${TEST_FRAMES} \ - "${YUV_RAW_INPUT}" vp9_lossless.ivf --lossless + local readonly output="${VPX_TEST_OUTPUT_DIR}/vp9_lossless_minq0_maxq0.ivf" + vpxenc --codec=vp9 \ + --width="${YUV_RAW_INPUT_WIDTH}" \ + --height="${YUV_RAW_INPUT_HEIGHT}" \ + --limit="${TEST_FRAMES}" \ + --ivf \ + --output="${output}" \ + --min-q=0 \ + --max-q=0 \ + --test-decode=fatal \ + "${YUV_RAW_INPUT}" + + if [ ! -e "${output}" ]; then + elog "Output file does not exist." + return 1 + fi fi } vpxenc_tests="vpxenc_vp8_ivf vpxenc_vp8_webm - vpxenc_vp8_ivf_pipe_input + vpxenc_vp8_ivf_piped_input vpxenc_vp9_ivf vpxenc_vp9_webm - DISABLED_vpxenc_vp9_ivf_lossless" + vpxenc_vp9_ivf_lossless + vpxenc_vp9_ivf_minq0_maxq0" run_tests vpxenc_verify_environment "${vpxenc_tests}" diff --git a/tools_common.c b/tools_common.c index b481579b4..7cfd066ec 100644 --- a/tools_common.c +++ b/tools_common.c @@ -246,7 +246,7 @@ int vpx_img_read(vpx_image_t *img, FILE *file) { int y; for (y = 0; y < h; ++y) { - if (fread(buf, 1, w, file) != w) + if (fread(buf, 1, w, file) != (size_t)w) return 0; buf += stride; } diff --git a/vp8/common/onyx.h b/vp8/common/onyx.h index ef7f61b12..a46fbfbbd 100644 --- a/vp8/common/onyx.h +++ b/vp8/common/onyx.h @@ -108,7 +108,7 @@ extern "C" * For temporal denoiser: noise_sensitivity = 0 means off, * noise_sensitivity = 1 means temporal denoiser on for Y channel only, * noise_sensitivity = 2 means temporal denoiser on for all channels. - * noise_sensitivity = 3 means aggressive denoising mode. + * noise_sensitivity >= 3 means aggressive denoising mode. * Temporal denoiser is enabled via the configuration option: * CONFIG_TEMPORAL_DENOISING. * For spatial denoiser: noise_sensitivity controls the amount of diff --git a/vp8/encoder/denoising.c b/vp8/encoder/denoising.c index c4c0de81b..75401fc2b 100644 --- a/vp8/encoder/denoising.c +++ b/vp8/encoder/denoising.c @@ -335,8 +335,16 @@ int vp8_denoiser_filter_uv_c(unsigned char *mc_running_avg_uv, return FILTER_BLOCK; } -void vp8_denoiser_set_parameters(VP8_DENOISER *denoiser) { - if (!denoiser->aggressive_mode) { +void vp8_denoiser_set_parameters(VP8_DENOISER *denoiser, int mode) { + assert(mode > 0); // Denoiser is allocated only if mode > 0. + if (mode == 1) { + denoiser->denoiser_mode = kDenoiserOnYOnly; + } else if (mode == 2) { + denoiser->denoiser_mode = kDenoiserOnYUV; + } else { + denoiser->denoiser_mode = kDenoiserOnYUVAggressive; + } + if (denoiser->denoiser_mode != kDenoiserOnYUVAggressive) { denoiser->denoise_pars.scale_sse_thresh = 1; denoiser->denoise_pars.scale_motion_thresh = 8; denoiser->denoise_pars.scale_increase_filter = 0; @@ -361,7 +369,6 @@ int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height, int i; assert(denoiser); denoiser->num_mb_cols = num_mb_cols; - denoiser->aggressive_mode = mode; for (i = 0; i < MAX_REF_FRAMES; i++) { @@ -392,7 +399,7 @@ int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height, denoiser->denoise_state = vpx_calloc((num_mb_rows * num_mb_cols), 1); vpx_memset(denoiser->denoise_state, 0, (num_mb_rows * num_mb_cols)); - vp8_denoiser_set_parameters(denoiser); + vp8_denoiser_set_parameters(denoiser, mode); return 0; } @@ -420,8 +427,8 @@ void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser, loop_filter_info_n *lfi_n, int mb_row, int mb_col, - int block_index, - int uv_denoise) + int block_index) + { int mv_row; int mv_col; @@ -558,7 +565,7 @@ void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser, denoiser->denoise_state[block_index] = motion_magnitude2 > 0 ? kFilterNonZeroMV : kFilterZeroMV; // Only denoise UV for zero motion, and if y channel was denoised. - if (uv_denoise && + if (denoiser->denoiser_mode != kDenoiserOnYOnly && motion_magnitude2 == 0 && decision == FILTER_BLOCK) { unsigned char *mc_running_avg_u = @@ -595,7 +602,7 @@ void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser, denoiser->yv12_running_avg[INTRA_FRAME].y_stride); denoiser->denoise_state[block_index] = kNoFilter; } - if (uv_denoise) { + if (denoiser->denoiser_mode != kDenoiserOnYOnly) { if (decision_u == COPY_BLOCK) { vp8_copy_mem8x8( x->block[16].src + *x->block[16].base_src, x->block[16].src_stride, diff --git a/vp8/encoder/denoising.h b/vp8/encoder/denoising.h index 1a42f86d3..89832d3c2 100644 --- a/vp8/encoder/denoising.h +++ b/vp8/encoder/denoising.h @@ -39,6 +39,13 @@ enum vp8_denoiser_filter_state { kFilterNonZeroMV }; +enum vp8_denoiser_mode { + kDenoiserOff, + kDenoiserOnYOnly, + kDenoiserOnYUV, + kDenoiserOnYUVAggressive +}; + typedef struct { // Scale factor on sse threshold above which no denoising is done. unsigned int scale_sse_thresh; @@ -67,7 +74,7 @@ typedef struct vp8_denoiser YV12_BUFFER_CONFIG yv12_mc_running_avg; unsigned char* denoise_state; int num_mb_cols; - int aggressive_mode; + int denoiser_mode; denoise_params denoise_pars; } VP8_DENOISER; @@ -85,8 +92,7 @@ void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser, loop_filter_info_n *lfi_n, int mb_row, int mb_col, - int block_index, - int uv_denoise); + int block_index); #ifdef __cplusplus } // extern "C" diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index 298f50f65..7140f2f1b 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -615,7 +615,7 @@ static void cyclic_background_refresh(VP8_COMP *cpi, int Q, int lf_adjustment) cpi->cyclic_refresh_mode_index = i; #if CONFIG_TEMPORAL_DENOISING - if (cpi->denoiser.aggressive_mode != 0 && + if (cpi->denoiser.denoiser_mode == kDenoiserOnYUVAggressive && Q < (int)cpi->denoiser.denoise_pars.qp_thresh) { // Under aggressive denoising mode, use segmentation to turn off loop // filter below some qp thresh. The loop filter is turned off for all @@ -1277,6 +1277,15 @@ void vp8_alloc_compressor_data(VP8_COMP *cpi) vpx_free(cpi->tplist); CHECK_MEM_ERROR(cpi->tplist, vpx_malloc(sizeof(TOKENLIST) * cm->mb_rows)); + +#if CONFIG_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity > 0) { + vp8_denoiser_free(&cpi->denoiser); + vp8_denoiser_allocate(&cpi->denoiser, width, height, + cm->mb_rows, cm->mb_cols, + cpi->oxcf.noise_sensitivity); + } +#endif } @@ -1771,7 +1780,7 @@ void vp8_change_config(VP8_COMP *cpi, VP8_CONFIG *oxcf) int height = (cpi->oxcf.Height + 15) & ~15; vp8_denoiser_allocate(&cpi->denoiser, width, height, cm->mb_rows, cm->mb_cols, - ((cpi->oxcf.noise_sensitivity == 3) ? 1 : 0)); + cpi->oxcf.noise_sensitivity); } } #endif diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c index ec1ea146f..d0ad7212d 100644 --- a/vp8/encoder/pickinter.c +++ b/vp8/encoder/pickinter.c @@ -1174,7 +1174,6 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, #if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity) { - int uv_denoise = (cpi->oxcf.noise_sensitivity >= 2) ? 1 : 0; int block_index = mb_row * cpi->common.mb_cols + mb_col; if (x->best_sse_inter_mode == DC_PRED) { @@ -1189,8 +1188,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse, recon_yoffset, recon_uvoffset, &cpi->common.lf_info, mb_row, mb_col, - block_index, uv_denoise); - + block_index); /* Reevaluate ZEROMV after denoising. */ if (best_mbmode.ref_frame == INTRA_FRAME && diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c index 98d60160c..2f6f5d07c 100644 --- a/vp8/encoder/rdopt.c +++ b/vp8/encoder/rdopt.c @@ -2511,7 +2511,6 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, #if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity) { - int uv_denoise = (cpi->oxcf.noise_sensitivity == 2) ? 1 : 0; int block_index = mb_row * cpi->common.mb_cols + mb_col; if (x->best_sse_inter_mode == DC_PRED) { @@ -2525,8 +2524,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse, recon_yoffset, recon_uvoffset, &cpi->common.lf_info, mb_row, mb_col, - block_index, uv_denoise); - + block_index); /* Reevaluate ZEROMV after denoising. */ if (best_mode.mbmode.ref_frame == INTRA_FRAME && diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c index 83938dd3d..8767f0d0f 100644 --- a/vp8/vp8_cx_iface.c +++ b/vp8/vp8_cx_iface.c @@ -1342,8 +1342,6 @@ CODEC_INTERFACE(vpx_codec_vp8_cx) = vp8e_init, /* vpx_codec_init_fn_t init; */ vp8e_destroy, /* vpx_codec_destroy_fn_t destroy; */ vp8e_ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */ - NOT_IMPLEMENTED, /* vpx_codec_get_mmap_fn_t get_mmap; */ - NOT_IMPLEMENTED, /* vpx_codec_set_mmap_fn_t set_mmap; */ { NOT_IMPLEMENTED, /* vpx_codec_peek_si_fn_t peek_si; */ NOT_IMPLEMENTED, /* vpx_codec_get_si_fn_t get_si; */ diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c index f768b5c47..0fe0c921f 100644 --- a/vp8/vp8_dx_iface.c +++ b/vp8/vp8_dx_iface.c @@ -60,6 +60,7 @@ struct vpx_codec_alg_priv vpx_decrypt_cb decrypt_cb; void *decrypt_state; vpx_image_t img; + int flushed; int img_setup; struct frame_buffers yv12_frame_buffers; void *user_priv; @@ -88,6 +89,7 @@ static void vp8_init_ctx(vpx_codec_ctx_t *ctx) ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si); ctx->priv->alg_priv->decrypt_cb = NULL; ctx->priv->alg_priv->decrypt_state = NULL; + ctx->priv->alg_priv->flushed = 0; ctx->priv->init_flags = ctx->init_flags; if (ctx->config.dec) @@ -328,6 +330,13 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, unsigned int resolution_change = 0; unsigned int w, h; + if (data == NULL && data_sz == 0) { + ctx->flushed = 1; + return VPX_CODEC_OK; + } + + /* Reset flushed when receiving a valid frame */ + ctx->flushed = 0; /* Update the input fragment data */ if(update_fragments(ctx, data, data_sz, &res) <= 0) @@ -794,8 +803,6 @@ CODEC_INTERFACE(vpx_codec_vp8_dx) = vp8_init, /* vpx_codec_init_fn_t init; */ vp8_destroy, /* vpx_codec_destroy_fn_t destroy; */ vp8_ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */ - NOT_IMPLEMENTED, /* vpx_codec_get_mmap_fn_t get_mmap; */ - NOT_IMPLEMENTED, /* vpx_codec_set_mmap_fn_t set_mmap; */ { vp8_peek_si, /* vpx_codec_peek_si_fn_t peek_si; */ vp8_get_si, /* vpx_codec_get_si_fn_t get_si; */ diff --git a/vp9/common/vp9_entropy.h b/vp9/common/vp9_entropy.h index 5af88c3bd..8a10f2320 100644 --- a/vp9/common/vp9_entropy.h +++ b/vp9/common/vp9_entropy.h @@ -183,6 +183,7 @@ static INLINE int get_entropy_context(TX_SIZE tx_size, const ENTROPY_CONTEXT *a, break; default: assert(0 && "Invalid transform size."); + break; } return combine_entropy_contexts(above_ec, left_ec); diff --git a/vp9/common/vp9_enums.h b/vp9/common/vp9_enums.h index 0c2898d21..d77631341 100644 --- a/vp9/common/vp9_enums.h +++ b/vp9/common/vp9_enums.h @@ -27,10 +27,10 @@ extern "C" { // Bitstream profiles indicated by 2-3 bits in the uncompressed header. // 00: Profile 0. 8-bit 4:2:0 only. -// 10: Profile 1. Adds 4:4:4, 4:2:2, and 4:4:0 to Profile 0. -// 01: Profile 2. Supports 10-bit and 12-bit color only, with 4:2:0 sampling. -// 110: Profile 3. Supports 10-bit and 12-bit color only, with 4:2:2/4:4:4/4:4:0 -// subsampling. +// 10: Profile 1. 8-bit 4:4:4, 4:2:2, and 4:4:0. +// 01: Profile 2. 10-bit and 12-bit color only, with 4:2:0 sampling. +// 110: Profile 3. 10-bit and 12-bit color only, with 4:2:2/4:4:4/4:4:0 +// sampling. // 111: Undefined profile. typedef enum BITSTREAM_PROFILE { PROFILE_0, diff --git a/vp9/common/vp9_idct.h b/vp9/common/vp9_idct.h index 3253bcbf4..7f595e1cc 100644 --- a/vp9/common/vp9_idct.h +++ b/vp9/common/vp9_idct.h @@ -81,6 +81,16 @@ static const int sinpi_4_9 = 15212; static INLINE int dct_const_round_shift(int input) { int rv = ROUND_POWER_OF_TWO(input, DCT_CONST_BITS); +#if CONFIG_COEFFICIENT_RANGE_CHECKING + // For valid VP9 input streams, intermediate stage coefficients should always + // stay within the range of a signed 16 bit integer. Coefficients can go out + // of this range for invalid/corrupt VP9 streams. However, strictly checking + // this range for every intermediate coefficient can burdensome for a decoder, + // therefore the following assertion is only enabled when configured with + // --enable-coefficient-range-checking. + assert(INT16_MIN <= rv); + assert(rv <= INT16_MAX); +#endif return (int16_t)rv; } diff --git a/vp9/common/vp9_mvref_common.c b/vp9/common/vp9_mvref_common.c index 0fe58c5c8..ab64d3036 100644 --- a/vp9/common/vp9_mvref_common.c +++ b/vp9/common/vp9_mvref_common.c @@ -20,7 +20,7 @@ static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd, int block, int mi_row, int mi_col) { const int *ref_sign_bias = cm->ref_frame_sign_bias; int i, refmv_count = 0; - const MODE_INFO *prev_mi = cm->coding_use_prev_mi && cm->prev_mi + const MODE_INFO *prev_mi = !cm->error_resilient_mode && cm->prev_mi ? cm->prev_mi_grid_visible[mi_row * xd->mi_stride + mi_col] : NULL; const MB_MODE_INFO *const prev_mbmi = prev_mi ? &prev_mi->mbmi : NULL; diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h index 97b267c0b..ae32aff7d 100644 --- a/vp9/common/vp9_onyxc_int.h +++ b/vp9/common/vp9_onyxc_int.h @@ -188,11 +188,6 @@ typedef struct VP9Common { int error_resilient_mode; int frame_parallel_decoding_mode; - // Flag indicates if prev_mi can be used in coding: - // 0: encoder assumes decoder does not have prev_mi - // 1: encoder assumes decoder has and uses prev_mi - unsigned int coding_use_prev_mi; - int log2_tile_cols, log2_tile_rows; // Private data associated with the frame buffer callbacks. @@ -207,6 +202,12 @@ typedef struct VP9Common { ENTROPY_CONTEXT *above_context; } VP9_COMMON; +static INLINE YV12_BUFFER_CONFIG *get_ref_frame(VP9_COMMON *cm, int index) { + if (index < 0 || index >= REF_FRAMES) + return NULL; + return &cm->frame_bufs[cm->ref_frame_map[index]].buf; +} + static INLINE YV12_BUFFER_CONFIG *get_frame_new_buffer(VP9_COMMON *cm) { return &cm->frame_bufs[cm->new_fb_idx].buf; } diff --git a/vp9/common/vp9_pred_common.c b/vp9/common/vp9_pred_common.c index bc9d6ef5e..014638466 100644 --- a/vp9/common/vp9_pred_common.c +++ b/vp9/common/vp9_pred_common.c @@ -353,9 +353,9 @@ int vp9_get_tx_size_context(const MACROBLOCKD *xd) { const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd)); const int has_above = above_mbmi != NULL; const int has_left = left_mbmi != NULL; - int above_ctx = (has_above && !above_mbmi->skip) ? above_mbmi->tx_size + int above_ctx = (has_above && !above_mbmi->skip) ? (int)above_mbmi->tx_size : max_tx_size; - int left_ctx = (has_left && !left_mbmi->skip) ? left_mbmi->tx_size + int left_ctx = (has_left && !left_mbmi->skip) ? (int)left_mbmi->tx_size : max_tx_size; if (!has_left) left_ctx = above_ctx; @@ -366,7 +366,7 @@ int vp9_get_tx_size_context(const MACROBLOCKD *xd) { return (above_ctx + left_ctx) > max_tx_size; } -int vp9_get_segment_id(VP9_COMMON *cm, const uint8_t *segment_ids, +int vp9_get_segment_id(const VP9_COMMON *cm, const uint8_t *segment_ids, BLOCK_SIZE bsize, int mi_row, int mi_col) { const int mi_offset = mi_row * cm->mi_cols + mi_col; const int bw = num_8x8_blocks_wide_lookup[bsize]; diff --git a/vp9/common/vp9_pred_common.h b/vp9/common/vp9_pred_common.h index 1a7ba86e4..2c965068a 100644 --- a/vp9/common/vp9_pred_common.h +++ b/vp9/common/vp9_pred_common.h @@ -26,7 +26,7 @@ static INLINE const MODE_INFO *get_left_mi(const MACROBLOCKD *const xd) { return xd->left_available ? xd->mi[-1] : NULL; } -int vp9_get_segment_id(VP9_COMMON *cm, const uint8_t *segment_ids, +int vp9_get_segment_id(const VP9_COMMON *cm, const uint8_t *segment_ids, BLOCK_SIZE bsize, int mi_row, int mi_col); static INLINE int vp9_get_pred_context_seg_id(const MACROBLOCKD *xd) { diff --git a/vp9/common/vp9_rtcd_defs.pl b/vp9/common/vp9_rtcd_defs.pl index 8d917919b..708f41b87 100644 --- a/vp9/common/vp9_rtcd_defs.pl +++ b/vp9/common/vp9_rtcd_defs.pl @@ -447,10 +447,10 @@ add_proto qw/unsigned int vp9_variance4x4/, "const uint8_t *src_ptr, int source_ specialize qw/vp9_variance4x4 mmx/, "$sse2_x86inc"; add_proto qw/unsigned int vp9_sub_pixel_variance64x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse"; -specialize qw/vp9_sub_pixel_variance64x64/, "$sse2_x86inc", "$ssse3_x86inc"; +specialize qw/vp9_sub_pixel_variance64x64 avx2/, "$sse2_x86inc", "$ssse3_x86inc"; add_proto qw/unsigned int vp9_sub_pixel_avg_variance64x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse, const uint8_t *second_pred"; -specialize qw/vp9_sub_pixel_avg_variance64x64/, "$sse2_x86inc", "$ssse3_x86inc"; +specialize qw/vp9_sub_pixel_avg_variance64x64 avx2/, "$sse2_x86inc", "$ssse3_x86inc"; add_proto qw/unsigned int vp9_sub_pixel_variance32x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse"; specialize qw/vp9_sub_pixel_variance32x64/, "$sse2_x86inc", "$ssse3_x86inc"; @@ -477,10 +477,10 @@ add_proto qw/unsigned int vp9_sub_pixel_avg_variance16x32/, "const uint8_t *src_ specialize qw/vp9_sub_pixel_avg_variance16x32/, "$sse2_x86inc", "$ssse3_x86inc"; add_proto qw/unsigned int vp9_sub_pixel_variance32x32/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse"; -specialize qw/vp9_sub_pixel_variance32x32 neon/, "$sse2_x86inc", "$ssse3_x86inc"; +specialize qw/vp9_sub_pixel_variance32x32 avx2 neon/, "$sse2_x86inc", "$ssse3_x86inc"; add_proto qw/unsigned int vp9_sub_pixel_avg_variance32x32/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse, const uint8_t *second_pred"; -specialize qw/vp9_sub_pixel_avg_variance32x32/, "$sse2_x86inc", "$ssse3_x86inc"; +specialize qw/vp9_sub_pixel_avg_variance32x32 avx2/, "$sse2_x86inc", "$ssse3_x86inc"; add_proto qw/unsigned int vp9_sub_pixel_variance16x16/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse"; specialize qw/vp9_sub_pixel_variance16x16 neon/, "$sse2_x86inc", "$ssse3_x86inc"; @@ -653,7 +653,7 @@ add_proto qw/void vp9_sad4x4x8/, "const uint8_t *src_ptr, int src_stride, const specialize qw/vp9_sad4x4x8 sse4/; add_proto qw/void vp9_sad64x64x4d/, "const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, unsigned int *sad_array"; -specialize qw/vp9_sad64x64x4d sse2/; +specialize qw/vp9_sad64x64x4d sse2 avx2/; add_proto qw/void vp9_sad32x64x4d/, "const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, unsigned int *sad_array"; specialize qw/vp9_sad32x64x4d sse2/; @@ -668,7 +668,7 @@ add_proto qw/void vp9_sad16x32x4d/, "const uint8_t *src_ptr, int src_stride, co specialize qw/vp9_sad16x32x4d sse2/; add_proto qw/void vp9_sad32x32x4d/, "const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, unsigned int *sad_array"; -specialize qw/vp9_sad32x32x4d sse2/; +specialize qw/vp9_sad32x32x4d sse2 avx2/; add_proto qw/void vp9_sad16x16x4d/, "const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, unsigned int *sad_array"; specialize qw/vp9_sad16x16x4d sse2/; diff --git a/vp9/common/x86/vp9_postproc_x86.h b/vp9/common/x86/vp9_postproc_x86.h deleted file mode 100644 index cab9d34f2..000000000 --- a/vp9/common/x86/vp9_postproc_x86.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - -#ifndef VP9_COMMON_X86_VP9_POSTPROC_X86_H_ -#define VP9_COMMON_X86_VP9_POSTPROC_X86_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Note: - * - * This platform is commonly built for runtime CPU detection. If you modify - * any of the function mappings present in this file, be sure to also update - * them in the function pointer initialization code - */ - -#if HAVE_MMX -extern prototype_postproc_inplace(vp9_mbpost_proc_down_mmx); -extern prototype_postproc(vp9_post_proc_down_and_across_mmx); -extern prototype_postproc_addnoise(vp9_plane_add_noise_mmx); - -#if !CONFIG_RUNTIME_CPU_DETECT -#undef vp9_postproc_down -#define vp9_postproc_down vp9_mbpost_proc_down_mmx - -#undef vp9_postproc_downacross -#define vp9_postproc_downacross vp9_post_proc_down_and_across_mmx - -#undef vp9_postproc_addnoise -#define vp9_postproc_addnoise vp9_plane_add_noise_mmx - -#endif -#endif - - -#if HAVE_SSE2 -extern prototype_postproc_inplace(vp9_mbpost_proc_down_xmm); -extern prototype_postproc_inplace(vp9_mbpost_proc_across_ip_xmm); -extern prototype_postproc(vp9_post_proc_down_and_across_xmm); -extern prototype_postproc_addnoise(vp9_plane_add_noise_wmt); - -#if !CONFIG_RUNTIME_CPU_DETECT -#undef vp9_postproc_down -#define vp9_postproc_down vp9_mbpost_proc_down_xmm - -#undef vp9_postproc_across -#define vp9_postproc_across vp9_mbpost_proc_across_ip_xmm - -#undef vp9_postproc_downacross -#define vp9_postproc_downacross vp9_post_proc_down_and_across_xmm - -#undef vp9_postproc_addnoise -#define vp9_postproc_addnoise vp9_plane_add_noise_wmt - - -#endif -#endif - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // VP9_COMMON_X86_VP9_POSTPROC_X86_H_ diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c index a448bd2b4..07971687c 100644 --- a/vp9/decoder/vp9_decodeframe.c +++ b/vp9/decoder/vp9_decodeframe.c @@ -1095,6 +1095,40 @@ BITSTREAM_PROFILE vp9_read_profile(struct vp9_read_bit_buffer *rb) { return (BITSTREAM_PROFILE) profile; } +static void read_bitdepth_colorspace_sampling( + VP9_COMMON *cm, struct vp9_read_bit_buffer *rb) { + if (cm->profile >= PROFILE_2) + cm->bit_depth = vp9_rb_read_bit(rb) ? BITS_12 : BITS_10; + cm->color_space = (COLOR_SPACE)vp9_rb_read_literal(rb, 3); + if (cm->color_space != SRGB) { + vp9_rb_read_bit(rb); // [16,235] (including xvycc) vs [0,255] range + if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) { + cm->subsampling_x = vp9_rb_read_bit(rb); + cm->subsampling_y = vp9_rb_read_bit(rb); + if (cm->subsampling_x == 1 && cm->subsampling_y == 1) + vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, + "4:2:0 color not supported in profile 1 or 3"); + if (vp9_rb_read_bit(rb)) + vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, + "Reserved bit set"); + } else { + cm->subsampling_y = cm->subsampling_x = 1; + } + } else { + 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. + cm->subsampling_y = cm->subsampling_x = 0; + if (vp9_rb_read_bit(rb)) + vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, + "Reserved bit set"); + } else { + vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, + "4:4:4 color not supported in profile 0 or 2"); + } + } +} + static size_t read_uncompressed_header(VP9Decoder *pbi, struct vp9_read_bit_buffer *rb) { VP9_COMMON *const cm = &pbi->common; @@ -1137,32 +1171,8 @@ static size_t read_uncompressed_header(VP9Decoder *pbi, if (!vp9_read_sync_code(rb)) vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, "Invalid frame sync code"); - if (cm->profile > PROFILE_1) - cm->bit_depth = vp9_rb_read_bit(rb) ? BITS_12 : BITS_10; - cm->color_space = (COLOR_SPACE)vp9_rb_read_literal(rb, 3); - if (cm->color_space != SRGB) { - vp9_rb_read_bit(rb); // [16,235] (including xvycc) vs [0,255] range - if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) { - cm->subsampling_x = vp9_rb_read_bit(rb); - cm->subsampling_y = vp9_rb_read_bit(rb); - if (vp9_rb_read_bit(rb)) - vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, - "Reserved bit set"); - } else { - cm->subsampling_y = cm->subsampling_x = 1; - } - } else { - if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) { - cm->subsampling_y = cm->subsampling_x = 0; - if (vp9_rb_read_bit(rb)) - vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, - "Reserved bit set"); - } else { - vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, - "4:4:4 color not supported in profile 0"); - } - } + read_bitdepth_colorspace_sampling(cm, rb); pbi->refresh_frame_flags = (1 << REF_FRAMES) - 1; for (i = 0; i < REFS_PER_FRAME; ++i) { @@ -1181,15 +1191,18 @@ static size_t read_uncompressed_header(VP9Decoder *pbi, if (!vp9_read_sync_code(rb)) vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, "Invalid frame sync code"); + if (cm->profile > PROFILE_0) { + read_bitdepth_colorspace_sampling(cm, rb); + } else { + // NOTE: The intra-only frame header does not include the specification + // of either the color format or color sub-sampling in profile 0. VP9 + // specifies that the default color space should be YUV 4:2:0 in this + // case (normative). + cm->color_space = BT_601; + cm->subsampling_y = cm->subsampling_x = 1; + } pbi->refresh_frame_flags = vp9_rb_read_literal(rb, REF_FRAMES); - - // NOTE: The intra-only frame header does not include the specification of - // either the color format or color sub-sampling. VP9 specifies that the - // default color space should be YUV 4:2:0 in this case (normative). - cm->color_space = BT_601; - cm->subsampling_y = cm->subsampling_x = 1; - setup_frame_size(cm, rb); } else { pbi->refresh_frame_flags = vp9_rb_read_literal(rb, REF_FRAMES); @@ -1220,11 +1233,9 @@ static size_t read_uncompressed_header(VP9Decoder *pbi, } if (!cm->error_resilient_mode) { - cm->coding_use_prev_mi = 1; cm->refresh_frame_context = vp9_rb_read_bit(rb); cm->frame_parallel_decoding_mode = vp9_rb_read_bit(rb); } else { - cm->coding_use_prev_mi = 0; cm->refresh_frame_context = 0; cm->frame_parallel_decoding_mode = 1; } @@ -1400,7 +1411,7 @@ void vp9_decode_frame(VP9Decoder *pbi, init_macroblockd(cm, &pbi->mb); - if (cm->coding_use_prev_mi) + if (!cm->error_resilient_mode) set_prev_mi(cm); else cm->prev_mi = NULL; diff --git a/vp9/decoder/vp9_decoder.c b/vp9/decoder/vp9_decoder.c index 0343c214c..2a2f0f5fa 100644 --- a/vp9/decoder/vp9_decoder.c +++ b/vp9/decoder/vp9_decoder.c @@ -181,17 +181,6 @@ vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm, return cm->error.error_code; } - -int vp9_get_reference_dec(VP9Decoder *pbi, int index, YV12_BUFFER_CONFIG **fb) { - VP9_COMMON *cm = &pbi->common; - - if (index < 0 || index >= REF_FRAMES) - return -1; - - *fb = &cm->frame_bufs[cm->ref_frame_map[index]].buf; - return 0; -} - /* If any buffer updating is signaled it should be done here. */ static void swap_frame_buffers(VP9Decoder *pbi) { int ref_index = 0, mask; diff --git a/vp9/decoder/vp9_decoder.h b/vp9/decoder/vp9_decoder.h index 8e16e1cac..223b66fc7 100644 --- a/vp9/decoder/vp9_decoder.h +++ b/vp9/decoder/vp9_decoder.h @@ -74,9 +74,6 @@ vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm, VP9_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd); -int vp9_get_reference_dec(struct VP9Decoder *pbi, - int index, YV12_BUFFER_CONFIG **fb); - struct VP9Decoder *vp9_decoder_create(); void vp9_decoder_remove(struct VP9Decoder *pbi); diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 841b46521..d638a2146 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -78,13 +78,13 @@ static void prob_diff_update(const vp9_tree_index *tree, vp9_cond_prob_diff_update(w, &probs[i], branch_ct[i]); } -static void write_selected_tx_size(const VP9_COMP *cpi, +static void write_selected_tx_size(const VP9_COMMON *cm, + const MACROBLOCKD *xd, TX_SIZE tx_size, BLOCK_SIZE bsize, vp9_writer *w) { const TX_SIZE max_tx_size = max_txsize_lookup[bsize]; - const MACROBLOCKD *const xd = &cpi->mb.e_mbd; const vp9_prob *const tx_probs = get_tx_probs2(max_tx_size, xd, - &cpi->common.fc.tx_probs); + &cm->fc.tx_probs); vp9_write(w, tx_size != TX_4X4, tx_probs[0]); if (tx_size != TX_4X4 && max_tx_size >= TX_16X16) { vp9_write(w, tx_size != TX_8X8, tx_probs[1]); @@ -93,14 +93,13 @@ static void write_selected_tx_size(const VP9_COMP *cpi, } } -static int write_skip(const VP9_COMP *cpi, int segment_id, const MODE_INFO *mi, - vp9_writer *w) { - const MACROBLOCKD *const xd = &cpi->mb.e_mbd; - if (vp9_segfeature_active(&cpi->common.seg, segment_id, SEG_LVL_SKIP)) { +static int write_skip(const VP9_COMMON *cm, const MACROBLOCKD *xd, + int segment_id, const MODE_INFO *mi, vp9_writer *w) { + if (vp9_segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP)) { return 1; } else { const int skip = mi->mbmi.skip; - vp9_write(w, skip, vp9_get_skip_prob(&cpi->common, xd)); + vp9_write(w, skip, vp9_get_skip_prob(cm, xd)); return skip; } } @@ -121,7 +120,7 @@ static void update_switchable_interp_probs(VP9_COMMON *cm, vp9_writer *w) { } static void pack_mb_tokens(vp9_writer *w, - TOKENEXTRA **tp, const TOKENEXTRA *stop) { + TOKENEXTRA **tp, const TOKENEXTRA *const stop) { TOKENEXTRA *p = *tp; while (p < stop && p->token != EOSB_TOKEN) { @@ -188,9 +187,8 @@ static void write_segment_id(vp9_writer *w, const struct segmentation *seg, } // This function encodes the reference frame -static void write_ref_frames(const VP9_COMP *cpi, vp9_writer *w) { - const VP9_COMMON *const cm = &cpi->common; - const MACROBLOCKD *const xd = &cpi->mb.e_mbd; +static void write_ref_frames(const VP9_COMMON *cm, const MACROBLOCKD *xd, + vp9_writer *w) { const MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi; const int is_compound = has_second_ref(mbmi); const int segment_id = mbmi->segment_id; @@ -252,7 +250,7 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi, } } - skip = write_skip(cpi, segment_id, mi, w); + skip = write_skip(cm, xd, segment_id, mi, w); if (!vp9_segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME)) vp9_write(w, is_inter, vp9_get_intra_inter_prob(cm, xd)); @@ -260,7 +258,7 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi, if (bsize >= BLOCK_8X8 && cm->tx_mode == TX_MODE_SELECT && !(is_inter && (skip || vp9_segfeature_active(seg, segment_id, SEG_LVL_SKIP)))) { - write_selected_tx_size(cpi, mbmi->tx_size, bsize, w); + write_selected_tx_size(cm, xd, mbmi->tx_size, bsize, w); } if (!is_inter) { @@ -281,7 +279,7 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi, } else { const int mode_ctx = mbmi->mode_context[mbmi->ref_frame[0]]; const vp9_prob *const inter_probs = cm->fc.inter_mode_probs[mode_ctx]; - write_ref_frames(cpi, w); + write_ref_frames(cm, xd, w); // If segment skip is not enabled code the mode. if (!vp9_segfeature_active(seg, segment_id, SEG_LVL_SKIP)) { @@ -329,10 +327,8 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi, } } -static void write_mb_modes_kf(const VP9_COMP *cpi, MODE_INFO **mi_8x8, - vp9_writer *w) { - const VP9_COMMON *const cm = &cpi->common; - const MACROBLOCKD *const xd = &cpi->mb.e_mbd; +static void write_mb_modes_kf(const VP9_COMMON *cm, const MACROBLOCKD *xd, + MODE_INFO **mi_8x8, vp9_writer *w) { const struct segmentation *const seg = &cm->seg; const MODE_INFO *const mi = mi_8x8[0]; const MODE_INFO *const above_mi = mi_8x8[-xd->mi_stride]; @@ -343,10 +339,10 @@ static void write_mb_modes_kf(const VP9_COMP *cpi, MODE_INFO **mi_8x8, if (seg->update_map) write_segment_id(w, seg, mbmi->segment_id); - write_skip(cpi, mbmi->segment_id, mi, w); + write_skip(cm, xd, mbmi->segment_id, mi, w); if (bsize >= BLOCK_8X8 && cm->tx_mode == TX_MODE_SELECT) - write_selected_tx_size(cpi, mbmi->tx_size, bsize, w); + write_selected_tx_size(cm, xd, mbmi->tx_size, bsize, w); if (bsize >= BLOCK_8X8) { write_intra_mode(w, mbmi->mode, get_y_mode_probs(mi, above_mi, left_mi, 0)); @@ -368,9 +364,10 @@ static void write_mb_modes_kf(const VP9_COMP *cpi, MODE_INFO **mi_8x8, } static void write_modes_b(VP9_COMP *cpi, const TileInfo *const tile, - vp9_writer *w, TOKENEXTRA **tok, TOKENEXTRA *tok_end, + vp9_writer *w, TOKENEXTRA **tok, + const TOKENEXTRA *const tok_end, int mi_row, int mi_col) { - VP9_COMMON *const cm = &cpi->common; + const VP9_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &cpi->mb.e_mbd; MODE_INFO *m; @@ -382,7 +379,7 @@ static void write_modes_b(VP9_COMP *cpi, const TileInfo *const tile, mi_col, num_8x8_blocks_wide_lookup[m->mbmi.sb_type], cm->mi_rows, cm->mi_cols); if (frame_is_intra_only(cm)) { - write_mb_modes_kf(cpi, xd->mi, w); + write_mb_modes_kf(cm, xd, xd->mi, w); } else { pack_inter_mode_mvs(cpi, m, w); } @@ -391,7 +388,8 @@ static void write_modes_b(VP9_COMP *cpi, const TileInfo *const tile, pack_mb_tokens(w, tok, tok_end); } -static void write_partition(VP9_COMMON *cm, MACROBLOCKD *xd, +static void write_partition(const VP9_COMMON *const cm, + const MACROBLOCKD *const xd, int hbs, int mi_row, int mi_col, PARTITION_TYPE p, BLOCK_SIZE bsize, vp9_writer *w) { const int ctx = partition_plane_context(xd, mi_row, mi_col, bsize); @@ -413,17 +411,17 @@ static void write_partition(VP9_COMMON *cm, MACROBLOCKD *xd, } static void write_modes_sb(VP9_COMP *cpi, - const TileInfo *const tile, - vp9_writer *w, TOKENEXTRA **tok, TOKENEXTRA *tok_end, + const TileInfo *const tile, vp9_writer *w, + TOKENEXTRA **tok, const TOKENEXTRA *const tok_end, int mi_row, int mi_col, BLOCK_SIZE bsize) { - VP9_COMMON *const cm = &cpi->common; + const VP9_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &cpi->mb.e_mbd; const int bsl = b_width_log2(bsize); const int bs = (1 << bsl) / 4; PARTITION_TYPE partition; BLOCK_SIZE subsize; - MODE_INFO *m = cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col]; + const MODE_INFO *m = cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col]; if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; @@ -469,8 +467,8 @@ static void write_modes_sb(VP9_COMP *cpi, } static void write_modes(VP9_COMP *cpi, - const TileInfo *const tile, - vp9_writer *w, TOKENEXTRA **tok, TOKENEXTRA *tok_end) { + const TileInfo *const tile, vp9_writer *w, + TOKENEXTRA **tok, const TOKENEXTRA *const tok_end) { int mi_row, mi_col; for (mi_row = tile->mi_row_start; mi_row < tile->mi_row_end; @@ -731,7 +729,7 @@ static void write_delta_q(struct vp9_write_bit_buffer *wb, int delta_q) { } } -static void encode_quantization(VP9_COMMON *cm, +static void encode_quantization(const VP9_COMMON *const cm, struct vp9_write_bit_buffer *wb) { vp9_wb_write_literal(wb, cm->base_qindex, QINDEX_BITS); write_delta_q(wb, cm->y_dc_delta_q); @@ -739,11 +737,11 @@ static void encode_quantization(VP9_COMMON *cm, write_delta_q(wb, cm->uv_ac_delta_q); } -static void encode_segmentation(VP9_COMP *cpi, +static void encode_segmentation(VP9_COMMON *cm, MACROBLOCKD *xd, struct vp9_write_bit_buffer *wb) { int i, j; - struct segmentation *seg = &cpi->common.seg; + const struct segmentation *seg = &cm->seg; vp9_wb_write_bit(wb, seg->enabled); if (!seg->enabled) @@ -753,7 +751,7 @@ static void encode_segmentation(VP9_COMP *cpi, vp9_wb_write_bit(wb, seg->update_map); if (seg->update_map) { // Select the coding strategy (temporal or spatial) - vp9_choose_segmap_coding_method(cpi); + vp9_choose_segmap_coding_method(cm, xd); // Write out probabilities used to decode unpredicted macro-block segments for (i = 0; i < SEG_TREE_PROBS; i++) { const int prob = seg->tree_probs[i]; @@ -869,7 +867,8 @@ static void fix_interp_filter(VP9_COMMON *cm) { } } -static void write_tile_info(VP9_COMMON *cm, struct vp9_write_bit_buffer *wb) { +static void write_tile_info(const VP9_COMMON *const cm, + struct vp9_write_bit_buffer *wb) { int min_log2_tile_cols, max_log2_tile_cols, ones; vp9_get_tile_n_bits(cm->mi_cols, &min_log2_tile_cols, &max_log2_tile_cols); @@ -888,21 +887,22 @@ static void write_tile_info(VP9_COMMON *cm, struct vp9_write_bit_buffer *wb) { } static int get_refresh_mask(VP9_COMP *cpi) { - if (!cpi->multi_arf_allowed && cpi->refresh_golden_frame && - cpi->rc.is_src_frame_alt_ref && !cpi->use_svc) { - // Preserve the previously existing golden frame and update the frame in - // the alt ref slot instead. This is highly specific to the use of - // alt-ref as a forward reference, and this needs to be generalized as - // other uses are implemented (like RTC/temporal scaling) - // - // gld_fb_idx and alt_fb_idx need to be swapped for future frames, but - // that happens in vp9_encoder.c:update_reference_frames() so that it can - // be done outside of the recode loop. + if (vp9_preserve_existing_gf(cpi)) { + // We have decided to preserve the previously existing golden frame as our + // new ARF frame. However, in the short term we leave it in the GF slot and, + // if we're updating the GF with the current decoded frame, we save it + // instead to the ARF slot. + // Later, in the function vp9_encoder.c:vp9_update_reference_frames() we + // will swap gld_fb_idx and alt_fb_idx to achieve our objective. We do it + // there so that it can be done outside of the recode loop. + // Note: This is highly specific to the use of ARF as a forward reference, + // and this needs to be generalized as other uses are implemented + // (like RTC/temporal scalability). return (cpi->refresh_last_frame << cpi->lst_fb_idx) | (cpi->refresh_golden_frame << cpi->alt_fb_idx); } else { int arf_idx = cpi->alt_fb_idx; - if ((cpi->pass == 2) && cpi->multi_arf_allowed) { + if ((cpi->oxcf.pass == 2) && cpi->multi_arf_allowed) { const GF_GROUP *const gf_group = &cpi->twopass.gf_group; arf_idx = gf_group->arf_update_idx[gf_group->index]; } @@ -1040,6 +1040,29 @@ static void write_profile(BITSTREAM_PROFILE profile, } } +static void write_bitdepth_colorspace_sampling( + VP9_COMMON *const cm, struct vp9_write_bit_buffer *wb) { + if (cm->profile >= PROFILE_2) { + assert(cm->bit_depth > BITS_8); + vp9_wb_write_bit(wb, cm->bit_depth - BITS_10); + } + vp9_wb_write_literal(wb, cm->color_space, 3); + if (cm->color_space != SRGB) { + vp9_wb_write_bit(wb, 0); // 0: [16, 235] (i.e. xvYCC), 1: [0, 255] + if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) { + assert(cm->subsampling_x != 1 || cm->subsampling_y != 1); + vp9_wb_write_bit(wb, cm->subsampling_x); + vp9_wb_write_bit(wb, cm->subsampling_y); + vp9_wb_write_bit(wb, 0); // unused + } else { + assert(cm->subsampling_x == 1 && cm->subsampling_y == 1); + } + } else { + assert(cm->profile == PROFILE_1 || cm->profile == PROFILE_3); + vp9_wb_write_bit(wb, 0); // unused + } +} + static void write_uncompressed_header(VP9_COMP *cpi, struct vp9_write_bit_buffer *wb) { VP9_COMMON *const cm = &cpi->common; @@ -1054,25 +1077,8 @@ static void write_uncompressed_header(VP9_COMP *cpi, vp9_wb_write_bit(wb, cm->error_resilient_mode); if (cm->frame_type == KEY_FRAME) { - const COLOR_SPACE cs = UNKNOWN; write_sync_code(wb); - if (cm->profile > PROFILE_1) { - assert(cm->bit_depth > BITS_8); - vp9_wb_write_bit(wb, cm->bit_depth - BITS_10); - } - vp9_wb_write_literal(wb, cs, 3); - if (cs != SRGB) { - vp9_wb_write_bit(wb, 0); // 0: [16, 235] (i.e. xvYCC), 1: [0, 255] - if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) { - vp9_wb_write_bit(wb, cm->subsampling_x); - vp9_wb_write_bit(wb, cm->subsampling_y); - vp9_wb_write_bit(wb, 0); // unused - } - } else { - assert(cm->profile == PROFILE_1 || cm->profile == PROFILE_3); - vp9_wb_write_bit(wb, 0); // unused - } - + write_bitdepth_colorspace_sampling(cm, wb); write_frame_size(cm, wb); } else { if (!cm->show_frame) @@ -1084,6 +1090,11 @@ static void write_uncompressed_header(VP9_COMP *cpi, if (cm->intra_only) { write_sync_code(wb); + // Note for profile 0, 420 8bpp is assumed. + if (cm->profile > PROFILE_0) { + write_bitdepth_colorspace_sampling(cm, wb); + } + vp9_wb_write_literal(wb, get_refresh_mask(cpi), REF_FRAMES); write_frame_size(cm, wb); } else { @@ -1113,7 +1124,7 @@ static void write_uncompressed_header(VP9_COMP *cpi, encode_loopfilter(&cm->lf, wb); encode_quantization(cm, wb); - encode_segmentation(cpi, wb); + encode_segmentation(cm, &cpi->mb.e_mbd, wb); write_tile_info(cm, wb); } @@ -1208,8 +1219,6 @@ void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, size_t *size) { uncompressed_hdr_size = vp9_rb_bytes_written(&wb); data += uncompressed_hdr_size; - vp9_compute_update_table(); - vp9_clear_system_state(); first_part_size = write_compressed_header(cpi, data); diff --git a/vp9/encoder/vp9_bitstream.h b/vp9/encoder/vp9_bitstream.h index ddfd0ed4f..8e82d1c97 100644 --- a/vp9/encoder/vp9_bitstream.h +++ b/vp9/encoder/vp9_bitstream.h @@ -16,11 +16,21 @@ extern "C" { #endif -struct VP9_COMP; +#include "vp9/encoder/vp9_encoder.h" void vp9_entropy_mode_init(); -void vp9_pack_bitstream(struct VP9_COMP *cpi, uint8_t *dest, size_t *size); +void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, size_t *size); + +static INLINE int vp9_preserve_existing_gf(VP9_COMP *cpi) { + return !cpi->multi_arf_allowed && cpi->refresh_golden_frame && + cpi->rc.is_src_frame_alt_ref && + (!cpi->use_svc || // Add spatial svc base layer case here + (is_spatial_svc(cpi) && + cpi->svc.spatial_layer_id == 0 && + cpi->svc.layer_context[0].gold_ref_idx >=0 && + cpi->oxcf.ss_play_alternate[0])); +} #ifdef __cplusplus } // extern "C" diff --git a/vp9/encoder/vp9_block.h b/vp9/encoder/vp9_block.h index 39dfb7e1d..2c7739115 100644 --- a/vp9/encoder/vp9_block.h +++ b/vp9/encoder/vp9_block.h @@ -66,7 +66,7 @@ struct macroblock { int sadperbit4; int rddiv; int rdmult; - unsigned int mb_energy; + int mb_energy; int mv_best_ref_index[MAX_REF_FRAMES]; unsigned int max_mv_context[MAX_REF_FRAMES]; diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 1fcd1e91e..d83a9ed04 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -188,11 +188,9 @@ static void set_offsets(VP9_COMP *cpi, const TileInfo *const tile, } } -static void duplicate_mode_info_in_sb(VP9_COMMON * const cm, - MACROBLOCKD *const xd, - int mi_row, - int mi_col, - BLOCK_SIZE bsize) { +static void duplicate_mode_info_in_sb(VP9_COMMON *cm, MACROBLOCKD *xd, + int mi_row, int mi_col, + BLOCK_SIZE bsize) { const int block_width = num_8x8_blocks_wide_lookup[bsize]; const int block_height = num_8x8_blocks_high_lookup[bsize]; int i, j; @@ -293,6 +291,7 @@ static void tree_to_node(void *data, BLOCK_SIZE bsize, variance_node *node) { } default: { assert(0); + break; } } } @@ -798,9 +797,7 @@ static void rd_pick_sb_modes(VP9_COMP *cpi, const TileInfo *const tile, } } -static void update_stats(VP9_COMP *cpi) { - VP9_COMMON *const cm = &cpi->common; - const MACROBLOCK *const x = &cpi->mb; +static void update_stats(VP9_COMMON *cm, const MACROBLOCK *x) { const MACROBLOCKD *const xd = &x->e_mbd; const MODE_INFO *const mi = xd->mi[0]; const MB_MODE_INFO *const mbmi = &mi->mbmi; @@ -912,7 +909,7 @@ static void encode_b(VP9_COMP *cpi, const TileInfo *const tile, encode_superblock(cpi, tp, output_enabled, mi_row, mi_col, bsize, ctx); if (output_enabled) { - update_stats(cpi); + update_stats(&cpi->common, &cpi->mb); (*tp)->token = EOSB_TOKEN; (*tp)++; @@ -985,6 +982,7 @@ static void encode_sb(VP9_COMP *cpi, const TileInfo *const tile, break; default: assert("Invalid partition type."); + break; } if (partition != PARTITION_SPLIT || bsize == BLOCK_8X8) @@ -1328,8 +1326,6 @@ static void encode_b_rt(VP9_COMP *cpi, const TileInfo *const tile, TOKENEXTRA **tp, int mi_row, int mi_col, int output_enabled, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx) { - - set_offsets(cpi, tile, mi_row, mi_col, bsize); update_state_rt(cpi, ctx, mi_row, mi_col, bsize); @@ -1341,7 +1337,7 @@ static void encode_b_rt(VP9_COMP *cpi, const TileInfo *const tile, #endif encode_superblock(cpi, tp, output_enabled, mi_row, mi_col, bsize, ctx); - update_stats(cpi); + update_stats(&cpi->common, &cpi->mb); (*tp)->token = EOSB_TOKEN; (*tp)++; @@ -1364,7 +1360,6 @@ static void encode_sb_rt(VP9_COMP *cpi, const TileInfo *const tile, return; if (bsize >= BLOCK_8X8) { - MACROBLOCKD *const xd = &cpi->mb.e_mbd; const int idx_str = xd->mi_stride * mi_row + mi_col; MODE_INFO ** mi_8x8 = cm->mi_grid_visible + idx_str; ctx = partition_plane_context(xd, mi_row, mi_col, bsize); @@ -1412,6 +1407,7 @@ static void encode_sb_rt(VP9_COMP *cpi, const TileInfo *const tile, break; default: assert("Invalid partition type."); + break; } if (partition != PARTITION_SPLIT || bsize == BLOCK_8X8) @@ -1590,6 +1586,7 @@ static void rd_use_partition(VP9_COMP *cpi, break; default: assert(0); + break; } pl = partition_plane_context(xd, mi_row, mi_col, bsize); @@ -1725,10 +1722,9 @@ static const BLOCK_SIZE max_partition_size[BLOCK_SIZES] = { // // The min and max are assumed to have been initialized prior to calling this // function so repeat calls can accumulate a min and max of more than one sb64. -static void get_sb_partition_size_range(VP9_COMP *cpi, MODE_INFO ** mi_8x8, - BLOCK_SIZE * min_block_size, - BLOCK_SIZE * max_block_size ) { - MACROBLOCKD *const xd = &cpi->mb.e_mbd; +static void get_sb_partition_size_range(MACROBLOCKD *xd, MODE_INFO **mi_8x8, + BLOCK_SIZE *min_block_size, + BLOCK_SIZE *max_block_size ) { int sb_width_in_blocks = MI_BLOCK_SIZE; int sb_height_in_blocks = MI_BLOCK_SIZE; int i, j; @@ -1783,17 +1779,17 @@ static void rd_auto_partition_range(VP9_COMP *cpi, const TileInfo *const tile, if (cm->frame_type != KEY_FRAME) { MODE_INFO **const prev_mi = &cm->prev_mi_grid_visible[mi_row * xd->mi_stride + mi_col]; - get_sb_partition_size_range(cpi, prev_mi, &min_size, &max_size); + get_sb_partition_size_range(xd, prev_mi, &min_size, &max_size); } // Find the min and max partition sizes used in the left SB64 if (left_in_image) { MODE_INFO **left_sb64_mi = &mi[-MI_BLOCK_SIZE]; - get_sb_partition_size_range(cpi, left_sb64_mi, &min_size, &max_size); + get_sb_partition_size_range(xd, left_sb64_mi, &min_size, &max_size); } // Find the min and max partition sizes used in the above SB64. if (above_in_image) { MODE_INFO **above_sb64_mi = &mi[-xd->mi_stride * MI_BLOCK_SIZE]; - get_sb_partition_size_range(cpi, above_sb64_mi, &min_size, &max_size); + get_sb_partition_size_range(xd, above_sb64_mi, &min_size, &max_size); } // adjust observed min and max if (cpi->sf.auto_min_max_partition_size == RELAXED_NEIGHBORING_MIN_MAX) { @@ -1949,6 +1945,42 @@ const int num_16x16_blocks_high_lookup[BLOCK_SIZES] = {1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 4, 2, 4}; const int qindex_skip_threshold_lookup[BLOCK_SIZES] = {0, 10, 10, 30, 40, 40, 60, 80, 80, 90, 100, 100, 120}; +const int qindex_split_threshold_lookup[BLOCK_SIZES] = + {0, 3, 3, 7, 15, 15, 30, 40, 40, 60, 80, 80, 120}; +const int complexity_16x16_blocks_threshold[BLOCK_SIZES] = + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 6}; + +typedef enum { + MV_ZERO = 0, + MV_LEFT = 1, + MV_UP = 2, + MV_RIGHT = 3, + MV_DOWN = 4, + MV_INVALID +} MOTION_DIRECTION; + +static INLINE MOTION_DIRECTION get_motion_direction_fp(uint8_t fp_byte) { + if (fp_byte & FPMB_MOTION_ZERO_MASK) { + return MV_ZERO; + } else if (fp_byte & FPMB_MOTION_LEFT_MASK) { + return MV_LEFT; + } else if (fp_byte & FPMB_MOTION_RIGHT_MASK) { + return MV_RIGHT; + } else if (fp_byte & FPMB_MOTION_UP_MASK) { + return MV_UP; + } else { + return MV_DOWN; + } +} + +static INLINE int get_motion_inconsistency(MOTION_DIRECTION this_mv, + MOTION_DIRECTION that_mv) { + if (this_mv == that_mv) { + return 0; + } else { + return abs(this_mv - that_mv) == 2 ? 2 : 1; + } +} #endif // TODO(jingning,jimbankoski,rbultje): properly skip partition types that are @@ -1974,6 +2006,7 @@ static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, int64_t sum_rd = 0; int do_split = bsize >= BLOCK_8X8; int do_rect = 1; + // Override skipping rectangular partition operations for edge blocks const int force_horz_split = (mi_row + mi_step >= cm->mi_rows); const int force_vert_split = (mi_col + mi_step >= cm->mi_cols); @@ -1983,6 +2016,11 @@ static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, BLOCK_SIZE min_size = cpi->sf.min_partition_size; BLOCK_SIZE max_size = cpi->sf.max_partition_size; +#if CONFIG_FP_MB_STATS + unsigned int src_diff_var = UINT_MAX; + int none_complexity = 0; +#endif + int partition_none_allowed = !force_horz_split && !force_vert_split; int partition_horz_allowed = !force_vert_split && yss <= xss && bsize >= BLOCK_8X8; @@ -2034,6 +2072,65 @@ static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, } } +#if CONFIG_FP_MB_STATS + if (cpi->use_fp_mb_stats) { + set_offsets(cpi, tile, mi_row, mi_col, bsize); + src_diff_var = get_sby_perpixel_diff_variance(cpi, &cpi->mb.plane[0].src, + mi_row, mi_col, bsize); + } +#endif + +#if CONFIG_FP_MB_STATS + // Decide whether we shall split directly and skip searching NONE by using + // the first pass block statistics + if (cpi->use_fp_mb_stats && bsize >= BLOCK_32X32 && do_split && + partition_none_allowed && src_diff_var > 4 && + cm->base_qindex < qindex_split_threshold_lookup[bsize]) { + int mb_row = mi_row >> 1; + int mb_col = mi_col >> 1; + int mb_row_end = + MIN(mb_row + num_16x16_blocks_high_lookup[bsize], cm->mb_rows); + int mb_col_end = + MIN(mb_col + num_16x16_blocks_wide_lookup[bsize], cm->mb_cols); + int r, c; + + // compute a complexity measure, basically measure inconsistency of motion + // vectors obtained from the first pass in the current block + for (r = mb_row; r < mb_row_end ; r++) { + for (c = mb_col; c < mb_col_end; c++) { + const int mb_index = r * cm->mb_cols + c; + + MOTION_DIRECTION this_mv; + MOTION_DIRECTION right_mv; + MOTION_DIRECTION bottom_mv; + + this_mv = + get_motion_direction_fp(cpi->twopass.this_frame_mb_stats[mb_index]); + + // to its right + if (c != mb_col_end - 1) { + right_mv = get_motion_direction_fp( + cpi->twopass.this_frame_mb_stats[mb_index + 1]); + none_complexity += get_motion_inconsistency(this_mv, right_mv); + } + + // to its bottom + if (r != mb_row_end - 1) { + bottom_mv = get_motion_direction_fp( + cpi->twopass.this_frame_mb_stats[mb_index + cm->mb_cols]); + none_complexity += get_motion_inconsistency(this_mv, bottom_mv); + } + + // do not count its left and top neighbors to avoid double counting + } + } + + if (none_complexity > complexity_16x16_blocks_threshold[bsize]) { + partition_none_allowed = 0; + } + } +#endif + // PARTITION_NONE if (partition_none_allowed) { rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &this_rate, &this_dist, bsize, @@ -2044,6 +2141,7 @@ static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, this_rate += cpi->partition_cost[pl][PARTITION_NONE]; } sum_rd = RDCOST(x->rdmult, x->rddiv, this_rate, this_dist); + if (sum_rd < best_rd) { int64_t stop_thresh = 4096; int64_t stop_thresh_rd; @@ -2074,7 +2172,6 @@ static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, // stop further splitting in RD optimization if (cpi->use_fp_mb_stats && do_split != 0 && cm->base_qindex > qindex_skip_threshold_lookup[bsize]) { - VP9_COMMON *cm = &cpi->common; int mb_row = mi_row >> 1; int mb_col = mi_col >> 1; int mb_row_end = @@ -2087,10 +2184,10 @@ static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, for (r = mb_row; r < mb_row_end; r++) { for (c = mb_col; c < mb_col_end; c++) { const int mb_index = r * cm->mb_cols + c; - if ((cpi->twopass.this_frame_mb_stats[mb_index] & - FPMB_NONZERO_MOTION_MASK) || + if (!(cpi->twopass.this_frame_mb_stats[mb_index] & + FPMB_MOTION_ZERO_MASK) || !(cpi->twopass.this_frame_mb_stats[mb_index] & - FPMB_ERROR_LEVEL0_MASK)) { + FPMB_ERROR_SMALL_MASK)) { skip = 0; break; } @@ -2100,11 +2197,12 @@ static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, } } if (skip) { - unsigned int var; - set_offsets(cpi, tile, mi_row, mi_col, bsize); - var = get_sby_perpixel_diff_variance(cpi, &cpi->mb.plane[0].src, - mi_row, mi_col, bsize); - if (var < 8) { + if (src_diff_var == UINT_MAX) { + set_offsets(cpi, tile, mi_row, mi_col, bsize); + src_diff_var = get_sby_perpixel_diff_variance( + cpi, &cpi->mb.plane[0].src, mi_row, mi_col, bsize); + } + if (src_diff_var < 8) { do_split = 0; do_rect = 0; } @@ -2167,6 +2265,7 @@ static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, pl = partition_plane_context(xd, mi_row, mi_col, bsize); sum_rate += cpi->partition_cost[pl][PARTITION_SPLIT]; sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist); + if (sum_rd < best_rd) { best_rate = sum_rate; best_dist = sum_dist; @@ -2279,6 +2378,7 @@ static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, } restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize); } + // TODO(jbb): This code added so that we avoid static analysis // warning related to the fact that best_rd isn't used after this // point. This code should be refactored so that the duplicate @@ -2376,7 +2476,7 @@ static void encode_rd_sb_row(VP9_COMP *cpi, const TileInfo *const tile, } else { GF_GROUP * gf_grp = &cpi->twopass.gf_group; int last_was_mid_sequence_overlay = 0; - if ((cpi->pass == 2) && (gf_grp->index)) { + if ((cpi->oxcf.pass == 2) && (gf_grp->index)) { if (gf_grp->update_type[gf_grp->index - 1] == OVERLAY_UPDATE) last_was_mid_sequence_overlay = 1; } @@ -2598,6 +2698,8 @@ static void nonrd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, int mi_col, BLOCK_SIZE bsize, int *rate, int64_t *dist, int do_recon, int64_t best_rd, PC_TREE *pc_tree) { + const SPEED_FEATURES *const sf = &cpi->sf; + const VP9EncoderConfig *const oxcf = &cpi->oxcf; VP9_COMMON *const cm = &cpi->common; MACROBLOCK *const x = &cpi->mb; MACROBLOCKD *const xd = &x->e_mbd; @@ -2629,18 +2731,18 @@ static void nonrd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, // Determine partition types in search according to the speed features. // The threshold set here has to be of square block size. - if (cpi->sf.auto_min_max_partition_size) { - partition_none_allowed &= (bsize <= cpi->sf.max_partition_size && - bsize >= cpi->sf.min_partition_size); - partition_horz_allowed &= ((bsize <= cpi->sf.max_partition_size && - bsize > cpi->sf.min_partition_size) || + if (sf->auto_min_max_partition_size) { + partition_none_allowed &= (bsize <= sf->max_partition_size && + bsize >= sf->min_partition_size); + partition_horz_allowed &= ((bsize <= sf->max_partition_size && + bsize > sf->min_partition_size) || force_horz_split); - partition_vert_allowed &= ((bsize <= cpi->sf.max_partition_size && - bsize > cpi->sf.min_partition_size) || + partition_vert_allowed &= ((bsize <= sf->max_partition_size && + bsize > sf->min_partition_size) || force_vert_split); - do_split &= bsize > cpi->sf.min_partition_size; + do_split &= bsize > sf->min_partition_size; } - if (cpi->sf.use_square_partition_only) { + if (sf->use_square_partition_only) { partition_horz_allowed &= force_horz_split; partition_vert_allowed &= force_vert_split; } @@ -2719,7 +2821,7 @@ static void nonrd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, } else { // skip rectangular partition test when larger block size // gives better rd cost - if (cpi->sf.less_rectangular_check) + if (sf->less_rectangular_check) do_rect &= !partition_none_allowed; } } @@ -2727,7 +2829,7 @@ static void nonrd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, // PARTITION_HORZ if (partition_horz_allowed && do_rect) { subsize = get_subsize(bsize, PARTITION_HORZ); - if (cpi->sf.adaptive_motion_search) + if (sf->adaptive_motion_search) load_pred_mv(x, ctx); nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col, @@ -2772,7 +2874,7 @@ static void nonrd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, if (partition_vert_allowed && do_rect) { subsize = get_subsize(bsize, PARTITION_VERT); - if (cpi->sf.adaptive_motion_search) + if (sf->adaptive_motion_search) load_pred_mv(x, ctx); nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col, @@ -2829,12 +2931,12 @@ static void nonrd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, // Check the projected output rate for this SB against it's target // and and if necessary apply a Q delta using segmentation to get // closer to the target. - if ((cpi->oxcf.aq_mode == COMPLEXITY_AQ) && cm->seg.update_map) { + if ((oxcf->aq_mode == COMPLEXITY_AQ) && cm->seg.update_map) { vp9_select_in_frame_q_segment(cpi, mi_row, mi_col, output_enabled, best_rate); } - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) + if (oxcf->aq_mode == CYCLIC_REFRESH_AQ) vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh, best_rate, best_dist); @@ -2952,6 +3054,7 @@ static void nonrd_use_partition(VP9_COMP *cpi, break; default: assert("Invalid partition type."); + break; } if (bsize == BLOCK_64X64 && output_enabled) { @@ -2964,9 +3067,10 @@ static void nonrd_use_partition(VP9_COMP *cpi, static void encode_nonrd_sb_row(VP9_COMP *cpi, const TileInfo *const tile, int mi_row, TOKENEXTRA **tp) { - VP9_COMMON *cm = &cpi->common; - MACROBLOCK *x = &cpi->mb; - MACROBLOCKD *xd = &x->e_mbd; + SPEED_FEATURES *const sf = &cpi->sf; + VP9_COMMON *const cm = &cpi->common; + MACROBLOCK *const x = &cpi->mb; + MACROBLOCKD *const xd = &x->e_mbd; int mi_col; // Initialize the left context for the new SB row @@ -2976,7 +3080,6 @@ static void encode_nonrd_sb_row(VP9_COMP *cpi, const TileInfo *const tile, // Code each SB in the row for (mi_col = tile->mi_col_start; mi_col < tile->mi_col_end; mi_col += MI_BLOCK_SIZE) { - MACROBLOCK *x = &cpi->mb; int dummy_rate = 0; int64_t dummy_dist = 0; const int idx_str = cm->mi_stride * mi_row + mi_col; @@ -2989,7 +3092,7 @@ static void encode_nonrd_sb_row(VP9_COMP *cpi, const TileInfo *const tile, vp9_zero(x->pred_mv); // Set the partition type of the 64X64 block - switch (cpi->sf.partition_search_type) { + switch (sf->partition_search_type) { case VAR_BASED_PARTITION: choose_partitioning(cpi, tile, mi_row, mi_col); nonrd_use_partition(cpi, tile, mi, tp, mi_row, mi_col, BLOCK_64X64, @@ -3002,20 +3105,20 @@ static void encode_nonrd_sb_row(VP9_COMP *cpi, const TileInfo *const tile, break; case VAR_BASED_FIXED_PARTITION: case FIXED_PARTITION: - bsize = cpi->sf.partition_search_type == FIXED_PARTITION ? - cpi->sf.always_this_block_size : + bsize = sf->partition_search_type == FIXED_PARTITION ? + sf->always_this_block_size : get_nonrd_var_based_fixed_partition(cpi, mi_row, mi_col); set_fixed_partitioning(cpi, tile, mi, mi_row, mi_col, bsize); nonrd_use_partition(cpi, tile, mi, tp, mi_row, mi_col, BLOCK_64X64, 1, &dummy_rate, &dummy_dist, cpi->pc_root); break; case REFERENCE_PARTITION: - if (cpi->sf.partition_check || + if (sf->partition_check || !is_background(cpi, tile, mi_row, mi_col)) { set_modeinfo_offsets(cm, xd, mi_row, mi_col); auto_partition_range(cpi, tile, mi_row, mi_col, - &cpi->sf.min_partition_size, - &cpi->sf.max_partition_size); + &sf->min_partition_size, + &sf->max_partition_size); nonrd_pick_partition(cpi, tile, tp, mi_row, mi_col, BLOCK_64X64, &dummy_rate, &dummy_dist, 1, INT64_MAX, cpi->pc_root); @@ -3028,14 +3131,15 @@ static void encode_nonrd_sb_row(VP9_COMP *cpi, const TileInfo *const tile, break; default: assert(0); + break; } } } // end RTC play code static int set_var_thresh_from_histogram(VP9_COMP *cpi) { - SPEED_FEATURES *const sf = &cpi->sf; - VP9_COMMON *const cm = &cpi->common; + const SPEED_FEATURES *const sf = &cpi->sf; + const VP9_COMMON *const cm = &cpi->common; const uint8_t *src = cpi->Source->y_buffer; const uint8_t *last_src = cpi->Last_Source->y_buffer; @@ -3194,19 +3298,19 @@ static void encode_frame_internal(VP9_COMP *cpi) { vp9_zero(rd_opt->tx_select_diff); vp9_zero(rd_opt->tx_select_threshes); - cpi->mb.e_mbd.lossless = cm->base_qindex == 0 && - cm->y_dc_delta_q == 0 && - cm->uv_dc_delta_q == 0 && - cm->uv_ac_delta_q == 0; + xd->lossless = cm->base_qindex == 0 && + cm->y_dc_delta_q == 0 && + cm->uv_dc_delta_q == 0 && + cm->uv_ac_delta_q == 0; cm->tx_mode = select_tx_mode(cpi); - cpi->mb.fwd_txm4x4 = cpi->mb.e_mbd.lossless ? vp9_fwht4x4 : vp9_fdct4x4; - cpi->mb.itxm_add = cpi->mb.e_mbd.lossless ? vp9_iwht4x4_add : vp9_idct4x4_add; + x->fwd_txm4x4 = xd->lossless ? vp9_fwht4x4 : vp9_fdct4x4; + x->itxm_add = xd->lossless ? vp9_iwht4x4_add : vp9_idct4x4_add; - if (cpi->mb.e_mbd.lossless) { - cpi->mb.optimize = 0; - cpi->common.lf.filter_level = 0; + if (xd->lossless) { + x->optimize = 0; + cm->lf.filter_level = 0; cpi->zbin_mode_boost_enabled = 0; } @@ -3458,7 +3562,8 @@ static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled, MODE_INFO **mi_8x8 = xd->mi; MODE_INFO *mi = mi_8x8[0]; MB_MODE_INFO *mbmi = &mi->mbmi; - unsigned int segment_id = mbmi->segment_id; + const int seg_skip = vp9_segfeature_active(&cm->seg, mbmi->segment_id, + SEG_LVL_SKIP); const int mis = cm->mi_stride; const int mi_width = num_8x8_blocks_wide_lookup[bsize]; const int mi_height = num_8x8_blocks_high_lookup[bsize]; @@ -3502,7 +3607,7 @@ static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled, vp9_setup_pre_planes(xd, ref, cfg, mi_row, mi_col, &xd->block_refs[ref]->sf); } - if (!cpi->sf.reuse_inter_pred_sby) + if (!cpi->sf.reuse_inter_pred_sby || seg_skip) vp9_build_inter_predictors_sby(xd, mi_row, mi_col, MAX(bsize, BLOCK_8X8)); vp9_build_inter_predictors_sbuv(xd, mi_row, mi_col, MAX(bsize, BLOCK_8X8)); @@ -3513,8 +3618,7 @@ static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled, vp9_tokenize_sb(cpi, t, !output_enabled, MAX(bsize, BLOCK_8X8)); } else { mbmi->skip = 1; - if (output_enabled && - !vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) + if (output_enabled && !seg_skip) cm->counts.skip[vp9_get_skip_context(xd)][1]++; reset_skip_context(xd, MAX(bsize, BLOCK_8X8)); } @@ -3523,9 +3627,7 @@ static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled, if (output_enabled) { if (cm->tx_mode == TX_MODE_SELECT && mbmi->sb_type >= BLOCK_8X8 && - !(is_inter_block(mbmi) && - (mbmi->skip || - vp9_segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP)))) { + !(is_inter_block(mbmi) && (mbmi->skip || seg_skip))) { ++get_tx_counts(max_txsize_lookup[bsize], vp9_get_tx_size_context(xd), &cm->counts.tx)[mbmi->tx_size]; } else { diff --git a/vp9/encoder/vp9_encodemb.c b/vp9/encoder/vp9_encodemb.c index 0bb33e91c..6934f1188 100644 --- a/vp9/encoder/vp9_encodemb.c +++ b/vp9/encoder/vp9_encodemb.c @@ -348,6 +348,7 @@ void vp9_xform_quant_fp(MACROBLOCK *x, int plane, int block, break; default: assert(0); + break; } } @@ -394,6 +395,7 @@ void vp9_xform_quant_dc(MACROBLOCK *x, int plane, int block, break; default: assert(0); + break; } } @@ -444,6 +446,7 @@ void vp9_xform_quant(MACROBLOCK *x, int plane, int block, break; default: assert(0); + break; } } @@ -521,6 +524,7 @@ static void encode_block(int plane, int block, BLOCK_SIZE plane_bsize, break; default: assert(0 && "Invalid transform size"); + break; } } @@ -692,6 +696,7 @@ static void encode_block_intra(int plane, int block, BLOCK_SIZE plane_bsize, break; default: assert(0); + break; } if (*eob) *(args->skip) = 0; diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index f8d26110d..41f0e5c3b 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -131,7 +131,7 @@ static void setup_frame(VP9_COMP *cpi) { } if (cm->frame_type == KEY_FRAME) { - if (!(cpi->use_svc && cpi->svc.number_temporal_layers == 1)) + if (!is_spatial_svc(cpi)) cpi->refresh_golden_frame = 1; cpi->refresh_alt_ref_frame = 1; } else { @@ -477,7 +477,7 @@ static void update_frame_size(VP9_COMP *cpi) { vp9_init_context_buffers(cm); init_macroblockd(cm, xd); - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { + if (is_spatial_svc(cpi)) { if (vp9_realloc_frame_buffer(&cpi->alt_ref_buffer, cm->width, cm->height, cm->subsampling_x, cm->subsampling_y, @@ -524,6 +524,7 @@ static void init_config(struct VP9_COMP *cpi, VP9EncoderConfig *oxcf) { cm->profile = oxcf->profile; cm->bit_depth = oxcf->bit_depth; + cm->color_space = UNKNOWN; cm->width = oxcf->width; cm->height = oxcf->height; @@ -552,23 +553,6 @@ static void init_config(struct VP9_COMP *cpi, VP9EncoderConfig *oxcf) { set_tile_limits(cpi); } -static int get_pass(MODE mode) { - switch (mode) { - case REALTIME: - case ONE_PASS_GOOD: - case ONE_PASS_BEST: - return 0; - - case TWO_PASS_FIRST: - return 1; - - case TWO_PASS_SECOND_GOOD: - case TWO_PASS_SECOND_BEST: - return 2; - } - return -1; -} - void vp9_change_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) { VP9_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; @@ -583,7 +567,6 @@ void vp9_change_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) { assert(cm->bit_depth > BITS_8); cpi->oxcf = *oxcf; - cpi->pass = get_pass(cpi->oxcf.mode); rc->baseline_gf_interval = DEFAULT_GF_INTERVAL; @@ -653,7 +636,7 @@ void vp9_change_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) { if ((cpi->svc.number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) || - (cpi->svc.number_spatial_layers > 1 && cpi->pass == 2)) { + (cpi->svc.number_spatial_layers > 1 && cpi->oxcf.pass == 2)) { vp9_update_layer_context_change_config(cpi, (int)cpi->oxcf.target_bandwidth); } @@ -747,7 +730,7 @@ VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf) { cpi->use_svc = 0; init_config(cpi, oxcf); - vp9_rc_init(&cpi->oxcf, cpi->pass, &cpi->rc); + vp9_rc_init(&cpi->oxcf, oxcf->pass, &cpi->rc); cm->current_video_frame = 0; @@ -799,7 +782,7 @@ VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf) { // pending further tuning and testing. The code is left in place here // as a place holder in regard to the required paths. cpi->multi_arf_last_grp_enabled = 0; - if (cpi->pass == 2) { + if (oxcf->pass == 2) { if (cpi->use_svc) { cpi->multi_arf_allowed = 0; cpi->multi_arf_enabled = 0; @@ -887,9 +870,9 @@ VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf) { cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED; - if (cpi->pass == 1) { + if (oxcf->pass == 1) { vp9_init_first_pass(cpi); - } else if (cpi->pass == 2) { + } else if (oxcf->pass == 2) { const size_t packet_sz = sizeof(FIRSTPASS_STATS); const int packets = (int)(oxcf->two_pass_stats_in.sz / packet_sz); @@ -1065,7 +1048,7 @@ void vp9_remove_compressor(VP9_COMP *cpi) { vp9_clear_system_state(); // printf("\n8x8-4x4:%d-%d\n", cpi->t8x8_count, cpi->t4x4_count); - if (cpi->pass != 1) { + if (cpi->oxcf.pass != 1) { FILE *f = fopen("opsnr.stt", "a"); double time_encoded = (cpi->last_end_time_stamp_seen - cpi->first_time_stamp_ever) / 10000000.000; @@ -1302,16 +1285,6 @@ int vp9_copy_reference_enc(VP9_COMP *cpi, VP9_REFFRAME ref_frame_flag, } } -int vp9_get_reference_enc(VP9_COMP *cpi, int index, YV12_BUFFER_CONFIG **fb) { - VP9_COMMON *cm = &cpi->common; - - if (index < 0 || index >= REF_FRAMES) - return -1; - - *fb = &cm->frame_bufs[cm->ref_frame_map[index]].buf; - return 0; -} - int vp9_set_reference_enc(VP9_COMP *cpi, VP9_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) { YV12_BUFFER_CONFIG *cfg = get_vp9_ref_frame_buffer(cpi, ref_frame_flag); @@ -1564,17 +1537,15 @@ void vp9_update_reference_frames(VP9_COMP *cpi) { &cm->ref_frame_map[cpi->gld_fb_idx], cm->new_fb_idx); ref_cnt_fb(cm->frame_bufs, &cm->ref_frame_map[cpi->alt_fb_idx], cm->new_fb_idx); - } else if (!cpi->multi_arf_allowed && cpi->refresh_golden_frame && - cpi->rc.is_src_frame_alt_ref && !cpi->use_svc) { - /* Preserve the previously existing golden frame and update the frame in - * the alt ref slot instead. This is highly specific to the current use of - * alt-ref as a forward reference, and this needs to be generalized as - * other uses are implemented (like RTC/temporal scaling) - * - * The update to the buffer in the alt ref slot was signaled in - * vp9_pack_bitstream(), now swap the buffer pointers so that it's treated - * as the golden frame next time. - */ + } else if (vp9_preserve_existing_gf(cpi)) { + // We have decided to preserve the previously existing golden frame as our + // new ARF frame. However, in the short term in function + // vp9_bitstream.c::get_refresh_mask() we left it in the GF slot and, if + // we're updating the GF with the current decoded frame, we save it to the + // ARF slot instead. + // We now have to update the ARF with the current frame and swap gld_fb_idx + // and alt_fb_idx so that, overall, we've stored the old GF in the new ARF + // slot and, if we're updating the GF, the current frame becomes the new GF. int tmp; ref_cnt_fb(cm->frame_bufs, @@ -1583,10 +1554,15 @@ void vp9_update_reference_frames(VP9_COMP *cpi) { tmp = cpi->alt_fb_idx; cpi->alt_fb_idx = cpi->gld_fb_idx; cpi->gld_fb_idx = tmp; + + if (is_spatial_svc(cpi)) { + cpi->svc.layer_context[0].gold_ref_idx = cpi->gld_fb_idx; + cpi->svc.layer_context[0].alt_ref_idx = cpi->alt_fb_idx; + } } else { /* For non key/golden frames */ if (cpi->refresh_alt_ref_frame) { int arf_idx = cpi->alt_fb_idx; - if ((cpi->pass == 2) && cpi->multi_arf_allowed) { + if ((cpi->oxcf.pass == 2) && cpi->multi_arf_allowed) { const GF_GROUP *const gf_group = &cpi->twopass.gf_group; arf_idx = gf_group->arf_update_idx[gf_group->index]; } @@ -2003,7 +1979,7 @@ static void get_ref_frame_flags(VP9_COMP *cpi) { cpi->ref_frame_flags &= ~VP9_GOLD_FLAG; if (cpi->rc.frames_till_gf_update_due == INT_MAX && - !(cpi->use_svc && cpi->svc.number_temporal_layers == 1)) + !is_spatial_svc(cpi)) cpi->ref_frame_flags &= ~VP9_GOLD_FLAG; if (cpi->alt_is_last) @@ -2049,9 +2025,7 @@ static void configure_skippable_frame(VP9_COMP *cpi) { // according to the variance SVC *const svc = &cpi->svc; - const int is_spatial_svc = (svc->number_spatial_layers > 1) && - (svc->number_temporal_layers == 1); - TWO_PASS *const twopass = is_spatial_svc ? + TWO_PASS *const twopass = is_spatial_svc(cpi) ? &svc->layer_context[svc->spatial_layer_id].twopass : &cpi->twopass; @@ -2069,7 +2043,7 @@ static void set_arf_sign_bias(VP9_COMP *cpi) { VP9_COMMON *const cm = &cpi->common; int arf_sign_bias; - if ((cpi->pass == 2) && cpi->multi_arf_allowed) { + if ((cpi->oxcf.pass == 2) && cpi->multi_arf_allowed) { const GF_GROUP *const gf_group = &cpi->twopass.gf_group; arf_sign_bias = cpi->rc.source_alt_ref_active && (!cpi->refresh_alt_ref_frame || @@ -2157,9 +2131,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, (cpi->oxcf.frame_parallel_decoding_mode != 0); // By default, encoder assumes decoder can use prev_mi. - cm->coding_use_prev_mi = 1; if (cm->error_resilient_mode) { - cm->coding_use_prev_mi = 0; cm->frame_parallel_decoding_mode = 1; cm->reset_frame_context = 0; cm->refresh_frame_context = 0; @@ -2173,19 +2145,19 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, // static regions if indicated. // Only allowed in second pass of two pass (as requires lagged coding) // and if the relevant speed feature flag is set. - if (cpi->pass == 2 && cpi->sf.static_segmentation) + if (cpi->oxcf.pass == 2 && cpi->sf.static_segmentation) configure_static_seg_features(cpi); // Check if the current frame is skippable for the partition search in the // second pass according to the first pass stats - if (cpi->pass == 2 && - (!cpi->use_svc || cpi->svc.number_temporal_layers == 1)) { + if (cpi->oxcf.pass == 2 && + (!cpi->use_svc || is_spatial_svc(cpi))) { configure_skippable_frame(cpi); } // For 1 pass CBR, check if we are dropping this frame. // Never drop on key frame. - if (cpi->pass == 0 && + if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_CBR && cm->frame_type != KEY_FRAME) { if (vp9_rc_drop_frame(cpi)) { @@ -2431,7 +2403,7 @@ int vp9_receive_raw_frame(VP9_COMP *cpi, unsigned int frame_flags, vpx_usec_timer_start(&timer); #if CONFIG_SPATIAL_SVC - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) + if (is_spatial_svc(cpi)) res = vp9_svc_lookahead_push(cpi, cpi->lookahead, sd, time_stamp, end_time, frame_flags); else @@ -2443,9 +2415,16 @@ int vp9_receive_raw_frame(VP9_COMP *cpi, unsigned int frame_flags, vpx_usec_timer_mark(&timer); cpi->time_receive_data += vpx_usec_timer_elapsed(&timer); - if (cm->profile == PROFILE_0 && (subsampling_x != 1 || subsampling_y != 1)) { + if ((cm->profile == PROFILE_0 || cm->profile == PROFILE_2) && + (subsampling_x != 1 || subsampling_y != 1)) { + vpx_internal_error(&cm->error, VPX_CODEC_INVALID_PARAM, + "Non-4:2:0 color space requires profile 1 or 3"); + res = -1; + } + if ((cm->profile == PROFILE_1 || cm->profile == PROFILE_3) && + (subsampling_x == 1 && subsampling_y == 1)) { vpx_internal_error(&cm->error, VPX_CODEC_INVALID_PARAM, - "Non-4:2:0 color space requires profile >= 1"); + "4:2:0 color space requires profile 0 or 2"); res = -1; } @@ -2510,7 +2489,7 @@ static int get_arf_src_index(VP9_COMP *cpi) { RATE_CONTROL *const rc = &cpi->rc; int arf_src_index = 0; if (is_altref_enabled(cpi)) { - if (cpi->pass == 2) { + if (cpi->oxcf.pass == 2) { const GF_GROUP *const gf_group = &cpi->twopass.gf_group; if (gf_group->update_type[gf_group->index] == ARF_UPDATE) { arf_src_index = gf_group->arf_src_offset[gf_group->index]; @@ -2525,7 +2504,7 @@ static int get_arf_src_index(VP9_COMP *cpi) { static void check_src_altref(VP9_COMP *cpi) { RATE_CONTROL *const rc = &cpi->rc; - if (cpi->pass == 2) { + if (cpi->oxcf.pass == 2) { const GF_GROUP *const gf_group = &cpi->twopass.gf_group; rc->is_src_frame_alt_ref = (gf_group->update_type[gf_group->index] == OVERLAY_UPDATE); @@ -2554,14 +2533,11 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, YV12_BUFFER_CONFIG *force_src_buffer = NULL; MV_REFERENCE_FRAME ref_frame; int arf_src_index; - const int is_spatial_svc = cpi->use_svc && - (cpi->svc.number_temporal_layers == 1) && - (cpi->svc.number_spatial_layers > 1); if (!cpi) return -1; - if (is_spatial_svc && cpi->pass == 2) { + if (is_spatial_svc(cpi) && cpi->oxcf.pass == 2) { #if CONFIG_SPATIAL_SVC vp9_svc_lookahead_peek(cpi, cpi->lookahead, 0, 1); #endif @@ -2588,7 +2564,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, assert(arf_src_index <= rc->frames_to_key); #if CONFIG_SPATIAL_SVC - if (is_spatial_svc) + if (is_spatial_svc(cpi)) cpi->source = vp9_svc_lookahead_peek(cpi, cpi->lookahead, arf_src_index, 0); else @@ -2598,7 +2574,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, cpi->alt_ref_source = cpi->source; #if CONFIG_SPATIAL_SVC - if (is_spatial_svc && cpi->svc.spatial_layer_id > 0) { + if (is_spatial_svc(cpi) && cpi->svc.spatial_layer_id > 0) { int i; // Reference a hidden frame from a lower layer for (i = cpi->svc.spatial_layer_id - 1; i >= 0; --i) { @@ -2633,7 +2609,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, // Get last frame source. if (cm->current_video_frame > 0) { #if CONFIG_SPATIAL_SVC - if (is_spatial_svc) + if (is_spatial_svc(cpi)) cpi->last_source = vp9_svc_lookahead_peek(cpi, cpi->lookahead, -1, 0); else #endif @@ -2644,7 +2620,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, // Read in the source frame. #if CONFIG_SPATIAL_SVC - if (is_spatial_svc) + if (is_spatial_svc(cpi)) cpi->source = vp9_svc_lookahead_pop(cpi, cpi->lookahead, flush); else #endif @@ -2675,7 +2651,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, } else { *size = 0; - if (flush && cpi->pass == 1 && !cpi->twopass.first_pass_done) { + if (flush && cpi->oxcf.pass == 1 && !cpi->twopass.first_pass_done) { vp9_end_first_pass(cpi); /* get last stats packet */ cpi->twopass.first_pass_done = 1; } @@ -2713,7 +2689,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, if (!cpi->use_svc && cpi->multi_arf_allowed) { if (cm->frame_type == KEY_FRAME) { init_buffer_indices(cpi); - } else if (cpi->pass == 2) { + } else if (cpi->oxcf.pass == 2) { const GF_GROUP *const gf_group = &cpi->twopass.gf_group; cpi->alt_fb_idx = gf_group->arf_ref_idx[gf_group->index]; } @@ -2721,7 +2697,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, cpi->frame_flags = *frame_flags; - if (cpi->pass == 2 && + if (cpi->oxcf.pass == 2 && cm->current_video_frame == 0 && cpi->oxcf.allow_spatial_resampling && cpi->oxcf.rc_mode == VPX_VBR) { @@ -2759,14 +2735,14 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, vp9_vaq_init(); } - if (cpi->pass == 1 && - (!cpi->use_svc || cpi->svc.number_temporal_layers == 1)) { + if (cpi->oxcf.pass == 1 && + (!cpi->use_svc || is_spatial_svc(cpi))) { const int lossless = is_lossless_requested(&cpi->oxcf); cpi->mb.fwd_txm4x4 = lossless ? vp9_fwht4x4 : vp9_fdct4x4; cpi->mb.itxm_add = lossless ? vp9_iwht4x4_add : vp9_idct4x4_add; vp9_first_pass(cpi); - } else if (cpi->pass == 2 && - (!cpi->use_svc || cpi->svc.number_temporal_layers == 1)) { + } else if (cpi->oxcf.pass == 2 && + (!cpi->use_svc || is_spatial_svc(cpi))) { Pass2Encode(cpi, size, dest, frame_flags); } else if (cpi->use_svc) { SvcEncode(cpi, size, dest, frame_flags); @@ -2790,19 +2766,19 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, // Save layer specific state. if ((cpi->svc.number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) || - (cpi->svc.number_spatial_layers > 1 && cpi->pass == 2)) { + (cpi->svc.number_spatial_layers > 1 && cpi->oxcf.pass == 2)) { vp9_save_layer_context(cpi); } vpx_usec_timer_mark(&cmptimer); cpi->time_compress_data += vpx_usec_timer_elapsed(&cmptimer); - if (cpi->b_calculate_psnr && cpi->pass != 1 && cm->show_frame) + if (cpi->b_calculate_psnr && cpi->oxcf.pass != 1 && cm->show_frame) generate_psnr_packet(cpi); #if CONFIG_INTERNAL_STATS - if (cpi->pass != 1) { + if (cpi->oxcf.pass != 1) { cpi->bytes += (int)(*size); if (cm->show_frame) { diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index 2a6c4b362..c841da267 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -143,6 +143,7 @@ typedef struct VP9EncoderConfig { unsigned int rc_max_intra_bitrate_pct; MODE mode; + int pass; // Key Framing Operations int auto_key; // autodetect cut scenes and set the keyframes @@ -232,6 +233,7 @@ typedef struct VP9EncoderConfig { #endif vp8e_tuning tuning; + vp9e_tune_content content; } VP9EncoderConfig; static INLINE int is_lossless_requested(const VP9EncoderConfig *cfg) { @@ -312,9 +314,6 @@ typedef struct VP9_COMP { MBGRAPH_FRAME_STATS mbgraph_stats[MAX_LAG_BUFFERS]; int mbgraph_n_frames; // number of frames filled in the above int static_mb_pct; // % forced skip mbs by segmentation - - int pass; - int ref_frame_flags; SPEED_FEATURES sf; @@ -462,9 +461,6 @@ void vp9_update_reference(VP9_COMP *cpi, int ref_frame_flags); int vp9_copy_reference_enc(VP9_COMP *cpi, VP9_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd); -int vp9_get_reference_enc(VP9_COMP *cpi, int index, - YV12_BUFFER_CONFIG **fb); - int vp9_set_reference_enc(VP9_COMP *cpi, VP9_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd); @@ -535,10 +531,16 @@ YV12_BUFFER_CONFIG *vp9_scale_if_required(VP9_COMMON *cm, void vp9_apply_encoding_flags(VP9_COMP *cpi, vpx_enc_frame_flags_t flags); +static INLINE int is_spatial_svc(const struct VP9_COMP *const cpi) { + return cpi->use_svc && + cpi->svc.number_temporal_layers == 1 && + cpi->svc.number_spatial_layers > 1; +} + static INLINE int is_altref_enabled(const VP9_COMP *const cpi) { return cpi->oxcf.mode != REALTIME && cpi->oxcf.lag_in_frames > 0 && (cpi->oxcf.play_alternate && - (!(cpi->use_svc && cpi->svc.number_temporal_layers == 1) || + (!is_spatial_svc(cpi) || cpi->oxcf.ss_play_alternate[cpi->svc.spatial_layer_id])); } diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c index 1b574758b..5a79f726a 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -225,26 +225,6 @@ static void subtract_stats(FIRSTPASS_STATS *section, section->duration -= frame->duration; } -static void avg_stats(FIRSTPASS_STATS *section) { - if (section->count < 1.0) - return; - - section->intra_error /= section->count; - section->coded_error /= section->count; - section->sr_coded_error /= section->count; - section->pcnt_inter /= section->count; - section->pcnt_second_ref /= section->count; - section->pcnt_neutral /= section->count; - section->pcnt_motion /= section->count; - section->MVr /= section->count; - section->mvr_abs /= section->count; - section->MVc /= section->count; - section->mvc_abs /= section->count; - section->MVrv /= section->count; - section->MVcv /= section->count; - section->mv_in_out_count /= section->count; - section->duration /= section->count; -} // Calculate a modified Error used in distributing bits between easier and // harder frames. @@ -278,7 +258,7 @@ void vp9_init_first_pass(VP9_COMP *cpi) { } void vp9_end_first_pass(VP9_COMP *cpi) { - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { + if (is_spatial_svc(cpi)) { int i; for (i = 0; i < cpi->svc.number_spatial_layers; ++i) { output_stats(&cpi->svc.layer_context[i].twopass.total_stats, @@ -466,7 +446,7 @@ void vp9_first_pass(VP9_COMP *cpi) { set_first_pass_params(cpi); vp9_set_quantizer(cm, find_fp_qindex()); - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { + if (is_spatial_svc(cpi)) { MV_REFERENCE_FRAME ref_frame = LAST_FRAME; const YV12_BUFFER_CONFIG *scaled_ref_buf = NULL; twopass = &cpi->svc.layer_context[cpi->svc.spatial_layer_id].twopass; @@ -635,8 +615,7 @@ void vp9_first_pass(VP9_COMP *cpi) { &unscaled_last_source_buf_2d); // TODO(pengchong): Replace the hard-coded threshold - if (raw_motion_error > 25 || - (cpi->use_svc && cpi->svc.number_temporal_layers == 1)) { + if (raw_motion_error > 25 || is_spatial_svc(cpi)) { // Test last reference frame using the previous best mv as the // starting point (best reference) for the search. first_pass_motion_search(cpi, x, &best_ref_mv.as_mv, &mv.as_mv, @@ -709,18 +688,11 @@ void vp9_first_pass(VP9_COMP *cpi) { // intra predication statistics cpi->twopass.frame_mb_stats_buf[mb_index] = 0; cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_DCINTRA_MASK; - cpi->twopass.frame_mb_stats_buf[mb_index] &= - ~FPMB_NONZERO_MOTION_MASK; - if (this_error > FPMB_ERROR_LEVEL4_TH) { - cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_ERROR_LEVEL4_MASK; - } else if (this_error > FPMB_ERROR_LEVEL3_TH) { - cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_ERROR_LEVEL3_MASK; - } else if (this_error > FPMB_ERROR_LEVEL2_TH) { - cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_ERROR_LEVEL2_MASK; - } else if (this_error > FPMB_ERROR_LEVEL1_TH) { - cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_ERROR_LEVEL1_MASK; - } else { - cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_ERROR_LEVEL0_MASK; + cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_MOTION_ZERO_MASK; + if (this_error > FPMB_ERROR_LARGE_TH) { + cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_ERROR_LARGE_MASK; + } else if (this_error < FPMB_ERROR_SMALL_TH) { + cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_ERROR_SMALL_MASK; } } #endif @@ -758,23 +730,13 @@ void vp9_first_pass(VP9_COMP *cpi) { // inter predication statistics cpi->twopass.frame_mb_stats_buf[mb_index] = 0; cpi->twopass.frame_mb_stats_buf[mb_index] &= ~FPMB_DCINTRA_MASK; - cpi->twopass.frame_mb_stats_buf[mb_index] &= - ~FPMB_NONZERO_MOTION_MASK; - if (this_error > FPMB_ERROR_LEVEL4_TH) { - cpi->twopass.frame_mb_stats_buf[mb_index] |= - FPMB_ERROR_LEVEL4_MASK; - } else if (this_error > FPMB_ERROR_LEVEL3_TH) { - cpi->twopass.frame_mb_stats_buf[mb_index] |= - FPMB_ERROR_LEVEL3_MASK; - } else if (this_error > FPMB_ERROR_LEVEL2_TH) { - cpi->twopass.frame_mb_stats_buf[mb_index] |= - FPMB_ERROR_LEVEL2_MASK; - } else if (this_error > FPMB_ERROR_LEVEL1_TH) { + cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_MOTION_ZERO_MASK; + if (this_error > FPMB_ERROR_LARGE_TH) { cpi->twopass.frame_mb_stats_buf[mb_index] |= - FPMB_ERROR_LEVEL1_MASK; - } else { + FPMB_ERROR_LARGE_MASK; + } else if (this_error < FPMB_ERROR_SMALL_TH) { cpi->twopass.frame_mb_stats_buf[mb_index] |= - FPMB_ERROR_LEVEL0_MASK; + FPMB_ERROR_SMALL_MASK; } } #endif @@ -784,8 +746,28 @@ void vp9_first_pass(VP9_COMP *cpi) { #if CONFIG_FP_MB_STATS if (cpi->use_fp_mb_stats) { - cpi->twopass.frame_mb_stats_buf[mb_index] |= - FPMB_NONZERO_MOTION_MASK; + cpi->twopass.frame_mb_stats_buf[mb_index] &= + ~FPMB_MOTION_ZERO_MASK; + // check estimated motion direction + if (mv.as_mv.col > 0 && mv.as_mv.col >= abs(mv.as_mv.row)) { + // right direction + cpi->twopass.frame_mb_stats_buf[mb_index] |= + FPMB_MOTION_RIGHT_MASK; + } else if (mv.as_mv.row < 0 && + abs(mv.as_mv.row) >= abs(mv.as_mv.col)) { + // up direction + cpi->twopass.frame_mb_stats_buf[mb_index] |= + FPMB_MOTION_UP_MASK; + } else if (mv.as_mv.col < 0 && + abs(mv.as_mv.col) >= abs(mv.as_mv.row)) { + // left direction + cpi->twopass.frame_mb_stats_buf[mb_index] |= + FPMB_MOTION_LEFT_MASK; + } else { + // down direction + cpi->twopass.frame_mb_stats_buf[mb_index] |= + FPMB_MOTION_DOWN_MASK; + } } #endif @@ -915,7 +897,7 @@ void vp9_first_pass(VP9_COMP *cpi) { vp9_extend_frame_borders(new_yv12); - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { + if (is_spatial_svc(cpi)) { vp9_update_reference_frames(cpi); } else { // Swap frame pointers so last frame refers to the frame we just compressed. @@ -984,10 +966,8 @@ static int get_twopass_worst_quality(const VP9_COMP *cpi, BPER_MB_NORMBITS) / num_mbs; int q; int is_svc_upper_layer = 0; - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1 && - cpi->svc.spatial_layer_id > 0) { + if (is_spatial_svc(cpi) && cpi->svc.spatial_layer_id > 0) is_svc_upper_layer = 1; - } // Try and pick a max Q that will be high enough to encode the // content at the given rate. @@ -2117,9 +2097,11 @@ void configure_buffer_updates(VP9_COMP *cpi) { break; default: assert(0); + break; } - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { - cpi->refresh_golden_frame = 0; + if (is_spatial_svc(cpi)) { + if (cpi->svc.layer_context[cpi->svc.spatial_layer_id].gold_ref_idx < 0) + cpi->refresh_golden_frame = 0; if (cpi->alt_ref_source == NULL) cpi->refresh_alt_ref_frame = 0; } @@ -2136,9 +2118,8 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) { int target_rate; LAYER_CONTEXT *lc = NULL; - const int is_spatial_svc = (cpi->use_svc && - cpi->svc.number_temporal_layers == 1); - if (is_spatial_svc) { + + if (is_spatial_svc(cpi)) { lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id]; frames_left = (int)(twopass->total_stats.count - lc->current_video_frame_in_layer); @@ -2166,7 +2147,7 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) { vp9_rc_set_frame_target(cpi, target_rate); cm->frame_type = INTER_FRAME; - if (is_spatial_svc) { + if (is_spatial_svc(cpi)) { if (cpi->svc.spatial_layer_id == 0) { lc->is_key_frame = 0; } else { @@ -2182,7 +2163,7 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) { vp9_clear_system_state(); - if (is_spatial_svc && twopass->kf_intra_err_min == 0) { + if (is_spatial_svc(cpi) && twopass->kf_intra_err_min == 0) { twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs; twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs; } @@ -2190,7 +2171,8 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) { if (cpi->oxcf.rc_mode == VPX_Q) { twopass->active_worst_quality = cpi->oxcf.cq_level; } else if (cm->current_video_frame == 0 || - (is_spatial_svc && lc->current_video_frame_in_layer == 0)) { + (is_spatial_svc(cpi) && + lc->current_video_frame_in_layer == 0)) { // Special case code for first frame. const int section_target_bandwidth = (int)(twopass->bits_left / frames_left); @@ -2216,9 +2198,12 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) { cm->frame_type = INTER_FRAME; } - if (is_spatial_svc) { + if (is_spatial_svc(cpi)) { if (cpi->svc.spatial_layer_id == 0) { lc->is_key_frame = (cm->frame_type == KEY_FRAME); + if (lc->is_key_frame) + cpi->ref_frame_flags &= + (~VP9_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG); } else { cm->frame_type = INTER_FRAME; lc->is_key_frame = cpi->svc.layer_context[0].is_key_frame; @@ -2244,7 +2229,7 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) { } rc->frames_till_gf_update_due = rc->baseline_gf_interval; - if (!is_spatial_svc) + if (!is_spatial_svc(cpi)) cpi->refresh_golden_frame = 1; } diff --git a/vp9/encoder/vp9_firstpass.h b/vp9/encoder/vp9_firstpass.h index e898abc16..bf8c9fd96 100644 --- a/vp9/encoder/vp9_firstpass.h +++ b/vp9/encoder/vp9_firstpass.h @@ -21,17 +21,17 @@ extern "C" { #if CONFIG_FP_MB_STATS #define FPMB_DCINTRA_MASK 0x01 -#define FPMB_NONZERO_MOTION_MASK 0x02 -#define FPMB_ERROR_LEVEL0_MASK 0x04 -#define FPMB_ERROR_LEVEL1_MASK 0x10 -#define FPMB_ERROR_LEVEL2_MASK 0x20 -#define FPMB_ERROR_LEVEL3_MASK 0x40 -#define FPMB_ERROR_LEVEL4_MASK 0x80 - -#define FPMB_ERROR_LEVEL1_TH 2000 -#define FPMB_ERROR_LEVEL2_TH 8000 -#define FPMB_ERROR_LEVEL3_TH 24000 -#define FPMB_ERROR_LEVEL4_TH 48000 + +#define FPMB_MOTION_ZERO_MASK 0x02 +#define FPMB_MOTION_LEFT_MASK 0x04 +#define FPMB_MOTION_RIGHT_MASK 0x08 +#define FPMB_MOTION_UP_MASK 0x10 +#define FPMB_MOTION_DOWN_MASK 0x20 + +#define FPMB_ERROR_SMALL_MASK 0x40 +#define FPMB_ERROR_LARGE_MASK 0x80 +#define FPMB_ERROR_SMALL_TH 2000 +#define FPMB_ERROR_LARGE_TH 48000 typedef struct { uint8_t *mb_stats_start; diff --git a/vp9/encoder/vp9_picklpf.c b/vp9/encoder/vp9_picklpf.c index 0f363a7c3..d36548996 100644 --- a/vp9/encoder/vp9_picklpf.c +++ b/vp9/encoder/vp9_picklpf.c @@ -24,7 +24,7 @@ #include "vp9/encoder/vp9_quantize.h" static int get_max_filter_level(const VP9_COMP *cpi) { - if (cpi->pass == 2) { + if (cpi->oxcf.pass == 2) { return cpi->twopass.section_intra_rating > 8 ? MAX_LOOP_FILTER * 3 / 4 : MAX_LOOP_FILTER; } else { @@ -82,7 +82,7 @@ static int search_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi, // Bias against raising loop filter in favor of lowering it. int bias = (best_err >> (15 - (filt_mid / 8))) * filter_step; - if ((cpi->pass == 2) && (cpi->twopass.section_intra_rating < 20)) + if ((cpi->oxcf.pass == 2) && (cpi->twopass.section_intra_rating < 20)) bias = (bias * cpi->twopass.section_intra_rating) / 20; // yx, bias less for large block size diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c index 89b8fa146..9e57d6abe 100644 --- a/vp9/encoder/vp9_pickmode.c +++ b/vp9/encoder/vp9_pickmode.c @@ -458,7 +458,7 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, vp9_setup_pred_block(xd, yv12_mb[ref_frame], yv12, mi_row, mi_col, sf, sf); - if (cm->coding_use_prev_mi) + if (!cm->error_resilient_mode) vp9_find_mv_refs(cm, xd, tile, xd->mi[0], ref_frame, candidates, mi_row, mi_col); else diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index 1adbad9cf..04ab79538 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -277,7 +277,7 @@ static double get_rate_correction_factor(const VP9_COMP *cpi) { if (cpi->common.frame_type == KEY_FRAME) { return rc->rate_correction_factors[KF_STD]; - } else if (cpi->pass == 2) { + } else if (cpi->oxcf.pass == 2) { RATE_FACTOR_LEVEL rf_lvl = cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index]; return rc->rate_correction_factors[rf_lvl]; @@ -296,7 +296,7 @@ static void set_rate_correction_factor(VP9_COMP *cpi, double factor) { if (cpi->common.frame_type == KEY_FRAME) { rc->rate_correction_factors[KF_STD] = factor; - } else if (cpi->pass == 2) { + } else if (cpi->oxcf.pass == 2) { RATE_FACTOR_LEVEL rf_lvl = cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index]; rc->rate_correction_factors[rf_lvl] = factor; @@ -923,7 +923,7 @@ static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi, int vp9_rc_pick_q_and_bounds(const VP9_COMP *cpi, int *bottom_index, int *top_index) { int q; - if (cpi->pass == 0) { + if (cpi->oxcf.pass == 0) { if (cpi->oxcf.rc_mode == VPX_CBR) q = rc_pick_q_and_bounds_one_pass_cbr(cpi, bottom_index, top_index); else @@ -991,7 +991,7 @@ static void update_golden_frame_stats(VP9_COMP *cpi) { // this frame refreshes means next frames don't unless specified by user rc->frames_since_golden = 0; - if (cpi->pass == 2) { + if (cpi->oxcf.pass == 2) { if (!rc->source_alt_ref_pending && cpi->twopass.gf_group.rf_level[0] == GF_ARF_STD) rc->source_alt_ref_active = 0; @@ -1236,18 +1236,19 @@ void vp9_rc_get_svc_params(VP9_COMP *cpi) { cm->frame_type = KEY_FRAME; rc->source_alt_ref_active = 0; - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { + if (is_spatial_svc(cpi)) { cpi->svc.layer_context[cpi->svc.spatial_layer_id].is_key_frame = 1; - cpi->ref_frame_flags &= (~VP9_ALT_FLAG); + cpi->ref_frame_flags &= + (~VP9_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG); } - if (cpi->pass == 0 && cpi->oxcf.rc_mode == VPX_CBR) { + if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_CBR) { target = calc_iframe_target_size_one_pass_cbr(cpi); } } else { cm->frame_type = INTER_FRAME; - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { + if (is_spatial_svc(cpi)) { LAYER_CONTEXT *lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id]; if (cpi->svc.spatial_layer_id == 0) { lc->is_key_frame = 0; @@ -1259,7 +1260,7 @@ void vp9_rc_get_svc_params(VP9_COMP *cpi) { cpi->ref_frame_flags &= (~VP9_ALT_FLAG); } - if (cpi->pass == 0 && cpi->oxcf.rc_mode == VPX_CBR) { + if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_CBR) { target = calc_pframe_target_size_one_pass_cbr(cpi); } } diff --git a/vp9/encoder/vp9_rd.c b/vp9/encoder/vp9_rd.c index c149c6136..4fc3e9e08 100644 --- a/vp9/encoder/vp9_rd.c +++ b/vp9/encoder/vp9_rd.c @@ -121,7 +121,7 @@ int vp9_compute_rd_mult(const VP9_COMP *cpi, int qindex) { const int q = vp9_dc_quant(qindex, 0); int rdmult = 88 * q * q / 24; - if (cpi->pass == 2 && (cpi->common.frame_type != KEY_FRAME)) { + if (cpi->oxcf.pass == 2 && (cpi->common.frame_type != KEY_FRAME)) { const GF_GROUP *const gf_group = &cpi->twopass.gf_group; const FRAME_UPDATE_TYPE frame_type = gf_group->update_type[gf_group->index]; const int boost_index = MIN(15, (cpi->rc.gfu_boost / 100)); @@ -220,8 +220,6 @@ void vp9_initialize_rd_consts(VP9_COMP *cpi) { } } -static const int MAX_XSQ_Q10 = 245727; - static void model_rd_norm(int xsq_q10, int *r_q10, int *d_q10) { // NOTE: The tables below must be of the same size. @@ -311,10 +309,10 @@ void vp9_model_rd_from_var_lapndz(unsigned int var, unsigned int n, *dist = 0; } else { int d_q10, r_q10; + static const uint32_t MAX_XSQ_Q10 = 245727; const uint64_t xsq_q10_64 = ((((uint64_t)qstep * qstep * n) << 10) + (var >> 1)) / var; - const int xsq_q10 = xsq_q10_64 > MAX_XSQ_Q10 ? - MAX_XSQ_Q10 : (int)xsq_q10_64; + const int xsq_q10 = (int)MIN(xsq_q10_64, MAX_XSQ_Q10); model_rd_norm(xsq_q10, &r_q10, &d_q10); *rate = (n * r_q10 + 2) >> 2; *dist = (var * (int64_t)d_q10 + 512) >> 10; @@ -357,6 +355,7 @@ void vp9_get_entropy_contexts(BLOCK_SIZE bsize, TX_SIZE tx_size, break; default: assert(0 && "Invalid transform size."); + break; } } diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index 177066b32..5caafd370 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -1991,7 +1991,7 @@ static INLINE void restore_dst_buf(MACROBLOCKD *xd, static void rd_encode_breakout_test(VP9_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, int *rate2, int64_t *distortion, int64_t *distortion_uv, - int *disable_skip, int64_t this_rd) { + int *disable_skip) { VP9_COMMON *cm = &cpi->common; MACROBLOCKD *xd = &x->e_mbd; const BLOCK_SIZE y_size = get_plane_block_size(bsize, &xd->plane[0]); @@ -2062,7 +2062,6 @@ static void rd_encode_breakout_test(VP9_COMP *cpi, MACROBLOCK *x, *distortion = (sse << 4) + *distortion_uv; *disable_skip = 1; - this_rd = RDCOST(x->rdmult, x->rddiv, *rate2, *distortion); } } } @@ -2314,7 +2313,7 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, if (!is_comp_pred) { if (cpi->allow_encode_breakout) rd_encode_breakout_test(cpi, x, bsize, rate2, distortion, distortion_uv, - disable_skip, this_rd); + disable_skip); } if (!x->skip) { @@ -2520,9 +2519,8 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { x->pred_mv_sad[ref_frame] = INT_MAX; if (cpi->ref_frame_flags & flag_list[ref_frame]) { - setup_buffer_inter(cpi, x, tile, - ref_frame, bsize, mi_row, mi_col, - frame_mv[NEARESTMV], frame_mv[NEARMV], yv12_mb); + setup_buffer_inter(cpi, x, tile, ref_frame, bsize, mi_row, mi_col, + frame_mv[NEARESTMV], frame_mv[NEARMV], yv12_mb); } frame_mv[NEWMV][ref_frame].as_int = INVALID_MV; frame_mv[ZEROMV][ref_frame].as_int = 0; @@ -2628,6 +2626,7 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, case NONE: case MAX_REF_FRAMES: assert(0 && "Invalid Reference frame"); + break; } } if (mode_skip_mask & (1 << mode_index)) @@ -3225,6 +3224,7 @@ int64_t vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x, case NONE: case MAX_REF_FRAMES: assert(0 && "Invalid Reference frame"); + break; } } if (mode_skip_mask & (1 << ref_index)) diff --git a/vp9/encoder/vp9_segmentation.c b/vp9/encoder/vp9_segmentation.c index 897ae0129..d5676c3d1 100644 --- a/vp9/encoder/vp9_segmentation.c +++ b/vp9/encoder/vp9_segmentation.c @@ -110,14 +110,12 @@ static int cost_segmap(int *segcounts, vp9_prob *probs) { return cost; } -static void count_segs(VP9_COMP *cpi, const TileInfo *const tile, - MODE_INFO **mi, +static void count_segs(const VP9_COMMON *cm, MACROBLOCKD *xd, + const TileInfo *tile, MODE_INFO **mi, int *no_pred_segcounts, int (*temporal_predictor_count)[2], int *t_unpred_seg_counts, int bw, int bh, int mi_row, int mi_col) { - VP9_COMMON *const cm = &cpi->common; - MACROBLOCKD *const xd = &cpi->mb.e_mbd; int segment_id; if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) @@ -151,14 +149,13 @@ static void count_segs(VP9_COMP *cpi, const TileInfo *const tile, } } -static void count_segs_sb(VP9_COMP *cpi, const TileInfo *const tile, - MODE_INFO **mi, +static void count_segs_sb(const VP9_COMMON *cm, MACROBLOCKD *xd, + const TileInfo *tile, MODE_INFO **mi, int *no_pred_segcounts, int (*temporal_predictor_count)[2], int *t_unpred_seg_counts, int mi_row, int mi_col, BLOCK_SIZE bsize) { - const VP9_COMMON *const cm = &cpi->common; const int mis = cm->mi_stride; int bw, bh; const int bs = num_8x8_blocks_wide_lookup[bsize], hbs = bs / 2; @@ -170,18 +167,18 @@ static void count_segs_sb(VP9_COMP *cpi, const TileInfo *const tile, bh = num_8x8_blocks_high_lookup[mi[0]->mbmi.sb_type]; if (bw == bs && bh == bs) { - count_segs(cpi, tile, mi, no_pred_segcounts, temporal_predictor_count, + count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count, t_unpred_seg_counts, bs, bs, mi_row, mi_col); } else if (bw == bs && bh < bs) { - count_segs(cpi, tile, mi, no_pred_segcounts, temporal_predictor_count, + count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count, t_unpred_seg_counts, bs, hbs, mi_row, mi_col); - count_segs(cpi, tile, mi + hbs * mis, no_pred_segcounts, + count_segs(cm, xd, tile, mi + hbs * mis, no_pred_segcounts, temporal_predictor_count, t_unpred_seg_counts, bs, hbs, mi_row + hbs, mi_col); } else if (bw < bs && bh == bs) { - count_segs(cpi, tile, mi, no_pred_segcounts, temporal_predictor_count, + count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count, t_unpred_seg_counts, hbs, bs, mi_row, mi_col); - count_segs(cpi, tile, mi + hbs, + count_segs(cm, xd, tile, mi + hbs, no_pred_segcounts, temporal_predictor_count, t_unpred_seg_counts, hbs, bs, mi_row, mi_col + hbs); } else { @@ -194,7 +191,7 @@ static void count_segs_sb(VP9_COMP *cpi, const TileInfo *const tile, const int mi_dc = hbs * (n & 1); const int mi_dr = hbs * (n >> 1); - count_segs_sb(cpi, tile, &mi[mi_dr * mis + mi_dc], + count_segs_sb(cm, xd, tile, &mi[mi_dr * mis + mi_dc], no_pred_segcounts, temporal_predictor_count, t_unpred_seg_counts, mi_row + mi_dr, mi_col + mi_dc, subsize); @@ -202,8 +199,7 @@ static void count_segs_sb(VP9_COMP *cpi, const TileInfo *const tile, } } -void vp9_choose_segmap_coding_method(VP9_COMP *cpi) { - VP9_COMMON *const cm = &cpi->common; +void vp9_choose_segmap_coding_method(VP9_COMMON *cm, MACROBLOCKD *xd) { struct segmentation *seg = &cm->seg; int no_pred_cost; @@ -237,7 +233,7 @@ void vp9_choose_segmap_coding_method(VP9_COMP *cpi) { MODE_INFO **mi = mi_ptr; for (mi_col = tile.mi_col_start; mi_col < tile.mi_col_end; mi_col += 8, mi += 8) - count_segs_sb(cpi, &tile, mi, no_pred_segcounts, + count_segs_sb(cm, xd, &tile, mi, no_pred_segcounts, temporal_predictor_count, t_unpred_seg_counts, mi_row, mi_col, BLOCK_64X64); } diff --git a/vp9/encoder/vp9_segmentation.h b/vp9/encoder/vp9_segmentation.h index 50dd562c8..8c6944ad1 100644 --- a/vp9/encoder/vp9_segmentation.h +++ b/vp9/encoder/vp9_segmentation.h @@ -42,7 +42,7 @@ void vp9_clear_segdata(struct segmentation *seg, void vp9_set_segment_data(struct segmentation *seg, signed char *feature_data, unsigned char abs_delta); -void vp9_choose_segmap_coding_method(VP9_COMP *cpi); +void vp9_choose_segmap_coding_method(VP9_COMMON *cm, MACROBLOCKD *xd); void vp9_reset_segment_features(struct segmentation *seg); diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c index 6ca1bc525..f2e99cf22 100644 --- a/vp9/encoder/vp9_speed_features.c +++ b/vp9/encoder/vp9_speed_features.c @@ -160,7 +160,7 @@ static void set_good_speed_feature(VP9_COMP *cpi, VP9_COMMON *cm, } static void set_rt_speed_feature(VP9_COMP *cpi, SPEED_FEATURES *sf, - int speed) { + int speed, vp9e_tune_content content) { VP9_COMMON *const cm = &cpi->common; const int frames_since_key = cm->frame_type == KEY_FRAME ? 0 : cpi->rc.frames_since_key; @@ -275,6 +275,13 @@ static void set_rt_speed_feature(VP9_COMP *cpi, SPEED_FEATURES *sf, } if (speed >= 6) { + if (content == VP9E_CONTENT_SCREEN) { + int i; + // Allow fancy modes at all sizes since SOURCE_VAR_BASED_PARTITION is used + for (i = 0; i < BLOCK_SIZES; ++i) + sf->inter_mode_mask[i] = INTER_ALL; + } + // Adaptively switch between SOURCE_VAR_BASED_PARTITION and FIXED_PARTITION. sf->partition_search_type = SOURCE_VAR_BASED_PARTITION; sf->search_type_check_frequency = 50; @@ -392,17 +399,17 @@ void vp9_set_speed_features(VP9_COMP *cpi) { set_good_speed_feature(cpi, cm, sf, oxcf->speed); break; case REALTIME: - set_rt_speed_feature(cpi, sf, oxcf->speed); + set_rt_speed_feature(cpi, sf, oxcf->speed, oxcf->content); break; } // Slow quant, dct and trellis not worthwhile for first pass // so make sure they are always turned off. - if (cpi->pass == 1) + if (oxcf->pass == 1) sf->optimize_coefficients = 0; // No recode for 1 pass. - if (cpi->pass == 0) { + if (oxcf->pass == 0) { sf->recode_loop = DISALLOW_RECODE; sf->optimize_coefficients = 0; } @@ -411,7 +418,7 @@ void vp9_set_speed_features(VP9_COMP *cpi) { cpi->find_fractional_mv_step = vp9_find_best_sub_pixel_tree; } - cpi->mb.optimize = sf->optimize_coefficients == 1 && cpi->pass != 1; + cpi->mb.optimize = sf->optimize_coefficients == 1 && oxcf->pass != 1; if (sf->disable_split_mask == DISABLE_ALL_SPLIT) sf->adaptive_pred_interp_filter = 0; diff --git a/vp9/encoder/vp9_subexp.c b/vp9/encoder/vp9_subexp.c index 9796d6476..530b5923b 100644 --- a/vp9/encoder/vp9_subexp.c +++ b/vp9/encoder/vp9_subexp.c @@ -16,7 +16,24 @@ #define vp9_cost_upd256 ((int)(vp9_cost_one(upd) - vp9_cost_zero(upd))) -static int update_bits[255]; +static const int update_bits[255] = { + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 0, +}; static int recenter_nonneg(int v, int m) { if (v > (m << 1)) @@ -61,18 +78,6 @@ static int remap_prob(int v, int m) { return i; } -static int count_term_subexp(int word) { - if (word < 16) - return 5; - if (word < 32) - return 6; - if (word < 64) - return 8; - if (word < 129) - return 10; - return 11; -} - static int prob_diff_update_cost(vp9_prob newp, vp9_prob oldp) { int delp = remap_prob(newp, oldp); return update_bits[delp] * 256; @@ -111,12 +116,6 @@ void vp9_write_prob_diff_update(vp9_writer *w, vp9_prob newp, vp9_prob oldp) { encode_term_subexp(w, delp); } -void vp9_compute_update_table() { - int i; - for (i = 0; i < 254; i++) - update_bits[i] = count_term_subexp(i); -} - int vp9_prob_diff_update_savings_search(const unsigned int *ct, vp9_prob oldp, vp9_prob *bestp, vp9_prob upd) { diff --git a/vp9/encoder/vp9_subexp.h b/vp9/encoder/vp9_subexp.h index 8e9c0c62a..8e02a1d0d 100644 --- a/vp9/encoder/vp9_subexp.h +++ b/vp9/encoder/vp9_subexp.h @@ -16,9 +16,6 @@ extern "C" { #endif -void vp9_compute_update_table(); - - void vp9_write_prob_diff_update(vp9_writer *w, vp9_prob newp, vp9_prob oldp); diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c index f8d1a83c3..bf949c456 100644 --- a/vp9/encoder/vp9_svc_layercontext.c +++ b/vp9/encoder/vp9_svc_layercontext.c @@ -35,6 +35,7 @@ void vp9_init_layer_context(VP9_COMP *const cpi) { RATE_CONTROL *const lrc = &lc->rc; int i; lc->current_video_frame_in_layer = 0; + lc->layer_size = 0; lrc->ni_av_qi = oxcf->worst_allowed_q; lrc->total_actual_bits = 0; lrc->total_target_vs_actual = 0; @@ -48,7 +49,6 @@ void vp9_init_layer_context(VP9_COMP *const cpi) { for (i = 0; i < RATE_FACTOR_LEVELS; ++i) { lrc->rate_correction_factors[i] = 1.0; } - lc->layer_size = 0; if (svc->number_temporal_layers > 1) { lc->target_bandwidth = oxcf->ts_target_bitrate[layer]; @@ -66,12 +66,17 @@ void vp9_init_layer_context(VP9_COMP *const cpi) { lc->alt_ref_idx = alt_ref_idx++; else lc->alt_ref_idx = -1; + lc->gold_ref_idx = -1; } lrc->buffer_level = vp9_rescale((int)(oxcf->starting_buffer_level_ms), lc->target_bandwidth, 1000); lrc->bits_off_target = lrc->buffer_level; } + + // Still have extra buffer for base layer golden frame + if (svc->number_spatial_layers > 1 && alt_ref_idx < REF_FRAMES) + svc->layer_context[0].gold_ref_idx = alt_ref_idx; } // Update the layer context from a change_config() call. @@ -217,8 +222,7 @@ void vp9_inc_frame_in_layer(SVC *svc) { } int vp9_is_upper_layer_key_frame(const VP9_COMP *const cpi) { - return cpi->use_svc && - cpi->svc.number_temporal_layers == 1 && + return is_spatial_svc(cpi) && cpi->svc.spatial_layer_id > 0 && cpi->svc.layer_context[cpi->svc.spatial_layer_id].is_key_frame; } @@ -266,21 +270,25 @@ static int copy_svc_params(VP9_COMP *const cpi, struct lookahead_entry *buf) { layer_param = &buf->svc_params[layer_id]; cpi->svc.spatial_layer_id = layer_param->spatial_layer; cpi->svc.temporal_layer_id = layer_param->temporal_layer; + cpi->ref_frame_flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG; + + lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id]; cpi->lst_fb_idx = cpi->svc.spatial_layer_id; if (cpi->svc.spatial_layer_id < 1) - cpi->gld_fb_idx = cpi->lst_fb_idx; + cpi->gld_fb_idx = lc->gold_ref_idx >= 0 ? + lc->gold_ref_idx : cpi->lst_fb_idx; else cpi->gld_fb_idx = cpi->svc.spatial_layer_id - 1; - lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id]; - if (lc->current_video_frame_in_layer == 0) { - if (cpi->svc.spatial_layer_id >= 2) + if (cpi->svc.spatial_layer_id >= 2) { cpi->alt_fb_idx = cpi->svc.spatial_layer_id - 2; - else + } else { cpi->alt_fb_idx = cpi->lst_fb_idx; + cpi->ref_frame_flags &= (~VP9_LAST_FLAG & ~VP9_ALT_FLAG); + } } else { if (cpi->oxcf.ss_play_alternate[cpi->svc.spatial_layer_id]) { cpi->alt_fb_idx = lc->alt_ref_idx; diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h index 7b533e467..801449b6f 100644 --- a/vp9/encoder/vp9_svc_layercontext.h +++ b/vp9/encoder/vp9_svc_layercontext.h @@ -31,6 +31,7 @@ typedef struct { vpx_svc_parameters_t svc_params_received; struct lookahead_entry *alt_ref_source; int alt_ref_idx; + int gold_ref_idx; int has_alt_frame; size_t layer_size; } LAYER_CONTEXT; diff --git a/vp9/encoder/vp9_temporal_filter.c b/vp9/encoder/vp9_temporal_filter.c index 6af8510a4..ce3b31138 100644 --- a/vp9/encoder/vp9_temporal_filter.c +++ b/vp9/encoder/vp9_temporal_filter.c @@ -405,7 +405,7 @@ static void adjust_arnr_filter(VP9_COMP *cpi, } // Adjustments for second level arf in multi arf case. - if (cpi->pass == 2 && cpi->multi_arf_allowed) { + if (cpi->oxcf.pass == 2 && cpi->multi_arf_allowed) { const GF_GROUP *const gf_group = &cpi->twopass.gf_group; if (gf_group->rf_level[gf_group->index] != GF_ARF_STD) { cpi->active_arnr_strength >>= 1; @@ -442,7 +442,7 @@ void vp9_temporal_filter(VP9_COMP *cpi, int distance) { } // Setup scaling factors. Scaling on each of the arnr frames is not supported - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { + if (is_spatial_svc(cpi)) { // In spatial svc the scaling factors might be less then 1/2. So we will use // non-normative scaling. int frame_used = 0; diff --git a/vp9/encoder/x86/vp9_sad4d_intrin_avx2.c b/vp9/encoder/x86/vp9_sad4d_intrin_avx2.c index f31b176e5..1feed6256 100644 --- a/vp9/encoder/x86/vp9_sad4d_intrin_avx2.c +++ b/vp9/encoder/x86/vp9_sad4d_intrin_avx2.c @@ -31,7 +31,7 @@ void vp9_sad32x32x4d_avx2(uint8_t *src, sum_ref3 = _mm256_set1_epi16(0); for (i = 0; i < 32 ; i++) { // load src and all refs - src_reg = _mm256_load_si256((__m256i *)(src)); + src_reg = _mm256_loadu_si256((__m256i *)(src)); ref0_reg = _mm256_loadu_si256((__m256i *) (ref0)); ref1_reg = _mm256_loadu_si256((__m256i *) (ref1)); ref2_reg = _mm256_loadu_si256((__m256i *) (ref2)); @@ -103,8 +103,8 @@ void vp9_sad64x64x4d_avx2(uint8_t *src, sum_ref3 = _mm256_set1_epi16(0); for (i = 0; i < 64 ; i++) { // load 64 bytes from src and all refs - src_reg = _mm256_load_si256((__m256i *)(src)); - srcnext_reg = _mm256_load_si256((__m256i *)(src + 32)); + src_reg = _mm256_loadu_si256((__m256i *)(src)); + srcnext_reg = _mm256_loadu_si256((__m256i *)(src + 32)); ref0_reg = _mm256_loadu_si256((__m256i *) (ref0)); ref0next_reg = _mm256_loadu_si256((__m256i *) (ref0 + 32)); ref1_reg = _mm256_loadu_si256((__m256i *) (ref1)); diff --git a/vp9/encoder/x86/vp9_subpel_variance_impl_intrin_avx2.c b/vp9/encoder/x86/vp9_subpel_variance_impl_intrin_avx2.c index 34ed1867f..9aa4da962 100644 --- a/vp9/encoder/x86/vp9_subpel_variance_impl_intrin_avx2.c +++ b/vp9/encoder/x86/vp9_subpel_variance_impl_intrin_avx2.c @@ -67,7 +67,7 @@ DECLARE_ALIGNED(32, static const uint8_t, bilinear_filters_avx2[512]) = { #define LOAD_SRC_DST \ /* load source and destination */ \ src_reg = _mm256_loadu_si256((__m256i const *) (src)); \ - dst_reg = _mm256_load_si256((__m256i const *) (dst)); + dst_reg = _mm256_loadu_si256((__m256i const *) (dst)); #define AVG_NEXT_SRC(src_reg, size_stride) \ src_next_reg = _mm256_loadu_si256((__m256i const *) \ diff --git a/vp9/vp9_common.mk b/vp9/vp9_common.mk index 81fe6a620..8e3e88522 100644 --- a/vp9/vp9_common.mk +++ b/vp9/vp9_common.mk @@ -67,7 +67,6 @@ VP9_COMMON_SRCS-yes += common/vp9_common_data.h VP9_COMMON_SRCS-yes += common/vp9_scan.c VP9_COMMON_SRCS-yes += common/vp9_scan.h -VP9_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/vp9_postproc_x86.h VP9_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/vp9_asm_stubs.c VP9_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/vp9_loopfilter_intrin_sse2.c VP9_COMMON_SRCS-$(HAVE_AVX2) += common/x86/vp9_loopfilter_intrin_avx2.c diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index af32eb3e3..35ee1aee6 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c @@ -40,6 +40,7 @@ struct vp9_extracfg { AQ_MODE aq_mode; unsigned int frame_periodic_boost; BIT_DEPTH bit_depth; + vp9e_tune_content content; }; struct extraconfig_map { @@ -70,6 +71,7 @@ static const struct extraconfig_map extracfg_map[] = { NO_AQ, // aq_mode 0, // frame_periodic_delta_q BITS_8, // Bit depth + VP9E_CONTENT_DEFAULT // content } } }; @@ -219,6 +221,8 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK_HI(extra_cfg, arnr_strength, 6); RANGE_CHECK(extra_cfg, arnr_type, 1, 3); RANGE_CHECK(extra_cfg, cq_level, 0, 63); + RANGE_CHECK(extra_cfg, content, + VP9E_CONTENT_DEFAULT, VP9E_CONTENT_INVALID - 1); // TODO(yaowu): remove this when ssim tuning is implemented for vp9 if (extra_cfg->tuning == VP8_TUNE_SSIM) @@ -297,6 +301,7 @@ static vpx_codec_err_t validate_img(vpx_codec_alg_priv_t *ctx, default: ERROR("Invalid image format. Only YV12, I420, I422, I444 images are " "supported."); + break; } if (img->d_w != ctx->cfg.g_w || img->d_h != ctx->cfg.g_h) @@ -311,7 +316,7 @@ static int get_image_bps(const vpx_image_t *img) { case VPX_IMG_FMT_I420: return 12; case VPX_IMG_FMT_I422: return 16; case VPX_IMG_FMT_I444: return 24; - default: assert(0 && "Invalid image format"); + default: assert(0 && "Invalid image format"); break; } return 0; } @@ -332,12 +337,15 @@ static vpx_codec_err_t set_encoder_config( switch (cfg->g_pass) { case VPX_RC_ONE_PASS: oxcf->mode = ONE_PASS_GOOD; + oxcf->pass = 0; break; case VPX_RC_FIRST_PASS: oxcf->mode = TWO_PASS_FIRST; + oxcf->pass = 1; break; case VPX_RC_LAST_PASS: oxcf->mode = TWO_PASS_SECOND_BEST; + oxcf->pass = 2; break; } @@ -396,6 +404,7 @@ static vpx_codec_err_t set_encoder_config( oxcf->arnr_type = extra_cfg->arnr_type; oxcf->tuning = extra_cfg->tuning; + oxcf->content = extra_cfg->content; oxcf->tile_columns = extra_cfg->tile_columns; oxcf->tile_rows = extra_cfg->tile_rows; @@ -798,6 +807,20 @@ static int write_superframe_index(vpx_codec_alg_priv_t *ctx) { return index_sz; } +// vp9 uses 10,000,000 ticks/second as time stamp +#define TICKS_PER_SEC 10000000 + +static int64_t timebase_units_to_ticks(const vpx_rational_t *timebase, + int64_t n) { + return n * TICKS_PER_SEC * timebase->num / timebase->den; +} + +static int64_t ticks_to_timebase_units(const vpx_rational_t *timebase, + int64_t n) { + const int64_t round = TICKS_PER_SEC * timebase->num / 2 - 1; + return (n * timebase->den + round) / timebase->num / TICKS_PER_SEC; +} + static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx, const vpx_image_t *img, vpx_codec_pts_t pts, @@ -805,6 +828,7 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx, vpx_enc_frame_flags_t flags, unsigned long deadline) { vpx_codec_err_t res = VPX_CODEC_OK; + const vpx_rational_t *const timebase = &ctx->cfg.g_timebase; if (img != NULL) { res = validate_img(ctx, img); @@ -850,7 +874,9 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx, if (res == VPX_CODEC_OK && ctx->cpi != NULL) { unsigned int lib_flags = 0; YV12_BUFFER_CONFIG sd; - int64_t dst_time_stamp, dst_end_time_stamp; + int64_t dst_time_stamp = timebase_units_to_ticks(timebase, pts); + int64_t dst_end_time_stamp = + timebase_units_to_ticks(timebase, pts + duration); size_t size, cx_data_sz; unsigned char *cx_data; @@ -858,12 +884,6 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx, if (ctx->base.init_flags & VPX_CODEC_USE_PSNR) ((VP9_COMP *)ctx->cpi)->b_calculate_psnr = 1; - /* vp9 use 10,000,000 ticks/second as time stamp */ - dst_time_stamp = (pts * 10000000 * ctx->cfg.g_timebase.num) - / ctx->cfg.g_timebase.den; - dst_end_time_stamp = (pts + duration) * 10000000 * ctx->cfg.g_timebase.num / - ctx->cfg.g_timebase.den; - if (img != NULL) { res = image2yuvconfig(img, &sd); @@ -900,19 +920,18 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx, cx_data, &dst_time_stamp, &dst_end_time_stamp, !img)) { if (size) { - vpx_codec_pts_t round, delta; - vpx_codec_cx_pkt_t pkt; VP9_COMP *const cpi = (VP9_COMP *)ctx->cpi; + vpx_codec_cx_pkt_t pkt; #if CONFIG_SPATIAL_SVC - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) + if (is_spatial_svc(cpi)) cpi->svc.layer_context[cpi->svc.spatial_layer_id].layer_size += size; #endif // Pack invisible frames with the next visible frame if (cpi->common.show_frame == 0 #if CONFIG_SPATIAL_SVC - || (cpi->use_svc && cpi->svc.number_temporal_layers == 1 && + || (is_spatial_svc(cpi) && cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1) #endif ) { @@ -927,20 +946,16 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx, } // Add the frame packet to the list of returned packets. - round = (vpx_codec_pts_t)10000000 * ctx->cfg.g_timebase.num / 2 - 1; - delta = (dst_end_time_stamp - dst_time_stamp); pkt.kind = VPX_CODEC_CX_FRAME_PKT; - pkt.data.frame.pts = - (dst_time_stamp * ctx->cfg.g_timebase.den + round) - / ctx->cfg.g_timebase.num / 10000000; - pkt.data.frame.duration = (unsigned long) - ((delta * ctx->cfg.g_timebase.den + round) - / ctx->cfg.g_timebase.num / 10000000); + pkt.data.frame.pts = ticks_to_timebase_units(timebase, dst_time_stamp); + pkt.data.frame.duration = + (unsigned long)ticks_to_timebase_units(timebase, + dst_end_time_stamp - dst_time_stamp); pkt.data.frame.flags = lib_flags << 16; if (lib_flags & FRAMEFLAGS_KEY #if CONFIG_SPATIAL_SVC - || (cpi->use_svc && cpi->svc.number_temporal_layers == 1 && + || (is_spatial_svc(cpi) && cpi->svc.layer_context[0].is_key_frame) #endif ) @@ -953,9 +968,8 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx, // prior PTS so that if a decoder uses pts to schedule when // to do this, we start right after last frame was decoded. // Invisible frames have no duration. - pkt.data.frame.pts = ((cpi->last_time_stamp_seen - * ctx->cfg.g_timebase.den + round) - / ctx->cfg.g_timebase.num / 10000000) + 1; + pkt.data.frame.pts = + ticks_to_timebase_units(timebase, cpi->last_time_stamp_seen) + 1; pkt.data.frame.duration = 0; } @@ -982,7 +996,7 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx, cx_data += size; cx_data_sz -= size; #if CONFIG_SPATIAL_SVC - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { + if (is_spatial_svc(cpi)) { vpx_codec_cx_pkt_t pkt = {0}; int i; pkt.kind = VPX_CODEC_SPATIAL_SVC_LAYER_SIZES; @@ -1042,9 +1056,9 @@ static vpx_codec_err_t ctrl_get_reference(vpx_codec_alg_priv_t *ctx, vp9_ref_frame_t *const frame = va_arg(args, vp9_ref_frame_t *); if (frame != NULL) { - YV12_BUFFER_CONFIG *fb; + YV12_BUFFER_CONFIG *fb = get_ref_frame(&ctx->cpi->common, frame->idx); + if (fb == NULL) return VPX_CODEC_ERROR; - vp9_get_reference_enc(ctx->cpi, frame->idx, &fb); yuvconfig2image(&frame->img, fb, NULL); return VPX_CODEC_OK; } else { @@ -1212,6 +1226,13 @@ static vpx_codec_err_t ctrl_set_svc_parameters(vpx_codec_alg_priv_t *ctx, return VPX_CODEC_OK; } +static vpx_codec_err_t ctrl_set_tune_content(vpx_codec_alg_priv_t *ctx, + va_list args) { + struct vp9_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.content = CAST(VP9E_SET_TUNE_CONTENT, 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}, @@ -1244,6 +1265,7 @@ static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { {VP9E_SET_SVC, ctrl_set_svc}, {VP9E_SET_SVC_PARAMETERS, ctrl_set_svc_parameters}, {VP9E_SET_SVC_LAYER_ID, ctrl_set_svc_layer_id}, + {VP9E_SET_TUNE_CONTENT, ctrl_set_tune_content}, // Getters {VP8E_GET_LAST_QUANTIZER, ctrl_get_quantizer}, @@ -1329,8 +1351,6 @@ CODEC_INTERFACE(vpx_codec_vp9_cx) = { encoder_init, // vpx_codec_init_fn_t encoder_destroy, // vpx_codec_destroy_fn_t encoder_ctrl_maps, // vpx_codec_ctrl_fn_map_t - NOT_IMPLEMENTED, // vpx_codec_get_mmap_fn_t - NOT_IMPLEMENTED, // vpx_codec_set_mmap_fn_t { // NOLINT NOT_IMPLEMENTED, // vpx_codec_peek_si_fn_t NOT_IMPLEMENTED, // vpx_codec_get_si_fn_t diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c index c52884084..bc7801152 100644 --- a/vp9/vp9_dx_iface.c +++ b/vp9/vp9_dx_iface.c @@ -40,6 +40,7 @@ struct vpx_codec_alg_priv { void *decrypt_state; vpx_image_t img; int img_avail; + int flushed; int invert_tile_order; int frame_parallel_decode; // frame-based threading. @@ -69,6 +70,7 @@ static vpx_codec_err_t decoder_init(vpx_codec_ctx_t *ctx, ctx->priv->alg_priv = alg_priv; ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si); ctx->priv->init_flags = ctx->init_flags; + ctx->priv->alg_priv->flushed = 0; ctx->priv->alg_priv->frame_parallel_decode = (ctx->init_flags & VPX_CODEC_USE_FRAME_THREADING); @@ -96,6 +98,30 @@ static vpx_codec_err_t decoder_destroy(vpx_codec_alg_priv_t *ctx) { return VPX_CODEC_OK; } +static int parse_bitdepth_colorspace_sampling( + BITSTREAM_PROFILE profile, struct vp9_read_bit_buffer *rb) { + const int sRGB = 7; + int colorspace; + if (profile >= PROFILE_2) + rb->bit_offset += 1; // Bit-depth 10 or 12. + colorspace = vp9_rb_read_literal(rb, 3); + if (colorspace != sRGB) { + rb->bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range. + if (profile == PROFILE_1 || profile == PROFILE_3) { + rb->bit_offset += 2; // subsampling x/y. + rb->bit_offset += 1; // unused. + } + } else { + if (profile == PROFILE_1 || profile == PROFILE_3) { + rb->bit_offset += 1; // unused + } else { + // RGB is only available in version 1. + return 0; + } + } + return 1; +} + static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data, unsigned int data_sz, vpx_codec_stream_info_t *si, @@ -142,37 +168,24 @@ static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data, error_resilient = vp9_rb_read_bit(&rb); if (si->is_kf) { - const int sRGB = 7; - int colorspace; - if (!vp9_read_sync_code(&rb)) return VPX_CODEC_UNSUP_BITSTREAM; - if (profile > PROFILE_1) - rb.bit_offset += 1; // Bit-depth 10 or 12 - colorspace = vp9_rb_read_literal(&rb, 3); - if (colorspace != sRGB) { - rb.bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range - if (profile == PROFILE_1 || profile == PROFILE_3) { - rb.bit_offset += 2; // subsampling x/y - rb.bit_offset += 1; // unused - } - } else { - if (profile == PROFILE_1 || profile == PROFILE_3) { - rb.bit_offset += 1; // unused - } else { - // RGB is only available in version 1 - return VPX_CODEC_UNSUP_BITSTREAM; - } - } + if (!parse_bitdepth_colorspace_sampling(profile, &rb)) + return VPX_CODEC_UNSUP_BITSTREAM; vp9_read_frame_size(&rb, (int *)&si->w, (int *)&si->h); } else { intra_only_flag = show_frame ? 0 : vp9_rb_read_bit(&rb); + rb.bit_offset += error_resilient ? 0 : 2; // reset_frame_context if (intra_only_flag) { if (!vp9_read_sync_code(&rb)) return VPX_CODEC_UNSUP_BITSTREAM; + if (profile > PROFILE_0) { + if (!parse_bitdepth_colorspace_sampling(profile, &rb)) + return VPX_CODEC_UNSUP_BITSTREAM; + } rb.bit_offset += REF_FRAMES; // refresh_frame_flags vp9_read_frame_size(&rb, (int *)&si->w, (int *)&si->h); } @@ -403,8 +416,13 @@ static vpx_codec_err_t decoder_decode(vpx_codec_alg_priv_t *ctx, uint32_t frame_sizes[8]; int frame_count; - if (data == NULL || data_sz == 0) - return VPX_CODEC_INVALID_PARAM; + if (data == NULL && data_sz == 0) { + ctx->flushed = 1; + return VPX_CODEC_OK; + } + + // Reset flushed when receiving a valid frame. + ctx->flushed = 0; res = parse_superframe_index(data, data_sz, frame_sizes, &frame_count, ctx->decrypt_cb, ctx->decrypt_state); @@ -565,9 +583,9 @@ static vpx_codec_err_t ctrl_get_reference(vpx_codec_alg_priv_t *ctx, vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *); if (data) { - YV12_BUFFER_CONFIG* fb; + YV12_BUFFER_CONFIG* fb = get_ref_frame(&ctx->pbi->common, data->idx); + if (fb == NULL) return VPX_CODEC_ERROR; - vp9_get_reference_dec(ctx->pbi, data->idx, &fb); yuvconfig2image(&data->img, fb, NULL); return VPX_CODEC_OK; } else { @@ -697,8 +715,6 @@ CODEC_INTERFACE(vpx_codec_vp9_dx) = { decoder_init, // vpx_codec_init_fn_t decoder_destroy, // vpx_codec_destroy_fn_t decoder_ctrl_maps, // vpx_codec_ctrl_fn_map_t - NOT_IMPLEMENTED, // vpx_codec_get_mmap_fn_t - NOT_IMPLEMENTED, // vpx_codec_set_mmap_fn_t { // NOLINT decoder_peek_si, // vpx_codec_peek_si_fn_t decoder_get_si, // vpx_codec_get_si_fn_t diff --git a/vpx/internal/vpx_codec_internal.h b/vpx/internal/vpx_codec_internal.h index cdda3406b..f84bfedcf 100644 --- a/vpx/internal/vpx_codec_internal.h +++ b/vpx/internal/vpx_codec_internal.h @@ -248,37 +248,6 @@ typedef vpx_codec_err_t (*vpx_codec_set_fb_fn_t)( vpx_get_frame_buffer_cb_fn_t cb_get, vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv); -/*\brief eXternal Memory Allocation memory map get iterator - * - * Iterates over a list of the memory maps requested by the decoder. The - * iterator storage should be initialized to NULL to start the iteration. - * Iteration is complete when this function returns NULL. - * - * \param[in out] iter Iterator storage, initialized to NULL - * - * \return Returns a pointer to an memory segment descriptor, or NULL to - * indicate end-of-list. - */ -typedef vpx_codec_err_t (*vpx_codec_get_mmap_fn_t)(const vpx_codec_ctx_t *ctx, - vpx_codec_mmap_t *mmap, - vpx_codec_iter_t *iter); - - -/*\brief eXternal Memory Allocation memory map set iterator - * - * Sets a memory descriptor inside the decoder instance. - * - * \param[in] ctx Pointer to this instance's context - * \param[in] mmap Memory map to store. - * - * \retval #VPX_CODEC_OK - * The memory map was accepted and stored. - * \retval #VPX_CODEC_MEM_ERROR - * The memory map was rejected. - */ -typedef vpx_codec_err_t (*vpx_codec_set_mmap_fn_t)(vpx_codec_ctx_t *ctx, - const vpx_codec_mmap_t *mmap); - typedef vpx_codec_err_t (*vpx_codec_encode_fn_t)(vpx_codec_alg_priv_t *ctx, const vpx_image_t *img, @@ -330,8 +299,6 @@ struct vpx_codec_iface { vpx_codec_init_fn_t init; /**< \copydoc ::vpx_codec_init_fn_t */ vpx_codec_destroy_fn_t destroy; /**< \copydoc ::vpx_codec_destroy_fn_t */ vpx_codec_ctrl_fn_map_t *ctrl_maps; /**< \copydoc ::vpx_codec_ctrl_fn_map_t */ - vpx_codec_get_mmap_fn_t get_mmap; /**< \copydoc ::vpx_codec_get_mmap_fn_t */ - vpx_codec_set_mmap_fn_t set_mmap; /**< \copydoc ::vpx_codec_set_mmap_fn_t */ struct vpx_codec_dec_iface { vpx_codec_peek_si_fn_t peek_si; /**< \copydoc ::vpx_codec_peek_si_fn_t */ vpx_codec_get_si_fn_t get_si; /**< \copydoc ::vpx_codec_get_si_fn_t */ @@ -487,31 +454,6 @@ static void vpx_internal_error(struct vpx_internal_error_info *info, longjmp(info->jmp, info->error_code); } -//------------------------------------------------------------------------------ -// mmap interface - -typedef struct { - unsigned int id; - unsigned long sz; - unsigned int align; - unsigned int flags; - unsigned long (*calc_sz)(const vpx_codec_dec_cfg_t *, vpx_codec_flags_t); -} mem_req_t; - -// Allocates mmap.priv and sets mmap.base based on mmap.sz/align/flags -// requirements. -// Returns #VPX_CODEC_OK on success, #VPX_CODEC_MEM_ERROR otherwise. -vpx_codec_err_t vpx_mmap_alloc(vpx_codec_mmap_t *mmap); - -// Frees mmap.base allocated by a call to vpx_mmap_alloc(). -void vpx_mmap_dtor(vpx_codec_mmap_t *mmap); - -// Checks each mmap has the size requirement specificied by mem_reqs. -// Returns #VPX_CODEC_OK on success, #VPX_CODEC_MEM_ERROR otherwise. -vpx_codec_err_t vpx_validate_mmaps(const vpx_codec_stream_info_t *si, - const vpx_codec_mmap_t *mmaps, - const mem_req_t *mem_reqs, int nreqs, - vpx_codec_flags_t init_flags); #ifdef __cplusplus } // extern "C" #endif diff --git a/vpx/src/svc_encodeframe.c b/vpx/src/svc_encodeframe.c index 93e86e319..7828615b2 100644 --- a/vpx/src/svc_encodeframe.c +++ b/vpx/src/svc_encodeframe.c @@ -510,8 +510,10 @@ vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, } } +#if CONFIG_SPATIAL_SVC for (i = 0; i < si->layers; ++i) enc_cfg->ss_enable_auto_alt_ref[i] = si->enable_auto_alt_ref[i]; +#endif // modify encoder configuration enc_cfg->ss_number_layers = si->layers; @@ -709,12 +711,14 @@ vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, si->rc_stats_buf_used += cx_pkt->data.twopass_stats.sz; break; } +#if CONFIG_SPATIAL_SVC case VPX_CODEC_SPATIAL_SVC_LAYER_SIZES: { int i; for (i = 0; i < si->layers; ++i) si->bytes_sum[i] += cx_pkt->data.layer_sizes[i]; break; } +#endif default: { break; } diff --git a/vpx/src/vpx_codec.c b/vpx/src/vpx_codec.c index 6fb8f522d..9f7af9f83 100644 --- a/vpx/src/vpx_codec.c +++ b/vpx/src/vpx_codec.c @@ -134,51 +134,3 @@ vpx_codec_err_t vpx_codec_control_(vpx_codec_ctx_t *ctx, return SAVE_STATUS(ctx, res); } - -//------------------------------------------------------------------------------ -// mmap interface - -vpx_codec_err_t vpx_mmap_alloc(vpx_codec_mmap_t *mmap) { - unsigned int align = mmap->align ? mmap->align - 1 : 0; - - if (mmap->flags & VPX_CODEC_MEM_ZERO) - mmap->priv = calloc(1, mmap->sz + align); - else - mmap->priv = malloc(mmap->sz + align); - - if (mmap->priv == NULL) return VPX_CODEC_MEM_ERROR; - mmap->base = (void *)((((uintptr_t)mmap->priv) + align) & ~(uintptr_t)align); - mmap->dtor = vpx_mmap_dtor; - return VPX_CODEC_OK; -} - -void vpx_mmap_dtor(vpx_codec_mmap_t *mmap) { - free(mmap->priv); -} - -vpx_codec_err_t vpx_validate_mmaps(const vpx_codec_stream_info_t *si, - const vpx_codec_mmap_t *mmaps, - const mem_req_t *mem_reqs, int nreqs, - vpx_codec_flags_t init_flags) { - int i; - - for (i = 0; i < nreqs - 1; ++i) { - /* Ensure the segment has been allocated */ - if (mmaps[i].base == NULL) { - return VPX_CODEC_MEM_ERROR; - } - - /* Verify variable size segment is big enough for the current si. */ - if (mem_reqs[i].calc_sz != NULL) { - vpx_codec_dec_cfg_t cfg; - - cfg.w = si->w; - cfg.h = si->h; - - if (mmaps[i].sz < mem_reqs[i].calc_sz(&cfg, init_flags)) { - return VPX_CODEC_MEM_ERROR; - } - } - } - return VPX_CODEC_OK; -} diff --git a/vpx/src/vpx_decoder.c b/vpx/src/vpx_decoder.c index 63fdaf308..276238bdf 100644 --- a/vpx/src/vpx_decoder.c +++ b/vpx/src/vpx_decoder.c @@ -183,50 +183,6 @@ vpx_codec_err_t vpx_codec_register_put_slice_cb(vpx_codec_ctx_t *ctx return SAVE_STATUS(ctx, res); } - -vpx_codec_err_t vpx_codec_get_mem_map(vpx_codec_ctx_t *ctx, - vpx_codec_mmap_t *mmap, - vpx_codec_iter_t *iter) { - vpx_codec_err_t res = VPX_CODEC_OK; - - if (!ctx || !mmap || !iter || !ctx->iface) - res = VPX_CODEC_INVALID_PARAM; - else if (!(ctx->iface->caps & VPX_CODEC_CAP_XMA)) - res = VPX_CODEC_ERROR; - else - res = ctx->iface->get_mmap(ctx, mmap, iter); - - return SAVE_STATUS(ctx, res); -} - - -vpx_codec_err_t vpx_codec_set_mem_map(vpx_codec_ctx_t *ctx, - vpx_codec_mmap_t *mmap, - unsigned int num_maps) { - vpx_codec_err_t res = VPX_CODEC_MEM_ERROR; - - if (!ctx || !mmap || !ctx->iface) - res = VPX_CODEC_INVALID_PARAM; - else if (!(ctx->iface->caps & VPX_CODEC_CAP_XMA)) - res = VPX_CODEC_ERROR; - else { - unsigned int i; - - for (i = 0; i < num_maps; i++, mmap++) { - if (!mmap->base) - break; - - /* Everything look ok, set the mmap in the decoder */ - res = ctx->iface->set_mmap(ctx, mmap); - - if (res) - break; - } - } - - return SAVE_STATUS(ctx, res); -} - vpx_codec_err_t vpx_codec_set_frame_buffer_functions( vpx_codec_ctx_t *ctx, vpx_get_frame_buffer_cb_fn_t cb_get, vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv) { diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h index 36c587f61..796a7a1c2 100644 --- a/vpx/vp8cx.h +++ b/vpx/vp8cx.h @@ -205,7 +205,8 @@ enum vp8e_enc_control_id { * layer and 0..#vpx_codec_enc_cfg::ts_number_layers for * temporal layer. */ - VP9E_SET_SVC_LAYER_ID + VP9E_SET_SVC_LAYER_ID, + VP9E_SET_TUNE_CONTENT }; /*!\brief vpx 1-D scaling mode @@ -277,6 +278,12 @@ typedef enum { VP8_EIGHT_TOKENPARTITION = 3 } vp8e_token_partitions; +/*!brief VP9 encoder content type */ +typedef enum { + VP9E_CONTENT_DEFAULT, + VP9E_CONTENT_SCREEN, + VP9E_CONTENT_INVALID +} vp9e_tune_content; /*!\brief VP8 model tuning parameters * @@ -370,6 +377,7 @@ VPX_CTRL_USE_TYPE(VP9E_SET_AQ_MODE, unsigned int) VPX_CTRL_USE_TYPE(VP9E_SET_FRAME_PERIODIC_BOOST, unsigned int) +VPX_CTRL_USE_TYPE(VP9E_SET_TUNE_CONTENT, int) /* vp9e_tune_content */ /*! @} - end defgroup vp8_encoder */ #ifdef __cplusplus } // extern "C" diff --git a/vpx/vpx_codec.h b/vpx/vpx_codec.h index 45e702354..04f93020f 100644 --- a/vpx/vpx_codec.h +++ b/vpx/vpx_codec.h @@ -471,94 +471,6 @@ extern "C" { #endif - - /*!\defgroup cap_xma External Memory Allocation Functions - * - * The following functions are required to be implemented for all codecs - * that advertise the VPX_CODEC_CAP_XMA capability. Calling these functions - * for codecs that don't advertise this capability will result in an error - * code being returned, usually VPX_CODEC_INCAPABLE - * @{ - */ - - - /*!\brief Memory Map Entry - * - * This structure is used to contain the properties of a memory segment. It - * is populated by the codec in the request phase, and by the calling - * application once the requested allocation has been performed. - */ - typedef struct vpx_codec_mmap { - /* - * The following members are set by the codec when requesting a segment - */ - unsigned int id; /**< identifier for the segment's contents */ - unsigned long sz; /**< size of the segment, in bytes */ - unsigned int align; /**< required alignment of the segment, in bytes */ - unsigned int flags; /**< bitfield containing segment properties */ -#define VPX_CODEC_MEM_ZERO 0x1 /**< Segment must be zeroed by allocation */ -#define VPX_CODEC_MEM_WRONLY 0x2 /**< Segment need not be readable */ -#define VPX_CODEC_MEM_FAST 0x4 /**< Place in fast memory, if available */ - - /* The following members are to be filled in by the allocation function */ - void *base; /**< pointer to the allocated segment */ - void (*dtor)(struct vpx_codec_mmap *map); /**< destructor to call */ - void *priv; /**< allocator private storage */ - } vpx_codec_mmap_t; /**< alias for struct vpx_codec_mmap */ - - - /*!\brief Iterate over the list of segments to allocate. - * - * Iterates over a list of the segments to allocate. The iterator storage - * should be initialized to NULL to start the iteration. Iteration is complete - * when this function returns VPX_CODEC_LIST_END. The amount of memory needed to - * allocate is dependent upon the size of the encoded stream. In cases where the - * stream is not available at allocation time, a fixed size must be requested. - * The codec will not be able to operate on streams larger than the size used at - * allocation time. - * - * \param[in] ctx Pointer to this instance's context. - * \param[out] mmap Pointer to the memory map entry to populate. - * \param[in,out] iter Iterator storage, initialized to NULL - * - * \retval #VPX_CODEC_OK - * The memory map entry was populated. - * \retval #VPX_CODEC_ERROR - * Codec does not support XMA mode. - * \retval #VPX_CODEC_MEM_ERROR - * Unable to determine segment size from stream info. - */ - vpx_codec_err_t vpx_codec_get_mem_map(vpx_codec_ctx_t *ctx, - vpx_codec_mmap_t *mmap, - vpx_codec_iter_t *iter); - - - /*!\brief Identify allocated segments to codec instance - * - * Stores a list of allocated segments in the codec. Segments \ref MUST be - * passed in the order they are read from vpx_codec_get_mem_map(), but may be - * passed in groups of any size. Segments \ref MUST be set only once. The - * allocation function \ref MUST ensure that the vpx_codec_mmap_t::base member - * is non-NULL. If the segment requires cleanup handling (e.g., calling free() - * or close()) then the vpx_codec_mmap_t::dtor member \ref MUST be populated. - * - * \param[in] ctx Pointer to this instance's context. - * \param[in] mmaps Pointer to the first memory map entry in the list. - * \param[in] num_maps Number of entries being set at this time - * - * \retval #VPX_CODEC_OK - * The segment was stored in the codec context. - * \retval #VPX_CODEC_INCAPABLE - * Codec does not support XMA mode. - * \retval #VPX_CODEC_MEM_ERROR - * Segment base address was not set, or segment was already stored. - - */ - vpx_codec_err_t vpx_codec_set_mem_map(vpx_codec_ctx_t *ctx, - vpx_codec_mmap_t *mmaps, - unsigned int num_maps); - - /*!@} - end defgroup cap_xma*/ /*!@} - end defgroup codec*/ #ifdef __cplusplus } @@ -425,6 +425,7 @@ void generate_filename(const char *pattern, char *out, size_t q_len, break; default: die("Unrecognized pattern %%%c\n", p[1]); + break; } pat_len = strlen(q); @@ -511,7 +512,7 @@ int main_loop(int argc, const char **argv_) { int use_y4m = 1; int opt_yv12 = 0; int opt_i420 = 0; - vpx_codec_dec_cfg_t cfg = {0}; + vpx_codec_dec_cfg_t cfg = {0, 0, 0}; #if CONFIG_VP8_DECODER vp8_postproc_cfg_t vp8_pp_cfg = {0}; int vp8_dbg_color_ref_frame = 0; @@ -525,7 +526,7 @@ int main_loop(int argc, const char **argv_) { vpx_image_t *scaled_img = NULL; int frame_avail, got_data; int num_external_frame_buffers = 0; - struct ExternalFrameBufferList ext_fb_list = {0}; + struct ExternalFrameBufferList ext_fb_list = {0, NULL}; const char *outfile_pattern = NULL; char outfile_name[PATH_MAX] = {0}; @@ -534,10 +535,10 @@ int main_loop(int argc, const char **argv_) { MD5Context md5_ctx; unsigned char md5_digest[16]; - struct VpxDecInputContext input = {0}; - struct VpxInputContext vpx_input_ctx = {0}; + struct VpxDecInputContext input = {NULL, NULL}; + struct VpxInputContext vpx_input_ctx; #if CONFIG_WEBM_IO - struct WebmInputContext webm_ctx = {0}; + struct WebmInputContext webm_ctx; input.webm_ctx = &webm_ctx; #endif input.vpx_input_ctx = &vpx_input_ctx; |