Merge "Fix bug in stats output for HBD."
diff --git a/examples/vp8_multi_resolution_encoder.c b/examples/vp8_multi_resolution_encoder.c
index 0248ede..fc775ef 100644
--- a/examples/vp8_multi_resolution_encoder.c
+++ b/examples/vp8_multi_resolution_encoder.c
@@ -347,8 +347,7 @@
double psnr_totals[NUM_ENCODERS][4] = {{0,0}};
int psnr_count[NUM_ENCODERS] = {0};
- double cx_time = 0;
- struct timeval tv1, tv2, difftv;
+ int64_t cx_time = 0;
/* Set the required target bitrates for each resolution level.
* If target bitrate for highest-resolution level is set to 0,
@@ -582,6 +581,7 @@
while(frame_avail || got_data)
{
+ struct vpx_usec_timer timer;
vpx_codec_iter_t iter[NUM_ENCODERS]={NULL};
const vpx_codec_cx_pkt_t *pkt[NUM_ENCODERS];
@@ -636,18 +636,18 @@
vpx_codec_control(&codec[i], VP8E_SET_TEMPORAL_LAYER_ID, layer_id);
}
- gettimeofday(&tv1, NULL);
/* Encode each frame at multi-levels */
/* Note the flags must be set to 0 in the encode call if they are set
for each frame with the vpx_codec_control(), as done above. */
+ vpx_usec_timer_start(&timer);
if(vpx_codec_encode(&codec[0], frame_avail? &raw[0] : NULL,
frame_cnt, 1, 0, arg_deadline))
{
die_codec(&codec[0], "Failed to encode frame");
}
- gettimeofday(&tv2, NULL);
- timersub(&tv2, &tv1, &difftv);
- cx_time += (double)(difftv.tv_sec * 1000000 + difftv.tv_usec);
+ vpx_usec_timer_mark(&timer);
+ cx_time += vpx_usec_timer_elapsed(&timer);
+
for (i=NUM_ENCODERS-1; i>=0 ; i--)
{
got_data = 0;
@@ -686,8 +686,10 @@
frame_cnt++;
}
printf("\n");
- printf("FPS for encoding %d %f %f \n", frame_cnt, (float)cx_time / 1000000,
- 1000000 * (double)frame_cnt / (double)cx_time);
+ printf("Frame cnt and encoding time/FPS stats for encoding: %d %f %f \n",
+ frame_cnt,
+ 1000 * (float)cx_time / (double)(frame_cnt * 1000000),
+ 1000000 * (double)frame_cnt / (double)cx_time);
fclose(infile);
diff --git a/test/datarate_test.cc b/test/datarate_test.cc
index 1498923..c0796df 100644
--- a/test/datarate_test.cc
+++ b/test/datarate_test.cc
@@ -813,8 +813,6 @@
if (bits_total_) {
const double file_size_in_kb = bits_total_ / 1000.; // bits per kilobit
duration_ = (last_pts_ + 1) * timebase_;
- effective_datarate_ = (bits_total_ - bits_in_last_frame_) / 1000.0
- / (cfg_.rc_buf_initial_sz / 1000.0 + duration_);
file_datarate_ = file_size_in_kb / duration_;
}
}
@@ -838,7 +836,6 @@
int64_t bits_total_;
double duration_;
double file_datarate_;
- double effective_datarate_;
size_t bits_in_last_frame_;
vpx_svc_extra_cfg_t svc_params_;
int speed_setting_;
@@ -904,8 +901,6 @@
svc_params_.scaling_factor_num[1] = 288;
svc_params_.scaling_factor_den[1] = 288;
cfg_.rc_dropframe_thresh = 10;
- // TODO(marpan): another test should be added for default/small kf_max_dist
- // once https://bugs.chromium.org/p/webm/issues/detail?id=1150 is fixed.
cfg_.kf_max_dist = 9999;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200);
@@ -917,14 +912,94 @@
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
- ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.85)
+ ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85)
<< " The datarate for the file exceeds the target by too much!";
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15)
<< " The datarate for the file is lower than the target by too much!";
- EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
+ EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
}
}
+// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and
+// 3 temporal layers. Run CIF clip with 1 thread. Use short key frame period.
+TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayersSmallKf_dist) {
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_buf_optimal_sz = 500;
+ cfg_.rc_buf_sz = 1000;
+ cfg_.rc_min_quantizer = 0;
+ cfg_.rc_max_quantizer = 63;
+ cfg_.rc_end_usage = VPX_CBR;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.ss_number_layers = 2;
+ cfg_.ts_number_layers = 3;
+ cfg_.ts_rate_decimator[0] = 4;
+ cfg_.ts_rate_decimator[1] = 2;
+ cfg_.ts_rate_decimator[2] = 1;
+ cfg_.g_error_resilient = 1;
+ cfg_.g_threads = 1;
+ cfg_.temporal_layering_mode = 3;
+ svc_params_.scaling_factor_num[0] = 144;
+ svc_params_.scaling_factor_den[0] = 288;
+ svc_params_.scaling_factor_num[1] = 288;
+ svc_params_.scaling_factor_den[1] = 288;
+ cfg_.rc_dropframe_thresh = 10;
+ cfg_.kf_max_dist = 64;
+ ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
+ 30, 1, 0, 200);
+ // TODO(wonkap/marpan): Check that effective_datarate for each layer hits the
+ // layer target_bitrate. Also check if test can pass at lower bitrate (~200k).
+ for (int i = 400; i <= 800; i += 200) {
+ cfg_.rc_target_bitrate = i;
+ ResetModel();
+ assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
+ cfg_.ts_number_layers, cfg_.temporal_layering_mode);
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85)
+ << " The datarate for the file exceeds the target by too much!";
+ ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15)
+ << " The datarate for the file is lower than the target by too much!";
+ EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
+ }
+}
+
+// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and
+// 3 temporal layers. Run HD clip with 4 threads.
+TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayers4threads) {
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_buf_optimal_sz = 500;
+ cfg_.rc_buf_sz = 1000;
+ cfg_.rc_min_quantizer = 0;
+ cfg_.rc_max_quantizer = 63;
+ cfg_.rc_end_usage = VPX_CBR;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.ss_number_layers = 2;
+ cfg_.ts_number_layers = 3;
+ cfg_.ts_rate_decimator[0] = 4;
+ cfg_.ts_rate_decimator[1] = 2;
+ cfg_.ts_rate_decimator[2] = 1;
+ cfg_.g_error_resilient = 1;
+ cfg_.g_threads = 4;
+ cfg_.temporal_layering_mode = 3;
+ svc_params_.scaling_factor_num[0] = 144;
+ svc_params_.scaling_factor_den[0] = 288;
+ svc_params_.scaling_factor_num[1] = 288;
+ svc_params_.scaling_factor_den[1] = 288;
+ cfg_.rc_dropframe_thresh = 10;
+ cfg_.kf_max_dist = 9999;
+ ::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720,
+ 30, 1, 0, 300);
+ cfg_.rc_target_bitrate = 800;
+ ResetModel();
+ assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
+ cfg_.ts_number_layers, cfg_.temporal_layering_mode);
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85)
+ << " The datarate for the file exceeds the target by too much!";
+ ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15)
+ << " The datarate for the file is lower than the target by too much!";
+ EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
+}
+
// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and
// 3 temporal layers. Run CIF clip with 1 thread.
TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SpatialLayers) {
@@ -958,16 +1033,16 @@
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
- ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.85)
+ ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85)
<< " The datarate for the file exceeds the target by too much!";
- ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.17)
+ ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.22)
<< " The datarate for the file is lower than the target by too much!";
- EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
+ EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
}
-// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and
-// 3 temporal layers. Run HD clip with 4 threads.
-TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayers4threads) {
+// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and
+// 3 temporal layers. Run CIF clip with 1 thread. Use short key frame period.
+TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SpatialLayersSmallKf) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
@@ -975,32 +1050,34 @@
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
- cfg_.ss_number_layers = 2;
+ cfg_.ss_number_layers = 3;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
cfg_.g_error_resilient = 1;
- cfg_.g_threads = 4;
+ cfg_.g_threads = 1;
cfg_.temporal_layering_mode = 3;
- svc_params_.scaling_factor_num[0] = 144;
+ svc_params_.scaling_factor_num[0] = 72;
svc_params_.scaling_factor_den[0] = 288;
- svc_params_.scaling_factor_num[1] = 288;
+ svc_params_.scaling_factor_num[1] = 144;
svc_params_.scaling_factor_den[1] = 288;
+ svc_params_.scaling_factor_num[2] = 288;
+ svc_params_.scaling_factor_den[2] = 288;
cfg_.rc_dropframe_thresh = 10;
- cfg_.kf_max_dist = 9999;
+ cfg_.kf_max_dist = 32;
::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720,
30, 1, 0, 300);
cfg_.rc_target_bitrate = 800;
ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
- cfg_.ts_number_layers, cfg_.temporal_layering_mode);
+ cfg_.ts_number_layers, cfg_.temporal_layering_mode);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
- ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.85)
+ ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85)
<< " The datarate for the file exceeds the target by too much!";
- ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15)
+ ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.30)
<< " The datarate for the file is lower than the target by too much!";
- EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
+ EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
}
// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and
@@ -1036,19 +1113,19 @@
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
- ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.85)
+ ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85)
<< " The datarate for the file exceeds the target by too much!";
- ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.17)
+ ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.22)
<< " The datarate for the file is lower than the target by too much!";
- EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
+ EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
}
VP8_INSTANTIATE_TEST_CASE(DatarateTestLarge, ALL_TEST_MODES);
VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9Large,
::testing::Values(::libvpx_test::kOnePassGood,
::libvpx_test::kRealTime),
- ::testing::Range(2, 7));
+ ::testing::Range(2, 9));
VP9_INSTANTIATE_TEST_CASE(DatarateOnePassCbrSvc,
::testing::Values(::libvpx_test::kRealTime),
- ::testing::Range(5, 8));
+ ::testing::Range(5, 9));
} // namespace
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index cff1afe..a6d059b 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -243,14 +243,16 @@
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];
+ const int block_width = VPXMIN(num_8x8_blocks_wide_lookup[bsize],
+ cm->mi_cols - mi_col);
+ const int block_height = VPXMIN(num_8x8_blocks_high_lookup[bsize],
+ cm->mi_rows - mi_row);
+ const int mi_stride = xd->mi_stride;
+ MODE_INFO *const src_mi = xd->mi[0];
int i, j;
for (j = 0; j < block_height; ++j)
- for (i = 0; i < block_width; ++i) {
- if (mi_row + j < cm->mi_rows && mi_col + i < cm->mi_cols)
- xd->mi[j * xd->mi_stride + i] = xd->mi[0];
- }
+ for (i = 0; i < block_width; ++i)
+ xd->mi[j * mi_stride + i] = src_mi;
}
static void set_block_size(VP9_COMP * const cpi,
@@ -2440,7 +2442,8 @@
PARTITION_CONTEXT sl[8], sa[8];
TOKENEXTRA *tp_orig = *tp;
PICK_MODE_CONTEXT *ctx = &pc_tree->none;
- int i, pl;
+ int i;
+ const int pl = partition_plane_context(xd, mi_row, mi_col, bsize);
BLOCK_SIZE subsize;
RD_COST this_rdc, sum_rdc, best_rdc;
int do_split = bsize >= BLOCK_8X8;
@@ -2588,7 +2591,6 @@
&this_rdc, bsize, ctx, best_rdc.rdcost);
if (this_rdc.rate != INT_MAX) {
if (bsize >= BLOCK_8X8) {
- pl = partition_plane_context(xd, mi_row, mi_col, bsize);
this_rdc.rate += cpi->partition_cost[pl][PARTITION_NONE];
this_rdc.rdcost = RDCOST(x->rdmult, x->rddiv,
this_rdc.rate, this_rdc.dist);
@@ -2707,7 +2709,6 @@
}
if (sum_rdc.rdcost < best_rdc.rdcost && i == 4) {
- pl = partition_plane_context(xd, mi_row, mi_col, bsize);
sum_rdc.rate += cpi->partition_cost[pl][PARTITION_SPLIT];
sum_rdc.rdcost = RDCOST(x->rdmult, x->rddiv,
sum_rdc.rate, sum_rdc.dist);
@@ -2773,7 +2774,6 @@
}
if (sum_rdc.rdcost < best_rdc.rdcost) {
- pl = partition_plane_context(xd, mi_row, mi_col, bsize);
sum_rdc.rate += cpi->partition_cost[pl][PARTITION_HORZ];
sum_rdc.rdcost = RDCOST(x->rdmult, x->rddiv, sum_rdc.rate, sum_rdc.dist);
if (sum_rdc.rdcost < best_rdc.rdcost) {
@@ -2825,7 +2825,6 @@
}
if (sum_rdc.rdcost < best_rdc.rdcost) {
- pl = partition_plane_context(xd, mi_row, mi_col, bsize);
sum_rdc.rate += cpi->partition_cost[pl][PARTITION_VERT];
sum_rdc.rdcost = RDCOST(x->rdmult, x->rddiv,
sum_rdc.rate, sum_rdc.dist);
@@ -4272,13 +4271,9 @@
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &td->mb;
MACROBLOCKD *const xd = &x->e_mbd;
- MODE_INFO **mi_8x8 = xd->mi;
- MODE_INFO *mi = mi_8x8[0];
+ MODE_INFO *mi = xd->mi[0];
const int seg_skip = segfeature_active(&cm->seg, mi->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];
x->skip_recode = !x->select_tx_size && mi->sb_type >= BLOCK_8X8 &&
cpi->oxcf.aq_mode != COMPLEXITY_AQ &&
@@ -4334,20 +4329,14 @@
++get_tx_counts(max_txsize_lookup[bsize], get_tx_size_context(xd),
&td->counts->tx)[mi->tx_size];
} else {
- int x, y;
- TX_SIZE tx_size;
// The new intra coding scheme requires no change of transform size
if (is_inter_block(mi)) {
- tx_size = VPXMIN(tx_mode_to_biggest_tx_size[cm->tx_mode],
- max_txsize_lookup[bsize]);
+ mi->tx_size = VPXMIN(tx_mode_to_biggest_tx_size[cm->tx_mode],
+ max_txsize_lookup[bsize]);
} else {
- tx_size = (bsize >= BLOCK_8X8) ? mi->tx_size : TX_4X4;
+ mi->tx_size = (bsize >= BLOCK_8X8) ? mi->tx_size : TX_4X4;
}
- for (y = 0; y < mi_height; y++)
- for (x = 0; x < mi_width; x++)
- if (mi_col + x < cm->mi_cols && mi_row + y < cm->mi_rows)
- mi_8x8[mis * y + x]->tx_size = tx_size;
}
++td->counts->tx.tx_totals[mi->tx_size];
++td->counts->tx.tx_totals[get_uv_tx_size(mi, &xd->plane[1])];
diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c
index 00beb30..ac7c6de 100644
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -410,6 +410,9 @@
memset(&cpi->svc.scaled_frames[0], 0,
MAX_LAG_BUFFERS * sizeof(cpi->svc.scaled_frames[0]));
+ vpx_free_frame_buffer(&cpi->svc.scaled_temp);
+ memset(&cpi->svc.scaled_temp, 0, sizeof(cpi->svc.scaled_temp));
+
vpx_free_frame_buffer(&cpi->svc.empty_frame.img);
memset(&cpi->svc.empty_frame, 0, sizeof(cpi->svc.empty_frame));
@@ -3373,11 +3376,22 @@
vpx_clear_system_state();
set_frame_size(cpi);
- cpi->Source = vp9_scale_if_required(cm,
- cpi->un_scaled_source,
- &cpi->scaled_source,
- (cpi->oxcf.pass == 0));
+ if (is_one_pass_cbr_svc(cpi) &&
+ cpi->un_scaled_source->y_width == cm->width << 2 &&
+ cpi->un_scaled_source->y_height == cm->height << 2 &&
+ cpi->svc.scaled_temp.y_width == cm->width << 1 &&
+ cpi->svc.scaled_temp.y_height == cm->height << 1) {
+ cpi->Source = vp9_svc_twostage_scale(cm,
+ cpi->un_scaled_source,
+ &cpi->scaled_source,
+ &cpi->svc.scaled_temp);
+ } else {
+ cpi->Source = vp9_scale_if_required(cm,
+ cpi->un_scaled_source,
+ &cpi->scaled_source,
+ (cpi->oxcf.pass == 0));
+ }
// Avoid scaling last_source unless its needed.
// Last source is needed if vp9_avg_source_sad() is used, or if
// partition_search_type == SOURCE_VAR_BASED_PARTITION, or if noise
@@ -3403,12 +3417,10 @@
cpi->oxcf.rc_mode == VPX_VBR))
vp9_avg_source_sad(cpi);
- // TODO(wonkap/marpan): For 1 pass SVC, since only ZERMOV is allowed for
- // upsampled reference frame (i.e, svc->force_zero_mode_spatial_ref = 0),
- // we should be able to avoid this frame-level upsampling.
- // Keeping it for now as there is an asan error in the multi-threaded SVC
- // rate control test if this upsampling is removed.
- if (frame_is_intra_only(cm) == 0) {
+ // For 1 pass SVC, since only ZEROMV is allowed for upsampled reference
+ // frame (i.e, svc->force_zero_mode_spatial_ref = 0), we can avoid this
+ // frame-level upsampling.
+ if (frame_is_intra_only(cm) == 0 && !is_one_pass_cbr_svc(cpi)) {
vp9_scale_references(cpi);
}
@@ -3798,6 +3810,25 @@
}
}
+YV12_BUFFER_CONFIG *vp9_svc_twostage_scale(VP9_COMMON *cm,
+ YV12_BUFFER_CONFIG *unscaled,
+ YV12_BUFFER_CONFIG *scaled,
+ YV12_BUFFER_CONFIG *scaled_temp) {
+ if (cm->mi_cols * MI_SIZE != unscaled->y_width ||
+ cm->mi_rows * MI_SIZE != unscaled->y_height) {
+#if CONFIG_VP9_HIGHBITDEPTH
+ scale_and_extend_frame(unscaled, scaled_temp, (int)cm->bit_depth);
+ scale_and_extend_frame(scaled_temp, scaled, (int)cm->bit_depth);
+#else
+ vp9_scale_and_extend_frame(unscaled, scaled_temp);
+ vp9_scale_and_extend_frame(scaled_temp, scaled);
+#endif // CONFIG_VP9_HIGHBITDEPTH
+ return scaled;
+ } else {
+ return unscaled;
+ }
+}
+
YV12_BUFFER_CONFIG *vp9_scale_if_required(VP9_COMMON *cm,
YV12_BUFFER_CONFIG *unscaled,
YV12_BUFFER_CONFIG *scaled,
@@ -3968,6 +3999,8 @@
++cm->current_video_frame;
cpi->ext_refresh_frame_flags_pending = 0;
cpi->svc.rc_drop_superframe = 1;
+ if (cpi->use_svc)
+ vp9_inc_frame_in_layer(cpi);
return;
}
}
diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h
index c486ac2..2def941 100644
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -623,6 +623,11 @@
void vp9_set_high_precision_mv(VP9_COMP *cpi, int allow_high_precision_mv);
+YV12_BUFFER_CONFIG *vp9_svc_twostage_scale(VP9_COMMON *cm,
+ YV12_BUFFER_CONFIG *unscaled,
+ YV12_BUFFER_CONFIG *scaled,
+ YV12_BUFFER_CONFIG *scaled_temp);
+
YV12_BUFFER_CONFIG *vp9_scale_if_required(VP9_COMMON *cm,
YV12_BUFFER_CONFIG *unscaled,
YV12_BUFFER_CONFIG *scaled,
diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c
index 3046541..4fef9c0 100644
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -1594,14 +1594,15 @@
int target = rc->avg_frame_bandwidth;
int layer = LAYER_IDS_TO_IDX(cpi->svc.spatial_layer_id,
cpi->svc.temporal_layer_id, cpi->svc.number_temporal_layers);
-
+ // Periodic key frames is based on the super-frame counter
+ // (svc.current_superframe), also only base spatial layer is key frame.
if ((cm->current_video_frame == 0) ||
(cpi->frame_flags & FRAMEFLAGS_KEY) ||
- (cpi->oxcf.auto_key && (rc->frames_since_key %
- cpi->oxcf.key_freq == 0))) {
+ (cpi->oxcf.auto_key &&
+ (cpi->svc.current_superframe % cpi->oxcf.key_freq == 0) &&
+ cpi->svc.spatial_layer_id == 0)) {
cm->frame_type = KEY_FRAME;
rc->source_alt_ref_active = 0;
-
if (is_two_pass_svc(cpi)) {
cpi->svc.layer_context[layer].is_key_frame = 1;
cpi->ref_frame_flags &=
diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c
index 193c9d3..508c596 100644
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -387,47 +387,70 @@
cost = token_costs[0][0][pt][EOB_TOKEN];
c = 0;
} else {
- int band_left = *band_count++;
+ if (use_fast_coef_costing) {
+ int band_left = *band_count++;
- // dc token
- int v = qcoeff[0];
- int16_t prev_t;
- EXTRABIT e;
- vp9_get_token_extra(v, &prev_t, &e);
- cost = (*token_costs)[0][pt][prev_t] +
- vp9_get_cost(prev_t, e, cat6_high_cost);
+ // dc token
+ int v = qcoeff[0];
+ int16_t prev_t;
+ cost = vp9_get_token_cost(v, &prev_t, cat6_high_cost);
+ cost += (*token_costs)[0][pt][prev_t];
- token_cache[0] = vp9_pt_energy_class[prev_t];
- ++token_costs;
+ token_cache[0] = vp9_pt_energy_class[prev_t];
+ ++token_costs;
- // ac tokens
- for (c = 1; c < eob; c++) {
- const int rc = scan[c];
- int16_t t;
+ // ac tokens
+ for (c = 1; c < eob; c++) {
+ const int rc = scan[c];
+ int16_t t;
- v = qcoeff[rc];
- vp9_get_token_extra(v, &t, &e);
- if (use_fast_coef_costing) {
- cost += (*token_costs)[!prev_t][!prev_t][t] +
- vp9_get_cost(t, e, cat6_high_cost);
- } else {
- pt = get_coef_context(nb, token_cache, c);
- cost += (*token_costs)[!prev_t][pt][t] +
- vp9_get_cost(t, e, cat6_high_cost);
- token_cache[rc] = vp9_pt_energy_class[t];
+ v = qcoeff[rc];
+ cost += vp9_get_token_cost(v, &t, cat6_high_cost);
+ cost += (*token_costs)[!prev_t][!prev_t][t];
+ prev_t = t;
+ if (!--band_left) {
+ band_left = *band_count++;
+ ++token_costs;
+ }
}
- prev_t = t;
- if (!--band_left) {
- band_left = *band_count++;
- ++token_costs;
- }
- }
- // eob token
- if (band_left) {
- if (use_fast_coef_costing) {
+ // eob token
+ if (band_left)
cost += (*token_costs)[0][!prev_t][EOB_TOKEN];
- } else {
+
+ } else { // !use_fast_coef_costing
+ int band_left = *band_count++;
+
+ // dc token
+ int v = qcoeff[0];
+ int16_t tok;
+ unsigned int (*tok_cost_ptr)[COEFF_CONTEXTS][ENTROPY_TOKENS];
+ cost = vp9_get_token_cost(v, &tok, cat6_high_cost);
+ cost += (*token_costs)[0][pt][tok];
+
+ token_cache[0] = vp9_pt_energy_class[tok];
+ ++token_costs;
+
+ tok_cost_ptr = &((*token_costs)[!tok]);
+
+ // ac tokens
+ for (c = 1; c < eob; c++) {
+ const int rc = scan[c];
+
+ v = qcoeff[rc];
+ cost += vp9_get_token_cost(v, &tok, cat6_high_cost);
+ pt = get_coef_context(nb, token_cache, c);
+ cost += (*tok_cost_ptr)[pt][tok];
+ token_cache[rc] = vp9_pt_energy_class[tok];
+ if (!--band_left) {
+ band_left = *band_count++;
+ ++token_costs;
+ }
+ tok_cost_ptr = &((*token_costs)[!tok]);
+ }
+
+ // eob token
+ if (band_left) {
pt = get_coef_context(nb, token_cache, c);
cost += (*token_costs)[0][pt][EOB_TOKEN];
}
diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c
index 1d56154..79e5049 100644
--- a/vp9/encoder/vp9_svc_layercontext.c
+++ b/vp9/encoder/vp9_svc_layercontext.c
@@ -43,6 +43,26 @@
cpi->svc.ext_alt_fb_idx[sl] = 2;
}
+ // For 1 pass cbr: allocate scaled_frame that may be used as an intermediate
+ // buffer for a 2 stage down-sampling: two stages of 1:2 down-sampling for a
+ // target of 1/4x1/4.
+ if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_CBR) {
+ if (vpx_realloc_frame_buffer(&cpi->svc.scaled_temp,
+ cpi->common.width >> 1,
+ cpi->common.height >> 1,
+ cpi->common.subsampling_x,
+ cpi->common.subsampling_y,
+#if CONFIG_VP9_HIGHBITDEPTH
+ cpi->common.use_highbitdepth,
+#endif
+ VP9_ENC_BORDER_IN_PIXELS,
+ cpi->common.byte_alignment,
+ NULL, NULL, NULL))
+ vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
+ "Failed to allocate scaled_frame for svc ");
+ }
+
+
if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2) {
if (vpx_realloc_frame_buffer(&cpi->svc.empty_frame.img,
SMALL_FRAME_WIDTH, SMALL_FRAME_HEIGHT,
diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h
index 4e18640..f1b8556 100644
--- a/vp9/encoder/vp9_svc_layercontext.h
+++ b/vp9/encoder/vp9_svc_layercontext.h
@@ -70,6 +70,8 @@
// Store scaled source frames to be used for temporal filter to generate
// a alt ref frame.
YV12_BUFFER_CONFIG scaled_frames[MAX_LAG_BUFFERS];
+ // Temp buffer used for 2-stage down-sampling, for real-time mode.
+ YV12_BUFFER_CONFIG scaled_temp;
// Layer context used for rate control in one pass temporal CBR mode or
// two pass spatial mode.
diff --git a/vp9/encoder/vp9_temporal_filter.c b/vp9/encoder/vp9_temporal_filter.c
index 82f566b..ebe28b8 100644
--- a/vp9/encoder/vp9_temporal_filter.c
+++ b/vp9/encoder/vp9_temporal_filter.c
@@ -45,8 +45,7 @@
int x, int y) {
const int which_mv = 0;
const MV mv = { mv_row, mv_col };
- const InterpKernel *const kernel =
- vp9_filter_kernels[xd->mi[0]->interp_filter];
+ const InterpKernel *const kernel = vp9_filter_kernels[EIGHTTAP_SHARP];
enum mv_precision mv_precision_uv;
int uv_stride;
@@ -86,6 +85,7 @@
return;
}
#endif // CONFIG_VP9_HIGHBITDEPTH
+ (void)xd;
vp9_build_inter_predictor(y_mb_ptr, stride,
&pred[0], 16,
&mv,
diff --git a/vp9/encoder/vp9_tokenize.c b/vp9/encoder/vp9_tokenize.c
index 93be6d7..ee1d08a 100644
--- a/vp9/encoder/vp9_tokenize.c
+++ b/vp9/encoder/vp9_tokenize.c
@@ -50,6 +50,35 @@
const TOKENVALUE *vp9_dct_cat_lt_10_value_tokens = dct_cat_lt_10_value_tokens +
(sizeof(dct_cat_lt_10_value_tokens) / sizeof(*dct_cat_lt_10_value_tokens))
/ 2;
+// The corresponding costs of the extrabits for the tokens in the above table
+// are stored in the table below. The values are obtained from looking up the
+// entry for the specified extrabits in the table corresponding to the token
+// (as defined in cost element vp9_extra_bits)
+// e.g. {9, 63} maps to cat5_cost[63 >> 1], {1, 1} maps to sign_cost[1 >> 1]
+static const int dct_cat_lt_10_value_cost[] = {
+ 3773, 3750, 3704, 3681, 3623, 3600, 3554, 3531,
+ 3432, 3409, 3363, 3340, 3282, 3259, 3213, 3190,
+ 3136, 3113, 3067, 3044, 2986, 2963, 2917, 2894,
+ 2795, 2772, 2726, 2703, 2645, 2622, 2576, 2553,
+ 3197, 3116, 3058, 2977, 2881, 2800,
+ 2742, 2661, 2615, 2534, 2476, 2395,
+ 2299, 2218, 2160, 2079,
+ 2566, 2427, 2334, 2195, 2023, 1884, 1791, 1652,
+ 1893, 1696, 1453, 1256, 1229, 864,
+ 512, 512, 512, 512, 0,
+ 512, 512, 512, 512,
+ 864, 1229, 1256, 1453, 1696, 1893,
+ 1652, 1791, 1884, 2023, 2195, 2334, 2427, 2566,
+ 2079, 2160, 2218, 2299, 2395, 2476, 2534, 2615,
+ 2661, 2742, 2800, 2881, 2977, 3058, 3116, 3197,
+ 2553, 2576, 2622, 2645, 2703, 2726, 2772, 2795,
+ 2894, 2917, 2963, 2986, 3044, 3067, 3113, 3136,
+ 3190, 3213, 3259, 3282, 3340, 3363, 3409, 3432,
+ 3531, 3554, 3600, 3623, 3681, 3704, 3750, 3773,
+};
+const int *vp9_dct_cat_lt_10_value_cost = dct_cat_lt_10_value_cost +
+ (sizeof(dct_cat_lt_10_value_cost) / sizeof(*dct_cat_lt_10_value_cost))
+ / 2;
// Array indices are identical to previously-existing CONTEXT_NODE indices
const vpx_tree_index vp9_coef_tree[TREE_SIZE(ENTROPY_TOKENS)] = {
diff --git a/vp9/encoder/vp9_tokenize.h b/vp9/encoder/vp9_tokenize.h
index df979b2..fad7988 100644
--- a/vp9/encoder/vp9_tokenize.h
+++ b/vp9/encoder/vp9_tokenize.h
@@ -74,6 +74,7 @@
*/
extern const TOKENVALUE *vp9_dct_value_tokens_ptr;
extern const TOKENVALUE *vp9_dct_cat_lt_10_value_tokens;
+extern const int *vp9_dct_cat_lt_10_value_cost;
extern const int16_t vp9_cat6_low_cost[256];
extern const int vp9_cat6_high_cost[64];
extern const int vp9_cat6_high10_high_cost[256];
@@ -117,6 +118,18 @@
return vp9_dct_cat_lt_10_value_tokens[v].token;
}
+static INLINE int vp9_get_token_cost(int v, int16_t *token,
+ const int *cat6_high_table) {
+ if (v >= CAT6_MIN_VAL || v <= -CAT6_MIN_VAL) {
+ EXTRABIT extrabits;
+ *token = CATEGORY6_TOKEN;
+ extrabits = abs(v) - CAT6_MIN_VAL;
+ return vp9_cat6_low_cost[extrabits & 0xff] +
+ cat6_high_table[extrabits >> 8];
+ }
+ *token = vp9_dct_cat_lt_10_value_tokens[v].token;
+ return vp9_dct_cat_lt_10_value_cost[v];
+}
#ifdef __cplusplus
} // extern "C"