1391 lines · 48.9 KB · C
RawDownload
/* *  Copyright (c) 2010 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 <assert.h>#include <stdio.h>#include <limits.h> #include "vpx_config.h" #include "vpx/vpx_encoder.h"#include "vpx_dsp/bitwriter_buffer.h"#include "vpx_dsp/vpx_dsp_common.h"#include "vpx_mem/vpx_mem.h"#include "vpx_ports/mem_ops.h"#include "vpx_ports/system_state.h"#if CONFIG_BITSTREAM_DEBUG#include "vpx_util/vpx_debug_util.h"#endif  // CONFIG_BITSTREAM_DEBUG #include "vp9/common/vp9_entropy.h"#include "vp9/common/vp9_entropymode.h"#include "vp9/common/vp9_entropymv.h"#include "vp9/common/vp9_mvref_common.h"#include "vp9/common/vp9_pred_common.h"#include "vp9/common/vp9_seg_common.h"#include "vp9/common/vp9_tile_common.h" #include "vp9/encoder/vp9_cost.h"#include "vp9/encoder/vp9_bitstream.h"#include "vp9/encoder/vp9_encodemv.h"#include "vp9/encoder/vp9_mcomp.h"#include "vp9/encoder/vp9_segmentation.h"#include "vp9/encoder/vp9_subexp.h"#include "vp9/encoder/vp9_tokenize.h" static const struct vp9_token intra_mode_encodings[INTRA_MODES] = {  { 0, 1 },  { 6, 3 },   { 28, 5 },  { 30, 5 }, { 58, 6 },  { 59, 6 }, { 126, 7 }, { 127, 7 }, { 62, 6 }, { 2, 2 }};static const struct vp9_token    switchable_interp_encodings[SWITCHABLE_FILTERS] = { { 0, 1 },                                                        { 2, 2 },                                                        { 3, 2 } };static const struct vp9_token partition_encodings[PARTITION_TYPES] = {  { 0, 1 }, { 2, 2 }, { 6, 3 }, { 7, 3 }};static const struct vp9_token inter_mode_encodings[INTER_MODES] = {  { 2, 2 }, { 6, 3 }, { 0, 1 }, { 7, 3 }}; static void write_intra_mode(vpx_writer *w, PREDICTION_MODE mode,                             const vpx_prob *probs) {  vp9_write_token(w, vp9_intra_mode_tree, probs, &intra_mode_encodings[mode]);} static void write_inter_mode(vpx_writer *w, PREDICTION_MODE mode,                             const vpx_prob *probs) {  assert(is_inter_mode(mode));  vp9_write_token(w, vp9_inter_mode_tree, probs,                  &inter_mode_encodings[INTER_OFFSET(mode)]);} static void encode_unsigned_max(struct vpx_write_bit_buffer *wb, int data,                                int max) {  vpx_wb_write_literal(wb, data, get_unsigned_bits(max));} static void prob_diff_update(const vpx_tree_index *tree,                             vpx_prob probs[/*n - 1*/],                             const unsigned int counts[/*n - 1*/], int n,                             vpx_writer *w) {  int i;  unsigned int branch_ct[32][2];   // Assuming max number of probabilities <= 32  assert(n <= 32);   vp9_tree_probs_from_distribution(tree, branch_ct, counts);  for (i = 0; i < n - 1; ++i)    vp9_cond_prob_diff_update(w, &probs[i], branch_ct[i]);} static void write_selected_tx_size(const VP9_COMMON *cm,                                   const MACROBLOCKD *const xd, vpx_writer *w) {  TX_SIZE tx_size = xd->mi[0]->tx_size;  BLOCK_SIZE bsize = xd->mi[0]->sb_type;  const TX_SIZE max_tx_size = max_txsize_lookup[bsize];  const vpx_prob *const tx_probs =      get_tx_probs(max_tx_size, get_tx_size_context(xd), &cm->fc->tx_probs);  vpx_write(w, tx_size != TX_4X4, tx_probs[0]);  if (tx_size != TX_4X4 && max_tx_size >= TX_16X16) {    vpx_write(w, tx_size != TX_8X8, tx_probs[1]);    if (tx_size != TX_8X8 && max_tx_size >= TX_32X32)      vpx_write(w, tx_size != TX_16X16, tx_probs[2]);  }} static int write_skip(const VP9_COMMON *cm, const MACROBLOCKD *const xd,                      int segment_id, const MODE_INFO *mi, vpx_writer *w) {  if (segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP)) {    return 1;  } else {    const int skip = mi->skip;    vpx_write(w, skip, vp9_get_skip_prob(cm, xd));    return skip;  }} static void update_skip_probs(VP9_COMMON *cm, vpx_writer *w,                              FRAME_COUNTS *counts) {  int k;   for (k = 0; k < SKIP_CONTEXTS; ++k)    vp9_cond_prob_diff_update(w, &cm->fc->skip_probs[k], counts->skip[k]);} static void update_switchable_interp_probs(VP9_COMMON *cm, vpx_writer *w,                                           FRAME_COUNTS *counts) {  int j;  for (j = 0; j < SWITCHABLE_FILTER_CONTEXTS; ++j)    prob_diff_update(vp9_switchable_interp_tree,                     cm->fc->switchable_interp_prob[j],                     counts->switchable_interp[j], SWITCHABLE_FILTERS, w);} static void pack_mb_tokens(vpx_writer *w, TOKENEXTRA **tp,                           const TOKENEXTRA *const stop,                           vpx_bit_depth_t bit_depth) {  const TOKENEXTRA *p;  const vp9_extra_bit *const extra_bits =#if CONFIG_VP9_HIGHBITDEPTH      (bit_depth == VPX_BITS_12)          ? vp9_extra_bits_high12          : (bit_depth == VPX_BITS_10) ? vp9_extra_bits_high10 : vp9_extra_bits;#else      vp9_extra_bits;  (void)bit_depth;#endif  // CONFIG_VP9_HIGHBITDEPTH   for (p = *tp; p < stop && p->token != EOSB_TOKEN; ++p) {    if (p->token == EOB_TOKEN) {      vpx_write(w, 0, p->context_tree[0]);      continue;    }    vpx_write(w, 1, p->context_tree[0]);    while (p->token == ZERO_TOKEN) {      vpx_write(w, 0, p->context_tree[1]);      ++p;      if (p == stop || p->token == EOSB_TOKEN) {        *tp = (TOKENEXTRA *)(uintptr_t)p + (p->token == EOSB_TOKEN);        return;      }    }     {      const int t = p->token;      const vpx_prob *const context_tree = p->context_tree;      assert(t != ZERO_TOKEN);      assert(t != EOB_TOKEN);      assert(t != EOSB_TOKEN);      vpx_write(w, 1, context_tree[1]);      if (t == ONE_TOKEN) {        vpx_write(w, 0, context_tree[2]);        vpx_write_bit(w, p->extra & 1);      } else {  // t >= TWO_TOKEN && t < EOB_TOKEN        const struct vp9_token *const a = &vp9_coef_encodings[t];        const int v = a->value;        const int n = a->len;        const int e = p->extra;        vpx_write(w, 1, context_tree[2]);        vp9_write_tree(w, vp9_coef_con_tree,                       vp9_pareto8_full[context_tree[PIVOT_NODE] - 1], v,                       n - UNCONSTRAINED_NODES, 0);        if (t >= CATEGORY1_TOKEN) {          const vp9_extra_bit *const b = &extra_bits[t];          const unsigned char *pb = b->prob;          int v = e >> 1;          int n = b->len;  // number of bits in v, assumed nonzero          do {            const int bb = (v >> --n) & 1;            vpx_write(w, bb, *pb++);          } while (n);        }        vpx_write_bit(w, e & 1);      }    }  }  *tp = (TOKENEXTRA *)(uintptr_t)p + (p->token == EOSB_TOKEN);} static void write_segment_id(vpx_writer *w, const struct segmentation *seg,                             int segment_id) {  if (seg->enabled && seg->update_map)    vp9_write_tree(w, vp9_segment_tree, seg->tree_probs, segment_id, 3, 0);} // This function encodes the reference framestatic void write_ref_frames(const VP9_COMMON *cm, const MACROBLOCKD *const xd,                             vpx_writer *w) {  const MODE_INFO *const mi = xd->mi[0];  const int is_compound = has_second_ref(mi);  const int segment_id = mi->segment_id;   // If segment level coding of this signal is disabled...  // or the segment allows multiple reference frame options  if (segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME)) {    assert(!is_compound);    assert(mi->ref_frame[0] ==           get_segdata(&cm->seg, segment_id, SEG_LVL_REF_FRAME));  } else {    // does the feature use compound prediction or not    // (if not specified at the frame/segment level)    if (cm->reference_mode == REFERENCE_MODE_SELECT) {      vpx_write(w, is_compound, vp9_get_reference_mode_prob(cm, xd));    } else {      assert((!is_compound) == (cm->reference_mode == SINGLE_REFERENCE));    }     if (is_compound) {      const int idx = cm->ref_frame_sign_bias[cm->comp_fixed_ref];      vpx_write(w, mi->ref_frame[!idx] == cm->comp_var_ref[1],                vp9_get_pred_prob_comp_ref_p(cm, xd));    } else {      const int bit0 = mi->ref_frame[0] != LAST_FRAME;      vpx_write(w, bit0, vp9_get_pred_prob_single_ref_p1(cm, xd));      if (bit0) {        const int bit1 = mi->ref_frame[0] != GOLDEN_FRAME;        vpx_write(w, bit1, vp9_get_pred_prob_single_ref_p2(cm, xd));      }    }  }} static void pack_inter_mode_mvs(    VP9_COMP *cpi, const MACROBLOCKD *const xd,    const MB_MODE_INFO_EXT *const mbmi_ext, vpx_writer *w,    unsigned int *const max_mv_magnitude,    int interp_filter_selected[MAX_REF_FRAMES][SWITCHABLE]) {  VP9_COMMON *const cm = &cpi->common;  const nmv_context *nmvc = &cm->fc->nmvc;  const struct segmentation *const seg = &cm->seg;  const MODE_INFO *const mi = xd->mi[0];  const PREDICTION_MODE mode = mi->mode;  const int segment_id = mi->segment_id;  const BLOCK_SIZE bsize = mi->sb_type;  const int allow_hp = cm->allow_high_precision_mv;  const int is_inter = is_inter_block(mi);  const int is_compound = has_second_ref(mi);  int skip, ref;   if (seg->update_map) {    if (seg->temporal_update) {      const int pred_flag = mi->seg_id_predicted;      vpx_prob pred_prob = vp9_get_pred_prob_seg_id(seg, xd);      vpx_write(w, pred_flag, pred_prob);      if (!pred_flag) write_segment_id(w, seg, segment_id);    } else {      write_segment_id(w, seg, segment_id);    }  }   skip = write_skip(cm, xd, segment_id, mi, w);   if (!segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME))    vpx_write(w, is_inter, vp9_get_intra_inter_prob(cm, xd));   if (bsize >= BLOCK_8X8 && cm->tx_mode == TX_MODE_SELECT &&      !(is_inter && skip)) {    write_selected_tx_size(cm, xd, w);  }   if (!is_inter) {    if (bsize >= BLOCK_8X8) {      write_intra_mode(w, mode, cm->fc->y_mode_prob[size_group_lookup[bsize]]);    } else {      int idx, idy;      const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize];      const int num_4x4_h = num_4x4_blocks_high_lookup[bsize];      for (idy = 0; idy < 2; idy += num_4x4_h) {        for (idx = 0; idx < 2; idx += num_4x4_w) {          const PREDICTION_MODE b_mode = mi->bmi[idy * 2 + idx].as_mode;          write_intra_mode(w, b_mode, cm->fc->y_mode_prob[0]);        }      }    }    write_intra_mode(w, mi->uv_mode, cm->fc->uv_mode_prob[mode]);  } else {    const int mode_ctx = mbmi_ext->mode_context[mi->ref_frame[0]];    const vpx_prob *const inter_probs = cm->fc->inter_mode_probs[mode_ctx];    write_ref_frames(cm, xd, w);     // If segment skip is not enabled code the mode.    if (!segfeature_active(seg, segment_id, SEG_LVL_SKIP)) {      if (bsize >= BLOCK_8X8) {        write_inter_mode(w, mode, inter_probs);      }    }     if (cm->interp_filter == SWITCHABLE) {      const int ctx = get_pred_context_switchable_interp(xd);      vp9_write_token(w, vp9_switchable_interp_tree,                      cm->fc->switchable_interp_prob[ctx],                      &switchable_interp_encodings[mi->interp_filter]);      ++interp_filter_selected[0][mi->interp_filter];    } else {      assert(mi->interp_filter == cm->interp_filter);    }     if (bsize < BLOCK_8X8) {      const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize];      const int num_4x4_h = num_4x4_blocks_high_lookup[bsize];      int idx, idy;      for (idy = 0; idy < 2; idy += num_4x4_h) {        for (idx = 0; idx < 2; idx += num_4x4_w) {          const int j = idy * 2 + idx;          const PREDICTION_MODE b_mode = mi->bmi[j].as_mode;          write_inter_mode(w, b_mode, inter_probs);          if (b_mode == NEWMV) {            for (ref = 0; ref < 1 + is_compound; ++ref)              vp9_encode_mv(cpi, w, &mi->bmi[j].as_mv[ref].as_mv,                            &mbmi_ext->ref_mvs[mi->ref_frame[ref]][0].as_mv,                            nmvc, allow_hp, max_mv_magnitude);          }        }      }    } else {      if (mode == NEWMV) {        for (ref = 0; ref < 1 + is_compound; ++ref)          vp9_encode_mv(cpi, w, &mi->mv[ref].as_mv,                        &mbmi_ext->ref_mvs[mi->ref_frame[ref]][0].as_mv, nmvc,                        allow_hp, max_mv_magnitude);      }    }  }} static void write_mb_modes_kf(const VP9_COMMON *cm, const MACROBLOCKD *xd,                              vpx_writer *w) {  const struct segmentation *const seg = &cm->seg;  const MODE_INFO *const mi = xd->mi[0];  const MODE_INFO *const above_mi = xd->above_mi;  const MODE_INFO *const left_mi = xd->left_mi;  const BLOCK_SIZE bsize = mi->sb_type;   if (seg->update_map) write_segment_id(w, seg, mi->segment_id);   write_skip(cm, xd, mi->segment_id, mi, w);   if (bsize >= BLOCK_8X8 && cm->tx_mode == TX_MODE_SELECT)    write_selected_tx_size(cm, xd, w);   if (bsize >= BLOCK_8X8) {    write_intra_mode(w, mi->mode, get_y_mode_probs(mi, above_mi, left_mi, 0));  } else {    const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize];    const int num_4x4_h = num_4x4_blocks_high_lookup[bsize];    int idx, idy;     for (idy = 0; idy < 2; idy += num_4x4_h) {      for (idx = 0; idx < 2; idx += num_4x4_w) {        const int block = idy * 2 + idx;        write_intra_mode(w, mi->bmi[block].as_mode,                         get_y_mode_probs(mi, above_mi, left_mi, block));      }    }  }   write_intra_mode(w, mi->uv_mode, vp9_kf_uv_mode_prob[mi->mode]);} static void write_modes_b(    VP9_COMP *cpi, MACROBLOCKD *const xd, const TileInfo *const tile,    vpx_writer *w, TOKENEXTRA **tok, const TOKENEXTRA *const tok_end,    int mi_row, int mi_col, unsigned int *const max_mv_magnitude,    int interp_filter_selected[MAX_REF_FRAMES][SWITCHABLE]) {  const VP9_COMMON *const cm = &cpi->common;  const MB_MODE_INFO_EXT *const mbmi_ext =      cpi->td.mb.mbmi_ext_base + (mi_row * cm->mi_cols + mi_col);  MODE_INFO *m;   xd->mi = cm->mi_grid_visible + (mi_row * cm->mi_stride + mi_col);  m = xd->mi[0];   set_mi_row_col(xd, tile, mi_row, num_8x8_blocks_high_lookup[m->sb_type],                 mi_col, num_8x8_blocks_wide_lookup[m->sb_type], cm->mi_rows,                 cm->mi_cols);  if (frame_is_intra_only(cm)) {    write_mb_modes_kf(cm, xd, w);  } else {    pack_inter_mode_mvs(cpi, xd, mbmi_ext, w, max_mv_magnitude,                        interp_filter_selected);  }   assert(*tok < tok_end);  pack_mb_tokens(w, tok, tok_end, cm->bit_depth);} static void write_partition(const VP9_COMMON *const cm,                            const MACROBLOCKD *const xd, int hbs, int mi_row,                            int mi_col, PARTITION_TYPE p, BLOCK_SIZE bsize,                            vpx_writer *w) {  const int ctx = partition_plane_context(xd, mi_row, mi_col, bsize);  const vpx_prob *const probs = xd->partition_probs[ctx];  const int has_rows = (mi_row + hbs) < cm->mi_rows;  const int has_cols = (mi_col + hbs) < cm->mi_cols;   if (has_rows && has_cols) {    vp9_write_token(w, vp9_partition_tree, probs, &partition_encodings[p]);  } else if (!has_rows && has_cols) {    assert(p == PARTITION_SPLIT || p == PARTITION_HORZ);    vpx_write(w, p == PARTITION_SPLIT, probs[1]);  } else if (has_rows && !has_cols) {    assert(p == PARTITION_SPLIT || p == PARTITION_VERT);    vpx_write(w, p == PARTITION_SPLIT, probs[2]);  } else {    assert(p == PARTITION_SPLIT);  }} static void write_modes_sb(    VP9_COMP *cpi, MACROBLOCKD *const xd, const TileInfo *const tile,    vpx_writer *w, TOKENEXTRA **tok, const TOKENEXTRA *const tok_end,    int mi_row, int mi_col, BLOCK_SIZE bsize,    unsigned int *const max_mv_magnitude,    int interp_filter_selected[MAX_REF_FRAMES][SWITCHABLE]) {  const VP9_COMMON *const cm = &cpi->common;  const int bsl = b_width_log2_lookup[bsize];  const int bs = (1 << bsl) / 4;  PARTITION_TYPE partition;  BLOCK_SIZE subsize;  const MODE_INFO *m = NULL;   if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;   m = cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col];   partition = partition_lookup[bsl][m->sb_type];  write_partition(cm, xd, bs, mi_row, mi_col, partition, bsize, w);  subsize = get_subsize(bsize, partition);  if (subsize < BLOCK_8X8) {    write_modes_b(cpi, xd, tile, w, tok, tok_end, mi_row, mi_col,                  max_mv_magnitude, interp_filter_selected);  } else {    switch (partition) {      case PARTITION_NONE:        write_modes_b(cpi, xd, tile, w, tok, tok_end, mi_row, mi_col,                      max_mv_magnitude, interp_filter_selected);        break;      case PARTITION_HORZ:        write_modes_b(cpi, xd, tile, w, tok, tok_end, mi_row, mi_col,                      max_mv_magnitude, interp_filter_selected);        if (mi_row + bs < cm->mi_rows)          write_modes_b(cpi, xd, tile, w, tok, tok_end, mi_row + bs, mi_col,                        max_mv_magnitude, interp_filter_selected);        break;      case PARTITION_VERT:        write_modes_b(cpi, xd, tile, w, tok, tok_end, mi_row, mi_col,                      max_mv_magnitude, interp_filter_selected);        if (mi_col + bs < cm->mi_cols)          write_modes_b(cpi, xd, tile, w, tok, tok_end, mi_row, mi_col + bs,                        max_mv_magnitude, interp_filter_selected);        break;      default:        assert(partition == PARTITION_SPLIT);        write_modes_sb(cpi, xd, tile, w, tok, tok_end, mi_row, mi_col, subsize,                       max_mv_magnitude, interp_filter_selected);        write_modes_sb(cpi, xd, tile, w, tok, tok_end, mi_row, mi_col + bs,                       subsize, max_mv_magnitude, interp_filter_selected);        write_modes_sb(cpi, xd, tile, w, tok, tok_end, mi_row + bs, mi_col,                       subsize, max_mv_magnitude, interp_filter_selected);        write_modes_sb(cpi, xd, tile, w, tok, tok_end, mi_row + bs, mi_col + bs,                       subsize, max_mv_magnitude, interp_filter_selected);        break;    }  }   // update partition context  if (bsize >= BLOCK_8X8 &&      (bsize == BLOCK_8X8 || partition != PARTITION_SPLIT))    update_partition_context(xd, mi_row, mi_col, subsize, bsize);} static void write_modes(    VP9_COMP *cpi, MACROBLOCKD *const xd, const TileInfo *const tile,    vpx_writer *w, int tile_row, int tile_col,    unsigned int *const max_mv_magnitude,    int interp_filter_selected[MAX_REF_FRAMES][SWITCHABLE]) {  const VP9_COMMON *const cm = &cpi->common;  int mi_row, mi_col, tile_sb_row;  TOKENEXTRA *tok = NULL;  TOKENEXTRA *tok_end = NULL;   set_partition_probs(cm, xd);

Lines 1–500 of 1391.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t