vp9-svc: Add logic to enable for constrained framedrop.

Add the logic for the constrained framdrop mode for SVC.

Add test case in datarate unittests.
Also lower target bitrates in the tests to better test
frame dropper.

Change-Id: I8ee1b8cb56d835c233ad1fbe0fc1456cb2e7291f
This commit is contained in:
Marco Paniconi 2018-03-26 20:25:57 -07:00
parent 239511fad8
commit 7b9984b386
4 changed files with 60 additions and 28 deletions

View File

@ -1369,6 +1369,7 @@ class DatarateOnePassCbrSvc
superframe_count_ = -1; superframe_count_ = -1;
key_frame_spacing_ = 9999; key_frame_spacing_ = 9999;
num_nonref_frames_ = 0; num_nonref_frames_ = 0;
constrained_framedrop_ = 0;
} }
virtual void BeginPassHook(unsigned int /*pass*/) {} virtual void BeginPassHook(unsigned int /*pass*/) {}
@ -1451,6 +1452,14 @@ class DatarateOnePassCbrSvc
encoder->Control(VP9E_SET_ROW_MT, 1); encoder->Control(VP9E_SET_ROW_MT, 1);
encoder->Control(VP8E_SET_STATIC_THRESHOLD, 1); encoder->Control(VP8E_SET_STATIC_THRESHOLD, 1);
encoder->Control(VP9E_SET_TUNE_CONTENT, tune_content_); encoder->Control(VP9E_SET_TUNE_CONTENT, tune_content_);
if (constrained_framedrop_) {
vpx_svc_frame_drop_t svc_drop_frame;
svc_drop_frame.framedrop_mode = 1;
for (i = 0; i < number_spatial_layers_; i++)
svc_drop_frame.framedrop_thresh[i] = 30;
encoder->Control(VP9E_SET_SVC_FRAME_DROP_LAYER, &svc_drop_frame);
}
} }
superframe_count_++; superframe_count_++;
@ -1695,6 +1704,7 @@ class DatarateOnePassCbrSvc
int superframe_count_; int superframe_count_;
int key_frame_spacing_; int key_frame_spacing_;
unsigned int num_nonref_frames_; unsigned int num_nonref_frames_;
int constrained_framedrop_;
}; };
// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and 1 // Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and 1
@ -1926,20 +1936,25 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SL3TL4Threads) {
::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60); ::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
top_sl_width_ = 1280; top_sl_width_ = 1280;
top_sl_height_ = 720; top_sl_height_ = 720;
for (int i = 200; i <= 800; i += 300) { constrained_framedrop_ = 0;
cfg_.rc_target_bitrate = i; for (int k = 0; k < 2; k++) {
ResetModel(); for (int i = 200; i <= 600; i += 200) {
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, cfg_.rc_target_bitrate = i;
cfg_.ts_number_layers, cfg_.temporal_layering_mode, ResetModel();
layer_target_avg_bandwidth_, bits_in_buffer_model_); constrained_framedrop_ = k;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
CheckLayerRateTargeting(&cfg_, number_spatial_layers_, cfg_.ts_number_layers, cfg_.temporal_layering_mode,
number_temporal_layers_, file_datarate_, 0.75, 1.2); 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 #if CONFIG_VP9_DECODER
// The non-reference frames are expected to be mismatched frames as the // The non-reference frames are expected to be mismatched frames as the
// encoder will avoid loopfilter on these frames. // encoder will avoid loopfilter on these frames.
EXPECT_EQ(num_nonref_frames_, GetMismatchFrames()); EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
#endif #endif
}
} }
} }
@ -2222,20 +2237,25 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SL3TL4Threads) {
::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60); ::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
top_sl_width_ = 1280; top_sl_width_ = 1280;
top_sl_height_ = 720; top_sl_height_ = 720;
for (int i = 200; i <= 800; i += 300) { constrained_framedrop_ = 0;
cfg_.rc_target_bitrate = i; for (int k = 0; k < 2; k++) {
ResetModel(); for (int i = 200; i <= 600; i += 200) {
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, cfg_.rc_target_bitrate = i;
cfg_.ts_number_layers, cfg_.temporal_layering_mode, ResetModel();
layer_target_avg_bandwidth_, bits_in_buffer_model_); constrained_framedrop_ = k;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
CheckLayerRateTargeting(&cfg_, number_spatial_layers_, cfg_.ts_number_layers, cfg_.temporal_layering_mode,
number_temporal_layers_, file_datarate_, 0.73, 1.2); 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.73,
1.2);
#if CONFIG_VP9_DECODER #if CONFIG_VP9_DECODER
// The non-reference frames are expected to be mismatched frames as the // The non-reference frames are expected to be mismatched frames as the
// encoder will avoid loopfilter on these frames. // encoder will avoid loopfilter on these frames.
EXPECT_EQ(num_nonref_frames_, GetMismatchFrames()); EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
#endif #endif
}
} }
} }

View File

@ -137,6 +137,11 @@ class Encoder {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg); const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
} }
void Control(int ctrl_id, struct vpx_svc_frame_drop *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}
#if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
void Control(int ctrl_id, vpx_active_map_t *arg) { void Control(int ctrl_id, vpx_active_map_t *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg); const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);

View File

@ -4618,17 +4618,24 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, size_t *size,
} }
// For 1 pass CBR, check if we are dropping this frame. // For 1 pass CBR, check if we are dropping this frame.
// Never drop on key frame, of if base layer is key for svc. // Never drop on key frame, or if base layer is key for svc.
if (oxcf->pass == 0 && oxcf->rc_mode == VPX_CBR && if (oxcf->pass == 0 && oxcf->rc_mode == VPX_CBR &&
cm->frame_type != KEY_FRAME && cm->frame_type != KEY_FRAME &&
(!cpi->use_svc || (!cpi->use_svc ||
!cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame)) { !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame)) {
if (vp9_rc_drop_frame(cpi)) { int svc_prev_layer_dropped = 0;
// In the contrained framedrop mode for svc (framedrop_mode = 1), if the
// previous spatial layer was dropped, drop the current spatial layer.
if (cpi->use_svc && cpi->svc.spatial_layer_id > 0 &&
cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id - 1])
svc_prev_layer_dropped = 1;
if ((svc_prev_layer_dropped && cpi->svc.framedrop_mode) ||
vp9_rc_drop_frame(cpi)) {
vp9_rc_postencode_update_drop_frame(cpi); vp9_rc_postencode_update_drop_frame(cpi);
cpi->ext_refresh_frame_flags_pending = 0; cpi->ext_refresh_frame_flags_pending = 0;
cpi->last_frame_dropped = 1; cpi->last_frame_dropped = 1;
cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] = 1;
if (cpi->use_svc) { if (cpi->use_svc) {
cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] = 1;
cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id] = 1; cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id] = 1;
vp9_inc_frame_in_layer(cpi); vp9_inc_frame_in_layer(cpi);
cpi->svc.skip_enhancement_layer = 1; cpi->svc.skip_enhancement_layer = 1;

View File

@ -771,7 +771,7 @@ typedef struct vpx_svc_ref_frame_config {
* spatial layers to drop. * spatial layers to drop.
*/ */
typedef struct vpx_svc_frame_drop { typedef struct vpx_svc_frame_drop {
int framedrop_thresh[VPX_SS_MAX_LAYERS]; /**< Frame flags. */ int framedrop_thresh[VPX_SS_MAX_LAYERS]; /**< Frame drop thresholds */
int framedrop_mode; /**< Layer-based or constrained dropping. */ int framedrop_mode; /**< Layer-based or constrained dropping. */
} vpx_svc_frame_drop_t; } vpx_svc_frame_drop_t;