diff options
-rwxr-xr-x | configure | 5 | ||||
-rw-r--r-- | test/decode_test_driver.cc | 31 | ||||
-rw-r--r-- | vp8/encoder/onyx_if.c | 13 | ||||
-rw-r--r-- | vp8/vp8_dx_iface.c | 9 | ||||
-rw-r--r-- | vp9/common/vp9_idct.h | 10 | ||||
-rw-r--r-- | vp9/common/x86/vp9_postproc_x86.h | 72 | ||||
-rw-r--r-- | vp9/encoder/vp9_bitstream.c | 28 | ||||
-rw-r--r-- | vp9/encoder/vp9_bitstream.h | 14 | ||||
-rw-r--r-- | vp9/encoder/vp9_encodeframe.c | 116 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.c | 58 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.h | 9 | ||||
-rw-r--r-- | vp9/encoder/vp9_firstpass.c | 31 | ||||
-rw-r--r-- | vp9/encoder/vp9_ratectrl.c | 4 | ||||
-rw-r--r-- | vp9/encoder/vp9_rd.c | 6 | ||||
-rw-r--r-- | vp9/encoder/vp9_speed_features.c | 11 | ||||
-rw-r--r-- | vp9/encoder/vp9_subexp.c | 37 | ||||
-rw-r--r-- | vp9/encoder/vp9_subexp.h | 3 | ||||
-rw-r--r-- | vp9/encoder/vp9_svc_layercontext.c | 3 | ||||
-rw-r--r-- | vp9/encoder/vp9_temporal_filter.c | 2 | ||||
-rw-r--r-- | vp9/vp9_common.mk | 1 | ||||
-rw-r--r-- | vp9/vp9_cx_iface.c | 66 | ||||
-rw-r--r-- | vp9/vp9_dx_iface.c | 11 | ||||
-rw-r--r-- | vpx/vp8cx.h | 10 |
23 files changed, 328 insertions, 222 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/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index 298f50f65..91b9138bf 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -2762,6 +2762,19 @@ static int resize_key_frame(VP8_COMP *cpi) cm->Height = new_height; vp8_alloc_compressor_data(cpi); scale_and_extend_source(cpi->un_scaled_source, cpi); +#if CONFIG_TEMPORAL_DENOISING + // TODO(marpan): denoiser_allocate() is not called in + // vp8_alloc_compressor_data() (currently denoiser_allocate is + // only called in change_config()). Check if we can move this call + // of denoiser_free/allocate into vp8_alloc_compressor_data(). + if (cpi->oxcf.noise_sensitivity > 0) { + vp8_denoiser_free(&cpi->denoiser); + vp8_denoiser_allocate(&cpi->denoiser, new_width, new_height, + cm->mb_rows, cm->mb_cols, + ((cpi->oxcf.noise_sensitivity == 3) ? + 1 : 0)); + } +#endif return 1; } } diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c index f768b5c47..ccc0afbe3 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) 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/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/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 5e6af98f3..c3cbfaed7 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -888,21 +888,17 @@ 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 || // Add spatial svc base layer case here - (cpi->svc.number_temporal_layers == 1 && - cpi->svc.spatial_layer_id == 0 && - cpi->svc.layer_context[0].gold_ref_idx >=0 && - cpi->oxcf.ss_play_alternate[0]))) { - // 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 { @@ -1224,8 +1220,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_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 7c82b205c..d7efc5981 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -1953,6 +1953,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 @@ -1978,6 +2014,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); @@ -1987,6 +2024,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; @@ -2038,6 +2080,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, @@ -2048,6 +2149,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; @@ -2078,7 +2180,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 = @@ -2104,11 +2205,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; } @@ -2171,6 +2273,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; @@ -2283,6 +2386,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 diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 6ba4ac69f..8296cd943 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, @@ -1565,22 +1565,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 || // Add spatial svc base layer case here - (cpi->svc.number_temporal_layers == 1 && - cpi->svc.spatial_layer_id == 0 && - cpi->svc.layer_context[0].gold_ref_idx >=0 && - cpi->oxcf.ss_play_alternate[0]))) { - /* 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, @@ -1590,7 +1583,7 @@ void vp9_update_reference_frames(VP9_COMP *cpi) { cpi->alt_fb_idx = cpi->gld_fb_idx; cpi->gld_fb_idx = tmp; - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { + 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; } @@ -2014,7 +2007,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) @@ -2060,9 +2053,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; @@ -2190,7 +2181,7 @@ static void encode_frame_to_data_rate(VP9_COMP *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)) { + (!cpi->use_svc || is_spatial_svc(cpi))) { configure_skippable_frame(cpi); } @@ -2442,7 +2433,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 @@ -2572,14 +2563,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->pass == 2) { #if CONFIG_SPATIAL_SVC vp9_svc_lookahead_peek(cpi, cpi->lookahead, 0, 1); #endif @@ -2606,7 +2594,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 @@ -2616,7 +2604,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) { @@ -2651,7 +2639,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 @@ -2662,7 +2650,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 @@ -2778,13 +2766,13 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, } if (cpi->pass == 1 && - (!cpi->use_svc || cpi->svc.number_temporal_layers == 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)) { + (!cpi->use_svc || is_spatial_svc(cpi))) { Pass2Encode(cpi, size, dest, frame_flags); } else if (cpi->use_svc) { SvcEncode(cpi, size, dest, frame_flags); diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index 2a6c4b362..acff17351 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -232,6 +232,7 @@ typedef struct VP9EncoderConfig { #endif vp8e_tuning tuning; + vp9e_tune_content content; } VP9EncoderConfig; static INLINE int is_lossless_requested(const VP9EncoderConfig *cfg) { @@ -535,10 +536,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 627de47b1..5a79f726a 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -258,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, @@ -446,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; @@ -615,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, @@ -898,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. @@ -967,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. @@ -2102,7 +2099,7 @@ void configure_buffer_updates(VP9_COMP *cpi) { assert(0); break; } - if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { + 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) @@ -2121,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); @@ -2151,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 { @@ -2167,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; } @@ -2175,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); @@ -2201,7 +2198,7 @@ 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) @@ -2232,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_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index 1a479f112..73c6b89e8 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -1236,7 +1236,7 @@ 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_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG); @@ -1248,7 +1248,7 @@ void vp9_rc_get_svc_params(VP9_COMP *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; diff --git a/vp9/encoder/vp9_rd.c b/vp9/encoder/vp9_rd.c index a9cff1ee0..633ce088d 100644 --- a/vp9/encoder/vp9_rd.c +++ b/vp9/encoder/vp9_rd.c @@ -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 > (uint64_t)MAX_XSQ_Q10 ? - (int)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; diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c index 6ca1bc525..e770f33e9 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,7 +399,7 @@ 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; } 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 0e921be8c..bf949c456 100644 --- a/vp9/encoder/vp9_svc_layercontext.c +++ b/vp9/encoder/vp9_svc_layercontext.c @@ -222,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; } diff --git a/vp9/encoder/vp9_temporal_filter.c b/vp9/encoder/vp9_temporal_filter.c index 6af8510a4..2eca8fcef 100644 --- a/vp9/encoder/vp9_temporal_filter.c +++ b/vp9/encoder/vp9_temporal_filter.c @@ -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/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 32862c418..1c6413d05 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) @@ -397,6 +401,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; @@ -799,6 +804,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, @@ -806,6 +825,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); @@ -851,7 +871,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; @@ -859,12 +881,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); @@ -901,19 +917,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 ) { @@ -928,20 +943,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 ) @@ -954,9 +965,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; } @@ -983,7 +993,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; @@ -1213,6 +1223,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}, @@ -1245,6 +1262,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}, diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c index da537d946..ce5088397 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); @@ -414,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); 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" |