/* * 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. Load more
/* * 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 frame static 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);