summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xconfigure5
-rw-r--r--test/decode_test_driver.cc31
-rw-r--r--vp8/encoder/onyx_if.c13
-rw-r--r--vp8/vp8_dx_iface.c9
-rw-r--r--vp9/common/vp9_idct.h10
-rw-r--r--vp9/common/x86/vp9_postproc_x86.h72
-rw-r--r--vp9/encoder/vp9_bitstream.c28
-rw-r--r--vp9/encoder/vp9_bitstream.h14
-rw-r--r--vp9/encoder/vp9_encodeframe.c116
-rw-r--r--vp9/encoder/vp9_encoder.c58
-rw-r--r--vp9/encoder/vp9_encoder.h9
-rw-r--r--vp9/encoder/vp9_firstpass.c31
-rw-r--r--vp9/encoder/vp9_ratectrl.c4
-rw-r--r--vp9/encoder/vp9_rd.c6
-rw-r--r--vp9/encoder/vp9_speed_features.c11
-rw-r--r--vp9/encoder/vp9_subexp.c37
-rw-r--r--vp9/encoder/vp9_subexp.h3
-rw-r--r--vp9/encoder/vp9_svc_layercontext.c3
-rw-r--r--vp9/encoder/vp9_temporal_filter.c2
-rw-r--r--vp9/vp9_common.mk1
-rw-r--r--vp9/vp9_cx_iface.c66
-rw-r--r--vp9/vp9_dx_iface.c11
-rw-r--r--vpx/vp8cx.h10
23 files changed, 328 insertions, 222 deletions
diff --git a/configure b/configure
index 789e6c30a..92ca061b9 100755
--- a/configure
+++ b/configure
@@ -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"