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; }