Index: source/libvpx/vp9/common/vp9_pred_common.c |
=================================================================== |
--- source/libvpx/vp9/common/vp9_pred_common.c (revision 0) |
+++ source/libvpx/vp9/common/vp9_pred_common.c (revision 0) |
@@ -0,0 +1,465 @@ |
+ |
+/* |
+ * 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 "vp9/common/vp9_pred_common.h" |
+#include "vp9/common/vp9_seg_common.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; |
+ MODE_INFO *m = xd->mode_info_context; |
+ |
+ // 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 = (m - 1)->mbmi.seg_id_predicted + |
+ (m - cm->mode_info_stride)->mbmi.seg_id_predicted; |
+ break; |
+ |
+ |
+ case PRED_REF: |
+ pred_context = (m - 1)->mbmi.ref_predicted + |
+ (m - cm->mode_info_stride)->mbmi.ref_predicted; |
+ break; |
+ |
+ case PRED_COMP: |
+ // Context based on use of comp pred flag by neighbours |
+ // pred_context = |
+ // ((m - 1)->mbmi.second_ref_frame > INTRA_FRAME) + |
+ // ((m - cm->mode_info_stride)->mbmi.second_ref_frame > INTRA_FRAME); |
+ |
+ // Context based on mode and reference frame |
+ // if ( m->mbmi.ref_frame == LAST_FRAME ) |
+ // pred_context = 0 + (m->mbmi.mode != ZEROMV); |
+ // else if ( m->mbmi.ref_frame == GOLDEN_FRAME ) |
+ // pred_context = 2 + (m->mbmi.mode != ZEROMV); |
+ // else |
+ // pred_context = 4 + (m->mbmi.mode != ZEROMV); |
+ |
+ if (m->mbmi.ref_frame == LAST_FRAME) |
+ pred_context = 0; |
+ else |
+ pred_context = 1; |
+ |
+ break; |
+ |
+ case PRED_MBSKIP: |
+ pred_context = (m - 1)->mbmi.mb_skip_coeff + |
+ (m - cm->mode_info_stride)->mbmi.mb_skip_coeff; |
+ break; |
+ |
+ case PRED_SWITCHABLE_INTERP: |
+ { |
+ int left_in_image = (m - 1)->mbmi.mb_in_image; |
+ int above_in_image = (m - cm->mode_info_stride)->mbmi.mb_in_image; |
+ int left_mode = (m - 1)->mbmi.mode; |
+ int above_mode = (m - cm->mode_info_stride)->mbmi.mode; |
+ int left_interp, above_interp; |
+ if (left_in_image && left_mode >= NEARESTMV && left_mode <= SPLITMV) |
+ left_interp = vp9_switchable_interp_map[(m - 1)->mbmi.interp_filter]; |
+ else |
+ left_interp = VP9_SWITCHABLE_FILTERS; |
+ assert(left_interp != -1); |
+ if (above_in_image && above_mode >= NEARESTMV && above_mode <= SPLITMV) |
+ above_interp = vp9_switchable_interp_map[ |
+ (m - cm->mode_info_stride)->mbmi.interp_filter]; |
+ else |
+ above_interp = VP9_SWITCHABLE_FILTERS; |
+ 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: |
+ // TODO *** add error trap code. |
+ pred_context = 0; |
+ 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) { |
+ vp9_prob pred_probability; |
+ int pred_context; |
+ |
+ // Get the appropriate prediction context |
+ pred_context = vp9_get_pred_context(cm, xd, pred_id); |
+ |
+ switch (pred_id) { |
+ case PRED_SEG_ID: |
+ pred_probability = cm->segment_pred_probs[pred_context]; |
+ break; |
+ |
+ case PRED_REF: |
+ pred_probability = cm->ref_pred_probs[pred_context]; |
+ break; |
+ |
+ 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. |
+ pred_probability = cm->prob_comppred[pred_context]; |
+ break; |
+ |
+ case PRED_MBSKIP: |
+ pred_probability = cm->mbskip_pred_probs[pred_context]; |
+ break; |
+ |
+ default: |
+ // TODO *** add error trap code. |
+ pred_probability = 128; |
+ break; |
+ } |
+ |
+ return pred_probability; |
+} |
+ |
+// 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 vp9_prob *pred_probability; |
+ int pred_context; |
+ |
+ // Get the appropriate prediction context |
+ pred_context = vp9_get_pred_context(cm, xd, pred_id); |
+ |
+ switch (pred_id) { |
+ case PRED_SEG_ID: |
+ pred_probability = &cm->segment_pred_probs[pred_context]; |
+ break; |
+ |
+ case PRED_REF: |
+ pred_probability = &cm->ref_pred_probs[pred_context]; |
+ break; |
+ |
+ 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. |
+ pred_probability = &cm->prob_comppred[pred_context]; |
+ break; |
+ |
+ case PRED_MBSKIP: |
+ pred_probability = &cm->mbskip_pred_probs[pred_context]; |
+ break; |
+ |
+ case PRED_SWITCHABLE_INTERP: |
+ pred_probability = &cm->fc.switchable_interp_prob[pred_context][0]; |
+ break; |
+ |
+ default: |
+ // TODO *** add error trap code. |
+ pred_probability = NULL; |
+ break; |
+ } |
+ |
+ return pred_probability; |
+} |
+ |
+// 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) { |
+ unsigned char pred_flag = 0; |
+ |
+ switch (pred_id) { |
+ case PRED_SEG_ID: |
+ pred_flag = xd->mode_info_context->mbmi.seg_id_predicted; |
+ break; |
+ |
+ case PRED_REF: |
+ pred_flag = xd->mode_info_context->mbmi.ref_predicted; |
+ break; |
+ |
+ case PRED_MBSKIP: |
+ pred_flag = xd->mode_info_context->mbmi.mb_skip_coeff; |
+ break; |
+ |
+ default: |
+ // TODO *** add error trap code. |
+ pred_flag = 0; |
+ break; |
+ } |
+ |
+ return pred_flag; |
+} |
+ |
+// 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) { |
+#if CONFIG_SUPERBLOCKS |
+ const int mis = xd->mode_info_stride; |
+#endif |
+ |
+ switch (pred_id) { |
+ case PRED_SEG_ID: |
+ xd->mode_info_context->mbmi.seg_id_predicted = pred_flag; |
+#if CONFIG_SUPERBLOCKS |
+ if (xd->mode_info_context->mbmi.encoded_as_sb) { |
+ if (xd->mb_to_right_edge >= 0) |
+ xd->mode_info_context[1].mbmi.seg_id_predicted = pred_flag; |
+ if (xd->mb_to_bottom_edge >= 0) { |
+ xd->mode_info_context[mis].mbmi.seg_id_predicted = pred_flag; |
+ if (xd->mb_to_right_edge >= 0) |
+ xd->mode_info_context[mis + 1].mbmi.seg_id_predicted = pred_flag; |
+ } |
+ } |
+#endif |
+ break; |
+ |
+ case PRED_REF: |
+ xd->mode_info_context->mbmi.ref_predicted = pred_flag; |
+#if CONFIG_SUPERBLOCKS |
+ if (xd->mode_info_context->mbmi.encoded_as_sb) { |
+ if (xd->mb_to_right_edge >= 0) |
+ xd->mode_info_context[1].mbmi.ref_predicted = pred_flag; |
+ if (xd->mb_to_bottom_edge >= 0) { |
+ xd->mode_info_context[mis].mbmi.ref_predicted = pred_flag; |
+ if (xd->mb_to_right_edge >= 0) |
+ xd->mode_info_context[mis + 1].mbmi.ref_predicted = pred_flag; |
+ } |
+ } |
+#endif |
+ break; |
+ |
+ case PRED_MBSKIP: |
+ xd->mode_info_context->mbmi.mb_skip_coeff = pred_flag; |
+#if CONFIG_SUPERBLOCKS |
+ if (xd->mode_info_context->mbmi.encoded_as_sb) { |
+ if (xd->mb_to_right_edge >= 0) |
+ xd->mode_info_context[1].mbmi.mb_skip_coeff = pred_flag; |
+ if (xd->mb_to_bottom_edge >= 0) { |
+ xd->mode_info_context[mis].mbmi.mb_skip_coeff = pred_flag; |
+ if (xd->mb_to_right_edge >= 0) |
+ xd->mode_info_context[mis + 1].mbmi.mb_skip_coeff = pred_flag; |
+ } |
+ } |
+#endif |
+ break; |
+ |
+ default: |
+ // TODO *** 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 |
+unsigned char vp9_get_pred_mb_segid(const VP9_COMMON *const cm, |
+ const MACROBLOCKD *const xd, int MbIndex) { |
+ // Currently the prediction for the macroblock segment ID is |
+ // the value stored for this macroblock in the previous frame. |
+#if CONFIG_SUPERBLOCKS |
+ if (!xd->mode_info_context->mbmi.encoded_as_sb) { |
+#endif |
+ return cm->last_frame_seg_map[MbIndex]; |
+#if CONFIG_SUPERBLOCKS |
+ } else { |
+ int seg_id = cm->last_frame_seg_map[MbIndex]; |
+ int mb_col = MbIndex % cm->mb_cols; |
+ int mb_row = MbIndex / cm->mb_cols; |
+ if (mb_col + 1 < cm->mb_cols) |
+ seg_id = seg_id && cm->last_frame_seg_map[MbIndex + 1]; |
+ if (mb_row + 1 < cm->mb_rows) { |
+ seg_id = seg_id && cm->last_frame_seg_map[MbIndex + cm->mb_cols]; |
+ if (mb_col + 1 < cm->mb_cols) |
+ seg_id = seg_id && cm->last_frame_seg_map[MbIndex + cm->mb_cols + 1]; |
+ } |
+ return seg_id; |
+ } |
+#endif |
+} |
+ |
+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 seg_ref_active; |
+ 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 |
+ 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; |
+ 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; |
+ |
+ // 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; |
+ |
+ tot_count = count[0] + count[1] + count[2] + count[3]; |
+ if (tot_count) { |
+ probs[0] = (vp9_prob)((count[0] * 255 + (tot_count >> 1)) / tot_count); |
+ probs[0] += !probs[0]; |
+ } else |
+ probs[0] = 128; |
+ |
+ tot_count -= count[0]; |
+ if (tot_count) { |
+ probs[1] = (vp9_prob)((count[1] * 255 + (tot_count >> 1)) / tot_count); |
+ probs[1] += !probs[1]; |
+ } else |
+ probs[1] = 128; |
+ |
+ tot_count -= count[1]; |
+ if (tot_count) { |
+ probs[2] = (vp9_prob)((count[2] * 255 + (tot_count >> 1)) / tot_count); |
+ probs[2] += !probs[2]; |
+ } else |
+ probs[2] = 128; |
+ |
+} |
+ |
+// 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]; |
+ int intra_count; |
+ int inter_count; |
+ int last_count; |
+ int gfarf_count; |
+ int gf_count; |
+ int arf_count; |
+ |
+ intra_count = cm->prob_intra_coded; |
+ inter_count = (255 - intra_count); |
+ last_count = (inter_count * cm->prob_last_coded) / 255; |
+ gfarf_count = inter_count - last_count; |
+ gf_count = (gfarf_count * cm->prob_gf_coded) / 255; |
+ 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); |
+} |
Property changes on: source/libvpx/vp9/common/vp9_pred_common.c |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |