int is_key_frame,
vpx_svc_ref_frame_config_t *ref_frame_config) {
int sl;
+ for (sl = 0; sl < num_spatial_layers; ++sl)
+ ref_frame_config->update_buffer_slot[sl] = 0;
+
for (sl = 0; sl < num_spatial_layers; ++sl) {
- if (!tl) {
- if (!sl) {
- ref_frame_config->frame_flags[sl] =
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF;
- } else {
- if (is_key_frame) {
- ref_frame_config->frame_flags[sl] =
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
- } else {
- ref_frame_config->frame_flags[sl] =
- VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
- }
- }
- } else if (tl == 1) {
- if (!sl) {
- ref_frame_config->frame_flags[sl] =
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
- VP8_EFLAG_NO_UPD_GF;
- } else {
- ref_frame_config->frame_flags[sl] =
- VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
- if (sl == num_spatial_layers - 1)
- ref_frame_config->frame_flags[sl] =
- VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
- }
- }
+ // Set the buffer idx.
if (tl == 0) {
ref_frame_config->lst_fb_idx[sl] = sl;
if (sl) {
ref_frame_config->gld_fb_idx[sl] = num_spatial_layers + sl - 1;
ref_frame_config->alt_fb_idx[sl] = num_spatial_layers + sl;
}
+ // Set the reference and update flags.
+ if (!tl) {
+ if (!sl) {
+ // Base spatial and base temporal (sl = 0, tl = 0)
+ ref_frame_config->reference_last[sl] = 1;
+ ref_frame_config->reference_golden[sl] = 0;
+ ref_frame_config->reference_alt_ref[sl] = 0;
+ ref_frame_config->update_buffer_slot[sl] |=
+ 1 << ref_frame_config->lst_fb_idx[sl];
+ } else {
+ if (is_key_frame) {
+ ref_frame_config->reference_last[sl] = 1;
+ ref_frame_config->reference_golden[sl] = 0;
+ ref_frame_config->reference_alt_ref[sl] = 0;
+ ref_frame_config->update_buffer_slot[sl] |=
+ 1 << ref_frame_config->gld_fb_idx[sl];
+ } else {
+ // Non-zero spatiall layer.
+ ref_frame_config->reference_last[sl] = 1;
+ ref_frame_config->reference_golden[sl] = 1;
+ ref_frame_config->reference_alt_ref[sl] = 1;
+ ref_frame_config->update_buffer_slot[sl] |=
+ 1 << ref_frame_config->lst_fb_idx[sl];
+ }
+ }
+ } else if (tl == 1) {
+ if (!sl) {
+ // Base spatial and top temporal (tl = 1)
+ ref_frame_config->reference_last[sl] = 1;
+ ref_frame_config->reference_golden[sl] = 0;
+ ref_frame_config->reference_alt_ref[sl] = 0;
+ ref_frame_config->update_buffer_slot[sl] |=
+ 1 << ref_frame_config->alt_fb_idx[sl];
+ } else {
+ // Non-zero spatial.
+ if (sl < num_spatial_layers - 1) {
+ ref_frame_config->reference_last[sl] = 1;
+ ref_frame_config->reference_golden[sl] = 1;
+ ref_frame_config->reference_alt_ref[sl] = 0;
+ ref_frame_config->update_buffer_slot[sl] |=
+ 1 << ref_frame_config->alt_fb_idx[sl];
+ } else if (sl == num_spatial_layers - 1) {
+ // Top spatial and top temporal (non-reference -- doesn't update any
+ // reference buffers)
+ ref_frame_config->reference_last[sl] = 1;
+ ref_frame_config->reference_golden[sl] = 1;
+ ref_frame_config->reference_alt_ref[sl] = 0;
+ }
+ }
+ }
}
}
#include "test/svc_test.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
+#include "vp9/common/vp9_onyxc_int.h"
#include "vpx/vpx_codec.h"
#include "vpx_ports/bitops.h"
void set_frame_flags_bypass_mode(
int tl, int num_spatial_layers, int is_key_frame,
vpx_svc_ref_frame_config_t *ref_frame_config) {
+ for (int sl = 0; sl < num_spatial_layers; ++sl)
+ ref_frame_config->update_buffer_slot[sl] = 0;
+
for (int sl = 0; sl < num_spatial_layers; ++sl) {
- if (!tl) {
- if (!sl) {
- ref_frame_config->frame_flags[sl] =
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF;
- } else {
- if (is_key_frame) {
- ref_frame_config->frame_flags[sl] =
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
- } else {
- ref_frame_config->frame_flags[sl] =
- VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF |
- VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF;
- }
- }
- } else if (tl == 1) {
- if (!sl) {
- ref_frame_config->frame_flags[sl] =
- VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
- VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
- } else {
- ref_frame_config->frame_flags[sl] =
- VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
- VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_REF_GF;
- }
- }
if (tl == 0) {
ref_frame_config->lst_fb_idx[sl] = sl;
if (sl) {
ref_frame_config->alt_fb_idx[sl] = 0;
} else if (tl == 1) {
ref_frame_config->lst_fb_idx[sl] = sl;
- ref_frame_config->gld_fb_idx[sl] = num_spatial_layers + sl - 1;
- ref_frame_config->alt_fb_idx[sl] = num_spatial_layers + sl;
+ ref_frame_config->gld_fb_idx[sl] =
+ VPXMIN(REF_FRAMES - 1, num_spatial_layers + sl - 1);
+ ref_frame_config->alt_fb_idx[sl] =
+ VPXMIN(REF_FRAMES - 1, num_spatial_layers + sl);
+ }
+ if (!tl) {
+ if (!sl) {
+ ref_frame_config->reference_last[sl] = 1;
+ ref_frame_config->reference_golden[sl] = 0;
+ ref_frame_config->reference_alt_ref[sl] = 0;
+ ref_frame_config->update_buffer_slot[sl] |=
+ 1 << ref_frame_config->lst_fb_idx[sl];
+ } else {
+ if (is_key_frame) {
+ ref_frame_config->reference_last[sl] = 1;
+ ref_frame_config->reference_golden[sl] = 0;
+ ref_frame_config->reference_alt_ref[sl] = 0;
+ ref_frame_config->update_buffer_slot[sl] |=
+ 1 << ref_frame_config->gld_fb_idx[sl];
+ } else {
+ ref_frame_config->reference_last[sl] = 1;
+ ref_frame_config->reference_golden[sl] = 0;
+ ref_frame_config->reference_alt_ref[sl] = 0;
+ ref_frame_config->update_buffer_slot[sl] |=
+ 1 << ref_frame_config->lst_fb_idx[sl];
+ }
+ }
+ } else if (tl == 1) {
+ if (!sl) {
+ ref_frame_config->reference_last[sl] = 1;
+ ref_frame_config->reference_golden[sl] = 0;
+ ref_frame_config->reference_alt_ref[sl] = 0;
+ ref_frame_config->update_buffer_slot[sl] |=
+ 1 << ref_frame_config->alt_fb_idx[sl];
+ } else {
+ ref_frame_config->reference_last[sl] = 1;
+ ref_frame_config->reference_golden[sl] = 0;
+ ref_frame_config->reference_alt_ref[sl] = 0;
+ ref_frame_config->update_buffer_slot[sl] |=
+ 1 << ref_frame_config->alt_fb_idx[sl];
+ }
}
}
}
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += alt_ref_aq_segment_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += vp8_datarate_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += vp9_datarate_test.cc
-LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += svc_datarate_test.cc
-LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += svc_test.cc
-LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += svc_test.h
-LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += svc_end_to_end_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += encode_api_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += error_resilience_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += i420_video_source.h
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_ethread_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_motion_vector_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += level_test.cc
+LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_datarate_test.cc
+LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_test.cc
+LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_test.h
+LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_end_to_end_test.cc
LIBVPX_TEST_SRCS-yes += decode_test_driver.cc
LIBVPX_TEST_SRCS-yes += decode_test_driver.h
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
- ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
- 30, 1, 0, 140);
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
const int bitrates[4] = { 150, 350, 550, 750 };
const int bitrate_index = GET_PARAM(3);
cfg_.rc_target_bitrate = bitrates[bitrate_index];
cfg_.g_lag_in_frames = 0;
cfg_.g_error_resilient = 0;
- ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
- 30, 1, 0, 140);
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
const int bitrates[4] = { 150, 350, 550, 750 };
const int bitrate_index = GET_PARAM(3);
cfg_.rc_target_bitrate = bitrates[bitrate_index];
// Encode using multiple threads.
cfg_.g_threads = 2;
- ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
- 30, 1, 0, 140);
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
cfg_.rc_target_bitrate = 200;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// interval (128).
cfg_.kf_max_dist = 9999;
- ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
- 30, 1, 0, 140);
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
const int kDropFrameThreshTestStep = 30;
const int bitrates[2] = { 50, 150 };
cfg_.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS;
- ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
- 30, 1, 0, 200);
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
const int bitrates[4] = { 200, 400, 600, 800 };
const int bitrate_index = GET_PARAM(3);
cfg_.rc_target_bitrate = bitrates[bitrate_index];
cfg_.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS;
- ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
- 30, 1, 0, 200);
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
const int bitrates[4] = { 200, 400, 600, 800 };
const int bitrate_index = GET_PARAM(3);
cfg_.rc_target_bitrate = bitrates[bitrate_index];
cfg_.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS;
- ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
- 30, 1, 0, 200);
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
cfg_.rc_target_bitrate = 200;
ResetModel();
// 40-20-40 bitrate allocation for 3 temporal layers.
// Expect some frame drops in this test: for this 200 frames test,
// expect at least 10% and not more than 60% drops.
ASSERT_GE(num_drops_, 20);
- ASSERT_LE(num_drops_, 130);
+ ASSERT_LE(num_drops_, 280);
}
}
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
- ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
- 30, 1, 0, 300);
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
cfg_.rc_target_bitrate = 450;
- cfg_.g_w = 352;
- cfg_.g_h = 288;
+ cfg_.g_w = 640;
+ cfg_.g_h = 480;
ResetModel();
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
- ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
- 30, 1, 0, 140);
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
// For the temporal denoiser (#if CONFIG_VP9_TEMPORAL_DENOISING),
// there is only one denoiser mode: denoiserYonly(which is 1),
// but may add more modes in the future.
- cfg_.rc_target_bitrate = 300;
+ cfg_.rc_target_bitrate = 400;
ResetModel();
// Turn on the denoiser.
denoiser_on_ = 1;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
- ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
- 30, 1, 0, 299);
+ ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
+ 0, 400);
// For the temporal denoiser (#if CONFIG_VP9_TEMPORAL_DENOISING),
// there is only one denoiser mode: denoiserYonly(which is 1),
// but may add more modes in the future.
- cfg_.rc_target_bitrate = 300;
+ cfg_.rc_target_bitrate = 400;
ResetModel();
// The denoiser is off by default.
denoiser_on_ = 0;
const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
arf_idx = gf_group->arf_update_idx[gf_group->index];
}
+ if (cpi->use_svc &&
+ cpi->svc.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_BYPASS)
+ return cpi->svc.update_buffer_slot[cpi->svc.spatial_layer_id];
return (cpi->refresh_last_frame << cpi->lst_fb_idx) |
(cpi->refresh_golden_frame << cpi->gld_fb_idx) |
(cpi->refresh_alt_ref_frame << arf_idx);
return threshold;
}
+void vp9_denoiser_update_ref_frame(VP9_COMP *const cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ SVC *const svc = &cpi->svc;
+ if (cpi->oxcf.noise_sensitivity > 0 && denoise_svc(cpi) &&
+ cpi->denoiser.denoising_level > kDenLowLow) {
+ int svc_refresh_denoiser_buffers = 0;
+ int denoise_svc_second_layer = 0;
+ FRAME_TYPE frame_type = cm->intra_only ? KEY_FRAME : cm->frame_type;
+ if (cpi->use_svc) {
+ const int svc_buf_shift =
+ svc->number_spatial_layers - svc->spatial_layer_id == 2
+ ? cpi->denoiser.num_ref_frames
+ : 0;
+ int layer =
+ LAYER_IDS_TO_IDX(svc->spatial_layer_id, svc->temporal_layer_id,
+ svc->number_temporal_layers);
+ LAYER_CONTEXT *const lc = &svc->layer_context[layer];
+ svc_refresh_denoiser_buffers =
+ lc->is_key_frame || svc->spatial_layer_sync[svc->spatial_layer_id];
+ denoise_svc_second_layer =
+ svc->number_spatial_layers - svc->spatial_layer_id == 2 ? 1 : 0;
+ // Check if we need to allocate extra buffers in the denoiser
+ // for refreshed frames.
+ if (vp9_denoiser_realloc_svc(
+ cm, &cpi->denoiser, svc_buf_shift, cpi->refresh_alt_ref_frame,
+ cpi->refresh_golden_frame, cpi->refresh_last_frame,
+ cpi->alt_fb_idx, cpi->gld_fb_idx, cpi->lst_fb_idx))
+ vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+ "Failed to re-allocate denoiser for SVC");
+ }
+ vp9_denoiser_update_frame_info(
+ &cpi->denoiser, *cpi->Source, frame_type, cpi->refresh_alt_ref_frame,
+ cpi->refresh_golden_frame, cpi->refresh_last_frame, cpi->alt_fb_idx,
+ cpi->gld_fb_idx, cpi->lst_fb_idx, cpi->resize_pending,
+ svc_refresh_denoiser_buffers, denoise_svc_second_layer);
+ }
+}
+
#ifdef OUTPUT_YUV_DENOISED
static void make_grayscale(YV12_BUFFER_CONFIG *yuv) {
int r, c;
VP9_DENOISER_LEVEL noise_level, int abs_sumdiff,
int temporal_layer_id);
+void vp9_denoiser_update_ref_frame(struct VP9_COMP *const cpi);
+
#ifdef __cplusplus
} // extern "C"
#endif
}
// store estimated motion vector
- if (cpi->sf.adaptive_motion_search) store_pred_mv(x, ctx);
+ store_pred_mv(x, ctx);
// If the interp_filter is marked as SWITCHABLE_FILTERS, it was for an
// intra block and used for context purposes.
// the starting point of motion search in the following partition type check.
if (do_split || must_split) {
subsize = get_subsize(bsize, PARTITION_SPLIT);
- if (cpi->sf.adaptive_motion_search) load_pred_mv(x, ctx);
+ load_pred_mv(x, ctx);
if (bsize == BLOCK_8X8) {
i = 4;
if (cpi->sf.adaptive_pred_interp_filter && partition_none_allowed)
const int64_t part_mode_rdcost =
RDCOST(partition_mul, x->rddiv, part_mode_rate, 0);
subsize = get_subsize(bsize, PARTITION_HORZ);
- if (cpi->sf.adaptive_motion_search) load_pred_mv(x, ctx);
+ load_pred_mv(x, ctx);
if (cpi->sf.adaptive_pred_interp_filter && bsize == BLOCK_8X8 &&
partition_none_allowed)
pc_tree->horizontal[0].pred_interp_filter = pred_interp_filter;
const int64_t part_mode_rdcost =
RDCOST(partition_mul, x->rddiv, part_mode_rate, 0);
subsize = get_subsize(bsize, PARTITION_VERT);
- if (cpi->sf.adaptive_motion_search) load_pred_mv(x, ctx);
+ load_pred_mv(x, ctx);
if (cpi->sf.adaptive_pred_interp_filter && bsize == BLOCK_8X8 &&
partition_none_allowed)
pc_tree->vertical[0].pred_interp_filter = pred_interp_filter;
// PARTITION_HORZ
if (partition_horz_allowed && do_rect) {
subsize = get_subsize(bsize, PARTITION_HORZ);
- if (sf->adaptive_motion_search) load_pred_mv(x, ctx);
+ load_pred_mv(x, ctx);
pc_tree->horizontal[0].pred_pixel_ready = 1;
nonrd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &sum_rdc, subsize,
&pc_tree->horizontal[0]);
// PARTITION_VERT
if (partition_vert_allowed && do_rect) {
subsize = get_subsize(bsize, PARTITION_VERT);
- if (sf->adaptive_motion_search) load_pred_mv(x, ctx);
+ load_pred_mv(x, ctx);
pc_tree->vertical[0].pred_pixel_ready = 1;
nonrd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &sum_rdc, subsize,
&pc_tree->vertical[0]);
}
void vp9_update_reference_frames(VP9_COMP *cpi) {
- VP9_COMMON *const cm = &cpi->common;
- BufferPool *const pool = cm->buffer_pool;
- SVC *const svc = &cpi->svc;
-
if (cpi->extra_arf_allowed)
update_multi_arf_ref_frames(cpi);
else
update_ref_frames(cpi);
#if CONFIG_VP9_TEMPORAL_DENOISING
- if (cpi->oxcf.noise_sensitivity > 0 && denoise_svc(cpi) &&
- cpi->denoiser.denoising_level > kDenLowLow) {
- int svc_refresh_denoiser_buffers = 0;
- int denoise_svc_second_layer = 0;
- FRAME_TYPE frame_type = cm->intra_only ? KEY_FRAME : cm->frame_type;
- if (cpi->use_svc) {
- int realloc_fail = 0;
- const int svc_buf_shift =
- svc->number_spatial_layers - svc->spatial_layer_id == 2
- ? cpi->denoiser.num_ref_frames
- : 0;
- int layer =
- LAYER_IDS_TO_IDX(svc->spatial_layer_id, svc->temporal_layer_id,
- svc->number_temporal_layers);
- LAYER_CONTEXT *const lc = &svc->layer_context[layer];
- svc_refresh_denoiser_buffers =
- lc->is_key_frame || svc->spatial_layer_sync[svc->spatial_layer_id];
- denoise_svc_second_layer =
- svc->number_spatial_layers - svc->spatial_layer_id == 2 ? 1 : 0;
- // Check if we need to allocate extra buffers in the denoiser
- // for
- // refreshed frames.
- realloc_fail = vp9_denoiser_realloc_svc(
- cm, &cpi->denoiser, svc_buf_shift, cpi->refresh_alt_ref_frame,
- cpi->refresh_golden_frame, cpi->refresh_last_frame, cpi->alt_fb_idx,
- cpi->gld_fb_idx, cpi->lst_fb_idx);
- if (realloc_fail)
- vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
- "Failed to re-allocate denoiser for SVC");
- }
- vp9_denoiser_update_frame_info(
- &cpi->denoiser, *cpi->Source, frame_type, cpi->refresh_alt_ref_frame,
- cpi->refresh_golden_frame, cpi->refresh_last_frame, cpi->alt_fb_idx,
- cpi->gld_fb_idx, cpi->lst_fb_idx, cpi->resize_pending,
- svc_refresh_denoiser_buffers, denoise_svc_second_layer);
- }
+ vp9_denoiser_update_ref_frame(cpi);
#endif
- if (is_one_pass_cbr_svc(cpi)) {
- // Keep track of frame index for each reference frame.
- if (cm->frame_type == KEY_FRAME) {
- int i;
- // On key frame update all reference frame slots.
- for (i = 0; i < REF_FRAMES; i++) {
- svc->fb_idx_spatial_layer_id[i] = svc->spatial_layer_id;
- svc->fb_idx_temporal_layer_id[i] = svc->temporal_layer_id;
- // LAST/GOLDEN/ALTREF is already updated above.
- if (i != cpi->lst_fb_idx && i != cpi->gld_fb_idx &&
- i != cpi->alt_fb_idx)
- ref_cnt_fb(pool->frame_bufs, &cm->ref_frame_map[i], cm->new_fb_idx);
- }
- } else {
- if (cpi->refresh_last_frame) {
- svc->fb_idx_spatial_layer_id[cpi->lst_fb_idx] = svc->spatial_layer_id;
- svc->fb_idx_temporal_layer_id[cpi->lst_fb_idx] = svc->temporal_layer_id;
- }
- if (cpi->refresh_golden_frame) {
- svc->fb_idx_spatial_layer_id[cpi->gld_fb_idx] = svc->spatial_layer_id;
- svc->fb_idx_temporal_layer_id[cpi->gld_fb_idx] = svc->temporal_layer_id;
- }
- if (cpi->refresh_alt_ref_frame) {
- svc->fb_idx_spatial_layer_id[cpi->alt_fb_idx] = svc->spatial_layer_id;
- svc->fb_idx_temporal_layer_id[cpi->alt_fb_idx] = svc->temporal_layer_id;
- }
- }
- // Copy flags from encoder to SVC struct.
- vp9_copy_flags_ref_update_idx(cpi);
- vp9_svc_update_ref_frame_buffer_idx(cpi);
- }
+ if (is_one_pass_cbr_svc(cpi)) vp9_svc_update_ref_frame(cpi);
}
static void loopfilter_frame(VP9_COMP *cpi, VP9_COMMON *cm) {
MACROBLOCKD *xd = &cpi->td.mb.e_mbd;
struct loopfilter *lf = &cm->lf;
-
- const int is_reference_frame =
+ int is_reference_frame =
(cm->frame_type == KEY_FRAME || cpi->refresh_last_frame ||
cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame);
+ if (cpi->use_svc &&
+ cpi->svc.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_BYPASS)
+ is_reference_frame = !cpi->svc.non_reference_frame;
if (xd->lossless) {
lf->filter_level = 0;
vp9_svc_assert_constraints_pattern(cpi);
}
- if (!cpi->sf.re_encode_overshoot_rt &&
- cpi->oxcf.content == VP9E_CONTENT_SCREEN &&
+ // Check if this high_source_sad (scene/slide change) frame should be
+ // encoded at high/max QP, and if so, set the q and adjust some rate
+ // control parameters.
+ if (cpi->sf.overshoot_detection_rt == 1 &&
(cpi->rc.high_source_sad ||
(cpi->use_svc && cpi->svc.high_source_sad_superframe))) {
- // Check if this high_source_sad (scene/slide change) frame should be
- // encoded at high/max QP, and if so, set the q and adjust some rate
- // control parameters.
if (vp9_encodedframe_overshoot(cpi, -1, &q)) {
vp9_set_quantizer(cm, q);
vp9_set_variance_partition_thresholds(cpi, q, 0);
vp9_encode_frame(cpi);
- // Check if we should drop this frame because of high overshoot.
- // Only for frames where high temporal-source SAD is detected.
+ // Check if we should re-encode this frame at high Q because of high
+ // overshoot based on the encoded frame size. Only for frames where
+ // high temporal-source SAD is detected.
// For SVC: all spatial layers are checked for re-encoding.
- if (cpi->sf.re_encode_overshoot_rt &&
+ if (cpi->sf.overshoot_detection_rt == 2 &&
(cpi->rc.high_source_sad ||
(cpi->use_svc && cpi->svc.high_source_sad_superframe))) {
int frame_size = 0;
if (cpi->svc.spatial_layer_id == 0 && src_width == last_src_width &&
src_height == last_src_height) {
YV12_BUFFER_CONFIG *frames[MAX_LAG_BUFFERS] = { NULL };
+ int num_mi_cols = cm->mi_cols;
+ int num_mi_rows = cm->mi_rows;
int start_frame = 0;
int frames_to_buffer = 1;
int frame = 0;
float thresh = 8.0f;
uint32_t thresh_key = 140000;
if (cpi->oxcf.speed <= 5) thresh_key = 240000;
- if (cpi->oxcf.rc_mode == VPX_VBR) {
- min_thresh = 65000;
- thresh = 2.1f;
+ if (cpi->oxcf.content != VP9E_CONTENT_SCREEN) min_thresh = 65000;
+ if (cpi->oxcf.rc_mode == VPX_VBR) thresh = 2.1f;
+ if (cpi->use_svc && cpi->svc.number_spatial_layers > 1) {
+ const int aligned_width = ALIGN_POWER_OF_TWO(src_width, MI_SIZE_LOG2);
+ const int aligned_height = ALIGN_POWER_OF_TWO(src_height, MI_SIZE_LOG2);
+ num_mi_cols = aligned_width >> MI_SIZE_LOG2;
+ num_mi_rows = aligned_height >> MI_SIZE_LOG2;
}
if (cpi->oxcf.lag_in_frames > 0) {
frames_to_buffer = (cm->current_video_frame == 1)
uint64_t avg_sad = 0;
uint64_t tmp_sad = 0;
int num_samples = 0;
- int sb_cols = (cm->mi_cols + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
- int sb_rows = (cm->mi_rows + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
+ int sb_cols = (num_mi_cols + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
+ int sb_rows = (num_mi_rows + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
if (cpi->oxcf.lag_in_frames > 0) {
src_y = frames[frame]->y_buffer;
src_ystride = frames[frame]->y_stride;
if (avg_sad >
VPXMAX(min_thresh,
(unsigned int)(rc->avg_source_sad[0] * thresh)) &&
- rc->frames_since_key > 1 &&
+ rc->frames_since_key > 1 + cpi->svc.number_spatial_layers &&
num_zero_temp_sad < 3 * (num_samples >> 2))
rc->high_source_sad = 1;
else
SPEED_FEATURES *const sf = &cpi->sf;
int thresh_qp = 7 * (rc->worst_quality >> 3);
int thresh_rate = rc->avg_frame_bandwidth << 3;
- // Lower rate threshold for video.
+ // Lower thresh_qp for video (more overshoot at lower Q) to be
+ // more conservative for video.
if (cpi->oxcf.content != VP9E_CONTENT_SCREEN)
- thresh_rate = rc->avg_frame_bandwidth << 2;
+ thresh_qp = rc->worst_quality >> 1;
// If this decision is not based on an encoded frame size but just on
- // scene/slide change detection (i.e., re_encode_overshoot_rt = 0), adjust the
- // qp_thresh and skip the (frame_size > thresh_rate) condition in this case.
- if (!sf->re_encode_overshoot_rt) thresh_qp = 3 * (rc->worst_quality >> 2);
- if ((!sf->re_encode_overshoot_rt || frame_size > thresh_rate) &&
+ // scene/slide change detection (i.e., re_encode_overshoot_rt = 1),
+ // for now skip the (frame_size > thresh_rate) condition in this case.
+ // TODO(marpan): Use a better size/rate condition for this case and
+ // adjust thresholds.
+ if ((sf->overshoot_detection_rt == 1 || frame_size > thresh_rate) &&
cm->base_qindex < thresh_qp) {
double rate_correction_factor =
cpi->rc.rate_correction_factors[INTER_NORMAL];
// and the encoded frame used alot of Intra modes, then force hybrid_intra
// encoding for the re-encode on this scene change. hybrid_intra will
// use rd-based intra mode selection for small blocks.
- if (sf->re_encode_overshoot_rt && frame_size > (thresh_rate << 1) &&
+ if (sf->overshoot_detection_rt == 2 && frame_size > (thresh_rate << 1) &&
cpi->svc.spatial_layer_id == 0) {
MODE_INFO **mi = cm->mi_grid_visible;
int sum_intra_usage = 0;
LAYER_CONTEXT *lc = &svc->layer_context[layer];
RATE_CONTROL *lrc = &lc->rc;
lrc->avg_frame_qindex[INTER_FRAME] = *q;
- lrc->buffer_level = rc->optimal_buffer_level;
- lrc->bits_off_target = rc->optimal_buffer_level;
+ lrc->buffer_level = lrc->optimal_buffer_level;
+ lrc->bits_off_target = lrc->optimal_buffer_level;
lrc->rc_1_frame = 0;
lrc->rc_2_frame = 0;
lrc->rate_correction_factors[INTER_NORMAL] = rate_correction_factor;
uint8_t *src_y_ptr = x->plane[0].src.buf;
uint8_t *ref_y_ptr;
const int num_mv_refs =
- MAX_MV_REF_CANDIDATES +
- (cpi->sf.adaptive_motion_search && block_size < x->max_partition_size);
+ MAX_MV_REF_CANDIDATES + (block_size < x->max_partition_size);
MV pred_mv[3];
pred_mv[0] = x->mbmi_ext->ref_mvs[ref_frame][0].as_mv;
seg_mvs[i][mi->ref_frame[0]].as_mv = *new_mv;
}
- if (sf->adaptive_motion_search)
- x->pred_mv[mi->ref_frame[0]] = *new_mv;
+ x->pred_mv[mi->ref_frame[0]] = *new_mv;
// restore src pointers
mi_buf_restore(x, orig_src, orig_pre);
}
if (cpi->sf.adaptive_motion_search && bsize < BLOCK_64X64) {
- int boffset =
+ const int boffset =
2 * (b_width_log2_lookup[BLOCK_64X64] -
VPXMIN(b_height_log2_lookup[bsize], b_width_log2_lookup[bsize]));
step_param = VPXMAX(step_param, boffset);
*rate_mv = vp9_mv_bit_cost(&tmp_mv->as_mv, &ref_mv, x->nmvjointcost,
x->mvcost, MV_COST_WEIGHT);
- if (cpi->sf.adaptive_motion_search) x->pred_mv[ref] = tmp_mv->as_mv;
+ x->pred_mv[ref] = tmp_mv->as_mv;
if (scaled_ref_frame) {
int i;
sf->use_compound_nonrd_pickmode = 0;
sf->nonrd_keyframe = 0;
sf->svc_use_lowres_part = 0;
- sf->re_encode_overshoot_rt = 0;
+ sf->overshoot_detection_rt = 0;
sf->disable_16x16part_nonkey = 0;
sf->disable_golden_ref = 0;
sf->enable_tpl_model = 0;
// Keep nonrd_keyframe = 1 for non-base spatial layers to prevent
// increase in encoding time.
if (cpi->use_svc && cpi->svc.spatial_layer_id > 0) sf->nonrd_keyframe = 1;
- if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_CBR &&
- cm->frame_type != KEY_FRAME && cpi->resize_state == ORIG &&
- (cpi->use_svc || cpi->oxcf.content == VP9E_CONTENT_SCREEN)) {
- sf->re_encode_overshoot_rt = 1;
- }
+ if (cm->frame_type != KEY_FRAME && cpi->resize_state == ORIG &&
+ cpi->oxcf.rc_mode == VPX_CBR)
+ sf->overshoot_detection_rt = 1;
if (cpi->oxcf.rc_mode == VPX_VBR && cpi->oxcf.lag_in_frames > 0 &&
cm->width <= 1280 && cm->height <= 720) {
sf->use_altref_onepass = 1;
}
if (speed >= 6) {
- sf->re_encode_overshoot_rt = 0;
if (cpi->oxcf.rc_mode == VPX_VBR && cpi->oxcf.lag_in_frames > 0) {
sf->use_altref_onepass = 1;
sf->use_compound_nonrd_pickmode = 1;
// For SVC: enables use of partition from lower spatial resolution.
int svc_use_lowres_part;
- // Enable re-encoding on scene change with potential high overshoot,
- // for real-time encoding flow.
- int re_encode_overshoot_rt;
+ // Flag to indicate process for handling overshoot on slide/scene change,
+ // for real-time CBR mode.
+ // 0: no reaction to rate control on a detected slide/scene change
+ // (prior to encoding the frame).
+ // 1: set to larger Q based only on the detected slide/scene change
+ // and current/past Q. No second pass encoding, so faster than option 2.
+ // 2: based on (first pass) encoded frame, if large frame size is detected
+ // then set to higher Q for second encode. This involves 2 pass encoding
+ // on slide change, so slower than 1, but more accurate for detecting
+ // overshoot.
+ int overshoot_detection_rt;
// Disable partitioning of 16x16 blocks.
int disable_16x16part_nonkey;
reset_fb_idx_unused(cpi);
}
+static void set_flags_and_fb_idx_bypass_via_set_ref_frame_config(
+ VP9_COMP *const cpi) {
+ SVC *const svc = &cpi->svc;
+ int sl = svc->spatial_layer_id = svc->spatial_layer_to_encode;
+ cpi->ext_refresh_frame_flags_pending = 1;
+ cpi->lst_fb_idx = svc->lst_fb_idx[sl];
+ cpi->gld_fb_idx = svc->gld_fb_idx[sl];
+ cpi->alt_fb_idx = svc->alt_fb_idx[sl];
+ cpi->ext_refresh_last_frame = 0;
+ cpi->ext_refresh_golden_frame = 0;
+ cpi->ext_refresh_alt_ref_frame = 0;
+ cpi->ref_frame_flags = 0;
+ if (svc->reference_last[sl]) cpi->ref_frame_flags |= VP9_LAST_FLAG;
+ if (svc->reference_golden[sl]) cpi->ref_frame_flags |= VP9_GOLD_FLAG;
+ if (svc->reference_altref[sl]) cpi->ref_frame_flags |= VP9_ALT_FLAG;
+}
+
void vp9_copy_flags_ref_update_idx(VP9_COMP *const cpi) {
SVC *const svc = &cpi->svc;
static const int flag_list[4] = { 0, VP9_LAST_FLAG, VP9_GOLD_FLAG,
svc->lst_fb_idx[sl] = cpi->lst_fb_idx;
svc->gld_fb_idx[sl] = cpi->gld_fb_idx;
svc->alt_fb_idx[sl] = cpi->alt_fb_idx;
-
+ // For the fixed SVC mode: pass the refresh_lst/gld/alt_frame flags to the
+ // update_buffer_slot, this is needed for the GET_SVC_REF_FRAME_CONFIG api.
+ if (svc->temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
+ int ref;
+ for (ref = 0; ref < REF_FRAMES; ++ref) {
+ svc->update_buffer_slot[sl] &= ~(1 << ref);
+ if ((ref == svc->lst_fb_idx[sl] && cpi->refresh_last_frame) ||
+ (ref == svc->gld_fb_idx[sl] && cpi->refresh_golden_frame) ||
+ (ref == svc->alt_fb_idx[sl] && cpi->refresh_alt_ref_frame))
+ svc->update_buffer_slot[sl] |= (1 << ref);
+ }
+ }
+ // TODO(jianj): Remove these 3, deprecated.
svc->update_last[sl] = (uint8_t)cpi->refresh_last_frame;
svc->update_golden[sl] = (uint8_t)cpi->refresh_golden_frame;
svc->update_altref[sl] = (uint8_t)cpi->refresh_alt_ref_frame;
+
svc->reference_last[sl] =
(uint8_t)(cpi->ref_frame_flags & flag_list[LAST_FRAME]);
svc->reference_golden[sl] =
set_flags_and_fb_idx_for_temporal_mode2(cpi);
} else if (svc->temporal_layering_mode ==
VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
- // In the BYPASS/flexible mode, the encoder is relying on the application
- // to specify, for each spatial layer, the flags and buffer indices for the
- // layering.
- // Note that the check (cpi->ext_refresh_frame_flags_pending == 0) is
- // needed to support the case where the frame flags may be passed in via
- // vpx_codec_encode(), which can be used for the temporal-only svc case.
- // TODO(marpan): Consider adding an enc_config parameter to better handle
- // this case.
- if (cpi->ext_refresh_frame_flags_pending == 0) {
- int sl;
- svc->spatial_layer_id = svc->spatial_layer_to_encode;
- sl = svc->spatial_layer_id;
- vp9_apply_encoding_flags(cpi, svc->ext_frame_flags[sl]);
- cpi->lst_fb_idx = svc->lst_fb_idx[sl];
- cpi->gld_fb_idx = svc->gld_fb_idx[sl];
- cpi->alt_fb_idx = svc->alt_fb_idx[sl];
- }
+ if (cpi->ext_refresh_frame_flags_pending == 0)
+ set_flags_and_fb_idx_bypass_via_set_ref_frame_config(cpi);
}
if (cpi->lst_fb_idx == svc->buffer_gf_temporal_ref[0].idx ||
memset(&svc->lst_fb_idx, -1, sizeof(svc->lst_fb_idx));
memset(&svc->gld_fb_idx, -1, sizeof(svc->lst_fb_idx));
memset(&svc->alt_fb_idx, -1, sizeof(svc->lst_fb_idx));
+ // These are set by API before the superframe is encoded and they are
+ // passed to encoder layer by layer. Don't reset them on layer 0 in bypass
+ // mode.
+ vp9_zero(svc->update_buffer_slot);
+ vp9_zero(svc->reference_last);
+ vp9_zero(svc->reference_golden);
+ vp9_zero(svc->reference_altref);
+ // TODO(jianj): Remove these 3, deprecated.
+ vp9_zero(svc->update_last);
+ vp9_zero(svc->update_golden);
+ vp9_zero(svc->update_altref);
}
- vp9_zero(svc->update_last);
- vp9_zero(svc->update_golden);
- vp9_zero(svc->update_altref);
- vp9_zero(svc->reference_last);
- vp9_zero(svc->reference_golden);
- vp9_zero(svc->reference_altref);
}
lc = &svc->layer_context[svc->spatial_layer_id * svc->number_temporal_layers +
svc->non_reference_frame = 0;
if (cpi->common.frame_type != KEY_FRAME && !cpi->ext_refresh_last_frame &&
- !cpi->ext_refresh_golden_frame && !cpi->ext_refresh_alt_ref_frame) {
+ !cpi->ext_refresh_golden_frame && !cpi->ext_refresh_alt_ref_frame)
svc->non_reference_frame = 1;
+ // For non-flexible mode, where update_buffer_slot is used, need to check if
+ // all buffer slots are not refreshed.
+ if (svc->temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
+ if (svc->update_buffer_slot[svc->spatial_layer_id] != 0)
+ svc->non_reference_frame = 0;
}
if (svc->spatial_layer_id == 0) svc->high_source_sad_superframe = 0;
void vp9_svc_constrain_inter_layer_pred(VP9_COMP *const cpi) {
VP9_COMMON *const cm = &cpi->common;
+ SVC *const svc = &cpi->svc;
// Check for disabling inter-layer (spatial) prediction, if
// svc.disable_inter_layer_pred is set. If the previous spatial layer was
// dropped then disable the prediction from this (scaled) reference.
// For INTER_LAYER_PRED_OFF_NONKEY: inter-layer prediction is disabled
// on key frames or if any spatial layer is a sync layer.
- if ((cpi->svc.disable_inter_layer_pred == INTER_LAYER_PRED_OFF_NONKEY &&
- !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame &&
- !cpi->svc.superframe_has_layer_sync) ||
- cpi->svc.disable_inter_layer_pred == INTER_LAYER_PRED_OFF ||
- cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id - 1]) {
+ if ((svc->disable_inter_layer_pred == INTER_LAYER_PRED_OFF_NONKEY &&
+ !svc->layer_context[svc->temporal_layer_id].is_key_frame &&
+ !svc->superframe_has_layer_sync) ||
+ svc->disable_inter_layer_pred == INTER_LAYER_PRED_OFF ||
+ svc->drop_spatial_layer[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 };
// prediction (the reference that is scaled) is not the previous spatial layer
// from the same superframe, then we disable inter-layer prediction.
// Only need to check when inter_layer prediction is not set to OFF mode.
- if (cpi->svc.disable_inter_layer_pred != INTER_LAYER_PRED_OFF) {
+ if (svc->disable_inter_layer_pred != INTER_LAYER_PRED_OFF) {
// We only use LAST and GOLDEN for prediction in real-time mode, so we
// check both here.
MV_REFERENCE_FRAME ref_frame;
int fb_idx =
ref_frame == LAST_FRAME ? cpi->lst_fb_idx : cpi->gld_fb_idx;
int ref_flag = ref_frame == LAST_FRAME ? VP9_LAST_FLAG : VP9_GOLD_FLAG;
- int sl = cpi->svc.spatial_layer_id;
+ int sl = svc->spatial_layer_id;
int disable = 1;
- if ((fb_idx == cpi->svc.lst_fb_idx[sl - 1] &&
- cpi->svc.update_last[sl - 1]) ||
- (fb_idx == cpi->svc.gld_fb_idx[sl - 1] &&
- cpi->svc.update_golden[sl - 1]) ||
- (fb_idx == cpi->svc.alt_fb_idx[sl - 1] &&
- cpi->svc.update_altref[sl - 1]))
+ if (fb_idx < 0) continue;
+ if ((fb_idx == svc->lst_fb_idx[sl - 1] &&
+ (svc->update_buffer_slot[sl - 1] & (1 << fb_idx))) ||
+ (fb_idx == svc->gld_fb_idx[sl - 1] &&
+ (svc->update_buffer_slot[sl - 1] & (1 << fb_idx))) ||
+ (fb_idx == svc->alt_fb_idx[sl - 1] &&
+ (svc->update_buffer_slot[sl - 1] & (1 << fb_idx))))
disable = 0;
if (disable) cpi->ref_frame_flags &= (~ref_flag);
}
svc->fb_idx_base[cpi->alt_fb_idx] = 1;
}
}
+
+static void vp9_svc_update_ref_frame_bypass_mode(VP9_COMP *const cpi) {
+ // For non-flexible/bypass SVC mode: check for refreshing other buffer
+ // slots.
+ SVC *const svc = &cpi->svc;
+ VP9_COMMON *const cm = &cpi->common;
+ BufferPool *const pool = cm->buffer_pool;
+ int i;
+ for (i = 0; i < REF_FRAMES; i++) {
+ if (cm->frame_type == KEY_FRAME ||
+ svc->update_buffer_slot[svc->spatial_layer_id] & (1 << i)) {
+ ref_cnt_fb(pool->frame_bufs, &cm->ref_frame_map[i], cm->new_fb_idx);
+ svc->fb_idx_spatial_layer_id[i] = svc->spatial_layer_id;
+ svc->fb_idx_temporal_layer_id[i] = svc->temporal_layer_id;
+ }
+ }
+}
+
+void vp9_svc_update_ref_frame(VP9_COMP *const cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ SVC *const svc = &cpi->svc;
+ BufferPool *const pool = cm->buffer_pool;
+
+ if (svc->temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
+ vp9_svc_update_ref_frame_bypass_mode(cpi);
+ } else if (cm->frame_type == KEY_FRAME) {
+ // Keep track of frame index for each reference frame.
+ int i;
+ // On key frame update all reference frame slots.
+ for (i = 0; i < REF_FRAMES; i++) {
+ svc->fb_idx_spatial_layer_id[i] = svc->spatial_layer_id;
+ svc->fb_idx_temporal_layer_id[i] = svc->temporal_layer_id;
+ // LAST/GOLDEN/ALTREF is already updated above.
+ if (i != cpi->lst_fb_idx && i != cpi->gld_fb_idx && i != cpi->alt_fb_idx)
+ ref_cnt_fb(pool->frame_bufs, &cm->ref_frame_map[i], cm->new_fb_idx);
+ }
+ } else {
+ if (cpi->refresh_last_frame) {
+ svc->fb_idx_spatial_layer_id[cpi->lst_fb_idx] = svc->spatial_layer_id;
+ svc->fb_idx_temporal_layer_id[cpi->lst_fb_idx] = svc->temporal_layer_id;
+ }
+ if (cpi->refresh_golden_frame) {
+ svc->fb_idx_spatial_layer_id[cpi->gld_fb_idx] = svc->spatial_layer_id;
+ svc->fb_idx_temporal_layer_id[cpi->gld_fb_idx] = svc->temporal_layer_id;
+ }
+ if (cpi->refresh_alt_ref_frame) {
+ svc->fb_idx_spatial_layer_id[cpi->alt_fb_idx] = svc->spatial_layer_id;
+ svc->fb_idx_temporal_layer_id[cpi->alt_fb_idx] = svc->temporal_layer_id;
+ }
+ }
+ // Copy flags from encoder to SVC struct.
+ vp9_copy_flags_ref_update_idx(cpi);
+ vp9_svc_update_ref_frame_buffer_idx(cpi);
+}
int high_source_sad_superframe;
// Flags used to get SVC pattern info.
- uint8_t update_last[VPX_SS_MAX_LAYERS];
- uint8_t update_golden[VPX_SS_MAX_LAYERS];
- uint8_t update_altref[VPX_SS_MAX_LAYERS];
+ int update_buffer_slot[VPX_SS_MAX_LAYERS];
uint8_t reference_last[VPX_SS_MAX_LAYERS];
uint8_t reference_golden[VPX_SS_MAX_LAYERS];
uint8_t reference_altref[VPX_SS_MAX_LAYERS];
+ // TODO(jianj): Remove these last 3, deprecated.
+ uint8_t update_last[VPX_SS_MAX_LAYERS];
+ uint8_t update_golden[VPX_SS_MAX_LAYERS];
+ uint8_t update_altref[VPX_SS_MAX_LAYERS];
// Keep track of the frame buffer index updated/refreshed on the base
// temporal superframe.
void vp9_svc_update_ref_frame_buffer_idx(struct VP9_COMP *const cpi);
+void vp9_svc_update_ref_frame(struct VP9_COMP *const cpi);
+
#ifdef __cplusplus
} // extern "C"
#endif
vpx_svc_ref_frame_config_t *data = va_arg(args, vpx_svc_ref_frame_config_t *);
int sl;
for (sl = 0; sl <= cpi->svc.spatial_layer_id; sl++) {
- data->update_last[sl] = cpi->svc.update_last[sl];
- data->update_golden[sl] = cpi->svc.update_golden[sl];
- data->update_alt_ref[sl] = cpi->svc.update_altref[sl];
+ data->update_buffer_slot[sl] = cpi->svc.update_buffer_slot[sl];
data->reference_last[sl] = cpi->svc.reference_last[sl];
data->reference_golden[sl] = cpi->svc.reference_golden[sl];
data->reference_alt_ref[sl] = cpi->svc.reference_altref[sl];
data->lst_fb_idx[sl] = cpi->svc.lst_fb_idx[sl];
data->gld_fb_idx[sl] = cpi->svc.gld_fb_idx[sl];
data->alt_fb_idx[sl] = cpi->svc.alt_fb_idx[sl];
+ // TODO(jianj): Remove these 3, deprecated.
+ data->update_last[sl] = cpi->svc.update_last[sl];
+ data->update_golden[sl] = cpi->svc.update_golden[sl];
+ data->update_alt_ref[sl] = cpi->svc.update_altref[sl];
}
return VPX_CODEC_OK;
}
vpx_svc_ref_frame_config_t *data = va_arg(args, vpx_svc_ref_frame_config_t *);
int sl;
for (sl = 0; sl < cpi->svc.number_spatial_layers; ++sl) {
- cpi->svc.ext_frame_flags[sl] = data->frame_flags[sl];
+ cpi->svc.update_buffer_slot[sl] = data->update_buffer_slot[sl];
+ cpi->svc.reference_last[sl] = data->reference_last[sl];
+ cpi->svc.reference_golden[sl] = data->reference_golden[sl];
+ cpi->svc.reference_altref[sl] = data->reference_alt_ref[sl];
cpi->svc.lst_fb_idx[sl] = data->lst_fb_idx[sl];
cpi->svc.gld_fb_idx[sl] = data->gld_fb_idx[sl];
cpi->svc.alt_fb_idx[sl] = data->alt_fb_idx[sl];
*
*/
typedef struct vpx_svc_ref_frame_config {
- // TODO(jianj/marpan): Remove the usage of frame_flags, instead use the
- // update and reference flags.
- int frame_flags[VPX_SS_MAX_LAYERS]; /**< Frame flags. */
- int lst_fb_idx[VPX_SS_MAX_LAYERS]; /**< Last buffer index. */
- int gld_fb_idx[VPX_SS_MAX_LAYERS]; /**< Golden buffer index. */
- int alt_fb_idx[VPX_SS_MAX_LAYERS]; /**< Altref buffer index. */
+ int lst_fb_idx[VPX_SS_MAX_LAYERS]; /**< Last buffer index. */
+ int gld_fb_idx[VPX_SS_MAX_LAYERS]; /**< Golden buffer index. */
+ int alt_fb_idx[VPX_SS_MAX_LAYERS]; /**< Altref buffer index. */
+ int update_buffer_slot[VPX_SS_MAX_LAYERS]; /**< Update reference frames. */
+ // TODO(jianj): Remove update_last/golden/alt_ref, these are deprecated.
int update_last[VPX_SS_MAX_LAYERS]; /**< Update last. */
int update_golden[VPX_SS_MAX_LAYERS]; /**< Update golden. */
int update_alt_ref[VPX_SS_MAX_LAYERS]; /**< Update altref. */