michael@0: /* michael@0: * Copyright (c) 2010 The WebM project authors. All Rights Reserved. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license michael@0: * that can be found in the LICENSE file in the root of the source michael@0: * tree. An additional intellectual property rights grant can be found michael@0: * in the file PATENTS. All contributing project authors may michael@0: * be found in the AUTHORS file in the root of the source tree. michael@0: */ michael@0: michael@0: michael@0: #ifndef VP9_COMMON_VP9_BLOCKD_H_ michael@0: #define VP9_COMMON_VP9_BLOCKD_H_ michael@0: michael@0: #include "./vpx_config.h" michael@0: michael@0: #include "vpx_ports/mem.h" michael@0: #include "vpx_scale/yv12config.h" michael@0: michael@0: #include "vp9/common/vp9_common.h" michael@0: #include "vp9/common/vp9_common_data.h" michael@0: #include "vp9/common/vp9_enums.h" michael@0: #include "vp9/common/vp9_filter.h" michael@0: #include "vp9/common/vp9_mv.h" michael@0: #include "vp9/common/vp9_scale.h" michael@0: #include "vp9/common/vp9_seg_common.h" michael@0: #include "vp9/common/vp9_treecoder.h" michael@0: michael@0: #define BLOCK_SIZE_GROUPS 4 michael@0: #define MBSKIP_CONTEXTS 3 michael@0: michael@0: /* Segment Feature Masks */ michael@0: #define MAX_MV_REF_CANDIDATES 2 michael@0: michael@0: #define INTRA_INTER_CONTEXTS 4 michael@0: #define COMP_INTER_CONTEXTS 5 michael@0: #define REF_CONTEXTS 5 michael@0: michael@0: typedef enum { michael@0: PLANE_TYPE_Y_WITH_DC, michael@0: PLANE_TYPE_UV, michael@0: } PLANE_TYPE; michael@0: michael@0: typedef char ENTROPY_CONTEXT; michael@0: michael@0: typedef char PARTITION_CONTEXT; michael@0: michael@0: static INLINE int combine_entropy_contexts(ENTROPY_CONTEXT a, michael@0: ENTROPY_CONTEXT b) { michael@0: return (a != 0) + (b != 0); michael@0: } michael@0: michael@0: typedef enum { michael@0: KEY_FRAME = 0, michael@0: INTER_FRAME = 1, michael@0: FRAME_TYPES, michael@0: } FRAME_TYPE; michael@0: michael@0: typedef enum { michael@0: DC_PRED, // Average of above and left pixels michael@0: V_PRED, // Vertical michael@0: H_PRED, // Horizontal michael@0: D45_PRED, // Directional 45 deg = round(arctan(1/1) * 180/pi) michael@0: D135_PRED, // Directional 135 deg = 180 - 45 michael@0: D117_PRED, // Directional 117 deg = 180 - 63 michael@0: D153_PRED, // Directional 153 deg = 180 - 27 michael@0: D207_PRED, // Directional 207 deg = 180 + 27 michael@0: D63_PRED, // Directional 63 deg = round(arctan(2/1) * 180/pi) michael@0: TM_PRED, // True-motion michael@0: NEARESTMV, michael@0: NEARMV, michael@0: ZEROMV, michael@0: NEWMV, michael@0: MB_MODE_COUNT michael@0: } MB_PREDICTION_MODE; michael@0: michael@0: static INLINE int is_inter_mode(MB_PREDICTION_MODE mode) { michael@0: return mode >= NEARESTMV && mode <= NEWMV; michael@0: } michael@0: michael@0: #define INTRA_MODES (TM_PRED + 1) michael@0: michael@0: #define INTER_MODES (1 + NEWMV - NEARESTMV) michael@0: michael@0: #define INTER_OFFSET(mode) ((mode) - NEARESTMV) michael@0: michael@0: michael@0: /* For keyframes, intra block modes are predicted by the (already decoded) michael@0: modes for the Y blocks to the left and above us; for interframes, there michael@0: is a single probability table. */ michael@0: michael@0: typedef struct { michael@0: MB_PREDICTION_MODE as_mode; michael@0: int_mv as_mv[2]; // first, second inter predictor motion vectors michael@0: } b_mode_info; michael@0: michael@0: typedef enum { michael@0: NONE = -1, michael@0: INTRA_FRAME = 0, michael@0: LAST_FRAME = 1, michael@0: GOLDEN_FRAME = 2, michael@0: ALTREF_FRAME = 3, michael@0: MAX_REF_FRAMES = 4 michael@0: } MV_REFERENCE_FRAME; michael@0: michael@0: static INLINE int b_width_log2(BLOCK_SIZE sb_type) { michael@0: return b_width_log2_lookup[sb_type]; michael@0: } michael@0: static INLINE int b_height_log2(BLOCK_SIZE sb_type) { michael@0: return b_height_log2_lookup[sb_type]; michael@0: } michael@0: michael@0: static INLINE int mi_width_log2(BLOCK_SIZE sb_type) { michael@0: return mi_width_log2_lookup[sb_type]; michael@0: } michael@0: michael@0: static INLINE int mi_height_log2(BLOCK_SIZE sb_type) { michael@0: return mi_height_log2_lookup[sb_type]; michael@0: } michael@0: michael@0: // This structure now relates to 8x8 block regions. michael@0: typedef struct { michael@0: MB_PREDICTION_MODE mode, uv_mode; michael@0: MV_REFERENCE_FRAME ref_frame[2]; michael@0: TX_SIZE tx_size; michael@0: int_mv mv[2]; // for each reference frame used michael@0: int_mv ref_mvs[MAX_REF_FRAMES][MAX_MV_REF_CANDIDATES]; michael@0: int_mv best_mv[2]; michael@0: michael@0: uint8_t mode_context[MAX_REF_FRAMES]; michael@0: michael@0: unsigned char skip_coeff; // 0=need to decode coeffs, 1=no coefficients michael@0: unsigned char segment_id; // Segment id for this block. michael@0: michael@0: // Flags used for prediction status of various bit-stream signals michael@0: unsigned char seg_id_predicted; michael@0: michael@0: INTERPOLATION_TYPE interp_filter; michael@0: michael@0: BLOCK_SIZE sb_type; michael@0: } MB_MODE_INFO; michael@0: michael@0: typedef struct { michael@0: MB_MODE_INFO mbmi; michael@0: b_mode_info bmi[4]; michael@0: } MODE_INFO; michael@0: michael@0: static INLINE int is_inter_block(const MB_MODE_INFO *mbmi) { michael@0: return mbmi->ref_frame[0] > INTRA_FRAME; michael@0: } michael@0: michael@0: static INLINE int has_second_ref(const MB_MODE_INFO *mbmi) { michael@0: return mbmi->ref_frame[1] > INTRA_FRAME; michael@0: } michael@0: michael@0: enum mv_precision { michael@0: MV_PRECISION_Q3, michael@0: MV_PRECISION_Q4 michael@0: }; michael@0: michael@0: #if CONFIG_ALPHA michael@0: enum { MAX_MB_PLANE = 4 }; michael@0: #else michael@0: enum { MAX_MB_PLANE = 3 }; michael@0: #endif michael@0: michael@0: struct buf_2d { michael@0: uint8_t *buf; michael@0: int stride; michael@0: }; michael@0: michael@0: struct macroblockd_plane { michael@0: int16_t *qcoeff; michael@0: int16_t *dqcoeff; michael@0: uint16_t *eobs; michael@0: PLANE_TYPE plane_type; michael@0: int subsampling_x; michael@0: int subsampling_y; michael@0: struct buf_2d dst; michael@0: struct buf_2d pre[2]; michael@0: int16_t *dequant; michael@0: ENTROPY_CONTEXT *above_context; michael@0: ENTROPY_CONTEXT *left_context; michael@0: }; michael@0: michael@0: #define BLOCK_OFFSET(x, i) ((x) + (i) * 16) michael@0: michael@0: typedef struct macroblockd { michael@0: struct macroblockd_plane plane[MAX_MB_PLANE]; michael@0: michael@0: struct scale_factors scale_factor[2]; michael@0: michael@0: MODE_INFO *last_mi; michael@0: int mode_info_stride; michael@0: michael@0: // A NULL indicates that the 8x8 is not part of the image michael@0: MODE_INFO **mi_8x8; michael@0: MODE_INFO **prev_mi_8x8; michael@0: MODE_INFO *mi_stream; michael@0: michael@0: int up_available; michael@0: int left_available; michael@0: michael@0: /* Distance of MB away from frame edges */ michael@0: int mb_to_left_edge; michael@0: int mb_to_right_edge; michael@0: int mb_to_top_edge; michael@0: int mb_to_bottom_edge; michael@0: michael@0: int lossless; michael@0: /* Inverse transform function pointers. */ michael@0: void (*itxm_add)(const int16_t *input, uint8_t *dest, int stride, int eob); michael@0: michael@0: struct subpix_fn_table subpix; michael@0: michael@0: int corrupted; michael@0: michael@0: /* Y,U,V,(A) */ michael@0: ENTROPY_CONTEXT *above_context[MAX_MB_PLANE]; michael@0: ENTROPY_CONTEXT left_context[MAX_MB_PLANE][16]; michael@0: michael@0: PARTITION_CONTEXT *above_seg_context; michael@0: PARTITION_CONTEXT left_seg_context[8]; michael@0: } MACROBLOCKD; michael@0: michael@0: michael@0: michael@0: static BLOCK_SIZE get_subsize(BLOCK_SIZE bsize, PARTITION_TYPE partition) { michael@0: const BLOCK_SIZE subsize = subsize_lookup[partition][bsize]; michael@0: assert(subsize < BLOCK_SIZES); michael@0: return subsize; michael@0: } michael@0: michael@0: extern const TX_TYPE mode2txfm_map[MB_MODE_COUNT]; michael@0: michael@0: static INLINE TX_TYPE get_tx_type_4x4(PLANE_TYPE plane_type, michael@0: const MACROBLOCKD *xd, int ib) { michael@0: const MODE_INFO *const mi = xd->mi_8x8[0]; michael@0: const MB_MODE_INFO *const mbmi = &mi->mbmi; michael@0: michael@0: if (plane_type != PLANE_TYPE_Y_WITH_DC || michael@0: xd->lossless || michael@0: is_inter_block(mbmi)) michael@0: return DCT_DCT; michael@0: michael@0: return mode2txfm_map[mbmi->sb_type < BLOCK_8X8 ? michael@0: mi->bmi[ib].as_mode : mbmi->mode]; michael@0: } michael@0: michael@0: static INLINE TX_TYPE get_tx_type_8x8(PLANE_TYPE plane_type, michael@0: const MACROBLOCKD *xd) { michael@0: return plane_type == PLANE_TYPE_Y_WITH_DC ? michael@0: mode2txfm_map[xd->mi_8x8[0]->mbmi.mode] : DCT_DCT; michael@0: } michael@0: michael@0: static INLINE TX_TYPE get_tx_type_16x16(PLANE_TYPE plane_type, michael@0: const MACROBLOCKD *xd) { michael@0: return plane_type == PLANE_TYPE_Y_WITH_DC ? michael@0: mode2txfm_map[xd->mi_8x8[0]->mbmi.mode] : DCT_DCT; michael@0: } michael@0: michael@0: static void setup_block_dptrs(MACROBLOCKD *xd, int ss_x, int ss_y) { michael@0: int i; michael@0: michael@0: for (i = 0; i < MAX_MB_PLANE; i++) { michael@0: xd->plane[i].plane_type = i ? PLANE_TYPE_UV : PLANE_TYPE_Y_WITH_DC; michael@0: xd->plane[i].subsampling_x = i ? ss_x : 0; michael@0: xd->plane[i].subsampling_y = i ? ss_y : 0; michael@0: } michael@0: #if CONFIG_ALPHA michael@0: // TODO(jkoleszar): Using the Y w/h for now michael@0: xd->plane[3].subsampling_x = 0; michael@0: xd->plane[3].subsampling_y = 0; michael@0: #endif michael@0: } michael@0: michael@0: michael@0: static INLINE TX_SIZE get_uv_tx_size(const MB_MODE_INFO *mbmi) { michael@0: return MIN(mbmi->tx_size, max_uv_txsize_lookup[mbmi->sb_type]); michael@0: } michael@0: michael@0: static BLOCK_SIZE get_plane_block_size(BLOCK_SIZE bsize, michael@0: const struct macroblockd_plane *pd) { michael@0: BLOCK_SIZE bs = ss_size_lookup[bsize][pd->subsampling_x][pd->subsampling_y]; michael@0: assert(bs < BLOCK_SIZES); michael@0: return bs; michael@0: } michael@0: michael@0: static INLINE int plane_block_width(BLOCK_SIZE bsize, michael@0: const struct macroblockd_plane* plane) { michael@0: return 4 << (b_width_log2(bsize) - plane->subsampling_x); michael@0: } michael@0: michael@0: static INLINE int plane_block_height(BLOCK_SIZE bsize, michael@0: const struct macroblockd_plane* plane) { michael@0: return 4 << (b_height_log2(bsize) - plane->subsampling_y); michael@0: } michael@0: michael@0: typedef void (*foreach_transformed_block_visitor)(int plane, int block, michael@0: BLOCK_SIZE plane_bsize, michael@0: TX_SIZE tx_size, michael@0: void *arg); michael@0: michael@0: static INLINE void foreach_transformed_block_in_plane( michael@0: const MACROBLOCKD *const xd, BLOCK_SIZE bsize, int plane, michael@0: foreach_transformed_block_visitor visit, void *arg) { michael@0: const struct macroblockd_plane *const pd = &xd->plane[plane]; michael@0: const MB_MODE_INFO* mbmi = &xd->mi_8x8[0]->mbmi; michael@0: // block and transform sizes, in number of 4x4 blocks log 2 ("*_b") michael@0: // 4x4=0, 8x8=2, 16x16=4, 32x32=6, 64x64=8 michael@0: // transform size varies per plane, look it up in a common way. michael@0: const TX_SIZE tx_size = plane ? get_uv_tx_size(mbmi) michael@0: : mbmi->tx_size; michael@0: const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd); michael@0: const int num_4x4_w = num_4x4_blocks_wide_lookup[plane_bsize]; michael@0: const int num_4x4_h = num_4x4_blocks_high_lookup[plane_bsize]; michael@0: const int step = 1 << (tx_size << 1); michael@0: int i; michael@0: michael@0: // If mb_to_right_edge is < 0 we are in a situation in which michael@0: // the current block size extends into the UMV and we won't michael@0: // visit the sub blocks that are wholly within the UMV. michael@0: if (xd->mb_to_right_edge < 0 || xd->mb_to_bottom_edge < 0) { michael@0: int r, c; michael@0: michael@0: int max_blocks_wide = num_4x4_w; michael@0: int max_blocks_high = num_4x4_h; michael@0: michael@0: // xd->mb_to_right_edge is in units of pixels * 8. This converts michael@0: // it to 4x4 block sizes. michael@0: if (xd->mb_to_right_edge < 0) michael@0: max_blocks_wide += (xd->mb_to_right_edge >> (5 + pd->subsampling_x)); michael@0: michael@0: if (xd->mb_to_bottom_edge < 0) michael@0: max_blocks_high += (xd->mb_to_bottom_edge >> (5 + pd->subsampling_y)); michael@0: michael@0: i = 0; michael@0: // Unlike the normal case - in here we have to keep track of the michael@0: // row and column of the blocks we use so that we know if we are in michael@0: // the unrestricted motion border. michael@0: for (r = 0; r < num_4x4_h; r += (1 << tx_size)) { michael@0: for (c = 0; c < num_4x4_w; c += (1 << tx_size)) { michael@0: if (r < max_blocks_high && c < max_blocks_wide) michael@0: visit(plane, i, plane_bsize, tx_size, arg); michael@0: i += step; michael@0: } michael@0: } michael@0: } else { michael@0: for (i = 0; i < num_4x4_w * num_4x4_h; i += step) michael@0: visit(plane, i, plane_bsize, tx_size, arg); michael@0: } michael@0: } michael@0: michael@0: static INLINE void foreach_transformed_block( michael@0: const MACROBLOCKD* const xd, BLOCK_SIZE bsize, michael@0: foreach_transformed_block_visitor visit, void *arg) { michael@0: int plane; michael@0: michael@0: for (plane = 0; plane < MAX_MB_PLANE; plane++) michael@0: foreach_transformed_block_in_plane(xd, bsize, plane, visit, arg); michael@0: } michael@0: michael@0: static INLINE void foreach_transformed_block_uv( michael@0: const MACROBLOCKD* const xd, BLOCK_SIZE bsize, michael@0: foreach_transformed_block_visitor visit, void *arg) { michael@0: int plane; michael@0: michael@0: for (plane = 1; plane < MAX_MB_PLANE; plane++) michael@0: foreach_transformed_block_in_plane(xd, bsize, plane, visit, arg); michael@0: } michael@0: michael@0: static int raster_block_offset(BLOCK_SIZE plane_bsize, michael@0: int raster_block, int stride) { michael@0: const int bw = b_width_log2(plane_bsize); michael@0: const int y = 4 * (raster_block >> bw); michael@0: const int x = 4 * (raster_block & ((1 << bw) - 1)); michael@0: return y * stride + x; michael@0: } michael@0: static int16_t* raster_block_offset_int16(BLOCK_SIZE plane_bsize, michael@0: int raster_block, int16_t *base) { michael@0: const int stride = 4 << b_width_log2(plane_bsize); michael@0: return base + raster_block_offset(plane_bsize, raster_block, stride); michael@0: } michael@0: static uint8_t* raster_block_offset_uint8(BLOCK_SIZE plane_bsize, michael@0: int raster_block, uint8_t *base, michael@0: int stride) { michael@0: return base + raster_block_offset(plane_bsize, raster_block, stride); michael@0: } michael@0: michael@0: static int txfrm_block_to_raster_block(BLOCK_SIZE plane_bsize, michael@0: TX_SIZE tx_size, int block) { michael@0: const int bwl = b_width_log2(plane_bsize); michael@0: const int tx_cols_log2 = bwl - tx_size; michael@0: const int tx_cols = 1 << tx_cols_log2; michael@0: const int raster_mb = block >> (tx_size << 1); michael@0: const int x = (raster_mb & (tx_cols - 1)) << tx_size; michael@0: const int y = (raster_mb >> tx_cols_log2) << tx_size; michael@0: return x + (y << bwl); michael@0: } michael@0: michael@0: static void txfrm_block_to_raster_xy(BLOCK_SIZE plane_bsize, michael@0: TX_SIZE tx_size, int block, michael@0: int *x, int *y) { michael@0: const int bwl = b_width_log2(plane_bsize); michael@0: const int tx_cols_log2 = bwl - tx_size; michael@0: const int tx_cols = 1 << tx_cols_log2; michael@0: const int raster_mb = block >> (tx_size << 1); michael@0: *x = (raster_mb & (tx_cols - 1)) << tx_size; michael@0: *y = (raster_mb >> tx_cols_log2) << tx_size; michael@0: } michael@0: michael@0: static void extend_for_intra(MACROBLOCKD *xd, BLOCK_SIZE plane_bsize, michael@0: int plane, int block, TX_SIZE tx_size) { michael@0: struct macroblockd_plane *const pd = &xd->plane[plane]; michael@0: uint8_t *const buf = pd->dst.buf; michael@0: const int stride = pd->dst.stride; michael@0: michael@0: int x, y; michael@0: txfrm_block_to_raster_xy(plane_bsize, tx_size, block, &x, &y); michael@0: x = x * 4 - 1; michael@0: y = y * 4 - 1; michael@0: // Copy a pixel into the umv if we are in a situation where the block size michael@0: // extends into the UMV. michael@0: // TODO(JBB): Should be able to do the full extend in place so we don't have michael@0: // to do this multiple times. michael@0: if (xd->mb_to_right_edge < 0) { michael@0: const int bw = 4 << b_width_log2(plane_bsize); michael@0: const int umv_border_start = bw + (xd->mb_to_right_edge >> michael@0: (3 + pd->subsampling_x)); michael@0: michael@0: if (x + bw > umv_border_start) michael@0: vpx_memset(&buf[y * stride + umv_border_start], michael@0: buf[y * stride + umv_border_start - 1], bw); michael@0: } michael@0: michael@0: if (xd->mb_to_bottom_edge < 0) { michael@0: if (xd->left_available || x >= 0) { michael@0: const int bh = 4 << b_height_log2(plane_bsize); michael@0: const int umv_border_start = michael@0: bh + (xd->mb_to_bottom_edge >> (3 + pd->subsampling_y)); michael@0: michael@0: if (y + bh > umv_border_start) { michael@0: const uint8_t c = buf[(umv_border_start - 1) * stride + x]; michael@0: uint8_t *d = &buf[umv_border_start * stride + x]; michael@0: int i; michael@0: for (i = 0; i < bh; ++i, d += stride) michael@0: *d = c; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: static void set_contexts(const MACROBLOCKD *xd, struct macroblockd_plane *pd, michael@0: BLOCK_SIZE plane_bsize, TX_SIZE tx_size, michael@0: int has_eob, int aoff, int loff) { michael@0: ENTROPY_CONTEXT *const a = pd->above_context + aoff; michael@0: ENTROPY_CONTEXT *const l = pd->left_context + loff; michael@0: const int tx_size_in_blocks = 1 << tx_size; michael@0: michael@0: // above michael@0: if (has_eob && xd->mb_to_right_edge < 0) { michael@0: int i; michael@0: const int blocks_wide = num_4x4_blocks_wide_lookup[plane_bsize] + michael@0: (xd->mb_to_right_edge >> (5 + pd->subsampling_x)); michael@0: int above_contexts = tx_size_in_blocks; michael@0: if (above_contexts + aoff > blocks_wide) michael@0: above_contexts = blocks_wide - aoff; michael@0: michael@0: for (i = 0; i < above_contexts; ++i) michael@0: a[i] = has_eob; michael@0: for (i = above_contexts; i < tx_size_in_blocks; ++i) michael@0: a[i] = 0; michael@0: } else { michael@0: vpx_memset(a, has_eob, sizeof(ENTROPY_CONTEXT) * tx_size_in_blocks); michael@0: } michael@0: michael@0: // left michael@0: if (has_eob && xd->mb_to_bottom_edge < 0) { michael@0: int i; michael@0: const int blocks_high = num_4x4_blocks_high_lookup[plane_bsize] + michael@0: (xd->mb_to_bottom_edge >> (5 + pd->subsampling_y)); michael@0: int left_contexts = tx_size_in_blocks; michael@0: if (left_contexts + loff > blocks_high) michael@0: left_contexts = blocks_high - loff; michael@0: michael@0: for (i = 0; i < left_contexts; ++i) michael@0: l[i] = has_eob; michael@0: for (i = left_contexts; i < tx_size_in_blocks; ++i) michael@0: l[i] = 0; michael@0: } else { michael@0: vpx_memset(l, has_eob, sizeof(ENTROPY_CONTEXT) * tx_size_in_blocks); michael@0: } michael@0: } michael@0: michael@0: static int get_tx_eob(const struct segmentation *seg, int segment_id, michael@0: TX_SIZE tx_size) { michael@0: const int eob_max = 16 << (tx_size << 1); michael@0: return vp9_segfeature_active(seg, segment_id, SEG_LVL_SKIP) ? 0 : eob_max; michael@0: } michael@0: michael@0: #endif // VP9_COMMON_VP9_BLOCKD_H_