From c83bcb34741c55535727da8e4b66ec24ecd573a9 Mon Sep 17 00:00:00 2001 From: Marco Date: Thu, 25 Feb 2016 08:38:08 -0800 Subject: vp9-svc: Allow for 2 stage downscaling for spatial layers. For 1 pass cbr mode: allow for two-stage 1:2 scaling (which will use the 1:2 optimized scaler) if the spatial layer is 1/4x1/4 of souce. Without this change, the base layer for 3 spatial layers would be using the non-normative scaler which is un-optimized/C code. Change-Id: I9d73f92a4a96927d0f1d6bf75315c1e60513226a --- vp9/encoder/vp9_encoder.c | 41 ++++++++++++++++++++++++++++++++++---- vp9/encoder/vp9_encoder.h | 5 +++++ vp9/encoder/vp9_svc_layercontext.c | 20 +++++++++++++++++++ vp9/encoder/vp9_svc_layercontext.h | 2 ++ 4 files changed, 64 insertions(+), 4 deletions(-) (limited to 'vp9/encoder') diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 14ef88ff6..6d6915c8d 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -410,6 +410,9 @@ static void dealloc_compressor_data(VP9_COMP *cpi) { 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)); @@ -3357,11 +3360,22 @@ static void encode_without_recode_loop(VP9_COMP *cpi, 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 @@ -3780,6 +3794,25 @@ static void set_ext_overrides(VP9_COMP *cpi) { } } +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, diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index c486ac258..2def941ef 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -623,6 +623,11 @@ void vp9_update_reference_frames(VP9_COMP *cpi); 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_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c index 1d561545c..79e5049a5 100644 --- a/vp9/encoder/vp9_svc_layercontext.c +++ b/vp9/encoder/vp9_svc_layercontext.c @@ -43,6 +43,26 @@ void vp9_init_layer_context(VP9_COMP *const cpi) { 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 4e186401f..f1b85565d 100644 --- a/vp9/encoder/vp9_svc_layercontext.h +++ b/vp9/encoder/vp9_svc_layercontext.h @@ -70,6 +70,8 @@ typedef struct { // 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. -- cgit v1.2.3