int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) { int width = 0, height = 0; LAYER_CONTEXT *lc = NULL; if (cpi->svc.number_spatial_layers > 1) cpi->svc.use_base_mv = 1; cpi->svc.force_zero_mode_spatial_ref = 1; if (cpi->svc.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0212) { set_flags_and_fb_idx_for_temporal_mode3(cpi); } else if (cpi->svc.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING) { set_flags_and_fb_idx_for_temporal_mode_noLayering(cpi); } else if (cpi->svc.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0101) { set_flags_and_fb_idx_for_temporal_mode2(cpi); } else if (cpi->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; cpi->svc.spatial_layer_id = cpi->svc.spatial_layer_to_encode; sl = cpi->svc.spatial_layer_id; vp9_apply_encoding_flags(cpi, cpi->svc.ext_frame_flags[sl]); cpi->lst_fb_idx = cpi->svc.ext_lst_fb_idx[sl]; cpi->gld_fb_idx = cpi->svc.ext_gld_fb_idx[sl]; cpi->alt_fb_idx = cpi->svc.ext_alt_fb_idx[sl]; } } if (cpi->svc.spatial_layer_id == cpi->svc.first_spatial_layer_to_encode) cpi->svc.rc_drop_superframe = 0; lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id * cpi->svc.number_temporal_layers + cpi->svc.temporal_layer_id]; // Setting the worst/best_quality via the encoder control: SET_SVC_PARAMETERS, // only for non-BYPASS mode for now. if (cpi->svc.temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS) { RATE_CONTROL *const lrc = &lc->rc; lrc->worst_quality = vp9_quantizer_to_qindex(lc->max_q); lrc->best_quality = vp9_quantizer_to_qindex(lc->min_q); } get_layer_resolution(cpi->oxcf.width, cpi->oxcf.height, lc->scaling_factor_num, lc->scaling_factor_den, &width, &height); if (vp9_set_size_literal(cpi, width, height) != 0) return VPX_CODEC_INVALID_PARAM; return 0; }
int vp9_svc_start_frame(VP9_COMP *const cpi) { int width = 0, height = 0; LAYER_CONTEXT *lc; struct lookahead_entry *buf; int count = 1 << (cpi->svc.number_temporal_layers - 1); cpi->svc.spatial_layer_id = cpi->svc.spatial_layer_to_encode; lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id]; cpi->svc.temporal_layer_id = 0; while ((lc->current_video_frame_in_layer % count) != 0) { ++cpi->svc.temporal_layer_id; count >>= 1; } cpi->ref_frame_flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG; cpi->lst_fb_idx = cpi->svc.spatial_layer_id; if (cpi->svc.spatial_layer_id == 0) cpi->gld_fb_idx = (lc->gold_ref_idx >= 0) ? lc->gold_ref_idx : cpi->lst_fb_idx; else cpi->gld_fb_idx = cpi->svc.spatial_layer_id - 1; if (lc->current_video_frame_in_layer == 0) { if (cpi->svc.spatial_layer_id >= 2) { cpi->alt_fb_idx = cpi->svc.spatial_layer_id - 2; } else { cpi->alt_fb_idx = cpi->lst_fb_idx; cpi->ref_frame_flags &= (~VP9_LAST_FLAG & ~VP9_ALT_FLAG); } } else { if (cpi->oxcf.ss_enable_auto_arf[cpi->svc.spatial_layer_id]) { cpi->alt_fb_idx = lc->alt_ref_idx; if (!lc->has_alt_frame) cpi->ref_frame_flags &= (~VP9_ALT_FLAG); } else { // Find a proper alt_fb_idx for layers that don't have alt ref frame if (cpi->svc.spatial_layer_id == 0) { cpi->alt_fb_idx = cpi->lst_fb_idx; } else { LAYER_CONTEXT *lc_lower = &cpi->svc.layer_context[cpi->svc.spatial_layer_id - 1]; if (cpi->oxcf.ss_enable_auto_arf[cpi->svc.spatial_layer_id - 1] && lc_lower->alt_ref_source != NULL) cpi->alt_fb_idx = lc_lower->alt_ref_idx; else if (cpi->svc.spatial_layer_id >= 2) cpi->alt_fb_idx = cpi->svc.spatial_layer_id - 2; else cpi->alt_fb_idx = cpi->lst_fb_idx; } } } get_layer_resolution(cpi->oxcf.width, cpi->oxcf.height, lc->scaling_factor_num, lc->scaling_factor_den, &width, &height); // Workaround for multiple frame contexts. In some frames we can't use prev_mi // since its previous frame could be changed during decoding time. The idea is // we put a empty invisible frame in front of them, then we will not use // prev_mi when encoding these frames. buf = vp9_lookahead_peek(cpi->lookahead, 0); if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2 && cpi->svc.encode_empty_frame_state == NEED_TO_ENCODE && lc->rc.frames_to_key != 0 && !(buf != NULL && (buf->flags & VPX_EFLAG_FORCE_KF))) { if ((cpi->svc.number_temporal_layers > 1 && cpi->svc.temporal_layer_id < cpi->svc.number_temporal_layers - 1) || (cpi->svc.number_spatial_layers > 1 && cpi->svc.spatial_layer_id == 0)) { struct lookahead_entry *buf = vp9_lookahead_peek(cpi->lookahead, 0); if (buf != NULL) { cpi->svc.empty_frame.ts_start = buf->ts_start; cpi->svc.empty_frame.ts_end = buf->ts_end; cpi->svc.encode_empty_frame_state = ENCODING; cpi->common.show_frame = 0; cpi->ref_frame_flags = 0; cpi->common.frame_type = INTER_FRAME; cpi->lst_fb_idx = cpi->gld_fb_idx = cpi->alt_fb_idx = SMALL_FRAME_FB_IDX; if (cpi->svc.encode_intra_empty_frame != 0) cpi->common.intra_only = 1; width = SMALL_FRAME_WIDTH; height = SMALL_FRAME_HEIGHT; } } } cpi->oxcf.worst_allowed_q = vp9_quantizer_to_qindex(lc->max_q); cpi->oxcf.best_allowed_q = vp9_quantizer_to_qindex(lc->min_q); vp9_change_config(cpi, &cpi->oxcf); if (vp9_set_size_literal(cpi, width, height) != 0) return VPX_CODEC_INVALID_PARAM; vp9_set_high_precision_mv(cpi, 1); cpi->alt_ref_source = get_layer_context(cpi)->alt_ref_source; return 0; }
static int copy_svc_params(VP9_COMP *const cpi, struct lookahead_entry *buf) { int layer_id; vpx_svc_parameters_t *layer_param; LAYER_CONTEXT *lc; int count = 1 << (cpi->svc.number_temporal_layers - 1); // Find the next layer to be encoded for (layer_id = 0; layer_id < cpi->svc.number_spatial_layers; ++layer_id) { if (buf->svc_params[layer_id].spatial_layer >=0) break; } if (layer_id == cpi->svc.number_spatial_layers) return 1; layer_param = &buf->svc_params[layer_id]; cpi->svc.spatial_layer_id = layer_param->spatial_layer; cpi->svc.temporal_layer_id = layer_param->temporal_layer; cpi->ref_frame_flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG; lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id]; cpi->svc.temporal_layer_id = 0; while ((lc->current_video_frame_in_layer % count) != 0) { ++cpi->svc.temporal_layer_id; count >>= 1; } cpi->lst_fb_idx = cpi->svc.spatial_layer_id * cpi->svc.number_temporal_layers + cpi->svc.temporal_layer_id; if (lc->frames_from_key_frame < cpi->svc.number_temporal_layers) cpi->ref_frame_flags &= ~VP9_LAST_FLAG; if (cpi->svc.spatial_layer_id == 0) { if (cpi->svc.temporal_layer_id == 0) cpi->gld_fb_idx = lc->gold_ref_idx >= 0 ? lc->gold_ref_idx : cpi->lst_fb_idx; else cpi->gld_fb_idx = cpi->lst_fb_idx - 1; } else { if (cpi->svc.temporal_layer_id == 0) cpi->gld_fb_idx = cpi->svc.spatial_layer_id - cpi->svc.number_temporal_layers; else cpi->gld_fb_idx = cpi->lst_fb_idx - 1; } if (lc->current_video_frame_in_layer == 0) { if (cpi->svc.spatial_layer_id >= 2) { cpi->alt_fb_idx = cpi->svc.spatial_layer_id - 2 * cpi->svc.number_temporal_layers; } else { cpi->alt_fb_idx = cpi->lst_fb_idx; cpi->ref_frame_flags &= (~VP9_LAST_FLAG & ~VP9_ALT_FLAG); } } else { if (cpi->oxcf.ss_play_alternate[cpi->svc.spatial_layer_id]) { cpi->alt_fb_idx = lc->alt_ref_idx; if (!lc->has_alt_frame) cpi->ref_frame_flags &= (~VP9_ALT_FLAG); } else { // Find a proper alt_fb_idx for layers that don't have alt ref frame if (cpi->svc.spatial_layer_id == 0) { cpi->alt_fb_idx = cpi->lst_fb_idx; } else { LAYER_CONTEXT *lc_lower = &cpi->svc.layer_context[cpi->svc.spatial_layer_id - 1]; if (cpi->oxcf.ss_play_alternate[cpi->svc.spatial_layer_id - 1] && lc_lower->alt_ref_source != NULL) cpi->alt_fb_idx = lc_lower->alt_ref_idx; else if (cpi->svc.spatial_layer_id >= 2) cpi->alt_fb_idx = cpi->svc.spatial_layer_id - 2 * cpi->svc.number_temporal_layers; else cpi->alt_fb_idx = cpi->lst_fb_idx; } } } if (vp9_set_size_literal(cpi, layer_param->width, layer_param->height) != 0) return VPX_CODEC_INVALID_PARAM; cpi->oxcf.worst_allowed_q = vp9_quantizer_to_qindex(layer_param->max_quantizer); cpi->oxcf.best_allowed_q = vp9_quantizer_to_qindex(layer_param->min_quantizer); vp9_change_config(cpi, &cpi->oxcf); vp9_set_high_precision_mv(cpi, 1); cpi->alt_ref_source = get_layer_context(cpi)->alt_ref_source; return 0; }