printf("Average, rms-variance, and percent-fluct: %f %f %f \n",
rc->avg_st_encoding_bitrate, sqrt(rc->variance_st_encoding_bitrate),
perc_fluctuation);
- if (frame_cnt != tot_num_frames)
- die("Error: Number of input frames not equal to output encoded frames != "
- "%d tot_num_frames = %d\n",
- frame_cnt, tot_num_frames);
+ printf("Num of input, num of encoded (super) frames: %d %d \n", frame_cnt,
+ tot_num_frames);
}
vpx_codec_err_t parse_superframe_index(const uint8_t *data, size_t data_sz,
if (cx_pkt->data.frame.sz > 0) {
#if OUTPUT_RC_STATS
uint64_t sizes[8];
+ uint64_t sizes_parsed[8];
int count = 0;
vp9_zero(sizes);
+ vp9_zero(sizes_parsed);
#endif
vpx_video_writer_write_frame(writer, cx_pkt->data.frame.buf,
cx_pkt->data.frame.sz,
if (svc_ctx.output_rc_stat) {
vpx_codec_control(&codec, VP9E_GET_SVC_LAYER_ID, &layer_id);
parse_superframe_index(cx_pkt->data.frame.buf,
- cx_pkt->data.frame.sz, sizes, &count);
+ cx_pkt->data.frame.sz, sizes_parsed,
+ &count);
if (enc_cfg.ss_number_layers == 1)
sizes[0] = cx_pkt->data.frame.sz;
- // Note computing input_layer_frames here won't account for frame
- // drops in rate control stats.
- // TODO(marpan): Fix this for non-bypass mode so we can get stats
- // for dropped frames.
if (svc_ctx.temporal_layering_mode !=
VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
+ int num_layers_encoded = 0;
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
++rc.layer_input_frames[sl * enc_cfg.ts_number_layers +
layer_id.temporal_layer_id];
+ sizes[sl] = 0;
+ if (cx_pkt->data.frame.spatial_layer_encoded[sl]) {
+ sizes[sl] = sizes_parsed[num_layers_encoded];
+ num_layers_encoded++;
+ }
}
}
for (tl = layer_id.temporal_layer_id;
}
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
- for (tl = layer_id.temporal_layer_id;
- tl < enc_cfg.ts_number_layers; ++tl) {
- const int layer = sl * enc_cfg.ts_number_layers + tl;
- ++rc.layer_tot_enc_frames[layer];
- rc.layer_encoding_bitrate[layer] += 8.0 * sizes[sl];
- // Keep count of rate control stats per layer, for non-key
- // frames.
- if (tl == (unsigned int)layer_id.temporal_layer_id &&
- !(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY)) {
- rc.layer_avg_frame_size[layer] += 8.0 * sizes[sl];
- rc.layer_avg_rate_mismatch[layer] +=
- fabs(8.0 * sizes[sl] - rc.layer_pfb[layer]) /
- rc.layer_pfb[layer];
- ++rc.layer_enc_frames[layer];
+ if (cx_pkt->data.frame.spatial_layer_encoded[sl]) {
+ for (tl = layer_id.temporal_layer_id;
+ tl < enc_cfg.ts_number_layers; ++tl) {
+ const int layer = sl * enc_cfg.ts_number_layers + tl;
+ ++rc.layer_tot_enc_frames[layer];
+ rc.layer_encoding_bitrate[layer] += 8.0 * sizes[sl];
+ // Keep count of rate control stats per layer, for non-key
+ // frames.
+ if (tl == (unsigned int)layer_id.temporal_layer_id &&
+ !(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY)) {
+ rc.layer_avg_frame_size[layer] += 8.0 * sizes[sl];
+ rc.layer_avg_rate_mismatch[layer] +=
+ fabs(8.0 * sizes[sl] - rc.layer_pfb[layer]) /
+ rc.layer_pfb[layer];
+ ++rc.layer_enc_frames[layer];
+ }
}
}
}
// Ignore first window segment, due to key frame.
if (frame_cnt > (unsigned int)rc.window_size) {
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
- sum_bitrate += 0.001 * 8.0 * sizes[sl] * framerate;
+ if (cx_pkt->data.frame.spatial_layer_encoded[sl])
+ sum_bitrate += 0.001 * 8.0 * sizes[sl] * framerate;
}
if (frame_cnt % rc.window_size == 0) {
rc.window_count += 1;
top_bitrate_ = 0;
superframe_count_ = -1;
key_frame_spacing_ = 9999;
+ num_nonref_frames_ = 0;
}
virtual void BeginPassHook(unsigned int /*pass*/) {}
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
uint32_t sizes[8] = { 0 };
+ uint32_t sizes_parsed[8] = { 0 };
int count = 0;
+ int num_layers_encoded = 0;
last_pts_ = pkt->data.frame.pts;
const bool key_frame =
(pkt->data.frame.flags & VPX_FRAME_IS_KEY) ? true : false;
superframe_count_ = 0;
}
parse_superframe_index(static_cast<const uint8_t *>(pkt->data.frame.buf),
- pkt->data.frame.sz, sizes, &count);
+ pkt->data.frame.sz, sizes_parsed, &count);
// Count may be less than number of spatial layers because of frame drops.
- ASSERT_LE(count, number_spatial_layers_);
+ for (int sl = 0; sl < number_spatial_layers_; ++sl) {
+ if (pkt->data.frame.spatial_layer_encoded[sl]) {
+ sizes[sl] = sizes_parsed[num_layers_encoded];
+ num_layers_encoded++;
+ }
+ }
+ ASSERT_EQ(count, num_layers_encoded);
+ // Keep track of number of non-reference frames, needed for mismatch check.
+ // Non-reference frames are top spatial and temporal layer frames,
+ // for TL > 0.
+ if (temporal_layer_id_ == number_temporal_layers_ - 1 &&
+ temporal_layer_id_ > 0 &&
+ pkt->data.frame.spatial_layer_encoded[number_spatial_layers_ - 1])
+ num_nonref_frames_++;
for (int sl = 0; sl < number_spatial_layers_; ++sl) {
sizes[sl] = sizes[sl] << 3;
// Update the total encoded bits per layer.
int top_bitrate_;
int superframe_count_;
int key_frame_spacing_;
+ unsigned int num_nonref_frames_;
};
// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and 1
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
number_temporal_layers_, file_datarate_, 0.78, 1.15);
- EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
+#if CONFIG_VP9_DECODER
+ // The non-reference frames are expected to be mismatched frames as the
+ // encoder will avoid loopfilter on these frames.
+ EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
+#endif
}
// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and
layer_target_avg_bandwidth_, bits_in_buffer_model_);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
- number_temporal_layers_, file_datarate_, 0.78,
- 1.15);
+ number_temporal_layers_, file_datarate_, 0.75, 1.2);
#if CONFIG_VP9_DECODER
- // Number of temporal layers > 1, so half of the frames in this SVC pattern
- // will be non-reference frame and hence encoder will avoid loopfilter.
- // Since frame dropper is off, we can expect 200 (half of the sequence)
- // mismatched frames.
- EXPECT_EQ(static_cast<unsigned int>(200), GetMismatchFrames());
+ // The non-reference frames are expected to be mismatched frames as the
+ // encoder will avoid loopfilter on these frames.
+ EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
#endif
}
}
number_temporal_layers_, file_datarate_, 0.78,
1.15);
#if CONFIG_VP9_DECODER
- // Number of temporal layers > 1, so half of the frames in this SVC
- // pattern
- // will be non-reference frame and hence encoder will avoid loopfilter.
- // Since frame dropper is off, we can expect 200 (half of the sequence)
- // mismatched frames.
- EXPECT_EQ(static_cast<unsigned int>(200), GetMismatchFrames());
+ // The non-reference frames are expected to be mismatched frames as the
+ // encoder will avoid loopfilter on these frames.
+ EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
#endif
}
}
CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
number_temporal_layers_, file_datarate_, 0.78,
1.15);
+#if CONFIG_VP9_DECODER
+ // The non-reference frames are expected to be mismatched frames as the
+ // encoder will avoid loopfilter on these frames.
+ EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
+#endif
}
}
::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
top_sl_width_ = 1280;
top_sl_height_ = 720;
- cfg_.rc_target_bitrate = 800;
- ResetModel();
- assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
- cfg_.ts_number_layers, cfg_.temporal_layering_mode,
- layer_target_avg_bandwidth_, bits_in_buffer_model_);
- ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
- CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
- number_temporal_layers_, file_datarate_, 0.78, 1.15);
+ for (int i = 200; i <= 800; i += 300) {
+ cfg_.rc_target_bitrate = i;
+ ResetModel();
+ assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
+ cfg_.ts_number_layers, cfg_.temporal_layering_mode,
+ layer_target_avg_bandwidth_, bits_in_buffer_model_);
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
+ number_temporal_layers_, file_datarate_, 0.75, 1.2);
#if CONFIG_VP9_DECODER
- // Number of temporal layers > 1, so half of the frames in this SVC pattern
- // will be non-reference frame and hence encoder will avoid loopfilter.
- // Since frame dropper is off, we can expect 30 (half of the sequence)
- // mismatched frames.
- EXPECT_EQ(static_cast<unsigned int>(30), GetMismatchFrames());
+ // The non-reference frames are expected to be mismatched frames as the
+ // encoder will avoid loopfilter on these frames.
+ EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
#endif
+ }
}
// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and
CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
number_temporal_layers_, file_datarate_, 0.78, 1.15);
#if CONFIG_VP9_DECODER
- // Number of temporal layers > 1, so half of the frames in this SVC pattern
- // will be non-reference frame and hence encoder will avoid loopfilter.
- // Since frame dropper is off, we can expect 200 (half of the sequence)
- // mismatched frames.
- EXPECT_EQ(static_cast<unsigned int>(200), GetMismatchFrames());
+ // The non-reference frames are expected to be mismatched frames as the
+ // encoder will avoid loopfilter on these frames.
+ EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
#endif
}
CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
number_temporal_layers_, file_datarate_, 0.78, 1.15);
#if CONFIG_VP9_DECODER
- // Number of temporal layers > 1, so half of the frames in this SVC pattern
- // will be non-reference frame and hence encoder will avoid loopfilter.
- // Since frame dropper is off, we can expect 200 (half of the sequence)
- // mismatched frames.
- EXPECT_EQ(static_cast<unsigned int>(200), GetMismatchFrames());
+ // The non-reference frames are expected to be mismatched frames as the
+ // encoder will avoid loopfilter on these frames.
+ EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
#endif
}
CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
number_temporal_layers_, file_datarate_, 0.78, 1.15);
#if CONFIG_VP9_DECODER
- // Number of temporal layers > 1, so half of the frames in this SVC pattern
- // will be non-reference frame and hence encoder will avoid loopfilter.
- // Since frame dropper is off, we can expect 200 (half of the sequence)
- // mismatched frames.
- EXPECT_EQ(static_cast<unsigned int>(200), GetMismatchFrames());
+ // The non-reference frames are expected to be mismatched frames as the
+ // encoder will avoid loopfilter on these frames.
+ EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
#endif
}
// for part of the sequence.
CheckLayerRateTargeting(&cfg_, number_spatial_layers_ - 1,
number_temporal_layers_, file_datarate_, 0.78, 1.15);
+#if CONFIG_VP9_DECODER
+ // The non-reference frames are expected to be mismatched frames as the
+ // encoder will avoid loopfilter on these frames.
+ EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
+#endif
}
// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and 3
CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
number_temporal_layers_, file_datarate_, 0.78,
1.15);
+#if CONFIG_VP9_DECODER
+ // The non-reference frames are expected to be mismatched frames as the
+ // encoder will avoid loopfilter on these frames.
+ EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
+#endif
}
}
// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and
// 3 temporal layers. Run HD clip with 4 threads.
-TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SL3TL4threads) {
+TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SL3TL4Threads) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
top_sl_width_ = 1280;
top_sl_height_ = 720;
- cfg_.rc_target_bitrate = 800;
- ResetModel();
- assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
- cfg_.ts_number_layers, cfg_.temporal_layering_mode,
- layer_target_avg_bandwidth_, bits_in_buffer_model_);
- ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
- CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
- number_temporal_layers_, file_datarate_, 0.78, 1.15);
+ for (int i = 200; i <= 800; i += 300) {
+ cfg_.rc_target_bitrate = i;
+ ResetModel();
+ assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
+ cfg_.ts_number_layers, cfg_.temporal_layering_mode,
+ layer_target_avg_bandwidth_, bits_in_buffer_model_);
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
+ number_temporal_layers_, file_datarate_, 0.75, 1.2);
#if CONFIG_VP9_DECODER
- // Number of temporal layers > 1, so half of the frames in this SVC pattern
- // will be non-reference frame and hence encoder will avoid loopfilter.
- // Since frame dropper is off, we can expect 30 (half of the sequence)
- // mismatched frames.
- EXPECT_EQ(static_cast<unsigned int>(30), GetMismatchFrames());
+ // The non-reference frames are expected to be mismatched frames as the
+ // encoder will avoid loopfilter on these frames.
+ EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
#endif
+ }
}
// Run SVC encoder for 1 temporal layer, 2 spatial layers, with spatial
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
number_temporal_layers_, file_datarate_, 0.78, 1.15);
- EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
+#if CONFIG_VP9_DECODER
+ // The non-reference frames are expected to be mismatched frames as the
+ // encoder will avoid loopfilter on these frames.
+ EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
+#endif
}
VP8_INSTANTIATE_TEST_CASE(DatarateTestLarge, ALL_TEST_MODES,
suppress_active_map(cpi);
+ // For SVC on non-zero spatial layer: if the previous spatial layer
+ // was dropped then disable the prediciton from this (scaled) reference.
+ if (cpi->use_svc && cpi->svc.spatial_layer_id > 0 &&
+ cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id - 1]) {
+ MV_REFERENCE_FRAME ref_frame;
+ static const int flag_list[4] = { 0, VP9_LAST_FLAG, VP9_GOLD_FLAG,
+ VP9_ALT_FLAG };
+ for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
+ const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, ref_frame);
+ if (yv12 != NULL && (cpi->ref_frame_flags & flag_list[ref_frame])) {
+ const struct scale_factors *const scale_fac =
+ &cm->frame_refs[ref_frame - 1].sf;
+ if (vp9_is_scaled(scale_fac))
+ cpi->ref_frame_flags &= (~flag_list[ref_frame]);
+ }
+ }
+ }
+
// Variance adaptive and in frame q adjustment experiments are mutually
// exclusive.
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
vp9_rc_postencode_update_drop_frame(cpi);
vp9_inc_frame_in_layer(cpi);
cpi->ext_refresh_frame_flags_pending = 0;
+ cpi->last_frame_dropped = 1;
+ cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] = 1;
+ cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id] = 1;
return;
}
}
// For 1 pass CBR, check if we are dropping this frame.
- // For spatial layers, for now if we decide to drop current spatial
- // layer then we will also drop all upper spatial layers.
- // TODO(marpan): Allow for the case of dropping single layer only without
- // dropping all upper layers.
+ // Never drop on key frame, of if base layer is key for svc.
if (oxcf->pass == 0 && oxcf->rc_mode == VPX_CBR &&
- cm->frame_type != KEY_FRAME) {
- if (vp9_rc_drop_frame(cpi) ||
- (is_one_pass_cbr_svc(cpi) &&
- cpi->svc.rc_drop_spatial_layer[cpi->svc.spatial_layer_id] == 1)) {
+ cm->frame_type != KEY_FRAME &&
+ (!cpi->use_svc ||
+ !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame)) {
+ if (vp9_rc_drop_frame(cpi)) {
vp9_rc_postencode_update_drop_frame(cpi);
cpi->ext_refresh_frame_flags_pending = 0;
cpi->last_frame_dropped = 1;
+ cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] = 1;
if (cpi->use_svc) {
- int i;
- // If we are dropping this spatial layer, then we will drop all
- // upper spatial layers.
- for (i = cpi->svc.spatial_layer_id; i < cpi->svc.number_spatial_layers;
- i++)
- cpi->svc.rc_drop_spatial_layer[i] = 1;
+ cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id] = 1;
vp9_inc_frame_in_layer(cpi);
- if (cpi->svc.rc_drop_spatial_layer[0] == 0)
- cpi->svc.skip_enhancement_layer = 1;
+ cpi->svc.skip_enhancement_layer = 1;
+ if (cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1) {
+ int i;
+ int all_layers_drop = 1;
+ for (i = 0; i < cpi->svc.spatial_layer_id; i++) {
+ if (cpi->svc.drop_spatial_layer[i] == 0) {
+ all_layers_drop = 0;
+ break;
+ }
+ }
+ if (all_layers_drop == 1) cpi->svc.skip_enhancement_layer = 0;
+ }
}
return;
}
}
cpi->last_frame_dropped = 0;
- cpi->svc.last_layer_encoded = cpi->svc.spatial_layer_id;
+ cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] = 0;
// Disable segmentation if it decrease rate/distortion ratio
if (cpi->oxcf.aq_mode == LOOKAHEAD_AQ)