| |
| /* |
| * Copyright (c) 2012 The WebM project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include <limits.h> |
| |
| #include "vp9/common/vp9_common.h" |
| #include "vp9/common/vp9_pred_common.h" |
| #include "vp9/common/vp9_seg_common.h" |
| #include "vp9/common/vp9_treecoder.h" |
| |
| // TBD prediction functions for various bitstream signals |
| |
| // Returns a context number for the given MB prediction signal |
| unsigned char vp9_get_pred_context(const VP9_COMMON *const cm, |
| const MACROBLOCKD *const xd, |
| PRED_ID pred_id) { |
| int pred_context; |
| const MODE_INFO *const mi = xd->mode_info_context; |
| const MODE_INFO *const above_mi = mi - cm->mode_info_stride; |
| const MODE_INFO *const left_mi = mi - 1; |
| // Note: |
| // The mode info data structure has a one element border above and to the |
| // left of the entries correpsonding to real macroblocks. |
| // The prediction flags in these dummy entries are initialised to 0. |
| switch (pred_id) { |
| case PRED_SEG_ID: |
| pred_context = above_mi->mbmi.seg_id_predicted; |
| if (xd->left_available) |
| pred_context += left_mi->mbmi.seg_id_predicted; |
| break; |
| |
| case PRED_REF: |
| pred_context = above_mi->mbmi.ref_predicted; |
| if (xd->left_available) |
| pred_context += left_mi->mbmi.ref_predicted; |
| break; |
| |
| case PRED_COMP: |
| if (mi->mbmi.ref_frame == LAST_FRAME) |
| pred_context = 0; |
| else |
| pred_context = 1; |
| break; |
| |
| case PRED_MBSKIP: |
| pred_context = above_mi->mbmi.mb_skip_coeff; |
| if (xd->left_available) |
| pred_context += left_mi->mbmi.mb_skip_coeff; |
| break; |
| |
| case PRED_SWITCHABLE_INTERP: { |
| // left |
| const int left_in_image = xd->left_available && left_mi->mbmi.mb_in_image; |
| const int left_mv_pred = is_inter_mode(left_mi->mbmi.mode); |
| const int left_interp = left_in_image && left_mv_pred ? |
| vp9_switchable_interp_map[left_mi->mbmi.interp_filter] : |
| VP9_SWITCHABLE_FILTERS; |
| |
| // above |
| const int above_in_image = xd->up_available && above_mi->mbmi.mb_in_image; |
| const int above_mv_pred = is_inter_mode(above_mi->mbmi.mode); |
| const int above_interp = above_in_image && above_mv_pred ? |
| vp9_switchable_interp_map[above_mi->mbmi.interp_filter] : |
| VP9_SWITCHABLE_FILTERS; |
| |
| assert(left_interp != -1); |
| assert(above_interp != -1); |
| |
| if (left_interp == above_interp) |
| pred_context = left_interp; |
| else if (left_interp == VP9_SWITCHABLE_FILTERS && |
| above_interp != VP9_SWITCHABLE_FILTERS) |
| pred_context = above_interp; |
| else if (left_interp != VP9_SWITCHABLE_FILTERS && |
| above_interp == VP9_SWITCHABLE_FILTERS) |
| pred_context = left_interp; |
| else |
| pred_context = VP9_SWITCHABLE_FILTERS; |
| |
| break; |
| } |
| |
| default: |
| pred_context = 0; // *** add error trap code. |
| break; |
| } |
| |
| return pred_context; |
| } |
| |
| // This function returns a context probability for coding a given |
| // prediction signal |
| vp9_prob vp9_get_pred_prob(const VP9_COMMON *const cm, |
| const MACROBLOCKD *const xd, |
| PRED_ID pred_id) { |
| const int pred_context = vp9_get_pred_context(cm, xd, pred_id); |
| |
| switch (pred_id) { |
| case PRED_SEG_ID: |
| return cm->segment_pred_probs[pred_context]; |
| case PRED_REF: |
| return cm->ref_pred_probs[pred_context]; |
| case PRED_COMP: |
| // In keeping with convention elsewhre the probability returned is |
| // the probability of a "0" outcome which in this case means the |
| // probability of comp pred off. |
| return cm->prob_comppred[pred_context]; |
| case PRED_MBSKIP: |
| return cm->mbskip_pred_probs[pred_context]; |
| default: |
| return 128; // *** add error trap code. |
| } |
| } |
| |
| // This function returns a context probability ptr for coding a given |
| // prediction signal |
| const vp9_prob *vp9_get_pred_probs(const VP9_COMMON *const cm, |
| const MACROBLOCKD *const xd, |
| PRED_ID pred_id) { |
| const int pred_context = vp9_get_pred_context(cm, xd, pred_id); |
| |
| switch (pred_id) { |
| case PRED_SEG_ID: |
| return &cm->segment_pred_probs[pred_context]; |
| case PRED_REF: |
| return &cm->ref_pred_probs[pred_context]; |
| case PRED_COMP: |
| // In keeping with convention elsewhre the probability returned is |
| // the probability of a "0" outcome which in this case means the |
| // probability of comp pred off. |
| return &cm->prob_comppred[pred_context]; |
| case PRED_MBSKIP: |
| return &cm->mbskip_pred_probs[pred_context]; |
| case PRED_SWITCHABLE_INTERP: |
| return &cm->fc.switchable_interp_prob[pred_context][0]; |
| default: |
| return NULL; // *** add error trap code. |
| } |
| } |
| |
| // This function returns the status of the given prediction signal. |
| // I.e. is the predicted value for the given signal correct. |
| unsigned char vp9_get_pred_flag(const MACROBLOCKD *const xd, |
| PRED_ID pred_id) { |
| switch (pred_id) { |
| case PRED_SEG_ID: |
| return xd->mode_info_context->mbmi.seg_id_predicted; |
| case PRED_REF: |
| return xd->mode_info_context->mbmi.ref_predicted; |
| case PRED_MBSKIP: |
| return xd->mode_info_context->mbmi.mb_skip_coeff; |
| default: |
| return 0; // *** add error trap code. |
| } |
| } |
| |
| // This function sets the status of the given prediction signal. |
| // I.e. is the predicted value for the given signal correct. |
| void vp9_set_pred_flag(MACROBLOCKD *const xd, |
| PRED_ID pred_id, |
| unsigned char pred_flag) { |
| const int mis = xd->mode_info_stride; |
| BLOCK_SIZE_TYPE bsize = xd->mode_info_context->mbmi.sb_type; |
| const int bh = 1 << mi_height_log2(bsize); |
| const int bw = 1 << mi_width_log2(bsize); |
| #define sub(a, b) (b) < 0 ? (a) + (b) : (a) |
| const int x_mis = sub(bw, xd->mb_to_right_edge >> (3 + LOG2_MI_SIZE)); |
| const int y_mis = sub(bh, xd->mb_to_bottom_edge >> (3 + LOG2_MI_SIZE)); |
| #undef sub |
| int x, y; |
| |
| switch (pred_id) { |
| case PRED_SEG_ID: |
| for (y = 0; y < y_mis; y++) { |
| for (x = 0; x < x_mis; x++) { |
| xd->mode_info_context[y * mis + x].mbmi.seg_id_predicted = pred_flag; |
| } |
| } |
| break; |
| |
| case PRED_REF: |
| for (y = 0; y < y_mis; y++) { |
| for (x = 0; x < x_mis; x++) { |
| xd->mode_info_context[y * mis + x].mbmi.ref_predicted = pred_flag; |
| } |
| } |
| break; |
| |
| case PRED_MBSKIP: |
| for (y = 0; y < y_mis; y++) { |
| for (x = 0; x < x_mis; x++) { |
| xd->mode_info_context[y * mis + x].mbmi.mb_skip_coeff = pred_flag; |
| } |
| } |
| break; |
| |
| default: |
| // *** add error trap code. |
| break; |
| } |
| } |
| |
| |
| // The following contain the guts of the prediction code used to |
| // peredict various bitstream signals. |
| |
| // Macroblock segment id prediction function |
| int vp9_get_pred_mi_segid(VP9_COMMON *cm, BLOCK_SIZE_TYPE sb_type, |
| int mi_row, int mi_col) { |
| const int mi_index = mi_row * cm->mi_cols + mi_col; |
| const int bw = 1 << mi_width_log2(sb_type); |
| const int bh = 1 << mi_height_log2(sb_type); |
| const int ymis = MIN(cm->mi_rows - mi_row, bh); |
| const int xmis = MIN(cm->mi_cols - mi_col, bw); |
| int segment_id = INT_MAX; |
| int x, y; |
| |
| for (y = 0; y < ymis; y++) { |
| for (x = 0; x < xmis; x++) { |
| const int index = mi_index + (y * cm->mi_cols + x); |
| segment_id = MIN(segment_id, cm->last_frame_seg_map[index]); |
| } |
| } |
| return segment_id; |
| } |
| |
| MV_REFERENCE_FRAME vp9_get_pred_ref(const VP9_COMMON *const cm, |
| const MACROBLOCKD *const xd) { |
| MODE_INFO *m = xd->mode_info_context; |
| |
| MV_REFERENCE_FRAME left; |
| MV_REFERENCE_FRAME above; |
| MV_REFERENCE_FRAME above_left; |
| MV_REFERENCE_FRAME pred_ref = LAST_FRAME; |
| |
| int segment_id = xd->mode_info_context->mbmi.segment_id; |
| int i; |
| |
| unsigned char frame_allowed[MAX_REF_FRAMES] = {1, 1, 1, 1}; |
| unsigned char ref_score[MAX_REF_FRAMES]; |
| unsigned char best_score = 0; |
| unsigned char left_in_image; |
| unsigned char above_in_image; |
| unsigned char above_left_in_image; |
| |
| // Is segment coding ennabled |
| int seg_ref_active = vp9_segfeature_active(xd, segment_id, SEG_LVL_REF_FRAME); |
| |
| // Special case treatment if segment coding is enabled. |
| // Dont allow prediction of a reference frame that the segment |
| // does not allow |
| if (seg_ref_active) { |
| for (i = 0; i < MAX_REF_FRAMES; i++) { |
| frame_allowed[i] = |
| vp9_check_segref(xd, segment_id, i); |
| |
| // Score set to 0 if ref frame not allowed |
| ref_score[i] = cm->ref_scores[i] * frame_allowed[i]; |
| } |
| } else |
| vpx_memcpy(ref_score, cm->ref_scores, sizeof(ref_score)); |
| |
| // Reference frames used by neighbours |
| left = (m - 1)->mbmi.ref_frame; |
| above = (m - cm->mode_info_stride)->mbmi.ref_frame; |
| above_left = (m - 1 - cm->mode_info_stride)->mbmi.ref_frame; |
| |
| // Are neighbours in image |
| left_in_image = (m - 1)->mbmi.mb_in_image && xd->left_available; |
| above_in_image = (m - cm->mode_info_stride)->mbmi.mb_in_image; |
| above_left_in_image = (m - 1 - cm->mode_info_stride)->mbmi.mb_in_image && |
| xd->left_available; |
| |
| // Adjust scores for candidate reference frames based on neigbours |
| if (frame_allowed[left] && left_in_image) { |
| ref_score[left] += 16; |
| if (above_left_in_image && (left == above_left)) |
| ref_score[left] += 4; |
| } |
| if (frame_allowed[above] && above_in_image) { |
| ref_score[above] += 16; |
| if (above_left_in_image && (above == above_left)) |
| ref_score[above] += 4; |
| } |
| |
| // Now choose the candidate with the highest score |
| for (i = 0; i < MAX_REF_FRAMES; i++) { |
| if (ref_score[i] > best_score) { |
| pred_ref = i; |
| best_score = ref_score[i]; |
| } |
| } |
| |
| return pred_ref; |
| } |
| |
| // Functions to computes a set of modified reference frame probabilities |
| // to use when the prediction of the reference frame value fails |
| void vp9_calc_ref_probs(int *count, vp9_prob *probs) { |
| int tot_count = count[0] + count[1] + count[2] + count[3]; |
| probs[0] = get_prob(count[0], tot_count); |
| |
| tot_count -= count[0]; |
| probs[1] = get_prob(count[1], tot_count); |
| |
| tot_count -= count[1]; |
| probs[2] = get_prob(count[2], tot_count); |
| } |
| |
| // Computes a set of modified conditional probabilities for the reference frame |
| // Values willbe set to 0 for reference frame options that are not possible |
| // because wither they were predicted and prediction has failed or because |
| // they are not allowed for a given segment. |
| void vp9_compute_mod_refprobs(VP9_COMMON *const cm) { |
| int norm_cnt[MAX_REF_FRAMES]; |
| const int intra_count = cm->prob_intra_coded; |
| const int inter_count = (255 - intra_count); |
| const int last_count = (inter_count * cm->prob_last_coded) / 255; |
| const int gfarf_count = inter_count - last_count; |
| const int gf_count = (gfarf_count * cm->prob_gf_coded) / 255; |
| const int arf_count = gfarf_count - gf_count; |
| |
| // Work out modified reference frame probabilities to use where prediction |
| // of the reference frame fails |
| norm_cnt[0] = 0; |
| norm_cnt[1] = last_count; |
| norm_cnt[2] = gf_count; |
| norm_cnt[3] = arf_count; |
| vp9_calc_ref_probs(norm_cnt, cm->mod_refprobs[INTRA_FRAME]); |
| cm->mod_refprobs[INTRA_FRAME][0] = 0; // This branch implicit |
| |
| norm_cnt[0] = intra_count; |
| norm_cnt[1] = 0; |
| norm_cnt[2] = gf_count; |
| norm_cnt[3] = arf_count; |
| vp9_calc_ref_probs(norm_cnt, cm->mod_refprobs[LAST_FRAME]); |
| cm->mod_refprobs[LAST_FRAME][1] = 0; // This branch implicit |
| |
| norm_cnt[0] = intra_count; |
| norm_cnt[1] = last_count; |
| norm_cnt[2] = 0; |
| norm_cnt[3] = arf_count; |
| vp9_calc_ref_probs(norm_cnt, cm->mod_refprobs[GOLDEN_FRAME]); |
| cm->mod_refprobs[GOLDEN_FRAME][2] = 0; // This branch implicit |
| |
| norm_cnt[0] = intra_count; |
| norm_cnt[1] = last_count; |
| norm_cnt[2] = gf_count; |
| norm_cnt[3] = 0; |
| vp9_calc_ref_probs(norm_cnt, cm->mod_refprobs[ALTREF_FRAME]); |
| cm->mod_refprobs[ALTREF_FRAME][2] = 0; // This branch implicit |
| |
| // Score the reference frames based on overal frequency. |
| // These scores contribute to the prediction choices. |
| // Max score 17 min 1 |
| cm->ref_scores[INTRA_FRAME] = 1 + (intra_count * 16 / 255); |
| cm->ref_scores[LAST_FRAME] = 1 + (last_count * 16 / 255); |
| cm->ref_scores[GOLDEN_FRAME] = 1 + (gf_count * 16 / 255); |
| cm->ref_scores[ALTREF_FRAME] = 1 + (arf_count * 16 / 255); |
| } |