Files
scummvm/image/codecs/vc1.cpp
T

15104 lines
597 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* WMV3 and VC-1 software video decoder.
*
* This decoder is a ScummVM port of the FFmpeg WMV3/VC-1 decoder path
* used by libavcodec revision c23123630e6a7e645c199599b8ade3fe7e9ab3db:
* https://git.ffmpeg.org/gitweb/ffmpeg.git/commit/c23123630e6a7e645c199599b8ade3fe7e9ab3db
* The original code was Copyright
* (c) 2005 Anonymous, Alex Beregszaszi and Michael Niedermayer,
* (c) 2006-2007 Konstantin Shishkov,
* (c) 2011 Mashiat Sarker Shakkhar,
* (c) 2000-2002 Fabrice Bellard,
* (c) 2001-2003 BERO <[email protected]>,
* (c) 2001-2012 Michael Niedermayer <[email protected]> et al,
* (c) 2010 Loren Merritt,
* (c) 2011 Oskar Arvidsson and
* (c) 2012 Ronald S. Bultje and distributed under the GNU LGPL
* version 2.1 or later. The migrated path includes sequence and picture
* headers, bitplanes, VLC tables, prediction, motion compensation, inverse
* transforms, overlap and loop filtering, IntraX8, error concealment,
* reference-frame ordering, and YUV420 output.
*/
#include "image/codecs/vc1.h"
#include "common/array.h"
#include "common/endian.h"
#include "common/memstream.h"
#include "common/ptr.h"
#include "common/rational.h"
#include "common/stream.h"
#include "common/textconsole.h"
#include "common/util.h"
#include "graphics/yuv_to_rgb.h"
#include "image/codecs/msmpeg4_vc1.h"
#include <limits.h>
namespace Image {
typedef void (*ChromaFunc)(uint8 *dst, const uint8 *src, ptrdiff_t stride, int height, int x, int y);
typedef void (*vc1op_pixels_func)(uint8 *block /*align width (8 or 16)*/, const uint8 *pixels /*align 1*/,
ptrdiff_t line_size, int round);
typedef struct WMV3DSP {
/* vc1 functions */
void (*vc1_inv_trans_8x8)(int16 *b);
void (*vc1_inv_trans_8x4)(uint8 *dest, ptrdiff_t stride, int16 *block);
void (*vc1_inv_trans_4x8)(uint8 *dest, ptrdiff_t stride, int16 *block);
void (*vc1_inv_trans_4x4)(uint8 *dest, ptrdiff_t stride, int16 *block);
void (*vc1_inv_trans_8x8_dc)(uint8 *dest, ptrdiff_t stride, int16 *block);
void (*vc1_inv_trans_8x4_dc)(uint8 *dest, ptrdiff_t stride, int16 *block);
void (*vc1_inv_trans_4x8_dc)(uint8 *dest, ptrdiff_t stride, int16 *block);
void (*vc1_inv_trans_4x4_dc)(uint8 *dest, ptrdiff_t stride, int16 *block);
void (*vc1_v_overlap)(uint8 *src, ptrdiff_t stride);
void (*vc1_h_overlap)(uint8 *src, ptrdiff_t stride);
void (*vc1_v_s_overlap)(int16 *top, int16 *bottom);
void (*vc1_h_s_overlap)(int16 *left, int16 *right, ptrdiff_t left_stride, ptrdiff_t right_stride, int flags);
void (*vc1_v_loop_filter4)(uint8 *src, ptrdiff_t stride, int pq);
void (*vc1_h_loop_filter4)(uint8 *src, ptrdiff_t stride, int pq);
void (*vc1_v_loop_filter8)(uint8 *src, ptrdiff_t stride, int pq);
void (*vc1_h_loop_filter8)(uint8 *src, ptrdiff_t stride, int pq);
void (*vc1_v_loop_filter16)(uint8 *src, ptrdiff_t stride, int pq);
void (*vc1_h_loop_filter16)(uint8 *src, ptrdiff_t stride, int pq);
/* put 8x8 block with bicubic interpolation and quarterpel precision
* last argument is actually round value instead of height
*/
vc1op_pixels_func put_vc1_mspel_pixels_tab[2][16];
vc1op_pixels_func avg_vc1_mspel_pixels_tab[2][16];
/* This is really one func used in VC-1 decoding */
ChromaFunc put_no_rnd_vc1_chroma_pixels_tab[3];
ChromaFunc avg_no_rnd_vc1_chroma_pixels_tab[3];
} WMV3DSP;
void initWMV3DSP(WMV3DSP *dsp);
namespace VC1 {
// Bitstream and VLC support
struct Bits {
Common::BitStream8MSB *stream;
int size_in_bits;
};
inline unsigned get_bits(Bits *b, int n) {
return b->stream->getBits(n);
}
inline unsigned get_bits1(Bits *b) {
return b->stream->getBit();
}
inline int get_bits_count(const Bits *b) {
return b->stream->pos();
}
inline int get_bits_left(const Bits *b) {
return b->size_in_bits - get_bits_count(b);
}
inline void skip_bits(Bits *b, int n) {
b->stream->skip(n);
}
inline int get_unary(Bits *b, int stop, int max) {
int i = 0;
while (i < max && get_bits1(b) != (unsigned)stop)
++i;
return i;
}
inline int decode012(Bits *b) {
return get_bits1(b) ? 1 + get_bits1(b) : 0;
}
inline int decode210(Bits *b) {
return get_bits1(b) ? 0 : 2 - get_bits1(b);
}
struct VLC {
struct Node {
int child[2];
int symbol;
Node() : child{-1, -1}, symbol(-1) {}
};
Common::Array<Node> nodes;
};
const VLC *makeVLC(int count, const void *lengths, int lengthStride, int lengthSize, const void *codes, int codeStride,
int codeSize);
int get_vlc2(Bits *b, const VLC *table);
void initTables();
inline int av_clip(int a, int low, int high) {
return CLIP(a, low, high);
}
inline int av_clip_uint8(int a) {
return CLIP(a, 0, 255);
}
inline int av_clip_uintp2(int a, int p) {
return CLIP(a, 0, (1 << p) - 1);
}
struct Crop {
uint8 operator[](int x) const { return av_clip_uint8(x); }
};
inline int mid_pred(int a, int b, int c) {
if (a > b)
SWAP(a, b);
return MAX(a, MIN(b, c));
}
#define FFALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
enum PictureType { AV_PICTURE_TYPE_I = 1, AV_PICTURE_TYPE_P = 2, AV_PICTURE_TYPE_B = 3, AV_PICTURE_TYPE_BI = 7 };
enum Profile { PROFILE_SIMPLE = 0, PROFILE_MAIN = 1, PROFILE_ADVANCED = 3 };
enum MacroblockType { MB_TYPE_INTRA = 1, MB_TYPE_16x16 = 8, MB_TYPE_SKIP = 131072 };
enum ErrorStatus { ER_MB_ERROR = 14, ER_MB_END = 112 };
static const int CONFIG_GRAY = 0;
static const int AV_CODEC_FLAG_GRAY = 8192;
static const int AVDISCARD_NONKEY = 32;
// Decoder state and picture storage
struct Settings {
int error_concealment = 3;
int flags;
int skip_loop_filter;
int coded_width;
int coded_height;
};
struct Planes {
uint8 *data[3];
int linesize[3];
int pict_type;
int width;
int height;
int format;
int decode_error_flags;
};
struct Picture {
Planes *f;
uint8 *data[3];
int linesize[3];
int16 (*motion_val[2])[2];
int8 *ref_index[2];
uint32 *mb_type;
int8 *qscale_table;
Picture *ptr;
int field_picture;
int interlaced;
};
typedef void (*PixelOp)(uint8 *, const uint8 *, ptrdiff_t, int);
typedef void (*QpelOp)(uint8 *, const uint8 *, ptrdiff_t);
struct QpelDSP {
QpelOp put_qpel_pixels_tab[2][16], put_no_rnd_qpel_pixels_tab[2][16], avg_qpel_pixels_tab[2][16];
};
void initQpel(QpelDSP *);
struct HalfDSP {
PixelOp put_pixels_tab[2][4], put_no_rnd_pixels_tab[2][4], avg_pixels_tab[2][4], avg_no_rnd_pixels_tab[4];
};
struct ChromaDSP {
ChromaFunc put_h264_chroma_pixels_tab[3], avg_h264_chroma_pixels_tab[3];
};
struct BlockDSP {
void (*clear_block)(int16 *);
void (*clear_blocks)(int16 *);
};
struct ClampDSP {
void (*put_pixels_clamped)(const int16 *, uint8 *, ptrdiff_t);
void (*put_signed_pixels_clamped)(const int16 *, uint8 *, ptrdiff_t);
void (*add_pixels_clamped)(const int16 *, uint8 *, ptrdiff_t);
};
struct EdgeDSP {
void (*emulated_edge_mc)(uint8 *, const uint8 *, ptrdiff_t, ptrdiff_t, int, int, int, int, int, int);
};
inline int median4(int a, int b, int c, int d) {
if (a < b) {
if (c < d)
return (MIN(b, d) + MAX(a, c)) / 2;
return (MIN(b, c) + MAX(a, d)) / 2;
}
if (c < d)
return (MIN(a, d) + MAX(b, c)) / 2;
return (MIN(a, c) + MAX(b, d)) / 2;
}
typedef struct ERContext {
Settings *avctx;
int (*sad)(void *unused, const uint8 *blk1, const uint8 *blk2, ptrdiff_t stride, int h);
int *mb_index2xy;
int mb_num;
int mb_width, mb_height;
ptrdiff_t mb_stride;
ptrdiff_t b8_stride;
int error_count;
int error_occurred;
uint8 *error_status_table;
uint8 *er_temp_buffer;
int16 *dc_val[3];
uint8 *mbskip_table;
uint8 *mbintra_table;
int mv[2][4][2];
Picture cur_pic;
Picture last_pic;
Picture next_pic;
int8 *ref_index[2];
int16 (*motion_val_base[2])[2];
uint16 pp_time;
uint16 pb_time;
int quarter_sample;
int partitioned_frame;
void (*decode_mb)(void *opaque, int ref, int mv_dir, int mv_type, int (*mv)[2][4][2], int mb_x, int mb_y,
int mb_intra, int mb_skipped);
void *opaque;
} ERContext;
void ff_er_add_slice(ERContext *, int, int, int, int, int);
void ff_er_frame_start(ERContext *);
void ff_er_frame_end(ERContext *, int *);
struct PictureState;
void initializeER(PictureState *);
struct PictureState {
Settings *avctx;
int ac_pred;
int b8_stride;
int chroma_x_shift;
int end_mb_y;
int first_slice_line;
int h_edge_pos;
int height;
int width;
int low_delay;
int linesize;
int mb_height;
int mb_intra;
int mb_stride;
int mb_width;
int mb_x;
int mb_y;
int mspel;
int pict_type;
int quarter_sample;
int start_mb_y;
int uvlinesize;
int v_edge_pos;
int y_dc_scale;
int16 (*ac_val)[16];
int16 *dc_val;
uint8 *coded_block;
uint8 *mbskip_table;
int block_index[6];
int block_wrap[6];
int mv[2][4][2];
uint8 *dest[3];
Picture cur_pic;
Picture last_pic;
Picture next_pic;
BlockDSP bdsp;
ClampDSP idsp;
HalfDSP hdsp;
QpelDSP qdsp;
EdgeDSP vdsp;
struct {
uint8 *edge_emu_buffer;
} sc;
ERContext er;
};
struct IntraX8Context;
int ff_intrax8_decode_picture(IntraX8Context *, Picture *, Bits *, int *, int *, int, int, int, int);
void ff_init_block_index(PictureState *s);
void ff_update_block_index(PictureState *s, int bits, int lowres, int chroma);
#define B_FRACTION_DEN 256
#define AC_VLC_BITS 9
/** Sequence quantizer mode */
//@{
enum QuantMode {
QUANT_FRAME_IMPLICIT, ///< Implicitly specified at frame level
QUANT_FRAME_EXPLICIT, ///< Explicitly specified at frame level
QUANT_NON_UNIFORM, ///< Non-uniform quant used for all frames
QUANT_UNIFORM ///< Uniform quant used for all frames
};
//@}
/** Where quant can be changed */
//@{
enum DQProfile { DQPROFILE_FOUR_EDGES, DQPROFILE_DOUBLE_EDGES, DQPROFILE_SINGLE_EDGE, DQPROFILE_ALL_MBS };
//@}
/** @name Where quant can be changed
*/
//@{
enum DQSingleEdge { DQSINGLE_BEDGE_LEFT, DQSINGLE_BEDGE_TOP, DQSINGLE_BEDGE_RIGHT, DQSINGLE_BEDGE_BOTTOM };
//@}
/** Which pair of edges is quantized with ALTPQUANT */
//@{
enum DQDoubleEdge {
DQDOUBLE_BEDGE_TOPLEFT,
DQDOUBLE_BEDGE_TOPRIGHT,
DQDOUBLE_BEDGE_BOTTOMRIGHT,
DQDOUBLE_BEDGE_BOTTOMLEFT
};
//@}
/** MV modes for P-frames */
//@{
enum MVModes { MV_PMODE_1MV_HPEL_BILIN, MV_PMODE_1MV, MV_PMODE_1MV_HPEL, MV_PMODE_MIXED_MV, MV_PMODE_INTENSITY_COMP };
//@}
/** MBMODE for interlaced frame P-picture */
//@{
enum MBModesIntfr {
MV_PMODE_INTFR_1MV,
MV_PMODE_INTFR_2MV_FIELD,
MV_PMODE_INTFR_2MV,
MV_PMODE_INTFR_4MV_FIELD,
MV_PMODE_INTFR_4MV,
MV_PMODE_INTFR_INTRA,
};
//@}
/** @name MV types for B-frames */
//@{
enum BMVTypes { BMV_TYPE_BACKWARD, BMV_TYPE_FORWARD, BMV_TYPE_INTERPOLATED, BMV_TYPE_DIRECT };
//@}
/** @name Block types for P/B-frames */
//@{
enum TransformTypes {
TT_8X8,
TT_8X4_BOTTOM,
TT_8X4_TOP,
TT_8X4, // both halves
TT_4X8_RIGHT,
TT_4X8_LEFT,
TT_4X8, // both halves
TT_4X4
};
//@}
enum CodingSet {
CS_HIGH_MOT_INTRA = 0,
CS_HIGH_MOT_INTER,
CS_LOW_MOT_INTRA,
CS_LOW_MOT_INTER,
CS_MID_RATE_INTRA,
CS_MID_RATE_INTER,
CS_HIGH_RATE_INTRA,
CS_HIGH_RATE_INTER
};
/** @name Overlap conditions for Advanced Profile */
//@{
enum COTypes { CONDOVER_NONE = 0, CONDOVER_ALL, CONDOVER_SELECT };
//@}
/**
* FCM Frame Coding Mode
* @note some content might be marked interlaced
* but have fcm set to 0 as well (e.g. HD-DVD)
*/
enum FrameCodingMode {
PROGRESSIVE = 0, ///< in the bitstream is reported as 00b
ILACE_FRAME, ///< in the bitstream is reported as 10b
ILACE_FIELD ///< in the bitstream is reported as 11b
};
/**
* Imode types
* @{
*/
enum Imode { IMODE_RAW, IMODE_NORM2, IMODE_DIFF2, IMODE_NORM6, IMODE_DIFF6, IMODE_ROWSKIP, IMODE_COLSKIP };
/** @} */ // imode defines
/** The VC1 Context
* @todo Change size wherever another size is more efficient
* Many members are only used for Advanced Profile
*/
// VC-1 picture context
struct VC1Context : VC1Header {
PictureState s;
Bits gb;
IntraX8Context *x8;
ChromaDSP h264chroma;
WMV3DSP vc1dsp;
/** Simple/Main Profile sequence header */
//@{
///< at frame level
int reserved; ///< reserved
//@}
/** Advanced Profile */
//@{
///< Decoder parameters
//@}
/** Sequence header data for all Profiles
* TODO: choose between ints, uint8_ts and monobit flags
*/
//@{
//@}
/** Frame decoding info for all profiles */
//@{
uint8 mv_mode; ///< MV coding mode
uint8 mv_mode2; ///< Secondary MV coding mode (B-frames)
int k_x; ///< Number of bits for MVs (depends on MV range)
int k_y; ///< Number of bits for MVs (depends on MV range)
int range_x, range_y; ///< MV range
uint8 pq, altpq; ///< Current/alternate frame quantizer scale
uint8 zz_8x8[4][64]; ///< Zigzag table for TT_8x8, permuted for IDCT
int left_blk_sh, top_blk_sh; ///< Either 3 or 0, positions of l/t in blk[]
/** pquant parameters */
//@{
uint8 dquantfrm;
uint8 dqprofile;
uint8 dqsbedge;
uint8 dqbilevel;
//@}
int dc_table_index;
/** AC coding set indexes
* @see 8.1.1.10, p(1)10
*/
//@{
int c_ac_table_index; ///< Chroma index from ACFRM element
int y_ac_table_index; ///< Luma index from AC2FRM element
//@}
int esc3_level_length;
int esc3_run_length;
int ttfrm; ///< Transform type info present at frame level
uint8 ttmbf; ///< Transform type flag
int *ttblk_base, *ttblk; ///< Transform type at the block level
int codingset; ///< index of current table set from 11.8 to use for luma block decoding
int codingset2; ///< index of current table set from 11.8 to use for chroma block decoding
int pqindex; ///< raw pqindex used in coding set selection
int a_avail, c_avail;
uint8 *mb_type_base, *mb_type;
/** Luma compensation parameters */
//@{
uint8 lumscale;
uint8 lumshift;
//@}
int16 bfraction; ///< Relative position % anchors=> how to scale MVs
uint8 halfpq; ///< Uniform quant over image and qp+.5
uint8 respic; ///< Frame-level flag for resized images
int buffer_fullness; ///< HRD info
/** Ranges:
* -# 0 -> [-64n 63.f] x [-32, 31.f]
* -# 1 -> [-128, 127.f] x [-64, 63.f]
* -# 2 -> [-512, 511.f] x [-128, 127.f]
* -# 3 -> [-1024, 1023.f] x [-256, 255.f]
*/
uint8 mvrange; ///< Extended MV range flag
uint8 pquantizer; ///< Uniform (over sequence) quantizer in use
const VLC *cbpcy_vlc; ///< CBPCY VLC table
int tt_index; ///< Index for Transform Type tables (to decode TTMB)
int mv_table_index;
uint8 *mv_type_mb_plane; ///< bitplane for mv_type == (4MV)
uint8 *direct_mb_plane; ///< bitplane for "direct" MBs
uint8 *forward_mb_plane; ///< bitplane for "forward" MBs
int mv_type_is_raw; ///< mv type mb plane is not coded
int dmb_is_raw; ///< direct mb plane is raw
int fmb_is_raw; ///< forward mb plane is raw
int skip_is_raw; ///< skip mb plane is not coded
uint8 last_luty[2][256], last_lutuv[2][256]; ///< lookup tables used for intensity compensation
uint8 aux_luty[2][256], aux_lutuv[2][256]; ///< lookup tables used for intensity compensation
uint8 next_luty[2][256], next_lutuv[2][256]; ///< lookup tables used for intensity compensation
uint8 (*curr_luty)[256], (*curr_lutuv)[256];
int last_use_ic, *curr_use_ic, next_use_ic, aux_use_ic;
int last_interlaced, next_interlaced; ///< whether last_pic, next_pic is interlaced
int rnd; ///< rounding control
int cbptab;
/** Frame decoding info for S/M profiles only */
//@{
uint8 rangeredfrm; ///< out_sample = CLIP((in_sample-128)*2+128)
uint8 interpfrm;
//@}
/** Frame decoding info for Advanced profile */
//@{
int fcm;
uint8 numpanscanwin;
uint8 tfcntr;
uint8 rptfrm, tff, rff;
uint8 uvsamp;
uint8 postproc;
uint8 bit_rate_exponent;
uint8 buffer_size_exponent;
uint8 *acpred_plane; ///< AC prediction flags bitplane
int acpred_is_raw;
uint8 *over_flags_plane; ///< Overflags bitplane
int overflg_is_raw;
uint8 condover;
//@}
/** Frame decoding info for interlaced picture */
uint8 dmvrange; ///< Extended differential MV range flag
int fourmvswitch;
int intcomp;
uint8 lumscale2; ///< for interlaced field P picture
uint8 lumshift2;
const VLC *mbmode_vlc;
const VLC *imv_vlc;
const VLC *twomvbp_vlc;
const VLC *fourmvbp_vlc;
uint8 twomvbp;
uint8 fourmvbp;
uint8 *fieldtx_plane;
int fieldtx_is_raw;
uint8 zzi_8x8[64];
uint8 *blk_mv_type_base, *blk_mv_type; ///< 0: frame MV, 1: field MV (interlaced frame)
uint8 *mv_f_base, *mv_f[2]; ///< 0: MV obtained from same field, 1: opposite field
uint8 *mv_f_next_base, *mv_f_next[2];
int field_mode; ///< 1 for interlaced field pictures
int fptype;
int second_field;
int refdist; ///< distance of the current picture from reference
int numref; ///< number of past field pictures used as reference
// 0 corresponds to 1 and 1 corresponds to 2 references
int reffield; ///< if numref = 0 (1 reference) then reffield decides which
// field to use among the two fields from previous frame
int intcompfield; ///< which of the two fields to be intensity compensated
// 0: both fields, 1: bottom field, 2: top field
int cur_field_type; ///< 0: top, 1: bottom
int ref_field_type[2]; ///< forward and backward reference field type (top or bottom)
int blocks_off, mb_off;
int bmvtype;
int frfd, brfd; ///< reference frame distance (forward or backward)
int first_pic_header_flag;
int pic_header_flag;
int mbmodetab;
int icbptab;
int imvtab;
int twomvbptab;
int fourmvbptab;
int new_sprite, two_sprites;
int p_frame_skipped;
int bi_type;
int x8_type;
int16 (*block)[6][64];
int n_allocated_blks, cur_blk_idx, left_blk_idx, topleft_blk_idx, top_blk_idx;
uint32 *cbp_base, *cbp;
uint8 *is_intra_base, *is_intra;
int16 (*luma_mv_base)[2], (*luma_mv)[2];
uint8 bfraction_lut_index; ///< Index for BFRACTION value (see Table 40, reproduced into ff_vc1_bfraction_lut[])
int end_mb_x; ///< Horizontal macroblock limit (used only by mss2)
int parse_only; ///< Context is used within parser
int16 blocks[6][64];
};
void ff_vc1_decode_blocks(VC1Context *v);
void ff_vc1_i_overlap_filter(VC1Context *v);
void ff_vc1_p_overlap_filter(VC1Context *v);
void ff_vc1_i_loop_filter(VC1Context *v);
void ff_vc1_p_loop_filter(VC1Context *v);
void ff_vc1_p_intfr_loop_filter(VC1Context *v);
void ff_vc1_b_intfi_loop_filter(VC1Context *v);
void ff_vc1_mc_1mv(VC1Context *v, int dir);
void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg);
void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir);
void ff_vc1_mc_4mv_chroma4(VC1Context *v, int dir, int dir2, int avg);
void ff_vc1_interp_mc(VC1Context *v);
void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, int mv1, int r_x, int r_y, uint8 *is_intra,
int pred_flag, int dir);
void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y, int mvn, int r_x, int r_y, int dir);
void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], int direct, int mvtype);
void ff_vc1_pred_b_mv_intfi(VC1Context *v, int n, int *dmv_x, int *dmv_y, int mv1, int *pred_flag);
static inline int scale_mv(int value, int bfrac, int inv, int qs) {
int n = bfrac;
#if B_FRACTION_DEN == 256
if (inv)
n -= 256;
if (!qs)
return 2 * ((value * n + 255) >> 9);
return (value * n + 128) >> 8;
#else
if (inv)
n -= B_FRACTION_DEN;
if (!qs)
return 2 * ((value * n + B_FRACTION_DEN - 1) / (2 * B_FRACTION_DEN));
return (value * n + B_FRACTION_DEN / 2) / B_FRACTION_DEN;
#endif
}
int ff_vc1_parse_frame_header(VC1Context *, Bits *);
int ff_vc1_parse_frame_header_adv(VC1Context *, Bits *);
void ff_simple_idct_int16_8bit(int16 *);
void ff_simple_idct_add_int16_8bit(uint8 *, ptrdiff_t, int16 *);
void ff_simple_idct84_add(uint8 *, ptrdiff_t, int16 *);
void ff_simple_idct48_add(uint8 *, ptrdiff_t, int16 *);
void ff_simple_idct44_add(uint8 *, ptrdiff_t, int16 *);
void initSupport(PictureState *, ChromaDSP *);
/** Table for conversion between TTBLK and TTMB */
extern const int ff_vc1_ttblk_to_tt[3][8];
extern const int ff_vc1_ttfrm_to_tt[4];
/** MV P mode - the 5th element is only used for mode 1 */
extern const uint8 ff_vc1_mv_pmode_table[2][5];
extern const uint8 ff_vc1_mv_pmode_table2[2][4];
extern const int ff_vc1_fps_nr[7], ff_vc1_fps_dr[2];
extern const uint8 ff_vc1_pquant_table[3][32];
/* MBMODE table for interlaced frame P-picture */
extern const uint8 ff_vc1_mbmode_intfrp[2][15][4];
/** @name VC-1 VLC tables
* @todo TODO move this into the context
*/
//@{
extern const VLC *ff_vc1_imode_vlc;
extern const VLC *ff_vc1_norm2_vlc;
extern const VLC *ff_vc1_norm6_vlc;
extern const VLC *ff_vc1_ttmb_vlc[3];
extern const VLC *ff_vc1_mv_diff_vlc[4];
extern const VLC *ff_vc1_cbpcy_p_vlc[4];
extern const VLC *ff_vc1_icbpcy_vlc[8];
extern const VLC *ff_vc1_4mv_block_pattern_vlc[4];
extern const VLC *ff_vc1_2mv_block_pattern_vlc[4];
extern const VLC *ff_vc1_ttblk_vlc[3];
extern const VLC *ff_vc1_subblkpat_vlc[3];
extern const VLC *ff_vc1_intfr_4mv_mbmode_vlc[4];
extern const VLC *ff_vc1_intfr_non4mv_mbmode_vlc[4];
extern const VLC *ff_vc1_if_mmv_mbmode_vlc[8];
extern const VLC *ff_vc1_if_1mv_mbmode_vlc[8];
extern const VLC *ff_vc1_1ref_mvdata_vlc[4];
extern const VLC *ff_vc1_2ref_mvdata_vlc[8];
extern const VLC *ff_vc1_ac_coeff_table[8];
//@}
/* pre-computed scales for all bfractions and base=256 */
extern const int16 ff_vc1_bfraction_lut[23];
// Same as H.264
extern const VC1Ratio ff_vc1_pixel_aspect[16];
extern const uint8 ff_wmv3_dc_scale_table[32];
/* DC differentials low+hi-mo, p217 are the same as in msmpeg4data .h */
/* Scantables/ZZ scan are at 11.9 (p262) and 8.1.1.12 (p10) */
extern const uint8 ff_vc1_simple_progressive_4x4_zz[16];
extern const uint8 ff_vc1_adv_progressive_8x4_zz[32];
extern const uint8 ff_vc1_adv_progressive_4x8_zz[32];
extern const uint8 ff_vc1_adv_interlaced_8x8_zz[64];
extern const uint8 ff_vc1_adv_interlaced_8x4_zz[32];
extern const uint8 ff_vc1_adv_interlaced_4x8_zz[32];
extern const uint8 ff_vc1_adv_interlaced_4x4_zz[16];
/* DQScale as specified in 8.1.3.9 - almost identical to 0x40000/i */
extern const int32 ff_vc1_dqscale[63];
/* P Interlaced field picture MV predictor scaling values (Table 114) */
extern const uint16 ff_vc1_field_mvpred_scales[2][7][4];
/* B Interlaced field picture backward MV predictor scaling values for first field (Table 115) */
extern const uint16 ff_vc1_b_field_mvpred_scales[7][4];
#define AC_MODES 8
extern const int ff_vc1_ac_sizes[AC_MODES];
extern const VLC *ff_msmp4_mb_i_vlc;
extern const VLC *ff_msmp4_dc_vlc[2 /* dc_table_index */][2 /* 0: luma, 1: chroma */];
/* intra picture macroblock coded block pattern */
using MSMPEG4VC1::ff_msmp4_mb_i_table;
#define WMV1_SCANTABLE_COUNT 4
extern const uint8 ff_wmv1_scantable[WMV1_SCANTABLE_COUNT][64];
using MSMPEG4VC1::ff_msmp4_dc_tables;
struct X8IDCT {
void (*idct_add)(uint8 *, ptrdiff_t, int16 *);
};
typedef struct IntraX8DSPContext {
void (*v_loop_filter)(uint8 *src, ptrdiff_t stride, int qscale);
void (*h_loop_filter)(uint8 *src, ptrdiff_t stride, int qscale);
void (*spatial_compensation[12])(const uint8 *src, uint8 *dst, ptrdiff_t stride);
void (*setup_spatial_compensation)(const uint8 *src, uint8 *dst, ptrdiff_t stride, int *range, int *sum, int edges);
} IntraX8DSPContext;
void ff_intrax8dsp_init(IntraX8DSPContext *dsp);
typedef struct IntraX8Context {
const VLC *j_ac_vlc_table[4]; // they point to the static j_mb_vlc.table
const VLC *j_orient_vlc_table;
const VLC *j_dc_vlc_table[3];
int use_quant_matrix;
// set by ff_intrax8_common_init
uint8 *prediction_table; // 2 * (mb_w * 2)
uint8 permutated_scantable[3][64];
X8IDCT idsp;
Settings *avctx;
int16 *block;
// set by the caller codec
IntraX8DSPContext dsp;
BlockDSP bdsp;
int quant;
int dquant;
int qsum;
int loopfilter;
Planes *frame;
Bits *gb;
// calculated per frame
int quant_dc_chroma;
int divide_quant_dc_luma;
int divide_quant_dc_chroma;
uint8 *dest[3];
uint8 scratchpad[42]; // size of the block is fixed (8x8 plus padding)
// changed per block
int edges;
int flat_dc;
int predicted_dc;
int raw_orient;
int chroma_orient;
int orient;
int est_run;
// block props
int mb_x, mb_y;
int mb_width, mb_height;
} IntraX8Context;
int initX8(IntraX8Context *, int16 *, int, int);
void endX8(IntraX8Context *);
// Packet decoder lifecycle
class Decoder {
public:
Decoder(int width, int height, bool advanced);
~Decoder();
bool initialize(const uint8 *data, uint32 size);
const Picture *decode(const uint8 *data, uint32 size);
const Picture *drain();
bool failed() const { return _failed; }
int width() const { return _v->width; }
int height() const { return _v->height; }
private:
VC1Context *_v;
Settings _settings;
Common::Array<uint8 *> _allocations;
Picture _pictures[3];
Planes _planes[3];
bool _advanced, _ready, _failed, _pending;
template<class T> T *allocate(uint32 n) {
uint8 *p = new uint8[sizeof(T) * n]();
_allocations.push_back(p);
return reinterpret_cast<T *>(p);
}
void allocatePictures();
void initializePictureLayout();
void allocatePredictors();
void allocateReferencePictures();
void initializeConcealment();
void initializeTransforms();
void clearPictures();
bool readHeader(const uint8 *, uint32, bool);
bool decodePacket(const uint8 *, uint32, const Picture *&);
};
/* which indexes point to last=1 entries in tables */
static const int vc1_last_decode_table[AC_MODES] = {119, 99, 85, 81, 67, 58, 126, 109};
static const uint8 vc1_index_decode_table[AC_MODES][185][2] = {
{{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}, {0, 10}, {0, 11}, {0, 12},
{0, 13}, {0, 14}, {0, 15}, {0, 16}, {0, 17}, {0, 18}, {0, 19}, {1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5},
{1, 6}, {1, 7}, {1, 8}, {1, 9}, {1, 10}, {1, 11}, {1, 12}, {1, 13}, {1, 14}, {1, 15}, {2, 1}, {2, 2},
{2, 3}, {2, 4}, {2, 5}, {2, 6}, {2, 7}, {2, 8}, {2, 9}, {2, 10}, {2, 11}, {2, 12}, {3, 1}, {3, 2},
{3, 3}, {3, 4}, {3, 5}, {3, 6}, {3, 7}, {3, 8}, {3, 9}, {3, 10}, {3, 11}, {4, 1}, {4, 2}, {4, 3},
{4, 4}, {4, 5}, {4, 6}, {5, 1}, {5, 2}, {5, 3}, {5, 4}, {5, 5}, {6, 1}, {6, 2}, {6, 3}, {6, 4},
{7, 1}, {7, 2}, {7, 3}, {7, 4}, {8, 1}, {8, 2}, {8, 3}, {8, 4}, {9, 1}, {9, 2}, {9, 3}, {9, 4},
{10, 1}, {10, 2}, {10, 3}, {11, 1}, {11, 2}, {11, 3}, {12, 1}, {12, 2}, {12, 3}, {13, 1}, {13, 2}, {13, 3},
{14, 1}, {14, 2}, {14, 3}, {15, 1}, {15, 2}, {15, 3}, {16, 1}, {16, 2}, {17, 1}, {17, 2}, {18, 1}, {19, 1},
{20, 1}, {21, 1}, {22, 1}, {23, 1}, {24, 1}, {25, 1}, {26, 1}, {27, 1}, {28, 1}, {29, 1}, {30, 1}, {0, 1},
{0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 1}, {2, 2},
{2, 3}, {2, 4}, {3, 1}, {3, 2}, {3, 3}, {3, 4}, {4, 1}, {4, 2}, {4, 3}, {5, 1}, {5, 2}, {6, 1},
{6, 2}, {7, 1}, {7, 2}, {8, 1}, {8, 2}, {9, 1}, {9, 2}, {10, 1}, {10, 2}, {11, 1}, {11, 2}, {12, 1},
{12, 2}, {13, 1}, {13, 2}, {14, 1}, {14, 2}, {15, 1}, {15, 2}, {16, 1}, {17, 1}, {18, 1}, {19, 1}, {20, 1},
{21, 1}, {22, 1}, {23, 1}, {24, 1}, {25, 1}, {26, 1}, {27, 1}, {28, 1}, {29, 1}, {30, 1}, {31, 1}, {32, 1},
{33, 1}, {34, 1}, {35, 1}, {36, 1}, {37, 1}},
{{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}, {0, 10}, {0, 11}, {0, 12},
{0, 13}, {0, 14}, {0, 15}, {0, 16}, {0, 17}, {0, 18}, {0, 19}, {0, 20}, {0, 21}, {0, 22}, {0, 23}, {1, 1},
{1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7}, {1, 8}, {1, 9}, {1, 10}, {1, 11}, {2, 1}, {2, 2},
{2, 3}, {2, 4}, {2, 5}, {2, 6}, {2, 7}, {2, 8}, {3, 1}, {3, 2}, {3, 3}, {3, 4}, {3, 5}, {3, 6},
{3, 7}, {4, 1}, {4, 2}, {4, 3}, {4, 4}, {4, 5}, {5, 1}, {5, 2}, {5, 3}, {5, 4}, {5, 5}, {6, 1},
{6, 2}, {6, 3}, {6, 4}, {7, 1}, {7, 2}, {7, 3}, {7, 4}, {8, 1}, {8, 2}, {8, 3}, {9, 1}, {9, 2},
{9, 3}, {10, 1}, {10, 2}, {10, 3}, {11, 1}, {11, 2}, {11, 3}, {12, 1}, {12, 2}, {13, 1}, {13, 2}, {14, 1},
{14, 2}, {15, 1}, {15, 2}, {16, 1}, {16, 2}, {17, 1}, {18, 1}, {19, 1}, {20, 1}, {21, 1}, {22, 1}, {23, 1},
{24, 1}, {25, 1}, {26, 1}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9},
{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 1}, {2, 2}, {2, 3}, {2, 4}, {3, 1}, {3, 2}, {3, 3},
{3, 4}, {4, 1}, {4, 2}, {4, 3}, {5, 1}, {5, 2}, {5, 3}, {6, 1}, {6, 2}, {6, 3}, {7, 1}, {7, 2},
{8, 1}, {8, 2}, {9, 1}, {9, 2}, {10, 1}, {10, 2}, {11, 1}, {11, 2}, {12, 1}, {12, 2}, {13, 1}, {13, 2},
{14, 1}, {14, 2}, {15, 1}, {16, 1}, {17, 1}, {18, 1}, {19, 1}, {20, 1}, {21, 1}, {22, 1}, {23, 1}, {24, 1},
{25, 1}, {26, 1}, {27, 1}, {28, 1}, {29, 1}, {30, 1}, {31, 1}, {32, 1}, {33, 1}, {34, 1}, {35, 1}, {36, 1}},
{{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}, {0, 10}, {0, 11}, {0, 12},
{0, 13}, {0, 14}, {0, 15}, {0, 16}, {1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7}, {1, 8},
{1, 9}, {1, 10}, {1, 11}, {2, 1}, {2, 2}, {2, 3}, {2, 4}, {2, 5}, {2, 6}, {2, 7}, {2, 8}, {3, 1},
{3, 2}, {3, 3}, {3, 4}, {3, 5}, {3, 6}, {3, 7}, {4, 1}, {4, 2}, {4, 3}, {4, 4}, {4, 5}, {5, 1},
{5, 2}, {5, 3}, {5, 4}, {6, 1}, {6, 2}, {6, 3}, {6, 4}, {7, 1}, {7, 2}, {7, 3}, {8, 1}, {8, 2},
{8, 3}, {9, 1}, {9, 2}, {9, 3}, {10, 1}, {10, 2}, {10, 3}, {11, 1}, {11, 2}, {11, 3}, {12, 1}, {12, 2},
{12, 3}, {13, 1}, {13, 2}, {13, 3}, {14, 1}, {14, 2}, {15, 1}, {15, 2}, {16, 1}, {17, 1}, {18, 1}, {19, 1},
{20, 1}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {1, 1}, {1, 2}, {1, 3}, {1, 4}, {2, 1}, {2, 2}, {2, 3},
{3, 1}, {3, 2}, {3, 3}, {4, 1}, {4, 2}, {5, 1}, {5, 2}, {6, 1}, {6, 2}, {7, 1}, {7, 2}, {8, 1},
{8, 2}, {9, 1}, {9, 2}, {10, 1}, {10, 2}, {11, 1}, {11, 2}, {12, 1}, {12, 2}, {13, 1}, {13, 2}, {14, 1},
{15, 1}, {16, 1}, {17, 1}, {18, 1}, {19, 1}, {20, 1}, {21, 1}, {22, 1}, {23, 1}, {24, 1}, {25, 1}, {26, 1}},
{{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}, {0, 10}, {0, 11}, {0, 12},
{0, 13}, {0, 14}, {1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7}, {1, 8}, {1, 9}, {2, 1},
{2, 2}, {2, 3}, {2, 4}, {2, 5}, {3, 1}, {3, 2}, {3, 3}, {3, 4}, {4, 1}, {4, 2}, {4, 3}, {4, 4},
{5, 1}, {5, 2}, {5, 3}, {5, 4}, {6, 1}, {6, 2}, {6, 3}, {7, 1}, {7, 2}, {7, 3}, {8, 1}, {8, 2},
{8, 3}, {9, 1}, {9, 2}, {9, 3}, {10, 1}, {10, 2}, {10, 3}, {11, 1}, {11, 2}, {11, 3}, {12, 1}, {12, 2},
{12, 3}, {13, 1}, {13, 2}, {14, 1}, {14, 2}, {15, 1}, {15, 2}, {16, 1}, {17, 1}, {18, 1}, {19, 1}, {20, 1},
{21, 1}, {22, 1}, {23, 1}, {24, 1}, {25, 1}, {26, 1}, {27, 1}, {28, 1}, {29, 1}, {0, 1}, {0, 2}, {0, 3},
{0, 4}, {0, 5}, {1, 1}, {1, 2}, {1, 3}, {1, 4}, {2, 1}, {2, 2}, {2, 3}, {3, 1}, {3, 2}, {3, 3},
{4, 1}, {4, 2}, {5, 1}, {5, 2}, {6, 1}, {6, 2}, {7, 1}, {7, 2}, {8, 1}, {8, 2}, {9, 1}, {9, 2},
{10, 1}, {10, 2}, {11, 1}, {11, 2}, {12, 1}, {12, 2}, {13, 1}, {13, 2}, {14, 1}, {14, 2}, {15, 1}, {15, 2},
{16, 1}, {17, 1}, {18, 1}, {19, 1}, {20, 1}, {21, 1}, {22, 1}, {23, 1}, {24, 1}, {25, 1}, {26, 1}, {27, 1},
{28, 1}, {29, 1}, {30, 1}, {31, 1}, {32, 1}, {33, 1}, {34, 1}, {35, 1}, {36, 1}, {37, 1}, {38, 1}, {39, 1},
{40, 1}, {41, 1}, {42, 1}, {43, 1}},
{{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}, {0, 10}, {0, 11}, {0, 12},
{0, 13}, {0, 14}, {0, 15}, {0, 16}, {0, 17}, {0, 18}, {0, 19}, {0, 20}, {0, 21}, {0, 22}, {0, 23}, {0, 24},
{0, 25}, {0, 26}, {0, 27}, {1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7}, {1, 8}, {1, 9},
{1, 10}, {2, 1}, {2, 2}, {2, 3}, {2, 4}, {2, 5}, {3, 1}, {3, 2}, {3, 3}, {3, 4}, {4, 1}, {4, 2},
{4, 3}, {5, 1}, {5, 2}, {5, 3}, {6, 1}, {6, 2}, {6, 3}, {7, 1}, {7, 2}, {7, 3}, {8, 1}, {8, 2},
{9, 1}, {9, 2}, {10, 1}, {11, 1}, {12, 1}, {13, 1}, {14, 1}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5},
{0, 6}, {0, 7}, {0, 8}, {1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {3, 1}, {3, 2}, {4, 1}, {4, 2},
{5, 1}, {5, 2}, {6, 1}, {6, 2}, {7, 1}, {8, 1}, {9, 1}, {10, 1}, {11, 1}, {12, 1}, {13, 1}, {14, 1},
{15, 1}, {16, 1}, {17, 1}, {18, 1}, {19, 1}, {20, 1}},
{{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}, {0, 10}, {0, 11}, {0, 12},
{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {2, 1}, {2, 2}, {2, 3}, {2, 4}, {3, 1}, {3, 2},
{3, 3}, {4, 1}, {4, 2}, {4, 3}, {5, 1}, {5, 2}, {5, 3}, {6, 1}, {6, 2}, {6, 3}, {7, 1}, {7, 2},
{8, 1}, {8, 2}, {9, 1}, {9, 2}, {10, 1}, {10, 2}, {11, 1}, {12, 1}, {13, 1}, {14, 1}, {15, 1}, {16, 1},
{17, 1}, {18, 1}, {19, 1}, {20, 1}, {21, 1}, {22, 1}, {23, 1}, {24, 1}, {25, 1}, {26, 1}, {0, 1}, {0, 2},
{0, 3}, {1, 1}, {1, 2}, {2, 1}, {3, 1}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {9, 1}, {10, 1},
{11, 1}, {12, 1}, {13, 1}, {14, 1}, {15, 1}, {16, 1}, {17, 1}, {18, 1}, {19, 1}, {20, 1}, {21, 1}, {22, 1},
{23, 1}, {24, 1}, {25, 1}, {26, 1}, {27, 1}, {28, 1}, {29, 1}, {30, 1}, {31, 1}, {32, 1}, {33, 1}, {34, 1},
{35, 1}, {36, 1}, {37, 1}, {38, 1}, {39, 1}, {40, 1}},
{{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}, {0, 10}, {0, 11}, {0, 12},
{0, 13}, {0, 14}, {0, 15}, {0, 16}, {0, 17}, {0, 18}, {0, 19}, {0, 20}, {0, 21}, {0, 22}, {0, 23}, {0, 24},
{0, 25}, {0, 26}, {0, 27}, {0, 28}, {0, 29}, {0, 30}, {0, 31}, {0, 32}, {0, 33}, {0, 34}, {0, 35}, {0, 36},
{0, 37}, {0, 38}, {0, 39}, {0, 40}, {0, 41}, {0, 42}, {0, 43}, {0, 44}, {0, 45}, {0, 46}, {0, 47}, {0, 48},
{0, 49}, {0, 50}, {0, 51}, {0, 52}, {0, 53}, {0, 54}, {0, 55}, {0, 56}, {1, 1}, {1, 2}, {1, 3}, {1, 4},
{1, 5}, {1, 6}, {1, 7}, {1, 8}, {1, 9}, {1, 10}, {1, 11}, {1, 12}, {1, 13}, {1, 14}, {1, 15}, {1, 16},
{1, 17}, {1, 18}, {1, 19}, {1, 20}, {2, 1}, {2, 2}, {2, 3}, {2, 4}, {2, 5}, {2, 6}, {2, 7}, {2, 8},
{2, 9}, {2, 10}, {3, 1}, {3, 2}, {3, 3}, {3, 4}, {3, 5}, {3, 6}, {3, 7}, {4, 1}, {4, 2}, {4, 3},
{4, 4}, {4, 5}, {4, 6}, {5, 1}, {5, 2}, {5, 3}, {5, 4}, {5, 5}, {6, 1}, {6, 2}, {6, 3}, {6, 4},
{7, 1}, {7, 2}, {7, 3}, {8, 1}, {8, 2}, {8, 3}, {9, 1}, {9, 2}, {9, 3}, {10, 1}, {10, 2}, {11, 1},
{11, 2}, {12, 1}, {12, 2}, {13, 1}, {13, 2}, {14, 1}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {1, 1}, {1, 2},
{1, 3}, {2, 1}, {2, 2}, {2, 3}, {3, 1}, {3, 2}, {4, 1}, {4, 2}, {5, 1}, {5, 2}, {6, 1}, {6, 2},
{7, 1}, {7, 2}, {8, 1}, {8, 2}, {9, 1}, {9, 2}, {10, 1}, {10, 2}, {11, 1}, {11, 2}, {12, 1}, {12, 2},
{13, 1}, {13, 2}, {14, 1}, {14, 2}, {15, 1}, {16, 1}},
{{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}, {0, 10}, {0, 11}, {0, 12},
{0, 13}, {0, 14}, {0, 15}, {0, 16}, {0, 17}, {0, 18}, {0, 19}, {0, 20}, {0, 21}, {0, 22}, {0, 23}, {0, 24},
{0, 25}, {0, 26}, {0, 27}, {0, 28}, {0, 29}, {0, 30}, {0, 31}, {0, 32}, {1, 1}, {1, 2}, {1, 3}, {1, 4},
{1, 5}, {1, 6}, {1, 7}, {1, 8}, {1, 9}, {1, 10}, {1, 11}, {1, 12}, {1, 13}, {2, 1}, {2, 2}, {2, 3},
{2, 4}, {2, 5}, {2, 6}, {2, 7}, {2, 8}, {3, 1}, {3, 2}, {3, 3}, {3, 4}, {3, 5}, {3, 6}, {4, 1},
{4, 2}, {4, 3}, {4, 4}, {4, 5}, {5, 1}, {5, 2}, {5, 3}, {5, 4}, {6, 1}, {6, 2}, {6, 3}, {6, 4},
{7, 1}, {7, 2}, {7, 3}, {8, 1}, {8, 2}, {8, 3}, {9, 1}, {9, 2}, {9, 3}, {10, 1}, {10, 2}, {11, 1},
{11, 2}, {12, 1}, {12, 2}, {13, 1}, {13, 2}, {14, 1}, {14, 2}, {15, 1}, {15, 2}, {16, 1}, {16, 2}, {17, 1},
{17, 2}, {18, 1}, {18, 2}, {19, 1}, {19, 2}, {20, 1}, {20, 2}, {21, 1}, {21, 2}, {22, 1}, {22, 2}, {23, 1},
{24, 1}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {2, 3}, {3, 1},
{3, 2}, {3, 3}, {4, 1}, {4, 2}, {5, 1}, {5, 2}, {6, 1}, {6, 2}, {7, 1}, {7, 2}, {8, 1}, {8, 2},
{9, 1}, {9, 2}, {10, 1}, {10, 2}, {11, 1}, {11, 2}, {12, 1}, {12, 2}, {13, 1}, {13, 2}, {14, 1}, {14, 2},
{15, 1}, {15, 2}, {16, 1}, {16, 2}, {17, 1}, {17, 2}, {18, 1}, {18, 2}, {19, 1}, {19, 2}, {20, 1}, {20, 2},
{21, 1}, {21, 2}, {22, 1}, {22, 2}, {23, 1}, {23, 2}, {24, 1}, {24, 2}, {25, 1}, {25, 2}, {26, 1}, {26, 2},
{27, 1}, {27, 2}, {28, 1}, {28, 2}, {29, 1}, {30, 1}}};
static const uint8 vc1_delta_level_table[AC_MODES][31] = {
{19, 15, 12, 11, 6, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{23, 11, 8, 7, 5, 5, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{16, 11, 8, 7, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 1},
{14, 9, 5, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{27, 10, 5, 4, 3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 1},
{12, 6, 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{56, 20, 10, 7, 6, 5, 4, 3, 3, 3, 2, 2, 2, 2, 1},
{32, 13, 8, 6, 5, 4, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1}};
static const uint8 vc1_last_delta_level_table[AC_MODES][44] = {
{6, 5, 4, 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{9, 5, 4, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{4, 4, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{5, 4, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{8, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{4, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1},
{4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1}};
static const uint8 vc1_delta_run_table[AC_MODES][57] = {
{255, 30, 17, 15, 9, 5, 4, 3, 3, 3, 3, 3, 2, 1, 1, 1, 0, 0, 0, 0},
{255, 26, 16, 11, 7, 5, 3, 3, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{255, 20, 15, 13, 6, 4, 3, 3, 2, 1, 1, 1, 0, 0, 0, 0, 0},
{255, 29, 15, 12, 5, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0},
{255, 14, 9, 7, 3, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{255, 26, 10, 6, 2, 1, 1, 0, 0, 0, 0, 0, 0},
{255, 14, 13, 9, 6, 5, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{255, 24, 22, 9, 6, 4, 3, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
static const uint8 vc1_last_delta_run_table[AC_MODES][10] = {{255, 37, 15, 4, 3, 1, 0},
{255, 36, 14, 6, 3, 1, 0, 0, 0, 0},
{255, 26, 13, 3, 1},
{255, 43, 15, 3, 1, 0},
{255, 20, 6, 1, 0, 0, 0, 0, 0},
{255, 40, 1, 0},
{255, 16, 14, 2, 0},
{255, 30, 28, 3, 0}};
/* BitPlane IMODE - such a small table... */
// Static coding tables
static const uint8 vc1_imode_codes[7] = {0, 2, 1, 3, 1, 2, 3};
static const uint8 vc1_imode_bits[7] = {4, 2, 3, 2, 4, 3, 3};
/* Normal-2 imode */
static const uint8 vc1_norm2_codes[4] = {0, 4, 5, 3};
static const uint8 vc1_norm2_bits[4] = {1, 3, 3, 2};
static const uint16 vc1_norm6_codes[64] = {
0x001, 0x002, 0x003, 0x000, 0x004, 0x001, 0x002, 0x047, 0x005, 0x003, 0x004, 0x04B, 0x005, 0x04D, 0x04E, 0x30E,
0x006, 0x006, 0x007, 0x053, 0x008, 0x055, 0x056, 0x30D, 0x009, 0x059, 0x05A, 0x30C, 0x05C, 0x30B, 0x30A, 0x037,
0x007, 0x00A, 0x00B, 0x043, 0x00C, 0x045, 0x046, 0x309, 0x00D, 0x049, 0x04A, 0x308, 0x04C, 0x307, 0x306, 0x036,
0x00E, 0x051, 0x052, 0x305, 0x054, 0x304, 0x303, 0x035, 0x058, 0x302, 0x301, 0x034, 0x300, 0x033, 0x032, 0x007,
};
static const uint8 vc1_norm6_bits[64] = {
1, 4, 4, 8, 4, 8, 8, 10, 4, 8, 8, 10, 8, 10, 10, 13, 4, 8, 8, 10, 8, 10,
10, 13, 8, 10, 10, 13, 10, 13, 13, 9, 4, 8, 8, 10, 8, 10, 10, 13, 8, 10, 10, 13,
10, 13, 13, 9, 8, 10, 10, 13, 10, 13, 13, 9, 10, 13, 13, 9, 13, 9, 9, 6,
};
/* 4MV Block pattern VLC tables */
static const uint8 vc1_4mv_block_pattern_codes[4][16] = {{14, 58, 59, 25, 12, 26, 15, 15, 13, 24, 27, 0, 28, 1, 2, 2},
{8, 18, 19, 4, 20, 5, 30, 11, 21, 31, 6, 12, 7, 13, 14, 0},
{15, 6, 7, 2, 8, 3, 28, 9, 10, 29, 4, 11, 5, 12, 13, 0},
{0, 11, 12, 4, 13, 5, 30, 16, 14, 31, 6, 17, 7, 18, 19, 10}};
static const uint8 vc1_4mv_block_pattern_bits[4][16] = {{5, 6, 6, 5, 5, 5, 5, 4, 5, 5, 5, 3, 5, 3, 3, 2},
{4, 5, 5, 4, 5, 4, 5, 4, 5, 5, 4, 4, 4, 4, 4, 2},
{4, 4, 4, 4, 4, 4, 5, 4, 4, 5, 4, 4, 4, 4, 4, 3},
{2, 4, 4, 4, 4, 4, 5, 5, 4, 5, 4, 5, 4, 5, 5, 4}};
/* 2MV Block pattern VLC tables */
static const uint8 vc1_2mv_block_pattern_codes[4][4] = {{2, 1, 0, 3}, {1, 0, 2, 3}, {2, 0, 3, 1}, {1, 3, 2, 0}};
static const uint8 vc1_2mv_block_pattern_bits[4][4] = {{2, 2, 2, 2}, {1, 2, 3, 3}, {3, 2, 3, 1}, {1, 3, 3, 2}};
/* Interlaced frame picture 4MV MBMODE VLC tables (p. 246, p. 360) */
static const uint16 vc1_intfr_4mv_mbmode_codes[4][15] = {
{22, 17, 0, 47, 32, 10, 1, 3, 67, 133, 132, 92, 19, 93, 18},
{3, 45, 0, 7, 23, 6, 1, 2, 10, 39, 44, 8, 18, 77, 76},
{15, 6, 28, 9, 41, 6, 2, 15, 14, 8, 40, 29, 0, 21, 11},
{7, 198, 1, 2, 193, 13, 25, 0, 97, 1599, 98, 398, 798, 192, 1598}};
static const uint8 vc1_intfr_4mv_mbmode_bits[4][15] = {{5, 5, 2, 6, 6, 4, 2, 2, 7, 8, 8, 7, 5, 7, 5},
{3, 6, 3, 3, 5, 3, 3, 3, 4, 6, 6, 4, 5, 7, 7},
{4, 3, 5, 5, 7, 4, 2, 5, 5, 5, 7, 5, 2, 6, 5},
{4, 9, 1, 3, 9, 5, 6, 2, 8, 12, 8, 10, 11, 9, 12}};
/* Interlaced frame picture NON-4MV MBMODE VLC tables (p. 363) */
static const uint8 vc1_intfr_non4mv_mbmode_codes[4][9] = {{9, 22, 0, 17, 16, 10, 1, 3, 23},
{7, 0, 5, 2, 1, 1, 6, 3, 4},
{1, 0, 10, 23, 44, 8, 3, 9, 45},
{7, 97, 1, 2, 49, 13, 25, 0, 96}};
static const uint8 vc1_intfr_non4mv_mbmode_bits[4][9] = {
{4, 5, 2, 5, 5, 4, 2, 2, 5}, {3, 4, 6, 2, 3, 2, 3, 5, 6}, {2, 2, 4, 5, 6, 4, 2, 4, 6}, {4, 8, 1, 3, 7, 5, 6, 2, 8}};
/* Interlaced field picture MBMODE VLC tables (p. 356 - 11.4.1, 11.4.2) */
/* mixed-MV */
static const uint8 vc1_if_mmv_mbmode_codes[8][8] = {{16, 17, 3, 3, 0, 5, 9, 2}, {8, 9, 3, 6, 7, 0, 5, 2},
{16, 17, 5, 3, 0, 3, 9, 2}, {56, 57, 15, 4, 5, 6, 29, 0},
{52, 53, 27, 14, 15, 2, 12, 0}, {56, 57, 29, 5, 6, 0, 15, 4},
{16, 17, 6, 7, 0, 1, 9, 5}, {56, 57, 0, 5, 6, 29, 4, 15}};
static const uint8 vc1_if_mmv_mbmode_bits[8][8] = {
{6, 6, 2, 3, 2, 4, 5, 2}, {5, 5, 3, 3, 3, 2, 4, 2}, {6, 6, 4, 3, 2, 2, 5, 2}, {6, 6, 4, 3, 3, 3, 5, 1},
{6, 6, 5, 4, 4, 2, 4, 1}, {6, 6, 5, 3, 3, 1, 4, 3}, {5, 5, 3, 3, 2, 2, 4, 3}, {6, 6, 1, 3, 3, 5, 3, 4}};
/* 1MV */
static const uint8 vc1_if_1mv_mbmode_codes[8][6] = {{0, 1, 1, 1, 1, 1}, {0, 1, 1, 1, 1, 1}, {16, 17, 3, 0, 9, 5},
{20, 21, 3, 11, 0, 4}, {4, 5, 2, 3, 3, 0}, {4, 5, 3, 2, 0, 3},
{0, 1, 1, 1, 1, 1}, {16, 17, 9, 5, 3, 0}};
static const uint8 vc1_if_1mv_mbmode_bits[8][6] = {{5, 5, 1, 3, 2, 4}, {5, 5, 1, 2, 3, 4}, {5, 5, 2, 1, 4, 3},
{5, 5, 2, 4, 1, 3}, {4, 4, 2, 3, 2, 2}, {4, 4, 3, 2, 2, 2},
{5, 5, 3, 4, 1, 2}, {5, 5, 4, 3, 2, 1}};
/* Interlaced frame/field picture MVDATA VLC tables */
/* 1-reference tables */
static const uint32 vc1_1ref_mvdata_codes[4][72] =
{/* uint32 may be too big */
{0x00005, 0x0000C, 0x0001E, 0x00012, 0x0000C, 0x00034, 0x00075, 0x00070, 0x00000, 0x00008, 0x0001B, 0x00008,
0x0001D, 0x0007C, 0x000D6, 0x001DE, 0x001AF, 0x00005, 0x0001B, 0x00026, 0x0001E, 0x00012, 0x00076, 0x0004D,
0x001F6, 0x001F4, 0x00039, 0x0007F, 0x00027, 0x0006A, 0x00071, 0x00035, 0x00071, 0x00068, 0x001DC, 0x00027,
0x00073, 0x000FF, 0x000E8, 0x000E9, 0x0007E, 0x001F9, 0x001F5, 0x001FD, 0x0003E, 0x001CA, 0x003F9, 0x0004C,
0x00069, 0x001FA, 0x001DF, 0x001F7, 0x00070, 0x001DD, 0x00E4D, 0x00727, 0x00392, 0x001C8, 0x001CB, 0x003F8,
0x001AE, 0x001F8, 0x001FB, 0x0E4CE, 0x0E4CF, 0x07260, 0x07261, 0x07262, 0x07263, 0x07264, 0x07265, 0x07266},
{0x00007, 0x00001, 0x00007, 0x00016, 0x00001, 0x00045, 0x00018, 0x002B6, 0x00006, 0x00004, 0x00017, 0x00010,
0x00029, 0x0002C, 0x0015A, 0x00066, 0x0019E, 0x00009, 0x00028, 0x00017, 0x00000, 0x0002A, 0x00004, 0x0005B,
0x000B5, 0x000CE, 0x00006, 0x00044, 0x0000F, 0x00046, 0x0000E, 0x000AC, 0x00032, 0x00037, 0x011EB, 0x0000A,
0x0001A, 0x0011F, 0x00016, 0x00014, 0x0002B, 0x00168, 0x00055, 0x023D5, 0x00057, 0x0002F, 0x00036, 0x0002E,
0x00169, 0x00054, 0x0047B, 0x0019F, 0x02B7D, 0x0008E, 0x00ADE, 0x00479, 0x0056E, 0x008F4, 0x015BF, 0x00478,
0x023D4, 0x0ADF1, 0x056F9, 0xADF0E, 0xADF0F, 0x56F80, 0x56F81, 0x56F82, 0x56F83, 0x56F84, 0x56F85, 0x56F86},
{0x00002, 0x00006, 0x00007, 0x0000D, 0x00007, 0x00030, 0x000FF, 0x001F0, 0x00002, 0x00000, 0x00005, 0x00019,
0x0001E, 0x00007, 0x00063, 0x000FD, 0x00023, 0x0000E, 0x0001B, 0x0001A, 0x00006, 0x00009, 0x00018, 0x000C5,
0x00033, 0x001F1, 0x00002, 0x003FB, 0x001F3, 0x00022, 0x001FC, 0x00042, 0x00623, 0x00083, 0x00620, 0x0007D,
0x00040, 0x00043, 0x003E4, 0x003E5, 0x00191, 0x00FE9, 0x00105, 0x00208, 0x000FC, 0x00624, 0x00622, 0x00190,
0x00626, 0x007F5, 0x00C4B, 0x01FD0, 0x0104D, 0x00065, 0x00C42, 0x000C9, 0x00627, 0x00C43, 0x00C4A, 0x0104E,
0x01FD1, 0x0104F, 0x00412, 0x104CE, 0x104CF, 0x08260, 0x08261, 0x08262, 0x08263, 0x08264, 0x08265, 0x08266},
{0x0000D, 0x00001, 0x00004, 0x00000, 0x00017, 0x00005, 0x0007F, 0x0004D, 0x00003, 0x00011, 0x0003E, 0x0003B,
0x00017, 0x00067, 0x0004A, 0x000C3, 0x000F2, 0x0000A, 0x0002C, 0x00032, 0x0003D, 0x00015, 0x00028, 0x00093,
0x000CC, 0x00096, 0x00003, 0x00075, 0x00020, 0x0002D, 0x00021, 0x00029, 0x00090, 0x001D0, 0x001FB, 0x0001C,
0x0004C, 0x00060, 0x00009, 0x00008, 0x0002D, 0x0009F, 0x001FA, 0x0013D, 0x00031, 0x000FC, 0x00058, 0x00092,
0x000F0, 0x000F1, 0x000CD, 0x00185, 0x00165, 0x0004E, 0x00091, 0x000E9, 0x00184, 0x001D1, 0x001E6, 0x00097,
0x001E7, 0x000B3, 0x0013C, 0x0164E, 0x0164F, 0x00B20, 0x00B21, 0x00B22, 0x00B23, 0x00B24, 0x00B25, 0x00B26}};
static const uint8 vc1_1ref_mvdata_bits[4][72] = {
{3, 4, 5, 5, 5, 6, 7, 7, 2, 4, 5, 5, 6, 7, 8, 9, 9, 4, 6, 6, 6, 6, 7, 8,
9, 9, 6, 8, 7, 7, 7, 7, 8, 8, 9, 6, 8, 8, 8, 8, 8, 9, 9, 9, 7, 10, 10, 8,
8, 9, 9, 9, 8, 9, 13, 12, 11, 10, 10, 10, 9, 9, 9, 17, 17, 16, 16, 16, 16, 16, 16, 16},
{3, 3, 4, 5, 5, 7, 8, 10, 3, 4, 5, 5, 6, 7, 9, 10, 12, 4, 6, 6, 5, 6, 6, 8,
9, 11, 4, 7, 7, 7, 7, 8, 9, 9, 13, 5, 8, 9, 8, 8, 9, 10, 10, 14, 7, 9, 9, 9,
10, 10, 11, 12, 14, 8, 12, 11, 11, 12, 13, 11, 14, 16, 15, 20, 20, 19, 19, 19, 19, 19, 19, 19},
{3, 4, 4, 4, 5, 6, 8, 9, 2, 4, 5, 5, 5, 6, 7, 8, 8, 4, 7, 7, 6, 6, 7, 8,
8, 9, 5, 10, 9, 8, 9, 9, 11, 10, 11, 7, 9, 9, 10, 10, 11, 12, 11, 12, 8, 11, 11, 11,
11, 11, 12, 13, 15, 9, 12, 10, 11, 12, 12, 15, 13, 15, 13, 19, 19, 18, 18, 18, 18, 18, 18, 18},
{4, 4, 4, 4, 5, 5, 7, 7, 3, 5, 6, 6, 6, 7, 7, 8, 8, 4, 6, 6, 6, 6, 7, 8,
8, 8, 4, 7, 6, 6, 6, 7, 8, 9, 9, 5, 7, 7, 6, 6, 7, 8, 9, 9, 6, 8, 8, 8,
8, 8, 8, 9, 10, 7, 8, 8, 9, 9, 9, 8, 9, 9, 9, 14, 14, 13, 13, 13, 13, 13, 13, 13}};
/* 2-reference tables */
static const uint32 vc1_2ref_mvdata_codes[8][126] =
{/* table 132 - table 139 */
{0x0000C, 0x0001C, 0x0000B, 0x00000, 0x0000E, 0x0002A, 0x00050, 0x00368, 0x00002, 0x0001A, 0x00004, 0x0003A,
0x0001D, 0x0006C, 0x000EF, 0x001BC, 0x0015F, 0x0000F, 0x00003, 0x0001C, 0x0000D, 0x0000B, 0x0003E, 0x000A7,
0x00146, 0x00199, 0x00006, 0x0001F, 0x00004, 0x0003C, 0x00007, 0x001BE, 0x0008B, 0x0002C, 0x007B3, 0x00005,
0x000DB, 0x00056, 0x000EC, 0x00052, 0x001BD, 0x00078, 0x000CF, 0x00573, 0x00009, 0x00023, 0x000ED, 0x00018,
0x00006, 0x00044, 0x000F5, 0x00079, 0x006D2, 0x0006E, 0x0002B, 0x0015D, 0x00017, 0x0037F, 0x00144, 0x000CE,
0x00028, 0x000AB, 0x00010, 0x001B5, 0x000F7, 0x000A6, 0x0007B, 0x00028, 0x001ED, 0x001E9, 0x006FD, 0x00004,
0x000F5, 0x00029, 0x0028A, 0x0028B, 0x0028F, 0x00DF9, 0x00335, 0x01E85, 0x000EE, 0x002BD, 0x0002B, 0x003D8,
0x003D1, 0x00198, 0x001E9, 0x0051D, 0x000B4, 0x0003F, 0x00455, 0x0022B, 0x00229, 0x00451, 0x00578, 0x007B2,
0x00570, 0x00155, 0x00032, 0x003D0, 0x00054, 0x006D3, 0x00571, 0x00454, 0x00334, 0x01BF1, 0x000B7, 0x00029,
0x01E84, 0x0016C, 0x0019B, 0x01BF0, 0x00579, 0x00F43, 0x000B5, 0x008A1, 0x0002A, 0x0016D, 0x008A0, 0x007A0,
0x003D1, 0x00AE5, 0x00154, 0x00AE4, 0x00A39, 0x00A38},
{0x00003, 0x00009, 0x00016, 0x00010, 0x000D7, 0x00335, 0x00574, 0x00555, 0x00000, 0x0001D, 0x00009, 0x00017,
0x0002C, 0x000AD, 0x00374, 0x006B3, 0x00577, 0x0000F, 0x00018, 0x0000A, 0x0002E, 0x00022, 0x0017C, 0x00E7B,
0x01B89, 0x015D8, 0x00008, 0x00034, 0x0006D, 0x00023, 0x001C2, 0x00376, 0x002D3, 0x01C4A, 0x0330A, 0x00014,
0x0006A, 0x00072, 0x0006C, 0x000E3, 0x0019B, 0x0073F, 0x01CF0, 0x00B41, 0x00032, 0x000E6, 0x000E0, 0x000CF,
0x000AB, 0x0019C, 0x002AB, 0x00E2B, 0x015D9, 0x0006F, 0x001C3, 0x000AF, 0x000BF, 0x000AC, 0x0017D, 0x006E3,
0x00E29, 0x01984, 0x00054, 0x000B5, 0x0017A, 0x001AD, 0x00199, 0x00178, 0x00358, 0x002D2, 0x01C4B, 0x0005B,
0x002A8, 0x00331, 0x00388, 0x0038B, 0x00370, 0x00713, 0x00CC3, 0x01CF1, 0x001B9, 0x005EF, 0x00738, 0x002F2,
0x0033B, 0x002B9, 0x006EB, 0x00570, 0x00E24, 0x0039D, 0x005A2, 0x005A3, 0x00E7D, 0x005EE, 0x00739, 0x00554,
0x00AA5, 0x00AA4, 0x00377, 0x01CF5, 0x00BCE, 0x00E79, 0x00660, 0x00674, 0x006EA, 0x00E7C, 0x00D65, 0x002F6,
0x015DA, 0x01B88, 0x005A1, 0x01CF4, 0x005E6, 0x00E28, 0x00575, 0x00D64, 0x00334, 0x0330B, 0x015DB, 0x00B40,
0x00BCF, 0x00DC5, 0x00E2A, 0x00675, 0x00571, 0x00553},
{0x00004, 0x00002, 0x00010, 0x00003, 0x00017, 0x00045, 0x0003E, 0x0007E, 0x00003, 0x00002, 0x00028, 0x0001E,
0x00015, 0x00047, 0x00002, 0x0014D, 0x00060, 0x0000B, 0x00026, 0x00024, 0x00014, 0x00032, 0x0006F, 0x000C3,
0x00531, 0x006E5, 0x00015, 0x0003F, 0x0002D, 0x00001, 0x0013E, 0x000DD, 0x000F6, 0x00305, 0x00331, 0x0000E,
0x00003, 0x00034, 0x00033, 0x0001A, 0x0014A, 0x000C5, 0x000F4, 0x006E4, 0x00001, 0x0003C, 0x0007D, 0x0008D,
0x0009D, 0x00031, 0x0006E, 0x00296, 0x000CD, 0x00025, 0x00149, 0x00032, 0x00089, 0x00036, 0x00088, 0x0006F,
0x00003, 0x0031D, 0x0000E, 0x001AA, 0x0027E, 0x00061, 0x0014E, 0x0014F, 0x00067, 0x000FF, 0x00183, 0x00036,
0x00357, 0x000F5, 0x000C6, 0x000C2, 0x00299, 0x00119, 0x00231, 0x00350, 0x0002C, 0x0018F, 0x00530, 0x00297,
0x00004, 0x001B8, 0x000C0, 0x0027A, 0x00311, 0x0009C, 0x00621, 0x00199, 0x0031C, 0x000F7, 0x003E3, 0x00356,
0x00189, 0x00005, 0x0006B, 0x008C2, 0x00330, 0x004FF, 0x004F0, 0x00351, 0x004F2, 0x001F2, 0x00373, 0x00000,
0x00C41, 0x008C3, 0x009EC, 0x003E2, 0x00304, 0x004F7, 0x004F1, 0x001F0, 0x00148, 0x00C40, 0x009ED, 0x008C0,
0x008C1, 0x004F3, 0x004FE, 0x000FE, 0x001F3, 0x001A9},
{0x00000, 0x00004, 0x0002F, 0x00052, 0x00010, 0x000AD, 0x0050B, 0x00190, 0x00003, 0x00016, 0x00007, 0x0000D,
0x000BB, 0x00173, 0x000C9, 0x0050F, 0x0172C, 0x00003, 0x00011, 0x00005, 0x00043, 0x00023, 0x0004B, 0x0032E,
0x02E5B, 0x00482, 0x00009, 0x0002A, 0x00014, 0x0002A, 0x00108, 0x005CA, 0x0065A, 0x02136, 0x02132, 0x0000B,
0x00013, 0x00041, 0x000B8, 0x00174, 0x00100, 0x014DA, 0x0404E, 0x01437, 0x0002B, 0x00085, 0x000A7, 0x000A0,
0x0014C, 0x0029A, 0x0032C, 0x02133, 0x0142A, 0x00051, 0x00284, 0x000AC, 0x00102, 0x00045, 0x00044, 0x0081B,
0x0065E, 0x00CB7, 0x00018, 0x0050C, 0x00212, 0x002E4, 0x00203, 0x00094, 0x00122, 0x0081A, 0x00655, 0x00033,
0x002BA, 0x00246, 0x00242, 0x00A6E, 0x0040C, 0x00808, 0x02134, 0x0404F, 0x00175, 0x00405, 0x00247, 0x0012A,
0x00A14, 0x002BB, 0x00191, 0x0084F, 0x01438, 0x000AF, 0x00B97, 0x00483, 0x0143B, 0x0032B, 0x00243, 0x0142B,
0x00958, 0x029BF, 0x00049, 0x00A6C, 0x014DB, 0x004AD, 0x014DE, 0x0084E, 0x01434, 0x00257, 0x02E5A, 0x00207,
0x01435, 0x01439, 0x00CB6, 0x0143A, 0x00194, 0x00654, 0x02135, 0x0537C, 0x0015C, 0x00240, 0x01012, 0x0537D,
0x00959, 0x01098, 0x01436, 0x0065F, 0x02026, 0x02137},
{0x00005, 0x00019, 0x00016, 0x00011, 0x0003E, 0x0005E, 0x000EF, 0x000E2, 0x00000, 0x00039, 0x0002B, 0x00026,
0x00028, 0x00012, 0x000C2, 0x000ED, 0x0011D, 0x0000D, 0x00031, 0x0002A, 0x00025, 0x00020, 0x0005C, 0x001ED,
0x0024D, 0x00770, 0x00006, 0x0007A, 0x00060, 0x0004F, 0x00048, 0x00039, 0x00186, 0x00213, 0x00EC6, 0x0000F,
0x00026, 0x0005F, 0x00075, 0x00070, 0x00027, 0x001DB, 0x003C6, 0x0078F, 0x0003F, 0x000A6, 0x000F0, 0x0003A,
0x00052, 0x0004E, 0x000E3, 0x001D9, 0x0030F, 0x00010, 0x001DD, 0x000A7, 0x000F7, 0x00022, 0x00092, 0x003C4,
0x002EF, 0x00762, 0x00079, 0x0008F, 0x001DA, 0x00087, 0x000E8, 0x000BA, 0x00176, 0x000EE, 0x003B0, 0x00085,
0x00119, 0x0030E, 0x00108, 0x001D2, 0x0010C, 0x00773, 0x00424, 0x00434, 0x00071, 0x005DD, 0x001C1, 0x003A7,
0x00127, 0x0008D, 0x0021B, 0x007B2, 0x001DF, 0x003D8, 0x00764, 0x00EE4, 0x003B3, 0x0074D, 0x001D8, 0x005DC,
0x0084A, 0x00499, 0x003C5, 0x01D8E, 0x00765, 0x00435, 0x00771, 0x001C2, 0x00118, 0x003BC, 0x00381, 0x00387,
0x07B33, 0x01097, 0x01096, 0x01ECD, 0x00E99, 0x00F1C, 0x00F1D, 0x00EE5, 0x0011C, 0x07B32, 0x03D98, 0x01D8F,
0x00E98, 0x00F67, 0x003BD, 0x00380, 0x00498, 0x00386},
{0x0000D, 0x00010, 0x0002E, 0x00039, 0x0000D, 0x00074, 0x000ED, 0x000B6, 0x00001, 0x00002, 0x00000, 0x00030,
0x00029, 0x00070, 0x000F3, 0x0008C, 0x00166, 0x00009, 0x00033, 0x00078, 0x00006, 0x000C4, 0x0000B, 0x00163,
0x000CC, 0x005BE, 0x0001F, 0x0002F, 0x00064, 0x00018, 0x000C6, 0x0000A, 0x00162, 0x002C0, 0x00EF3, 0x00007,
0x0000F, 0x000E3, 0x000CA, 0x000B2, 0x0018F, 0x003AE, 0x0075F, 0x00C51, 0x00015, 0x00047, 0x000EE, 0x000E2,
0x000EA, 0x00009, 0x0016A, 0x002C3, 0x0059D, 0x0003D, 0x00008, 0x001D9, 0x00032, 0x0000E, 0x0016E, 0x0032C,
0x0065B, 0x0196B, 0x00002, 0x0000F, 0x001D8, 0x0008D, 0x000B4, 0x001E4, 0x00067, 0x00317, 0x00794, 0x00022,
0x003BE, 0x00315, 0x00034, 0x00037, 0x002DE, 0x0006C, 0x00EFE, 0x0066C, 0x00028, 0x003CB, 0x003AC, 0x00035,
0x0016B, 0x003BD, 0x002C1, 0x0062C, 0x01DFE, 0x0000E, 0x0059E, 0x005BF, 0x000DA, 0x00629, 0x00584, 0x00EB7,
0x00B0A, 0x0066D, 0x0000C, 0x0077E, 0x0059C, 0x00778, 0x0075E, 0x0075A, 0x0062D, 0x00337, 0x00334, 0x00197,
0x01E57, 0x01DE4, 0x0196A, 0x01E56, 0x00C50, 0x00B3F, 0x01E54, 0x00B0B, 0x0018E, 0x001B6, 0x01E55, 0x00CB4,
0x00B3E, 0x00EB6, 0x01DE5, 0x01DFF, 0x00335, 0x001B7},
{0x00001, 0x0000B, 0x00019, 0x0006F, 0x0002A, 0x00075, 0x007EB, 0x00163, 0x00001, 0x0000E, 0x0001A, 0x0003E,
0x0001C, 0x0002D, 0x00164, 0x007EC, 0x00165, 0x00004, 0x00006, 0x00036, 0x0007F, 0x000AE, 0x00158, 0x0015C,
0x0056D, 0xFD510, 0x00000, 0x00004, 0x0007B, 0x000F3, 0x0003B, 0x007ED, 0x002B3, 0x002CC, 0x0056E, 0x00018,
0x0003E, 0x00017, 0x0001E, 0x000AF, 0x003F7, 0x0056F, 0x002CD, 0xFD511, 0x00014, 0x000AD, 0x000AA, 0x00014,
0x000A8, 0x00153, 0x000E8, 0x001FE, 0x00DCF, 0x00078, 0x001B8, 0x00152, 0x000FE, 0x002B1, 0x0015D, 0x00160,
0xFD512, 0xFD513, 0x0007A, 0x002B0, 0x001E5, 0x000E9, 0x000FC, 0x006E6, 0x00DC8, 0x00584, 0xFD514, 0x000AB,
0x00DDE, 0x00159, 0x003F4, 0x00DC9, 0x00DCA, 0x001FA, 0xFD515, 0xFD516, 0x000FC, 0x001FF, 0x001E4, 0x000AF,
0x0015A, 0x00167, 0x00DCB, 0x00585, 0xFD517, 0x003F7, 0x03F55, 0xFD518, 0x00DDC, 0x00586, 0x03F56, 0xFD519,
0x03F57, 0xFD51A, 0x001BA, 0x00587, 0x00588, 0x00DDF, 0x002B2, 0xFD51B, 0x00DCE, 0x003F6, 0xFD51C, 0x00FD4,
0xFD51D, 0xFD51E, 0xFD51F, 0x7EA80, 0x7EA81, 0x0056C, 0x7EA82, 0x7EA83, 0x00376, 0x00589, 0x0058A, 0x7EA84,
0x7EA85, 0x00DDD, 0x7EA86, 0x7EA87, 0x0058B, 0x07EA9},
{0x00003, 0x0000E, 0x0000F, 0x0007E, 0x00062, 0x000C6, 0x00CD9, 0x0063E, 0x00002, 0x00002, 0x00000, 0x00018,
0x0000C, 0x00069, 0x00039, 0x00707, 0x00C7E, 0x00002, 0x0000D, 0x0001B, 0x0000F, 0x0019A, 0x00647, 0x01A37,
0x346C4, 0x0346D, 0x00001, 0x0001E, 0x0007F, 0x0000A, 0x000E1, 0x00661, 0x00CE4, 0x346C5, 0x346C6, 0x0001D,
0x00030, 0x0000D, 0x000CB, 0x00199, 0x00320, 0x0008E, 0x0652E, 0x346C7, 0x0003E, 0x00039, 0x00035, 0x00033,
0x0019F, 0x001C0, 0x00CDA, 0x346C8, 0x346C9, 0x0000B, 0x000D0, 0x0019E, 0x00022, 0x00038, 0x0018E, 0x0031E,
0x03294, 0x0023C, 0x00032, 0x00012, 0x00013, 0x00071, 0x0019D, 0x00020, 0x00C87, 0x00CC0, 0x346CA, 0x00338,
0x00653, 0x001A2, 0x0032A, 0x00322, 0x00CE7, 0x00084, 0x0011F, 0x346CB, 0x00325, 0x00649, 0x0032B, 0x00077,
0x00648, 0x00642, 0x00C86, 0x00C8C, 0x346CC, 0x0003A, 0x019B7, 0x00043, 0x00327, 0x0008C, 0x0008D, 0x00C8D,
0x346CD, 0x346CE, 0x00337, 0x00CE5, 0x00085, 0x00326, 0x00347, 0x00CA4, 0x00C7F, 0x00D1A, 0x346CF, 0x00328,
0x1A360, 0x1A361, 0x00CD8, 0x0068C, 0x03295, 0x03296, 0x0652F, 0x066D8, 0x00331, 0x00706, 0x0023D, 0x00076,
0x00CC1, 0x00382, 0x00CE6, 0x066D9, 0x066DA, 0x066DB}};
static const uint8 vc1_2ref_mvdata_bits[8][126] = {
{4, 5, 5, 5, 6, 7, 8, 10, 2, 5, 5, 6, 6, 7, 8, 9, 10, 4, 5, 6, 6, 7, 8, 9, 10, 11,
4, 6, 6, 7, 7, 9, 9, 10, 12, 5, 8, 8, 8, 8, 9, 9, 10, 12, 5, 7, 8, 7, 7, 8, 9, 9,
11, 7, 9, 10, 9, 10, 10, 10, 10, 12, 6, 9, 9, 9, 9, 9, 10, 10, 11, 7, 10, 10, 11, 11, 11, 12,
12, 14, 8, 11, 10, 11, 11, 11, 11, 12, 12, 8, 12, 11, 11, 12, 12, 12, 12, 13, 8, 12, 11, 11, 12, 12,
12, 13, 12, 9, 14, 13, 11, 13, 12, 13, 12, 13, 9, 13, 13, 12, 12, 13, 13, 13, 13, 13},
{3, 4, 5, 6, 8, 10, 11, 11, 2, 5, 5, 6, 7, 8, 10, 11, 11, 4, 5, 5, 6, 7, 9, 12, 13, 13,
4, 6, 7, 7, 9, 10, 11, 13, 14, 5, 7, 7, 7, 8, 9, 11, 13, 13, 6, 8, 8, 8, 8, 9, 10, 12,
13, 7, 9, 8, 8, 8, 9, 11, 12, 13, 7, 9, 9, 9, 9, 9, 10, 11, 13, 8, 10, 10, 10, 10, 10, 11,
12, 13, 9, 11, 11, 10, 10, 10, 11, 11, 12, 10, 12, 12, 12, 11, 11, 11, 12, 12, 10, 13, 12, 12, 11, 11,
11, 12, 12, 10, 13, 13, 12, 13, 11, 12, 11, 12, 10, 14, 13, 13, 12, 12, 12, 11, 11, 11},
{4, 4, 5, 5, 6, 7, 8, 9, 2, 5, 6, 6, 6, 7, 7, 9, 9, 4, 6, 6, 6, 7, 8, 9, 11, 12,
5, 7, 7, 7, 9, 9, 10, 11, 12, 5, 7, 7, 7, 7, 9, 9, 10, 12, 5, 8, 8, 8, 8, 8, 9, 10,
10, 6, 9, 8, 8, 8, 8, 9, 9, 11, 6, 10, 10, 9, 9, 9, 9, 10, 10, 7, 11, 10, 9, 9, 10, 9,
10, 11, 7, 10, 11, 10, 10, 10, 9, 10, 11, 8, 12, 11, 11, 10, 11, 11, 10, 10, 8, 12, 12, 11, 11, 11,
11, 10, 11, 8, 13, 12, 12, 11, 11, 11, 11, 10, 9, 13, 12, 12, 12, 11, 11, 10, 10, 10},
{3, 4, 6, 7, 7, 9, 11, 11, 2, 5, 5, 6, 8, 9, 10, 11, 13, 3, 5, 5, 7, 8, 9, 12, 14, 13,
4, 6, 6, 7, 9, 11, 13, 14, 14, 5, 7, 7, 8, 9, 9, 13, 15, 13, 6, 8, 8, 8, 9, 10, 12, 14,
13, 7, 10, 9, 9, 9, 9, 12, 13, 14, 7, 11, 10, 10, 10, 10, 11, 12, 13, 8, 11, 12, 12, 12, 11, 12,
14, 15, 9, 11, 12, 11, 12, 11, 11, 12, 13, 9, 12, 13, 13, 12, 12, 13, 14, 14, 9, 12, 13, 13, 13, 12,
13, 12, 14, 10, 13, 13, 14, 13, 11, 13, 14, 15, 10, 12, 13, 15, 14, 13, 13, 13, 14, 14},
{4, 5, 5, 5, 6, 7, 8, 8, 2, 6, 6, 6, 6, 6, 8, 9, 10, 4, 6, 6, 6, 6, 7, 9, 10, 11,
4, 7, 7, 7, 7, 7, 9, 10, 12, 5, 7, 7, 7, 7, 7, 9, 10, 11, 6, 8, 8, 7, 7, 7, 8, 9,
10, 6, 9, 8, 8, 7, 8, 10, 10, 11, 7, 9, 9, 8, 8, 8, 9, 9, 10, 8, 10, 10, 9, 9, 9, 11,
11, 11, 8, 11, 10, 10, 9, 9, 10, 11, 10, 10, 12, 12, 11, 11, 10, 11, 12, 11, 10, 13, 12, 11, 11, 10,
10, 11, 11, 11, 15, 13, 13, 13, 12, 12, 12, 12, 10, 15, 14, 13, 12, 12, 11, 11, 11, 11},
{4, 5, 6, 6, 6, 7, 8, 8, 2, 4, 5, 6, 6, 7, 8, 8, 9, 4, 6, 7, 7, 8, 8, 9, 10, 11,
5, 6, 7, 7, 8, 8, 9, 10, 12, 5, 7, 8, 8, 8, 9, 10, 11, 12, 5, 7, 8, 8, 8, 8, 9, 10,
11, 6, 8, 9, 8, 8, 9, 10, 11, 13, 5, 8, 9, 8, 8, 9, 9, 10, 11, 6, 10, 10, 9, 9, 10, 10,
12, 13, 6, 10, 10, 9, 9, 10, 10, 11, 13, 7, 11, 11, 11, 11, 11, 12, 12, 13, 7, 11, 11, 11, 11, 11,
11, 12, 12, 9, 13, 13, 13, 13, 12, 12, 13, 12, 9, 12, 13, 12, 12, 12, 13, 13, 12, 12},
{3, 5, 6, 8, 9, 10, 12, 12, 1, 5, 6, 7, 8, 9, 12, 12, 12, 4, 6, 7, 8, 9, 12, 12, 14, 21,
4, 6, 8, 9, 9, 12, 13, 13, 14, 6, 9, 8, 8, 9, 13, 14, 13, 21, 6, 9, 9, 8, 9, 10, 11, 12,
13, 8, 10, 10, 11, 11, 12, 12, 21, 21, 8, 11, 10, 11, 11, 12, 13, 14, 21, 9, 13, 10, 11, 13, 13, 12,
21, 21, 9, 12, 10, 11, 12, 12, 13, 14, 21, 11, 15, 21, 13, 14, 15, 21, 15, 21, 10, 14, 14, 13, 13, 21,
13, 13, 21, 13, 21, 21, 21, 20, 20, 14, 20, 20, 11, 14, 14, 20, 20, 13, 20, 20, 14, 16},
{2, 5, 6, 8, 9, 10, 13, 13, 2, 4, 5, 6, 8, 9, 10, 13, 14, 3, 5, 7, 8, 10, 12, 15, 20, 16,
4, 6, 8, 8, 10, 12, 13, 20, 20, 7, 8, 8, 9, 10, 11, 12, 16, 20, 7, 8, 8, 8, 10, 11, 13, 20,
20, 8, 10, 10, 10, 10, 11, 12, 15, 14, 8, 9, 9, 9, 10, 10, 13, 13, 20, 11, 12, 11, 11, 11, 13, 12,
13, 20, 11, 12, 11, 11, 12, 12, 13, 13, 20, 10, 14, 11, 11, 12, 12, 13, 20, 20, 11, 13, 12, 11, 12, 13,
14, 14, 20, 11, 19, 19, 13, 13, 15, 15, 16, 16, 11, 13, 14, 11, 13, 12, 13, 16, 16, 16}};
/* P-Picture CBPCY VLC tables */
// Looks like original tables are not conforming to standard at all. Are they used for old WMV?
static const uint16 vc1_cbpcy_p_codes[4][64] = {
{0, 6, 15, 13, 13, 11, 3, 13, 5, 8, 49, 10, 12, 114, 102, 119, 1, 54, 96, 8, 10, 111,
5, 15, 12, 10, 2, 12, 13, 115, 53, 63, 1, 7, 1, 7, 14, 12, 4, 14, 1, 9, 97, 11,
7, 58, 52, 62, 4, 103, 1, 9, 11, 56, 101, 118, 4, 110, 100, 30, 2, 5, 4, 3},
{0, 9, 1, 18, 5, 14, 237, 26, 3, 121, 3, 22, 13, 16, 6, 30, 2, 10, 1, 20, 12, 241,
5, 28, 16, 12, 3, 24, 28, 124, 239, 247, 1, 240, 1, 19, 18, 15, 4, 27, 1, 122, 2, 23,
1, 17, 7, 31, 1, 11, 2, 21, 19, 246, 238, 29, 17, 13, 236, 25, 58, 63, 8, 125},
{0, 201, 25, 231, 5, 221, 1, 3, 2, 414, 2, 241, 16, 225, 195, 492, 2, 412, 1, 240, 7, 224,
98, 245, 1, 220, 96, 5, 9, 230, 101, 247, 1, 102, 1, 415, 24, 3, 2, 244, 3, 54, 3, 484,
17, 114, 200, 493, 3, 413, 1, 4, 13, 113, 99, 485, 4, 111, 194, 243, 5, 29, 26, 31},
{0, 28, 12, 44, 3, 36, 20, 52, 2, 32, 16, 48, 8, 40, 24, 28, 1, 30, 14, 46, 6, 38,
22, 54, 3, 34, 18, 50, 10, 42, 26, 30, 1, 29, 13, 45, 5, 37, 21, 53, 2, 33, 17, 49,
9, 41, 25, 29, 1, 31, 15, 47, 7, 39, 23, 55, 4, 35, 19, 51, 11, 43, 27, 31}};
static const uint8 vc1_cbpcy_p_bits[4][64] = {
{13, 13, 7, 13, 7, 13, 13, 12, 6, 13, 7, 12, 6, 8, 8, 8, 5, 7, 8, 12, 6, 8, 13, 12, 7, 13, 13, 12, 6, 8, 7, 7,
6, 13, 8, 12, 7, 13, 13, 12, 7, 13, 8, 12, 5, 7, 7, 7, 6, 8, 13, 12, 6, 7, 8, 8, 5, 8, 8, 6, 3, 3, 3, 2},
{14, 13, 8, 13, 3, 13, 8, 13, 3, 7, 8, 13, 4, 13, 13, 13, 3, 13, 13, 13, 4, 8,
13, 13, 5, 13, 13, 13, 5, 7, 8, 8, 3, 8, 14, 13, 5, 13, 13, 13, 4, 7, 13, 13,
6, 13, 13, 13, 5, 13, 8, 13, 5, 8, 8, 13, 5, 13, 8, 13, 6, 6, 13, 7},
{13, 8, 6, 8, 4, 8, 13, 12, 4, 9, 8, 8, 5, 8, 8, 9, 5, 9, 10, 8, 4, 8, 7, 8, 6, 8, 7, 13, 4, 8, 7, 8,
5, 7, 8, 9, 6, 13, 13, 8, 4, 6, 8, 9, 5, 7, 8, 9, 5, 9, 9, 13, 5, 7, 7, 9, 4, 7, 8, 8, 3, 5, 5, 5},
{9, 9, 9, 9, 2, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 8, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8,
2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8}};
/* Interlaced CBPCY VLC tables (Table 124 - Table 131) */
static const uint16 vc1_icbpcy_p_codes[8][63] = {
{0x2F1A, 0x2F1B, 0x178C, 0x0090, 0x02A8, 0x02A9, 0x0BC7, 0x0091, 0x02AA, 0x02AB, 0x05E0, 0x004A, 0x0096,
0x0097, 0x00BD, 0x0092, 0x02AC, 0x02AD, 0x05E1, 0x0098, 0x0132, 0x0133, 0x0179, 0x0134, 0x026A, 0x026B,
0x02FC, 0x004E, 0x0040, 0x0041, 0x002B, 0x0093, 0x02AE, 0x02AF, 0x05E2, 0x0136, 0x026E, 0x026F, 0x02FD,
0x009E, 0x013E, 0x013F, 0x017F, 0x0050, 0x0042, 0x0043, 0x002C, 0x0051, 0x00A4, 0x00A5, 0x00BE, 0x0053,
0x0044, 0x0045, 0x002D, 0x0054, 0x0046, 0x0047, 0x002E, 0x0003, 0x0000, 0x0001, 0x0001},
{0x0041, 0x0042, 0x0100, 0x0043, 0x0088, 0x0089, 0x0101, 0x0045, 0x008C, 0x008D, 0x0102, 0x0010, 0x0022,
0x0023, 0x0024, 0x0047, 0x0010, 0x0011, 0x0103, 0x0025, 0x0058, 0x0059, 0x005A, 0x005B, 0x005A, 0x005B,
0x005C, 0x000C, 0x0030, 0x0031, 0x0019, 0x0009, 0x0014, 0x0015, 0x002C, 0x005C, 0x005D, 0x005E, 0x005F,
0x0026, 0x005D, 0x005E, 0x005F, 0x000D, 0x0034, 0x0035, 0x001B, 0x0014, 0x0027, 0x002A, 0x002B, 0x000E,
0x0038, 0x0039, 0x001D, 0x000F, 0x003C, 0x003D, 0x001F, 0x0005, 0x0009, 0x0000, 0x0003},
{0x0032, 0x0033, 0x001A, 0x0026, 0x00E4, 0x00E5, 0x01E6, 0x0027, 0x00E6, 0x00E7, 0x01E7, 0x000E, 0x0063,
0x006C, 0x0077, 0x0028, 0x00E8, 0x00E9, 0x01E8, 0x007B, 0x00DA, 0x00DB, 0x00EC, 0x00F5, 0x01B8, 0x01B9,
0x01DA, 0x0021, 0x004B, 0x0054, 0x002B, 0x0029, 0x00EA, 0x00EB, 0x01E9, 0x004A, 0x01BA, 0x01BB, 0x01DB,
0x0020, 0x00DE, 0x00DF, 0x00F2, 0x0022, 0x0055, 0x0058, 0x002D, 0x000F, 0x0070, 0x0071, 0x0078, 0x0023,
0x0059, 0x005C, 0x002F, 0x0024, 0x005D, 0x0062, 0x0030, 0x0002, 0x001F, 0x0006, 0x0000},
{0x0028, 0x0029, 0x009D, 0x0000, 0x01EA, 0x01EB, 0x01EC, 0x0001, 0x01ED, 0x01EE, 0x01EF, 0x0005, 0x00F0,
0x00F1, 0x003B, 0x0002, 0x01F0, 0x01F1, 0x01F2, 0x003F, 0x015C, 0x015D, 0x0099, 0x0010, 0x03D0, 0x03D1,
0x0130, 0x000F, 0x009E, 0x009F, 0x00FB, 0x0003, 0x01F3, 0x01F4, 0x01F5, 0x0011, 0x03D2, 0x03D3, 0x0131,
0x0009, 0x015E, 0x015F, 0x009C, 0x0010, 0x00A8, 0x00A9, 0x0038, 0x0006, 0x00F2, 0x00F3, 0x004D, 0x0011,
0x00AA, 0x00AB, 0x0039, 0x0012, 0x00AC, 0x00AD, 0x003A, 0x0006, 0x0016, 0x0017, 0x000E},
{0x003C, 0x003D, 0x001F, 0x000A, 0x0061, 0x0062, 0x0002, 0x000B, 0x0063, 0x0064, 0x0003, 0x0007, 0x0003,
0x0004, 0x000B, 0x000C, 0x0065, 0x0066, 0x0004, 0x0012, 0x000A, 0x000B, 0x0014, 0x001B, 0x0018, 0x0019,
0x0034, 0x002C, 0x0067, 0x0068, 0x0035, 0x000D, 0x0069, 0x006C, 0x0005, 0x0060, 0x001A, 0x001B, 0x0035,
0x0013, 0x000E, 0x000F, 0x0015, 0x002D, 0x006D, 0x006E, 0x0038, 0x0008, 0x0008, 0x0009, 0x000C, 0x002E,
0x006F, 0x0072, 0x003A, 0x002F, 0x0073, 0x0000, 0x003B, 0x0007, 0x0014, 0x0015, 0x0004},
{0x0038, 0x0039, 0x009D, 0x000A, 0x0091, 0x0092, 0x0093, 0x000B, 0x0094, 0x0095, 0x0096, 0x0003, 0x00EE,
0x00EF, 0x0036, 0x000C, 0x0097, 0x0098, 0x0099, 0x0008, 0x01E4, 0x01E5, 0x006A, 0x0018, 0x03CC, 0x03CD,
0x00D6, 0x000E, 0x009E, 0x009F, 0x00F5, 0x000D, 0x009A, 0x009B, 0x009C, 0x0019, 0x03CE, 0x03CF, 0x00D7,
0x0009, 0x01E8, 0x01E9, 0x0090, 0x000F, 0x00E8, 0x00E9, 0x00F6, 0x0005, 0x00F0, 0x00F1, 0x0037, 0x0010,
0x00EA, 0x00EB, 0x00F7, 0x0011, 0x00EC, 0x00ED, 0x0034, 0x0000, 0x003E, 0x003F, 0x0002},
{0x003C, 0x003D, 0x01CF, 0x0000, 0x00BF, 0x00E0, 0x01FC, 0x0001, 0x00E1, 0x00E2, 0x01FD, 0x0009, 0x01F1,
0x01F2, 0x01F3, 0x0002, 0x00E3, 0x00E4, 0x01FE, 0x0011, 0x03EE, 0x03EF, 0x03F0, 0x0021, 0x07E2, 0x07E3,
0x07E4, 0x0018, 0x03F7, 0x03FE, 0x03FF, 0x0003, 0x00E5, 0x00E6, 0x0080, 0x002E, 0x07E5, 0x07E6, 0x07E7,
0x0016, 0x03F4, 0x03F5, 0x03F6, 0x0019, 0x0102, 0x0103, 0x0104, 0x000A, 0x01F4, 0x01F5, 0x01F6, 0x001A,
0x0105, 0x0106, 0x0107, 0x001B, 0x0178, 0x0179, 0x01CE, 0x001D, 0x00BD, 0x00BE, 0x01F0},
{0x0003, 0x0004, 0x01B6, 0x0004, 0x002E, 0x002F, 0x000E, 0x0005, 0x0030, 0x0031, 0x000F, 0x0003, 0x000A,
0x000B, 0x0014, 0x0006, 0x0032, 0x0033, 0x0010, 0x0005, 0x0030, 0x0031, 0x0032, 0x0009, 0x0066, 0x0067,
0x0068, 0x001D, 0x01B7, 0x01B8, 0x01B9, 0x0007, 0x0034, 0x0035, 0x0011, 0x0016, 0x0069, 0x006A, 0x006B,
0x000A, 0x0036, 0x0037, 0x00D8, 0x001E, 0x01BA, 0x01BB, 0x01BC, 0x0004, 0x0015, 0x0016, 0x0017, 0x001F,
0x01BD, 0x01BE, 0x01BF, 0x0000, 0x0010, 0x0011, 0x0012, 0x001C, 0x00D9, 0x00DA, 0x0013}};
static const uint8 vc1_icbpcy_p_bits[8][63] = {
{15, 15, 14, 9, 11, 11, 13, 9, 11, 11, 12, 8, 9, 9, 9, 9, 11, 11, 12, 9, 10, 10, 10, 10, 11, 11, 11, 8, 8, 8, 7, 9,
11, 11, 12, 10, 11, 11, 11, 9, 10, 10, 10, 8, 8, 8, 7, 8, 9, 9, 9, 8, 8, 8, 7, 8, 8, 8, 7, 3, 3, 3, 1},
{7, 7, 9, 7, 8, 8, 9, 7, 8, 8, 9, 6, 7, 7, 7, 7, 7, 7, 9, 7, 8, 8, 8, 8, 9, 9, 9, 6, 7, 7, 6, 6,
7, 7, 8, 8, 9, 9, 9, 7, 8, 8, 8, 6, 7, 7, 6, 6, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 6, 3, 4, 3, 2},
{6, 6, 5, 6, 8, 8, 9, 6, 8, 8, 9, 5, 7, 7, 7, 6, 8, 8, 9, 7, 8, 8, 8, 8, 9, 9, 9, 6, 7, 7, 6, 6,
8, 8, 9, 7, 9, 9, 9, 6, 8, 8, 8, 6, 7, 7, 6, 5, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 6, 3, 5, 4, 2},
{6, 6, 8, 4, 9, 9, 9, 4, 9, 9, 9, 4, 8, 8, 7, 4, 9, 9, 9, 6, 9, 9, 8, 6, 10, 10, 9, 5, 8, 8, 8, 4,
9, 9, 9, 6, 10, 10, 9, 5, 9, 9, 8, 5, 8, 8, 7, 4, 8, 8, 7, 5, 8, 8, 7, 5, 8, 8, 7, 3, 5, 5, 4},
{6, 6, 5, 5, 7, 7, 7, 5, 7, 7, 7, 5, 6, 6, 6, 5, 7, 7, 7, 6, 7, 7, 7, 7, 8, 8, 8, 6, 7, 7, 6, 5,
7, 7, 7, 7, 8, 8, 8, 6, 7, 7, 7, 6, 7, 7, 6, 5, 6, 6, 6, 6, 7, 7, 6, 6, 7, 6, 6, 4, 5, 5, 3},
{6, 6, 8, 4, 8, 8, 8, 4, 8, 8, 8, 4, 8, 8, 7, 4, 8, 8, 8, 5, 9, 9, 8, 6, 10, 10, 9, 5, 8, 8, 8, 4,
8, 8, 8, 6, 10, 10, 9, 5, 9, 9, 8, 5, 8, 8, 8, 4, 8, 8, 7, 5, 8, 8, 8, 5, 8, 8, 7, 3, 6, 6, 4},
{6, 6, 9, 3, 8, 8, 9, 3, 8, 8, 9, 4, 9, 9, 9, 3, 8, 8, 9, 5, 10, 10, 10, 6, 11, 11, 11, 5, 10, 10, 10, 3,
8, 8, 8, 6, 11, 11, 11, 5, 10, 10, 10, 5, 9, 9, 9, 4, 9, 9, 9, 5, 9, 9, 9, 5, 9, 9, 9, 5, 8, 8, 9},
{6, 6, 10, 3, 7, 7, 7, 3, 7, 7, 7, 4, 8, 8, 8, 3, 7, 7, 7, 5, 9, 9, 9, 6, 10, 10, 10, 6, 10, 10, 10, 3,
7, 7, 7, 6, 10, 10, 10, 5, 9, 9, 9, 6, 10, 10, 10, 4, 8, 8, 8, 6, 10, 10, 10, 5, 9, 9, 9, 6, 9, 9, 9}};
/* MacroBlock Transform Type: 7.1.3.11, p89
* 8x8:B
* 8x4:B:btm 8x4:B:top 8x4:B:both,
* 4x8:B:right 4x8:B:left 4x8:B:both
* 4x4:B 8x8:MB
* 8x4:MB:btm 8x4:MB:top 8x4,MB,both
* 4x8,MB,right 4x8,MB,left
* 4x4,MB */
static const uint16 vc1_ttmb_codes[3][16] = {{0x0003, 0x002E, 0x005F, 0x0000, 0x0016, 0x0015, 0x0001, 0x0004, 0x0014,
0x02F1, 0x0179, 0x017B, 0x0BC0, 0x0BC1, 0x05E1, 0x017A},
{0x0006, 0x0006, 0x0003, 0x0007, 0x000F, 0x000E, 0x0000, 0x0002, 0x0002,
0x0014, 0x0011, 0x000B, 0x0009, 0x0021, 0x0015, 0x0020},
{0x0006, 0x0000, 0x000E, 0x0005, 0x0002, 0x0003, 0x0003, 0x000F, 0x0002,
0x0081, 0x0021, 0x0009, 0x0101, 0x0041, 0x0011, 0x0100}};
static const uint8 vc1_ttmb_bits[3][16] = {{2, 6, 7, 2, 5, 5, 2, 3, 5, 10, 9, 9, 12, 12, 11, 9},
{3, 4, 4, 4, 4, 4, 3, 3, 2, 7, 7, 6, 6, 8, 7, 8},
{3, 3, 4, 5, 3, 3, 4, 4, 2, 10, 8, 6, 11, 9, 7, 11}};
/* TTBLK (Transform Type per Block) tables */
static const uint8 vc1_ttblk_codes[3][8] = {
{0, 1, 3, 5, 16, 17, 18, 19}, {3, 0, 1, 2, 3, 5, 8, 9}, {1, 0, 1, 4, 6, 7, 10, 11}};
static const uint8 vc1_ttblk_bits[3][8] = {
{2, 2, 2, 3, 5, 5, 5, 5}, {2, 3, 3, 3, 3, 3, 4, 4}, {2, 3, 3, 3, 3, 3, 4, 4}};
/* SUBBLKPAT tables, p93-94, reordered */
static const uint8 vc1_subblkpat_codes[3][15] = {{14, 12, 7, 11, 9, 26, 2, 10, 27, 8, 0, 6, 1, 15, 1},
{14, 0, 8, 15, 10, 4, 23, 13, 5, 9, 25, 3, 24, 22, 1},
{5, 6, 2, 2, 8, 0, 28, 3, 1, 3, 29, 1, 19, 18, 15}};
static const uint8 vc1_subblkpat_bits[3][15] = {{5, 5, 5, 5, 5, 6, 4, 5, 6, 5, 4, 5, 4, 5, 1},
{4, 3, 4, 4, 4, 5, 5, 4, 5, 4, 5, 4, 5, 5, 2},
{3, 3, 4, 3, 4, 5, 5, 3, 5, 4, 5, 4, 5, 5, 4}};
/* MV differential tables, p265 */
static const uint16 vc1_mv_diff_codes[4][73] =
{
{
0, 2, 3, 8, 576, 3, 2, 6, 5, 577, 578, 7, 8, 9, 40, 19, 37, 82, 21,
22, 23, 579, 580, 166, 96, 167, 49, 194, 195, 581, 582, 583, 292, 293, 294, 13, 2, 7,
24, 50, 102, 295, 13, 7, 8, 18, 50, 103, 38, 20, 21, 22, 39, 204, 103, 23, 24,
25, 104, 410, 105, 106, 107, 108, 109, 220, 411, 442, 222, 443, 446, 447, 7 /* 73 elements */
},
{
0, 4, 5, 3, 4, 3, 4, 5, 20, 6, 21, 44, 45, 46, 3008,
95, 112, 113, 57, 3009, 3010, 116, 117, 3011, 118, 3012, 3013, 3014, 3015, 3016,
3017, 3018, 3019, 3020, 3021, 3022, 1, 4, 15, 160, 161, 41, 6, 11, 42,
162, 43, 119, 56, 57, 58, 163, 236, 237, 3023, 119, 120, 242, 122, 486,
1512, 487, 246, 494, 1513, 495, 1514, 1515, 1516, 1517, 1518, 1519, 31 /* 73 elements */
},
{
0, 512, 513, 514, 515, 2, 3, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269,
270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 1, 5,
287, 288, 289, 290, 6, 7, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303,
304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319 /* 73 elements */
},
{
0, 1, 1, 2, 3, 4, 1, 5, 4, 3, 5, 8, 6, 9, 10, 11, 12, 7, 104,
14, 105, 4, 10, 15, 11, 6, 14, 8, 106, 107, 108, 15, 109, 9, 55, 10, 1, 2,
1, 2, 3, 12, 6, 2, 6, 7, 28, 7, 15, 8, 5, 18, 29, 152, 77, 24, 25,
26, 39, 108, 13, 109, 55, 56, 57, 116, 11, 153, 234, 235, 118, 119, 15 /* 73 elements */
}};
static const uint8 vc1_mv_diff_bits[4][73] = {
{
6, 7, 7, 8, 14, 6, 5, 6, 7, 14, 14, 6, 6, 6, 8, 9, 10, 9, 7, 7, 7, 14, 14, 10, 9,
10, 8, 10, 10, 14, 14, 14, 13, 13, 13, 6, 3, 5, 6, 8, 9, 13, 5, 4, 4, 5, 7, 9, 6, 5,
5, 5, 6, 9, 8, 5, 5, 5, 7, 10, 7, 7, 7, 7, 7, 8, 10, 9, 8, 9, 9, 9, 3 /* 73 elements */
},
{
5, 7, 7, 6, 6, 5, 5, 6, 7, 5, 7, 8, 8, 8, 14, 9, 9, 9, 8, 14, 14, 9, 9, 14, 9,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 3, 6, 8, 8, 6, 3, 4, 6, 8, 6, 9, 6, 6,
6, 8, 8, 8, 14, 7, 7, 8, 7, 9, 13, 9, 8, 9, 13, 9, 13, 13, 13, 13, 13, 13, 5 /* 73 elements */
},
{
3, 12, 12, 12, 12, 3, 4, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 1, 5, 11, 11, 11, 11, 4, 4, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 /* 73 elements */
},
{
15, 11, 15, 15, 15, 15, 12, 15, 12, 11, 12, 12, 15, 12, 12, 12, 12, 15, 15, 12, 15, 10, 11, 12, 11,
10, 11, 10, 15, 15, 15, 11, 15, 10, 14, 10, 4, 4, 5, 7, 8, 9, 5, 3, 4, 5, 6, 8, 5, 4,
3, 5, 6, 8, 7, 5, 5, 5, 6, 7, 9, 7, 6, 6, 6, 7, 10, 8, 8, 8, 7, 7, 4 /* 73 elements */
}};
static const uint32 vc1_ac_tables[AC_MODES][186][2] = {
{{0x0001, 2}, {0x0005, 3}, {0x000D, 4}, {0x0012, 5}, {0x000E, 6}, {0x0015, 7}, {0x0013, 8}, {0x003F, 8},
{0x004B, 9}, {0x011F, 9}, {0x00B8, 10}, {0x03E3, 10}, {0x0172, 11}, {0x024D, 12}, {0x03DA, 12}, {0x02DD, 13},
{0x1F55, 13}, {0x05B9, 14}, {0x3EAE, 14}, {0x0000, 4}, {0x0010, 5}, {0x0008, 7}, {0x0020, 8}, {0x0029, 9},
{0x01F4, 9}, {0x0233, 10}, {0x01E0, 11}, {0x012A, 12}, {0x03DD, 12}, {0x050A, 13}, {0x1F29, 13}, {0x0A42, 14},
{0x1272, 15}, {0x1737, 15}, {0x0003, 5}, {0x0011, 7}, {0x00C4, 8}, {0x004B, 10}, {0x00B4, 11}, {0x07D4, 11},
{0x0345, 12}, {0x02D7, 13}, {0x07BF, 13}, {0x0938, 14}, {0x0BBB, 14}, {0x095E, 15}, {0x0013, 5}, {0x0078, 7},
{0x0069, 9}, {0x0232, 10}, {0x0461, 11}, {0x03EC, 12}, {0x0520, 13}, {0x1F2A, 13}, {0x3E50, 14}, {0x3E51, 14},
{0x1486, 15}, {0x000C, 6}, {0x0024, 9}, {0x0094, 11}, {0x08C0, 12}, {0x0F09, 14}, {0x1EF0, 15}, {0x003D, 6},
{0x0053, 9}, {0x01A0, 11}, {0x02D6, 13}, {0x0F08, 14}, {0x0013, 7}, {0x007C, 9}, {0x07C1, 11}, {0x04AC, 14},
{0x001B, 7}, {0x00A0, 10}, {0x0344, 12}, {0x0F79, 14}, {0x0079, 7}, {0x03E1, 10}, {0x02D4, 13}, {0x2306, 14},
{0x0021, 8}, {0x023C, 10}, {0x0FAE, 12}, {0x23DE, 14}, {0x0035, 8}, {0x0175, 11}, {0x07B3, 13}, {0x00C5, 8},
{0x0174, 11}, {0x0785, 13}, {0x0048, 9}, {0x01A3, 11}, {0x049E, 13}, {0x002C, 9}, {0x00FA, 10}, {0x07D6, 11},
{0x0092, 10}, {0x05CC, 13}, {0x1EF1, 15}, {0x00A3, 10}, {0x03ED, 12}, {0x093E, 14}, {0x01E2, 11}, {0x1273, 15},
{0x07C4, 11}, {0x1487, 15}, {0x0291, 12}, {0x0293, 12}, {0x0F8A, 12}, {0x0509, 13}, {0x0508, 13}, {0x078D, 13},
{0x07BE, 13}, {0x078C, 13}, {0x04AE, 14}, {0x0BBA, 14}, {0x2307, 14}, {0x0B9A, 14}, {0x1736, 15}, {0x000E, 4},
{0x0045, 7}, {0x01F3, 9}, {0x047A, 11}, {0x05DC, 13}, {0x23DF, 14}, {0x0019, 5}, {0x0028, 9}, {0x0176, 11},
{0x049D, 13}, {0x23DD, 14}, {0x0030, 6}, {0x00A2, 10}, {0x02EF, 12}, {0x05B8, 14}, {0x003F, 6}, {0x00A5, 10},
{0x03DB, 12}, {0x093F, 14}, {0x0044, 7}, {0x07CB, 11}, {0x095F, 15}, {0x0063, 7}, {0x03C3, 12}, {0x0015, 8},
{0x08F6, 12}, {0x0017, 8}, {0x0498, 13}, {0x002C, 8}, {0x07B2, 13}, {0x002F, 8}, {0x1F54, 13}, {0x008D, 8},
{0x07BD, 13}, {0x008E, 8}, {0x1182, 13}, {0x00FB, 8}, {0x050B, 13}, {0x002D, 8}, {0x07C0, 11}, {0x0079, 9},
{0x1F5F, 13}, {0x007A, 9}, {0x1F56, 13}, {0x0231, 10}, {0x03E4, 10}, {0x01A1, 11}, {0x0143, 11}, {0x01F7, 11},
{0x016F, 12}, {0x0292, 12}, {0x02E7, 12}, {0x016C, 12}, {0x016D, 12}, {0x03DC, 12}, {0x0F8B, 12}, {0x0499, 13},
{0x03D8, 12}, {0x078E, 13}, {0x02D5, 13}, {0x1F5E, 13}, {0x1F2B, 13}, {0x078F, 13}, {0x04AD, 14}, {0x3EAF, 14},
{0x23DC, 14}, {0x004A, 9}},
{{0x0000, 3}, {0x0003, 4}, {0x000B, 5}, {0x0014, 6}, {0x003F, 6}, {0x005D, 7}, {0x00A2, 8}, {0x00AC, 9},
{0x016E, 9}, {0x020A, 10}, {0x02E2, 10}, {0x0432, 11}, {0x05C9, 11}, {0x0827, 12}, {0x0B54, 12}, {0x04E6, 13},
{0x105F, 13}, {0x172A, 13}, {0x20B2, 14}, {0x2D4E, 14}, {0x39F0, 14}, {0x4175, 15}, {0x5A9E, 15}, {0x0004, 4},
{0x001E, 5}, {0x0042, 7}, {0x00B6, 8}, {0x0173, 9}, {0x0395, 10}, {0x072E, 11}, {0x0B94, 12}, {0x16A4, 13},
{0x20B3, 14}, {0x2E45, 14}, {0x0005, 5}, {0x0040, 7}, {0x0049, 9}, {0x028F, 10}, {0x05CB, 11}, {0x048A, 13},
{0x09DD, 14}, {0x73E2, 15}, {0x0018, 5}, {0x0025, 8}, {0x008A, 10}, {0x051B, 11}, {0x0E5F, 12}, {0x09C9, 14},
{0x139C, 15}, {0x0029, 6}, {0x004F, 9}, {0x0412, 11}, {0x048D, 13}, {0x2E41, 14}, {0x0038, 6}, {0x010E, 9},
{0x05A8, 11}, {0x105C, 13}, {0x39F2, 14}, {0x0058, 7}, {0x021F, 10}, {0x0E7E, 12}, {0x39FF, 14}, {0x0023, 8},
{0x02E3, 10}, {0x04E5, 13}, {0x2E40, 14}, {0x00A1, 8}, {0x05BE, 11}, {0x09C8, 14}, {0x0083, 8}, {0x013A, 11},
{0x1721, 13}, {0x0044, 9}, {0x0276, 12}, {0x39F6, 14}, {0x008B, 10}, {0x04EF, 13}, {0x5A9B, 15}, {0x0208, 10},
{0x1CFE, 13}, {0x0399, 10}, {0x1CB4, 13}, {0x039E, 10}, {0x39F3, 14}, {0x05AB, 11}, {0x73E3, 15}, {0x0737, 11},
{0x5A9F, 15}, {0x082D, 12}, {0x0E69, 12}, {0x0E68, 12}, {0x0433, 11}, {0x0B7B, 12}, {0x2DF8, 14}, {0x2E56, 14},
{0x2E57, 14}, {0x39F7, 14}, {0x51A5, 15}, {0x0003, 3}, {0x002A, 6}, {0x00E4, 8}, {0x028E, 10}, {0x0735, 11},
{0x1058, 13}, {0x1CFA, 13}, {0x2DF9, 14}, {0x4174, 15}, {0x0009, 4}, {0x0054, 8}, {0x0398, 10}, {0x048B, 13},
{0x139D, 15}, {0x000D, 4}, {0x00AD, 9}, {0x0826, 12}, {0x2D4C, 14}, {0x0011, 5}, {0x016B, 9}, {0x0B7F, 12},
{0x51A4, 15}, {0x0019, 5}, {0x021B, 10}, {0x16FD, 13}, {0x001D, 5}, {0x0394, 10}, {0x28D3, 14}, {0x002B, 6},
{0x05BC, 11}, {0x5A9A, 15}, {0x002F, 6}, {0x0247, 12}, {0x0010, 7}, {0x0A35, 12}, {0x003E, 6}, {0x0B7A, 12},
{0x0059, 7}, {0x105E, 13}, {0x0026, 8}, {0x09CF, 14}, {0x0055, 8}, {0x1CB5, 13}, {0x0057, 8}, {0x0E5B, 12},
{0x00A0, 8}, {0x1468, 13}, {0x0170, 9}, {0x0090, 10}, {0x01CE, 9}, {0x021A, 10}, {0x0218, 10}, {0x0168, 9},
{0x021E, 10}, {0x0244, 12}, {0x0736, 11}, {0x0138, 11}, {0x0519, 11}, {0x0E5E, 12}, {0x072C, 11}, {0x0B55, 12},
{0x09DC, 14}, {0x20BB, 14}, {0x048C, 13}, {0x1723, 13}, {0x2E44, 14}, {0x16A5, 13}, {0x0518, 11}, {0x39FE, 14},
{0x0169, 9}},
{{0x0001, 2}, {0x0006, 3}, {0x000F, 4}, {0x0016, 5}, {0x0020, 6}, {0x0018, 7}, {0x0008, 8}, {0x009A, 8},
{0x0056, 9}, {0x013E, 9}, {0x00F0, 10}, {0x03A5, 10}, {0x0077, 11}, {0x01EF, 11}, {0x009A, 12}, {0x005D, 13},
{0x0001, 4}, {0x0011, 5}, {0x0002, 7}, {0x000B, 8}, {0x0012, 9}, {0x01D6, 9}, {0x027E, 10}, {0x0191, 11},
{0x00EA, 12}, {0x03DC, 12}, {0x013B, 13}, {0x0004, 5}, {0x0014, 7}, {0x009E, 8}, {0x0009, 10}, {0x01AC, 11},
{0x01E2, 11}, {0x03CA, 12}, {0x005F, 13}, {0x0017, 5}, {0x004E, 7}, {0x005E, 9}, {0x00F3, 10}, {0x01AD, 11},
{0x00EC, 12}, {0x05F0, 13}, {0x000E, 6}, {0x00E1, 8}, {0x03A4, 10}, {0x009C, 12}, {0x013D, 13}, {0x003B, 6},
{0x001C, 9}, {0x0014, 11}, {0x09BE, 12}, {0x0006, 7}, {0x007A, 9}, {0x0190, 11}, {0x0137, 13}, {0x001B, 7},
{0x0008, 10}, {0x075C, 11}, {0x0071, 7}, {0x00D7, 10}, {0x09BF, 12}, {0x0007, 8}, {0x00AF, 10}, {0x04CC, 11},
{0x0034, 8}, {0x0265, 10}, {0x009F, 12}, {0x00E0, 8}, {0x0016, 11}, {0x0327, 12}, {0x0015, 9}, {0x017D, 11},
{0x0EBB, 12}, {0x0014, 9}, {0x00F6, 10}, {0x01E4, 11}, {0x00CB, 10}, {0x099D, 12}, {0x00CA, 10}, {0x02FC, 12},
{0x017F, 11}, {0x04CD, 11}, {0x02FD, 12}, {0x04FE, 11}, {0x013A, 13}, {0x000A, 4}, {0x0042, 7}, {0x01D3, 9},
{0x04DD, 11}, {0x0012, 5}, {0x00E8, 8}, {0x004C, 11}, {0x0136, 13}, {0x0039, 6}, {0x0264, 10}, {0x0EBA, 12},
{0x0000, 7}, {0x00AE, 10}, {0x099C, 12}, {0x001F, 7}, {0x04DE, 11}, {0x0043, 7}, {0x04DC, 11}, {0x0003, 8},
{0x03CB, 12}, {0x0006, 8}, {0x099E, 12}, {0x002A, 8}, {0x05F1, 13}, {0x000F, 8}, {0x09FE, 12}, {0x0033, 8},
{0x09FF, 12}, {0x0098, 8}, {0x099F, 12}, {0x00EA, 8}, {0x013C, 13}, {0x002E, 8}, {0x0192, 11}, {0x0136, 9},
{0x006A, 9}, {0x0015, 11}, {0x03AF, 10}, {0x01E3, 11}, {0x0074, 11}, {0x00EB, 12}, {0x02F9, 12}, {0x005C, 13},
{0x00ED, 12}, {0x03DD, 12}, {0x0326, 12}, {0x005E, 13}, {0x0016, 7}},
{{0x0004, 3}, {0x0014, 5}, {0x0017, 7}, {0x007F, 8}, {0x0154, 9}, {0x01F2, 10}, {0x00BF, 11}, {0x0065, 12},
{0x0AAA, 12}, {0x0630, 13}, {0x1597, 13}, {0x03B7, 14}, {0x2B22, 14}, {0x0BE6, 15}, {0x000B, 4}, {0x0037, 7},
{0x0062, 9}, {0x0007, 11}, {0x0166, 12}, {0x00CE, 13}, {0x1590, 13}, {0x05F6, 14}, {0x0BE7, 15}, {0x0007, 5},
{0x006D, 8}, {0x0003, 11}, {0x031F, 12}, {0x05F2, 14}, {0x0002, 6}, {0x0061, 9}, {0x0055, 12}, {0x01DF, 14},
{0x001A, 6}, {0x001E, 10}, {0x0AC9, 12}, {0x2B23, 14}, {0x001E, 6}, {0x001F, 10}, {0x0AC3, 12}, {0x2B2B, 14},
{0x0006, 7}, {0x0004, 11}, {0x02F8, 13}, {0x0019, 7}, {0x0006, 11}, {0x063D, 13}, {0x0057, 7}, {0x0182, 11},
{0x2AA2, 14}, {0x0004, 8}, {0x0180, 11}, {0x059C, 14}, {0x007D, 8}, {0x0164, 12}, {0x076D, 15}, {0x0002, 9},
{0x018D, 11}, {0x1581, 13}, {0x00AD, 8}, {0x0060, 12}, {0x0C67, 14}, {0x001C, 9}, {0x00EE, 13}, {0x0003, 9},
{0x02CF, 13}, {0x00D9, 9}, {0x1580, 13}, {0x0002, 11}, {0x0183, 11}, {0x0057, 12}, {0x0061, 12}, {0x0031, 11},
{0x0066, 12}, {0x0631, 13}, {0x0632, 13}, {0x00AC, 13}, {0x031D, 12}, {0x0076, 12}, {0x003A, 11}, {0x0165, 12},
{0x0C66, 14}, {0x0003, 2}, {0x0054, 7}, {0x02AB, 10}, {0x0016, 13}, {0x05F7, 14}, {0x0005, 4}, {0x00F8, 9},
{0x0AA9, 12}, {0x005F, 15}, {0x0004, 4}, {0x001C, 10}, {0x1550, 13}, {0x0004, 5}, {0x0077, 11}, {0x076C, 15},
{0x000E, 5}, {0x000A, 12}, {0x000C, 5}, {0x0562, 11}, {0x0004, 6}, {0x031C, 12}, {0x0006, 6}, {0x00C8, 13},
{0x000D, 6}, {0x01DA, 13}, {0x0007, 6}, {0x00C9, 13}, {0x0001, 7}, {0x002E, 14}, {0x0014, 7}, {0x1596, 13},
{0x000A, 7}, {0x0AC2, 12}, {0x0016, 7}, {0x015B, 14}, {0x0015, 7}, {0x015A, 14}, {0x000F, 8}, {0x005E, 15},
{0x007E, 8}, {0x00AB, 8}, {0x002D, 9}, {0x00D8, 9}, {0x000B, 9}, {0x0014, 10}, {0x02B3, 10}, {0x01F3, 10},
{0x003A, 10}, {0x0000, 10}, {0x0058, 10}, {0x002E, 9}, {0x005E, 10}, {0x0563, 11}, {0x00EC, 12}, {0x0054, 12},
{0x0AC1, 12}, {0x1556, 13}, {0x02FA, 13}, {0x0181, 11}, {0x1557, 13}, {0x059D, 14}, {0x2AA3, 14}, {0x2B2A, 14},
{0x01DE, 14}, {0x063C, 13}, {0x00CF, 13}, {0x1594, 13}, {0x000D, 9}},
{{0x0002, 2}, {0x0006, 3}, {0x000F, 4}, {0x000D, 5}, {0x000C, 5}, {0x0015, 6}, {0x0013, 6}, {0x0012, 6},
{0x0017, 7}, {0x001F, 8}, {0x001E, 8}, {0x001D, 8}, {0x0025, 9}, {0x0024, 9}, {0x0023, 9}, {0x0021, 9},
{0x0021, 10}, {0x0020, 10}, {0x000F, 10}, {0x000E, 10}, {0x0007, 11}, {0x0006, 11}, {0x0020, 11}, {0x0021, 11},
{0x0050, 12}, {0x0051, 12}, {0x0052, 12}, {0x000E, 4}, {0x0014, 6}, {0x0016, 7}, {0x001C, 8}, {0x0020, 9},
{0x001F, 9}, {0x000D, 10}, {0x0022, 11}, {0x0053, 12}, {0x0055, 12}, {0x000B, 5}, {0x0015, 7}, {0x001E, 9},
{0x000C, 10}, {0x0056, 12}, {0x0011, 6}, {0x001B, 8}, {0x001D, 9}, {0x000B, 10}, {0x0010, 6}, {0x0022, 9},
{0x000A, 10}, {0x000D, 6}, {0x001C, 9}, {0x0008, 10}, {0x0012, 7}, {0x001B, 9}, {0x0054, 12}, {0x0014, 7},
{0x001A, 9}, {0x0057, 12}, {0x0019, 8}, {0x0009, 10}, {0x0018, 8}, {0x0023, 11}, {0x0017, 8}, {0x0019, 9},
{0x0018, 9}, {0x0007, 10}, {0x0058, 12}, {0x0007, 4}, {0x000C, 6}, {0x0016, 8}, {0x0017, 9}, {0x0006, 10},
{0x0005, 11}, {0x0004, 11}, {0x0059, 12}, {0x000F, 6}, {0x0016, 9}, {0x0005, 10}, {0x000E, 6}, {0x0004, 10},
{0x0011, 7}, {0x0024, 11}, {0x0010, 7}, {0x0025, 11}, {0x0013, 7}, {0x005A, 12}, {0x0015, 8}, {0x005B, 12},
{0x0014, 8}, {0x0013, 8}, {0x001A, 8}, {0x0015, 9}, {0x0014, 9}, {0x0013, 9}, {0x0012, 9}, {0x0011, 9},
{0x0026, 11}, {0x0027, 11}, {0x005C, 12}, {0x005D, 12}, {0x005E, 12}, {0x005F, 12}, {0x0003, 7}},
{{0x0002, 2}, {0x000F, 4}, {0x0015, 6}, {0x0017, 7}, {0x001F, 8}, {0x0025, 9}, {0x0024, 9}, {0x0021, 10},
{0x0020, 10}, {0x0007, 11}, {0x0006, 11}, {0x0020, 11}, {0x0006, 3}, {0x0014, 6}, {0x001E, 8}, {0x000F, 10},
{0x0021, 11}, {0x0050, 12}, {0x000E, 4}, {0x001D, 8}, {0x000E, 10}, {0x0051, 12}, {0x000D, 5}, {0x0023, 9},
{0x000D, 10}, {0x000C, 5}, {0x0022, 9}, {0x0052, 12}, {0x000B, 5}, {0x000C, 10}, {0x0053, 12}, {0x0013, 6},
{0x000B, 10}, {0x0054, 12}, {0x0012, 6}, {0x000A, 10}, {0x0011, 6}, {0x0009, 10}, {0x0010, 6}, {0x0008, 10},
{0x0016, 7}, {0x0055, 12}, {0x0015, 7}, {0x0014, 7}, {0x001C, 8}, {0x001B, 8}, {0x0021, 9}, {0x0020, 9},
{0x001F, 9}, {0x001E, 9}, {0x001D, 9}, {0x001C, 9}, {0x001B, 9}, {0x001A, 9}, {0x0022, 11}, {0x0023, 11},
{0x0056, 12}, {0x0057, 12}, {0x0007, 4}, {0x0019, 9}, {0x0005, 11}, {0x000F, 6}, {0x0004, 11}, {0x000E, 6},
{0x000D, 6}, {0x000C, 6}, {0x0013, 7}, {0x0012, 7}, {0x0011, 7}, {0x0010, 7}, {0x001A, 8}, {0x0019, 8},
{0x0018, 8}, {0x0017, 8}, {0x0016, 8}, {0x0015, 8}, {0x0014, 8}, {0x0013, 8}, {0x0018, 9}, {0x0017, 9},
{0x0016, 9}, {0x0015, 9}, {0x0014, 9}, {0x0013, 9}, {0x0012, 9}, {0x0011, 9}, {0x0007, 10}, {0x0006, 10},
{0x0005, 10}, {0x0004, 10}, {0x0024, 11}, {0x0025, 11}, {0x0026, 11}, {0x0027, 11}, {0x0058, 12}, {0x0059, 12},
{0x005A, 12}, {0x005B, 12}, {0x005C, 12}, {0x005D, 12}, {0x005E, 12}, {0x005F, 12}, {0x0003, 7}},
{{0x0000, 2}, {0x0003, 3}, {0x000D, 4}, {0x0005, 4}, {0x001C, 5}, {0x0016, 5}, {0x003F, 6}, {0x003A, 6},
{0x002E, 6}, {0x0022, 6}, {0x007B, 7}, {0x0067, 7}, {0x005F, 7}, {0x0047, 7}, {0x0026, 7}, {0x00EF, 8},
{0x00CD, 8}, {0x00C1, 8}, {0x00A9, 8}, {0x004F, 8}, {0x01F2, 9}, {0x01DD, 9}, {0x0199, 9}, {0x0185, 9},
{0x015D, 9}, {0x011B, 9}, {0x03EF, 10}, {0x03E1, 10}, {0x03C8, 10}, {0x0331, 10}, {0x0303, 10}, {0x02F1, 10},
{0x02A0, 10}, {0x0233, 10}, {0x0126, 10}, {0x07C0, 11}, {0x076F, 11}, {0x076C, 11}, {0x0661, 11}, {0x0604, 11},
{0x0572, 11}, {0x0551, 11}, {0x046A, 11}, {0x0274, 11}, {0x0F27, 12}, {0x0F24, 12}, {0x0EDB, 12}, {0x0C8E, 12},
{0x0C0B, 12}, {0x0C0A, 12}, {0x0AE3, 12}, {0x08D6, 12}, {0x0490, 12}, {0x0495, 12}, {0x1F19, 13}, {0x1DB5, 13},
{0x0009, 4}, {0x0010, 5}, {0x0029, 6}, {0x0062, 7}, {0x00F3, 8}, {0x00AD, 8}, {0x01E5, 9}, {0x0179, 9},
{0x009C, 9}, {0x03B1, 10}, {0x02AE, 10}, {0x0127, 10}, {0x076E, 11}, {0x0570, 11}, {0x0275, 11}, {0x0F25, 12},
{0x0EC0, 12}, {0x0AA0, 12}, {0x08D7, 12}, {0x1E4C, 13}, {0x0008, 5}, {0x0063, 7}, {0x00AF, 8}, {0x017B, 9},
{0x03B3, 10}, {0x07DD, 11}, {0x0640, 11}, {0x0F8D, 12}, {0x0BC1, 12}, {0x0491, 12}, {0x0028, 6}, {0x00C3, 8},
{0x0151, 9}, {0x02A1, 10}, {0x0573, 11}, {0x0EC3, 12}, {0x1F35, 13}, {0x0065, 7}, {0x01DA, 9}, {0x02AF, 10},
{0x0277, 11}, {0x08C9, 12}, {0x1781, 13}, {0x0025, 7}, {0x0118, 9}, {0x0646, 11}, {0x0AA6, 12}, {0x1780, 13},
{0x00C9, 8}, {0x0321, 10}, {0x0F9B, 12}, {0x191E, 13}, {0x0048, 8}, {0x07CC, 11}, {0x0AA1, 12}, {0x0180, 9},
{0x0465, 11}, {0x1905, 13}, {0x03E2, 10}, {0x0EC1, 12}, {0x3C9B, 14}, {0x02F4, 10}, {0x08C8, 12}, {0x07C1, 11},
{0x0928, 13}, {0x05E1, 11}, {0x320D, 14}, {0x0EC2, 12}, {0x6418, 15}, {0x1F34, 13}, {0x0078, 7}, {0x0155, 9},
{0x0552, 11}, {0x191F, 13}, {0x00FA, 8}, {0x07DC, 11}, {0x1907, 13}, {0x00AC, 8}, {0x0249, 11}, {0x13B1, 14},
{0x01F6, 9}, {0x0AE2, 12}, {0x01DC, 9}, {0x04ED, 12}, {0x0184, 9}, {0x1904, 13}, {0x0156, 9}, {0x09D9, 13},
{0x03E7, 10}, {0x0929, 13}, {0x03B2, 10}, {0x3B68, 14}, {0x02F5, 10}, {0x13B0, 14}, {0x0322, 10}, {0x3B69, 14},
{0x0234, 10}, {0x7935, 15}, {0x07C7, 11}, {0xC833, 16}, {0x0660, 11}, {0x7934, 15}, {0x024B, 11}, {0xC832, 16},
{0x0AA7, 12}, {0x1F18, 13}, {0x007A, 7}},
{{0x0002, 2}, {0x0000, 3}, {0x001E, 5}, {0x0004, 5}, {0x0012, 6}, {0x0070, 7}, {0x001A, 7},
{0x005F, 8}, {0x0047, 8}, {0x01D3, 9}, {0x00B5, 9}, {0x0057, 9}, {0x03B5, 10}, {0x016D, 10},
{0x0162, 10}, {0x07CE, 11}, {0x0719, 11}, {0x0691, 11}, {0x02C6, 11}, {0x0156, 11}, {0x0F92, 12},
{0x0D2E, 12}, {0x0D20, 12}, {0x059E, 12}, {0x0468, 12}, {0x02A6, 12}, {0x1DA2, 13}, {0x1C60, 13},
{0x1A43, 13}, {0x0B1D, 13}, {0x08C0, 13}, {0x055D, 13}, {0x0003, 3}, {0x000A, 5}, {0x0077, 7},
{0x00E5, 8}, {0x01D9, 9}, {0x03E5, 10}, {0x0166, 10}, {0x0694, 11}, {0x0152, 11}, {0x059F, 12},
{0x1F3C, 13}, {0x1A4B, 13}, {0x055E, 13}, {0x000C, 4}, {0x007D, 7}, {0x0044, 8}, {0x03E0, 10},
{0x0769, 11}, {0x0E31, 12}, {0x1F26, 13}, {0x055C, 13}, {0x001B, 5}, {0x00E2, 8}, {0x03A5, 10},
{0x02C9, 11}, {0x1F23, 13}, {0x3B47, 14}, {0x0007, 5}, {0x01D8, 9}, {0x02D8, 11}, {0x1F27, 13},
{0x3494, 14}, {0x0035, 6}, {0x03E1, 10}, {0x059C, 12}, {0x38C3, 14}, {0x000C, 6}, {0x0165, 10},
{0x1D23, 13}, {0x1638, 14}, {0x0068, 7}, {0x0693, 11}, {0x3A45, 14}, {0x0020, 7}, {0x0F90, 12},
{0x7CF6, 15}, {0x00E8, 8}, {0x058F, 12}, {0x2CEF, 15}, {0x0045, 8}, {0x0B3A, 13}, {0x01F1, 9},
{0x3B46, 14}, {0x01A7, 9}, {0x1676, 14}, {0x0056, 9}, {0x692A, 15}, {0x038D, 10}, {0xE309, 16},
{0x00AA, 10}, {0x1C611, 17}, {0x02DF, 11}, {0xB3B9, 17}, {0x02C8, 11}, {0x38C20, 18}, {0x01B0, 11},
{0x16390, 18}, {0x0F9F, 12}, {0x16771, 18}, {0x0ED0, 12}, {0x71843, 19}, {0x0D2A, 12}, {0xF9E8C, 20},
{0x0461, 12}, {0xF9E8E, 20}, {0x0B67, 13}, {0x055F, 13}, {0x003F, 6}, {0x006D, 9}, {0x0E90, 12},
{0x054E, 13}, {0x0013, 6}, {0x0119, 10}, {0x0B66, 13}, {0x000B, 6}, {0x0235, 11}, {0x7CF5, 15},
{0x0075, 7}, {0x0D24, 12}, {0xF9E9, 16}, {0x002E, 7}, {0x1F22, 13}, {0x0021, 7}, {0x054F, 13},
{0x0014, 7}, {0x3A44, 14}, {0x00E4, 8}, {0x7CF7, 15}, {0x005E, 8}, {0x7185, 15}, {0x0037, 8},
{0x2C73, 15}, {0x01DB, 9}, {0x59DD, 16}, {0x01C7, 9}, {0x692B, 15}, {0x01A6, 9}, {0x58E5, 16},
{0x00B4, 9}, {0x1F3D0, 17}, {0x00B0, 9}, {0xB1C9, 17}, {0x03E6, 10}, {0x16770, 18}, {0x016E, 10},
{0x3E7A2, 18}, {0x011B, 10}, {0xF9E8D, 20}, {0x00D9, 10}, {0xF9E8F, 20}, {0x00A8, 10}, {0x2C723, 19},
{0x0749, 11}, {0xE3084, 20}, {0x0696, 11}, {0x58E45, 20}, {0x02DE, 11}, {0xB1C88, 21}, {0x0231, 11},
{0x1C610A, 21}, {0x01B1, 11}, {0x71842D, 23}, {0x0D2B, 12}, {0x38C217, 22}, {0x0D2F, 12}, {0x163913, 22},
{0x05B2, 12}, {0x163912, 22}, {0x0469, 12}, {0x71842C, 23}, {0x1A42, 13}, {0x08C1, 13}, {0x0073, 7}}};
const int ff_vc1_ac_sizes[AC_MODES] = {186, 169, 133, 149, 103, 103, 163, 175};
} // namespace VC1
static inline uint8 clipByte(int value) {
return CLIP(value, 0, 255);
}
static inline uint32 roundAvg32(uint32 a, uint32 b) {
return (a | b) - (((a ^ b) & ~0x01010101U) >> 1);
}
/* Apply overlap transform to horizontal edge */
// Overlap and loop-filter DSP
static void vc1_v_overlap_c(uint8 *src, ptrdiff_t stride) {
int i;
int a, b, c, d;
int d1, d2;
int rnd = 1;
for (i = 0; i < 8; i++) {
a = src[-2 * stride];
b = src[-stride];
c = src[0];
d = src[stride];
d1 = (a - d + 3 + rnd) >> 3;
d2 = (a - d + b - c + 4 - rnd) >> 3;
src[-2 * stride] = a - d1;
src[-stride] = clipByte(b - d2);
src[0] = clipByte(c + d2);
src[stride] = d + d1;
src++;
rnd = !rnd;
}
}
/* Apply overlap transform to vertical edge */
static void vc1_h_overlap_c(uint8 *src, ptrdiff_t stride) {
int i;
int a, b, c, d;
int d1, d2;
int rnd = 1;
for (i = 0; i < 8; i++) {
a = src[-2];
b = src[-1];
c = src[0];
d = src[1];
d1 = (a - d + 3 + rnd) >> 3;
d2 = (a - d + b - c + 4 - rnd) >> 3;
src[-2] = a - d1;
src[-1] = clipByte(b - d2);
src[0] = clipByte(c + d2);
src[1] = d + d1;
src += stride;
rnd = !rnd;
}
}
static void vc1_v_s_overlap_c(int16 *top, int16 *bottom) {
int i;
int a, b, c, d;
int d1, d2;
int rnd1 = 4, rnd2 = 3;
for (i = 0; i < 8; i++) {
a = top[48];
b = top[56];
c = bottom[0];
d = bottom[8];
d1 = a - d;
d2 = a - d + b - c;
top[48] = ((a * 8) - d1 + rnd1) >> 3;
top[56] = ((b * 8) - d2 + rnd2) >> 3;
bottom[0] = ((c * 8) + d2 + rnd1) >> 3;
bottom[8] = ((d * 8) + d1 + rnd2) >> 3;
bottom++;
top++;
rnd2 = 7 - rnd2;
rnd1 = 7 - rnd1;
}
}
static void vc1_h_s_overlap_c(int16 *left, int16 *right, ptrdiff_t left_stride, ptrdiff_t right_stride, int flags) {
int i;
int a, b, c, d;
int d1, d2;
int rnd1 = flags & 2 ? 3 : 4;
int rnd2 = 7 - rnd1;
for (i = 0; i < 8; i++) {
a = left[6];
b = left[7];
c = right[0];
d = right[1];
d1 = a - d;
d2 = a - d + b - c;
left[6] = ((a * 8) - d1 + rnd1) >> 3;
left[7] = ((b * 8) - d2 + rnd2) >> 3;
right[0] = ((c * 8) + d2 + rnd1) >> 3;
right[1] = ((d * 8) + d1 + rnd2) >> 3;
right += right_stride;
left += left_stride;
if (flags & 1) {
rnd2 = 7 - rnd2;
rnd1 = 7 - rnd1;
}
}
}
/**
* VC-1 in-loop deblocking filter for one line
* @param src source block type
* @param stride block stride
* @param pq block quantizer
* @return whether other 3 pairs should be filtered or not
* @see 8.6
*/
static inline int vc1_filter_line(uint8 *src, ptrdiff_t stride, int pq) {
int a0 = (2 * (src[-2 * stride] - src[1 * stride]) - 5 * (src[-1 * stride] - src[0 * stride]) + 4) >> 3;
int a0_sign = a0 >> 31; /* Store sign */
a0 = (a0 ^ a0_sign) - a0_sign; /* a0 = ABS(a0); */
if (a0 < pq) {
int a1 = ABS((2 * (src[-4 * stride] - src[-1 * stride]) - 5 * (src[-3 * stride] - src[-2 * stride]) + 4) >> 3);
int a2 = ABS((2 * (src[0 * stride] - src[3 * stride]) - 5 * (src[1 * stride] - src[2 * stride]) + 4) >> 3);
if (a1 < a0 || a2 < a0) {
int clip = src[-1 * stride] - src[0 * stride];
int clip_sign = clip >> 31;
clip = ((clip ^ clip_sign) - clip_sign) >> 1;
if (clip) {
int a3 = MIN(a1, a2);
int d = 5 * (a3 - a0);
int d_sign = (d >> 31);
d = ((d ^ d_sign) - d_sign) >> 3;
d_sign ^= a0_sign;
if (d_sign ^ clip_sign)
d = 0;
else {
d = MIN(d, clip);
d = (d ^ d_sign) - d_sign; /* Restore sign */
src[-1 * stride] = clipByte(src[-1 * stride] - d);
src[0 * stride] = clipByte(src[0 * stride] + d);
}
return 1;
}
}
}
return 0;
}
/**
* VC-1 in-loop deblocking filter
* @param src source block type
* @param step distance between horizontally adjacent elements
* @param stride distance between vertically adjacent elements
* @param len edge length to filter (4 or 8 pixels)
* @param pq block quantizer
* @see 8.6
*/
static inline void vc1_loop_filter(uint8 *src, ptrdiff_t step, ptrdiff_t stride, int len, int pq) {
int i;
int filt3;
for (i = 0; i < len; i += 4) {
filt3 = vc1_filter_line(src + 2 * step, stride, pq);
if (filt3) {
vc1_filter_line(src + 0 * step, stride, pq);
vc1_filter_line(src + 1 * step, stride, pq);
vc1_filter_line(src + 3 * step, stride, pq);
}
src += step * 4;
}
}
static void vc1_v_loop_filter4_c(uint8 *src, ptrdiff_t stride, int pq) {
vc1_loop_filter(src, 1, stride, 4, pq);
}
static void vc1_h_loop_filter4_c(uint8 *src, ptrdiff_t stride, int pq) {
vc1_loop_filter(src, stride, 1, 4, pq);
}
static void vc1_v_loop_filter8_c(uint8 *src, ptrdiff_t stride, int pq) {
vc1_loop_filter(src, 1, stride, 8, pq);
}
static void vc1_h_loop_filter8_c(uint8 *src, ptrdiff_t stride, int pq) {
vc1_loop_filter(src, stride, 1, 8, pq);
}
static void vc1_v_loop_filter16_c(uint8 *src, ptrdiff_t stride, int pq) {
vc1_loop_filter(src, 1, stride, 16, pq);
}
static void vc1_h_loop_filter16_c(uint8 *src, ptrdiff_t stride, int pq) {
vc1_loop_filter(src, stride, 1, 16, pq);
}
/* Do inverse transform on 8x8 block */
// Inverse-transform DSP
static void vc1_inv_trans_8x8_dc_c(uint8 *dest, ptrdiff_t stride, int16 *block) {
int i;
int dc = block[0];
dc = (3 * dc + 1) >> 1;
dc = (3 * dc + 16) >> 5;
for (i = 0; i < 8; i++) {
dest[0] = clipByte(dest[0] + dc);
dest[1] = clipByte(dest[1] + dc);
dest[2] = clipByte(dest[2] + dc);
dest[3] = clipByte(dest[3] + dc);
dest[4] = clipByte(dest[4] + dc);
dest[5] = clipByte(dest[5] + dc);
dest[6] = clipByte(dest[6] + dc);
dest[7] = clipByte(dest[7] + dc);
dest += stride;
}
}
static void vc1_inv_trans_8x8_c(int16 block[64]) {
int i;
int t1, t2, t3, t4, t5, t6, t7, t8;
int16 *src, *dst, temp[64];
src = block;
dst = temp;
for (i = 0; i < 8; i++) {
t1 = 12 * (src[0] + src[32]) + 4;
t2 = 12 * (src[0] - src[32]) + 4;
t3 = 16 * src[16] + 6 * src[48];
t4 = 6 * src[16] - 16 * src[48];
t5 = t1 + t3;
t6 = t2 + t4;
t7 = t2 - t4;
t8 = t1 - t3;
t1 = 16 * src[8] + 15 * src[24] + 9 * src[40] + 4 * src[56];
t2 = 15 * src[8] - 4 * src[24] - 16 * src[40] - 9 * src[56];
t3 = 9 * src[8] - 16 * src[24] + 4 * src[40] + 15 * src[56];
t4 = 4 * src[8] - 9 * src[24] + 15 * src[40] - 16 * src[56];
dst[0] = (t5 + t1) >> 3;
dst[1] = (t6 + t2) >> 3;
dst[2] = (t7 + t3) >> 3;
dst[3] = (t8 + t4) >> 3;
dst[4] = (t8 - t4) >> 3;
dst[5] = (t7 - t3) >> 3;
dst[6] = (t6 - t2) >> 3;
dst[7] = (t5 - t1) >> 3;
src += 1;
dst += 8;
}
src = temp;
dst = block;
for (i = 0; i < 8; i++) {
t1 = 12 * (src[0] + src[32]) + 64;
t2 = 12 * (src[0] - src[32]) + 64;
t3 = 16 * src[16] + 6 * src[48];
t4 = 6 * src[16] - 16 * src[48];
t5 = t1 + t3;
t6 = t2 + t4;
t7 = t2 - t4;
t8 = t1 - t3;
t1 = 16 * src[8] + 15 * src[24] + 9 * src[40] + 4 * src[56];
t2 = 15 * src[8] - 4 * src[24] - 16 * src[40] - 9 * src[56];
t3 = 9 * src[8] - 16 * src[24] + 4 * src[40] + 15 * src[56];
t4 = 4 * src[8] - 9 * src[24] + 15 * src[40] - 16 * src[56];
dst[0] = (t5 + t1) >> 7;
dst[8] = (t6 + t2) >> 7;
dst[16] = (t7 + t3) >> 7;
dst[24] = (t8 + t4) >> 7;
dst[32] = (t8 - t4 + 1) >> 7;
dst[40] = (t7 - t3 + 1) >> 7;
dst[48] = (t6 - t2 + 1) >> 7;
dst[56] = (t5 - t1 + 1) >> 7;
src++;
dst++;
}
}
/* Do inverse transform on 8x4 part of block */
static void vc1_inv_trans_8x4_dc_c(uint8 *dest, ptrdiff_t stride, int16 *block) {
int i;
int dc = block[0];
dc = (3 * dc + 1) >> 1;
dc = (17 * dc + 64) >> 7;
for (i = 0; i < 4; i++) {
dest[0] = clipByte(dest[0] + dc);
dest[1] = clipByte(dest[1] + dc);
dest[2] = clipByte(dest[2] + dc);
dest[3] = clipByte(dest[3] + dc);
dest[4] = clipByte(dest[4] + dc);
dest[5] = clipByte(dest[5] + dc);
dest[6] = clipByte(dest[6] + dc);
dest[7] = clipByte(dest[7] + dc);
dest += stride;
}
}
static void vc1_inv_trans_8x4_c(uint8 *dest, ptrdiff_t stride, int16 *block) {
int i;
int t1, t2, t3, t4, t5, t6, t7, t8;
int16 *src, *dst;
src = block;
dst = block;
for (i = 0; i < 4; i++) {
t1 = 12 * (src[0] + src[4]) + 4;
t2 = 12 * (src[0] - src[4]) + 4;
t3 = 16 * src[2] + 6 * src[6];
t4 = 6 * src[2] - 16 * src[6];
t5 = t1 + t3;
t6 = t2 + t4;
t7 = t2 - t4;
t8 = t1 - t3;
t1 = 16 * src[1] + 15 * src[3] + 9 * src[5] + 4 * src[7];
t2 = 15 * src[1] - 4 * src[3] - 16 * src[5] - 9 * src[7];
t3 = 9 * src[1] - 16 * src[3] + 4 * src[5] + 15 * src[7];
t4 = 4 * src[1] - 9 * src[3] + 15 * src[5] - 16 * src[7];
dst[0] = (t5 + t1) >> 3;
dst[1] = (t6 + t2) >> 3;
dst[2] = (t7 + t3) >> 3;
dst[3] = (t8 + t4) >> 3;
dst[4] = (t8 - t4) >> 3;
dst[5] = (t7 - t3) >> 3;
dst[6] = (t6 - t2) >> 3;
dst[7] = (t5 - t1) >> 3;
src += 8;
dst += 8;
}
src = block;
for (i = 0; i < 8; i++) {
t1 = 17 * (src[0] + src[16]) + 64;
t2 = 17 * (src[0] - src[16]) + 64;
t3 = 22 * src[8] + 10 * src[24];
t4 = 22 * src[24] - 10 * src[8];
dest[0 * stride] = clipByte(dest[0 * stride] + ((t1 + t3) >> 7));
dest[1 * stride] = clipByte(dest[1 * stride] + ((t2 - t4) >> 7));
dest[2 * stride] = clipByte(dest[2 * stride] + ((t2 + t4) >> 7));
dest[3 * stride] = clipByte(dest[3 * stride] + ((t1 - t3) >> 7));
src++;
dest++;
}
}
/* Do inverse transform on 4x8 parts of block */
static void vc1_inv_trans_4x8_dc_c(uint8 *dest, ptrdiff_t stride, int16 *block) {
int i;
int dc = block[0];
dc = (17 * dc + 4) >> 3;
dc = (12 * dc + 64) >> 7;
for (i = 0; i < 8; i++) {
dest[0] = clipByte(dest[0] + dc);
dest[1] = clipByte(dest[1] + dc);
dest[2] = clipByte(dest[2] + dc);
dest[3] = clipByte(dest[3] + dc);
dest += stride;
}
}
static void vc1_inv_trans_4x8_c(uint8 *dest, ptrdiff_t stride, int16 *block) {
int i;
int t1, t2, t3, t4, t5, t6, t7, t8;
int16 *src, *dst;
src = block;
dst = block;
for (i = 0; i < 8; i++) {
t1 = 17 * (src[0] + src[2]) + 4;
t2 = 17 * (src[0] - src[2]) + 4;
t3 = 22 * src[1] + 10 * src[3];
t4 = 22 * src[3] - 10 * src[1];
dst[0] = (t1 + t3) >> 3;
dst[1] = (t2 - t4) >> 3;
dst[2] = (t2 + t4) >> 3;
dst[3] = (t1 - t3) >> 3;
src += 8;
dst += 8;
}
src = block;
for (i = 0; i < 4; i++) {
t1 = 12 * (src[0] + src[32]) + 64;
t2 = 12 * (src[0] - src[32]) + 64;
t3 = 16 * src[16] + 6 * src[48];
t4 = 6 * src[16] - 16 * src[48];
t5 = t1 + t3;
t6 = t2 + t4;
t7 = t2 - t4;
t8 = t1 - t3;
t1 = 16 * src[8] + 15 * src[24] + 9 * src[40] + 4 * src[56];
t2 = 15 * src[8] - 4 * src[24] - 16 * src[40] - 9 * src[56];
t3 = 9 * src[8] - 16 * src[24] + 4 * src[40] + 15 * src[56];
t4 = 4 * src[8] - 9 * src[24] + 15 * src[40] - 16 * src[56];
dest[0 * stride] = clipByte(dest[0 * stride] + ((t5 + t1) >> 7));
dest[1 * stride] = clipByte(dest[1 * stride] + ((t6 + t2) >> 7));
dest[2 * stride] = clipByte(dest[2 * stride] + ((t7 + t3) >> 7));
dest[3 * stride] = clipByte(dest[3 * stride] + ((t8 + t4) >> 7));
dest[4 * stride] = clipByte(dest[4 * stride] + ((t8 - t4 + 1) >> 7));
dest[5 * stride] = clipByte(dest[5 * stride] + ((t7 - t3 + 1) >> 7));
dest[6 * stride] = clipByte(dest[6 * stride] + ((t6 - t2 + 1) >> 7));
dest[7 * stride] = clipByte(dest[7 * stride] + ((t5 - t1 + 1) >> 7));
src++;
dest++;
}
}
/* Do inverse transform on 4x4 part of block */
static void vc1_inv_trans_4x4_dc_c(uint8 *dest, ptrdiff_t stride, int16 *block) {
int i;
int dc = block[0];
dc = (17 * dc + 4) >> 3;
dc = (17 * dc + 64) >> 7;
for (i = 0; i < 4; i++) {
dest[0] = clipByte(dest[0] + dc);
dest[1] = clipByte(dest[1] + dc);
dest[2] = clipByte(dest[2] + dc);
dest[3] = clipByte(dest[3] + dc);
dest += stride;
}
}
static void vc1_inv_trans_4x4_c(uint8 *dest, ptrdiff_t stride, int16 *block) {
int i;
int t1, t2, t3, t4;
int16 *src, *dst;
src = block;
dst = block;
for (i = 0; i < 4; i++) {
t1 = 17 * (src[0] + src[2]) + 4;
t2 = 17 * (src[0] - src[2]) + 4;
t3 = 22 * src[1] + 10 * src[3];
t4 = 22 * src[3] - 10 * src[1];
dst[0] = (t1 + t3) >> 3;
dst[1] = (t2 - t4) >> 3;
dst[2] = (t2 + t4) >> 3;
dst[3] = (t1 - t3) >> 3;
src += 8;
dst += 8;
}
src = block;
for (i = 0; i < 4; i++) {
t1 = 17 * (src[0] + src[16]) + 64;
t2 = 17 * (src[0] - src[16]) + 64;
t3 = 22 * src[8] + 10 * src[24];
t4 = 22 * src[24] - 10 * src[8];
dest[0 * stride] = clipByte(dest[0 * stride] + ((t1 + t3) >> 7));
dest[1 * stride] = clipByte(dest[1 * stride] + ((t2 - t4) >> 7));
dest[2 * stride] = clipByte(dest[2 * stride] + ((t2 + t4) >> 7));
dest[3 * stride] = clipByte(dest[3 * stride] + ((t1 - t3) >> 7));
src++;
dest++;
}
}
/* motion compensation functions */
/* Filter in case of 2 filters */
#define VC1_MSPEL_FILTER_16B(DIR, TYPE) \
static inline int vc1_mspel_##DIR##_filter_16bits(const TYPE *src, ptrdiff_t stride, int mode) { \
switch (mode) { \
case 0: /* no shift - should not occur */ \
return 0; \
case 1: /* 1/4 shift */ \
return -4 * src[-stride] + 53 * src[0] + 18 * src[stride] - 3 * src[stride * 2]; \
case 2: /* 1/2 shift */ \
return -1 * src[-stride] + 9 * src[0] + 9 * src[stride] - 1 * src[stride * 2]; \
case 3: /* 3/4 shift */ \
return -3 * src[-stride] + 18 * src[0] + 53 * src[stride] - 4 * src[stride * 2]; \
} \
return 0; /* should not occur */ \
}
VC1_MSPEL_FILTER_16B(ver, uint8)
VC1_MSPEL_FILTER_16B(hor, int16)
/* Filter used to interpolate fractional pel values */
static inline int vc1_mspel_filter(const uint8 *src, ptrdiff_t stride, int mode, int r) {
switch (mode) {
case 0: // no shift
return src[0];
case 1: // 1/4 shift
return (-4 * src[-stride] + 53 * src[0] + 18 * src[stride] - 3 * src[stride * 2] + 32 - r) >> 6;
case 2: // 1/2 shift
return (-1 * src[-stride] + 9 * src[0] + 9 * src[stride] - 1 * src[stride * 2] + 8 - r) >> 4;
case 3: // 3/4 shift
return (-3 * src[-stride] + 18 * src[0] + 53 * src[stride] - 4 * src[stride * 2] + 32 - r) >> 6;
}
return 0; // should not occur
}
/* Function used to do motion compensation with bicubic interpolation */
#define VC1_MSPEL_MC(OP, OP4, OPNAME) \
static inline void OPNAME##vc1_mspel_mc(uint8 *dst, const uint8 *src, ptrdiff_t stride, int hmode, int vmode, \
int rnd) { \
int i, j; \
\
if (vmode) { /* Horizontal filter to apply */ \
int r; \
\
if (hmode) { /* Vertical filter to apply, output to tmp */ \
static const int shift_value[] = {0, 5, 1, 5}; \
int shift = (shift_value[hmode] + shift_value[vmode]) >> 1; \
int16 tmp[11 * 8], *tptr = tmp; \
\
r = (1 << (shift - 1)) + rnd - 1; \
\
src -= 1; \
for (j = 0; j < 8; j++) { \
for (i = 0; i < 11; i++) \
tptr[i] = (vc1_mspel_ver_filter_16bits(src + i, stride, vmode) + r) >> shift; \
src += stride; \
tptr += 11; \
} \
\
r = 64 - rnd; \
tptr = tmp + 1; \
for (j = 0; j < 8; j++) { \
for (i = 0; i < 8; i++) \
OP(dst[i], (vc1_mspel_hor_filter_16bits(tptr + i, 1, hmode) + r) >> 7); \
dst += stride; \
tptr += 11; \
} \
\
return; \
} else { /* No horizontal filter, output 8 lines to dst */ \
r = 1 - rnd; \
\
for (j = 0; j < 8; j++) { \
for (i = 0; i < 8; i++) \
OP(dst[i], vc1_mspel_filter(src + i, stride, vmode, r)); \
src += stride; \
dst += stride; \
} \
return; \
} \
} \
\
/* Horizontal mode with no vertical mode */ \
for (j = 0; j < 8; j++) { \
for (i = 0; i < 8; i++) \
OP(dst[i], vc1_mspel_filter(src + i, 1, hmode, rnd)); \
dst += stride; \
src += stride; \
} \
} \
static inline void OPNAME##vc1_mspel_mc_16(uint8 *dst, const uint8 *src, ptrdiff_t stride, int hmode, int vmode, \
int rnd) { \
int i, j; \
\
if (vmode) { /* Horizontal filter to apply */ \
int r; \
\
if (hmode) { /* Vertical filter to apply, output to tmp */ \
static const int shift_value[] = {0, 5, 1, 5}; \
int shift = (shift_value[hmode] + shift_value[vmode]) >> 1; \
int16 tmp[19 * 16], *tptr = tmp; \
\
r = (1 << (shift - 1)) + rnd - 1; \
\
src -= 1; \
for (j = 0; j < 16; j++) { \
for (i = 0; i < 19; i++) \
tptr[i] = (vc1_mspel_ver_filter_16bits(src + i, stride, vmode) + r) >> shift; \
src += stride; \
tptr += 19; \
} \
\
r = 64 - rnd; \
tptr = tmp + 1; \
for (j = 0; j < 16; j++) { \
for (i = 0; i < 16; i++) \
OP(dst[i], (vc1_mspel_hor_filter_16bits(tptr + i, 1, hmode) + r) >> 7); \
dst += stride; \
tptr += 19; \
} \
\
return; \
} else { /* No horizontal filter, output 8 lines to dst */ \
r = 1 - rnd; \
\
for (j = 0; j < 16; j++) { \
for (i = 0; i < 16; i++) \
OP(dst[i], vc1_mspel_filter(src + i, stride, vmode, r)); \
src += stride; \
dst += stride; \
} \
return; \
} \
} \
\
/* Horizontal mode with no vertical mode */ \
for (j = 0; j < 16; j++) { \
for (i = 0; i < 16; i++) \
OP(dst[i], vc1_mspel_filter(src + i, 1, hmode, rnd)); \
dst += stride; \
src += stride; \
} \
} \
static void OPNAME##pixels8x8_c(uint8 *block, const uint8 *pixels, ptrdiff_t line_size, int rnd) { \
int i; \
for (i = 0; i < 8; i++) { \
OP4(block, READ_UINT32(pixels)); \
OP4(block + 4, READ_UINT32(pixels + 4)); \
pixels += line_size; \
block += line_size; \
} \
} \
static void OPNAME##pixels16x16_c(uint8 *block, const uint8 *pixels, ptrdiff_t line_size, int rnd) { \
int i; \
for (i = 0; i < 16; i++) { \
OP4(block, READ_UINT32(pixels)); \
OP4(block + 4, READ_UINT32(pixels + 4)); \
OP4(block + 8, READ_UINT32(pixels + 8)); \
OP4(block + 12, READ_UINT32(pixels + 12)); \
pixels += line_size; \
block += line_size; \
} \
}
#define op_put(a, b) (a) = clipByte(b)
#define op_avg(a, b) (a) = ((a) + clipByte(b) + 1) >> 1
#define op4_avg(a, b) WRITE_UINT32(a, roundAvg32(READ_UINT32(a), b))
#define op4_put(a, b) WRITE_UINT32(a, b)
VC1_MSPEL_MC(op_put, op4_put, put_)
VC1_MSPEL_MC(op_avg, op4_avg, avg_)
/* pixel functions - really are entry points to vc1_mspel_mc */
#define PUT_VC1_MSPEL(a, b) \
static void put_vc1_mspel_mc##a##b##_c(uint8 *dst, const uint8 *src, ptrdiff_t stride, int rnd) { \
put_vc1_mspel_mc(dst, src, stride, a, b, rnd); \
} \
static void avg_vc1_mspel_mc##a##b##_c(uint8 *dst, const uint8 *src, ptrdiff_t stride, int rnd) { \
avg_vc1_mspel_mc(dst, src, stride, a, b, rnd); \
} \
static void put_vc1_mspel_mc##a##b##_16_c(uint8 *dst, const uint8 *src, ptrdiff_t stride, int rnd) { \
put_vc1_mspel_mc_16(dst, src, stride, a, b, rnd); \
} \
static void avg_vc1_mspel_mc##a##b##_16_c(uint8 *dst, const uint8 *src, ptrdiff_t stride, int rnd) { \
avg_vc1_mspel_mc_16(dst, src, stride, a, b, rnd); \
}
PUT_VC1_MSPEL(1, 0)
PUT_VC1_MSPEL(2, 0)
PUT_VC1_MSPEL(3, 0)
PUT_VC1_MSPEL(0, 1)
PUT_VC1_MSPEL(1, 1)
PUT_VC1_MSPEL(2, 1)
PUT_VC1_MSPEL(3, 1)
PUT_VC1_MSPEL(0, 2)
PUT_VC1_MSPEL(1, 2)
PUT_VC1_MSPEL(2, 2)
PUT_VC1_MSPEL(3, 2)
PUT_VC1_MSPEL(0, 3)
PUT_VC1_MSPEL(1, 3)
PUT_VC1_MSPEL(2, 3)
PUT_VC1_MSPEL(3, 3)
#define chroma_mc(a) ((A * src[a] + B * src[a + 1] + C * src[stride + a] + D * src[stride + a + 1] + 32 - 4) >> 6)
static void put_no_rnd_vc1_chroma_mc8_c(uint8 *dst /* align 8 */, const uint8 *src /* align 1 */, ptrdiff_t stride,
int h, int x, int y) {
const int A = (8 - x) * (8 - y);
const int B = (x) * (8 - y);
const int C = (8 - x) * (y);
const int D = (x) * (y);
int i;
assert(x < 8 && y < 8 && x >= 0 && y >= 0);
for (i = 0; i < h; i++) {
dst[0] = chroma_mc(0);
dst[1] = chroma_mc(1);
dst[2] = chroma_mc(2);
dst[3] = chroma_mc(3);
dst[4] = chroma_mc(4);
dst[5] = chroma_mc(5);
dst[6] = chroma_mc(6);
dst[7] = chroma_mc(7);
dst += stride;
src += stride;
}
}
static void put_no_rnd_vc1_chroma_mc4_c(uint8 *dst, const uint8 *src, ptrdiff_t stride, int h, int x, int y) {
const int A = (8 - x) * (8 - y);
const int B = (x) * (8 - y);
const int C = (8 - x) * (y);
const int D = (x) * (y);
int i;
assert(x < 8 && y < 8 && x >= 0 && y >= 0);
for (i = 0; i < h; i++) {
dst[0] = chroma_mc(0);
dst[1] = chroma_mc(1);
dst[2] = chroma_mc(2);
dst[3] = chroma_mc(3);
dst += stride;
src += stride;
}
}
#define avg2(a, b) (((a) + (b) + 1) >> 1)
static void avg_no_rnd_vc1_chroma_mc8_c(uint8 *dst /* align 8 */, const uint8 *src /* align 1 */, ptrdiff_t stride,
int h, int x, int y) {
const int A = (8 - x) * (8 - y);
const int B = (x) * (8 - y);
const int C = (8 - x) * (y);
const int D = (x) * (y);
int i;
assert(x < 8 && y < 8 && x >= 0 && y >= 0);
for (i = 0; i < h; i++) {
dst[0] = avg2(dst[0], chroma_mc(0));
dst[1] = avg2(dst[1], chroma_mc(1));
dst[2] = avg2(dst[2], chroma_mc(2));
dst[3] = avg2(dst[3], chroma_mc(3));
dst[4] = avg2(dst[4], chroma_mc(4));
dst[5] = avg2(dst[5], chroma_mc(5));
dst[6] = avg2(dst[6], chroma_mc(6));
dst[7] = avg2(dst[7], chroma_mc(7));
dst += stride;
src += stride;
}
}
static void avg_no_rnd_vc1_chroma_mc4_c(uint8 *dst /* align 8 */, const uint8 *src /* align 1 */, ptrdiff_t stride,
int h, int x, int y) {
const int A = (8 - x) * (8 - y);
const int B = (x) * (8 - y);
const int C = (8 - x) * (y);
const int D = (x) * (y);
int i;
assert(x < 8 && y < 8 && x >= 0 && y >= 0);
for (i = 0; i < h; i++) {
dst[0] = avg2(dst[0], chroma_mc(0));
dst[1] = avg2(dst[1], chroma_mc(1));
dst[2] = avg2(dst[2], chroma_mc(2));
dst[3] = avg2(dst[3], chroma_mc(3));
dst += stride;
src += stride;
}
}
#define FN_ASSIGN(X, Y) \
dsp->put_vc1_mspel_pixels_tab[1][X + 4 * Y] = put_vc1_mspel_mc##X##Y##_c; \
dsp->put_vc1_mspel_pixels_tab[0][X + 4 * Y] = put_vc1_mspel_mc##X##Y##_16_c; \
dsp->avg_vc1_mspel_pixels_tab[1][X + 4 * Y] = avg_vc1_mspel_mc##X##Y##_c; \
dsp->avg_vc1_mspel_pixels_tab[0][X + 4 * Y] = avg_vc1_mspel_mc##X##Y##_16_c
void initWMV3DSP(WMV3DSP *dsp) {
*dsp = WMV3DSP();
dsp->vc1_inv_trans_8x8 = vc1_inv_trans_8x8_c;
dsp->vc1_inv_trans_4x8 = vc1_inv_trans_4x8_c;
dsp->vc1_inv_trans_8x4 = vc1_inv_trans_8x4_c;
dsp->vc1_inv_trans_4x4 = vc1_inv_trans_4x4_c;
dsp->vc1_inv_trans_8x8_dc = vc1_inv_trans_8x8_dc_c;
dsp->vc1_inv_trans_4x8_dc = vc1_inv_trans_4x8_dc_c;
dsp->vc1_inv_trans_8x4_dc = vc1_inv_trans_8x4_dc_c;
dsp->vc1_inv_trans_4x4_dc = vc1_inv_trans_4x4_dc_c;
dsp->vc1_h_overlap = vc1_h_overlap_c;
dsp->vc1_v_overlap = vc1_v_overlap_c;
dsp->vc1_h_s_overlap = vc1_h_s_overlap_c;
dsp->vc1_v_s_overlap = vc1_v_s_overlap_c;
dsp->vc1_v_loop_filter4 = vc1_v_loop_filter4_c;
dsp->vc1_h_loop_filter4 = vc1_h_loop_filter4_c;
dsp->vc1_v_loop_filter8 = vc1_v_loop_filter8_c;
dsp->vc1_h_loop_filter8 = vc1_h_loop_filter8_c;
dsp->vc1_v_loop_filter16 = vc1_v_loop_filter16_c;
dsp->vc1_h_loop_filter16 = vc1_h_loop_filter16_c;
dsp->put_vc1_mspel_pixels_tab[0][0] = put_pixels16x16_c;
dsp->avg_vc1_mspel_pixels_tab[0][0] = avg_pixels16x16_c;
dsp->put_vc1_mspel_pixels_tab[1][0] = put_pixels8x8_c;
dsp->avg_vc1_mspel_pixels_tab[1][0] = avg_pixels8x8_c;
FN_ASSIGN(0, 1);
FN_ASSIGN(0, 2);
FN_ASSIGN(0, 3);
FN_ASSIGN(1, 0);
FN_ASSIGN(1, 1);
FN_ASSIGN(1, 2);
FN_ASSIGN(1, 3);
FN_ASSIGN(2, 0);
FN_ASSIGN(2, 1);
FN_ASSIGN(2, 2);
FN_ASSIGN(2, 3);
FN_ASSIGN(3, 0);
FN_ASSIGN(3, 1);
FN_ASSIGN(3, 2);
FN_ASSIGN(3, 3);
dsp->put_no_rnd_vc1_chroma_pixels_tab[0] = put_no_rnd_vc1_chroma_mc8_c;
dsp->avg_no_rnd_vc1_chroma_pixels_tab[0] = avg_no_rnd_vc1_chroma_mc8_c;
dsp->put_no_rnd_vc1_chroma_pixels_tab[1] = put_no_rnd_vc1_chroma_mc4_c;
dsp->avg_no_rnd_vc1_chroma_pixels_tab[1] = avg_no_rnd_vc1_chroma_mc4_c;
}
#undef FN_ASSIGN
#undef PUT_VC1_MSPEL
#undef VC1_MSPEL_FILTER_16B
#undef VC1_MSPEL_MC
#undef avg2
#undef chroma_mc
#undef op4_avg
#undef op4_put
#undef op_avg
#undef op_put
enum { PROFILE_SIMPLE, PROFILE_MAIN, PROFILE_COMPLEX, PROFILE_ADVANCED };
static int setDimensions(VC1Header *v, int width, int height) {
if (width <= 0 || height <= 0) {
v->width = v->height = 0;
return -1;
}
v->width = width;
v->height = height;
return 0;
}
static void validateAspect(VC1Header *v) {
const VC1Ratio &sar = v->sample_aspect_ratio;
bool valid = sar.den > 0 && sar.num >= 0;
if (valid && sar.num && sar.num != sar.den) {
int64 scaled = sar.num < sar.den ? (int64)v->width * sar.num / sar.den : (int64)v->height * sar.den / sar.num;
valid = scaled > 0;
}
if (!valid)
v->sample_aspect_ratio = VC1Ratio();
}
static void reduceAspect(VC1Ratio &aspect, int num, int den) {
if (den <= 0) {
aspect = VC1Ratio();
return;
}
Common::Rational ratio(num, den);
aspect.num = ratio.getNumerator();
aspect.den = ratio.getDenominator();
}
static const uint8 ff_wmv2_scantableA[64] = {
0x00, 0x01, 0x02, 0x08, 0x03, 0x09, 0x0A, 0x10, 0x04, 0x0B, 0x11, 0x18, 0x12, 0x0C, 0x05, 0x13,
0x19, 0x0D, 0x14, 0x1A, 0x1B, 0x06, 0x15, 0x1C, 0x0E, 0x16, 0x1D, 0x07, 0x1E, 0x0F, 0x17, 0x1F,
};
static const uint8 ff_wmv2_scantableB[64] = {
0x00, 0x08, 0x01, 0x10, 0x09, 0x18, 0x11, 0x02, 0x20, 0x0A, 0x19, 0x28, 0x12, 0x30, 0x21, 0x1A,
0x38, 0x29, 0x22, 0x03, 0x31, 0x39, 0x0B, 0x2A, 0x13, 0x32, 0x1B, 0x3A, 0x23, 0x2B, 0x33, 0x3B,
};
static const uint8 ff_vc1_adv_progressive_8x4_zz[32] = {/* Table 233 */
0, 8, 1, 16, 2, 9, 10, 3, 24, 17, 4, 11, 18, 12, 5, 19,
25, 13, 20, 26, 27, 6, 21, 28, 14, 22, 29, 7, 30, 15, 23, 31};
static const uint8 ff_vc1_adv_progressive_4x8_zz[32] = {/* Table 234 */
0, 1, 8, 2, 9, 16, 17, 24, 10, 32, 25, 18, 40, 3, 33, 26,
48, 11, 56, 41, 34, 49, 57, 42, 19, 50, 27, 58, 35, 43, 51, 59};
static const VC1Ratio ff_vc1_pixel_aspect[16] = {{0, 1}, {1, 1}, {12, 11}, {10, 11}, {16, 11}, {40, 33},
{24, 11}, {20, 11}, {32, 11}, {80, 33}, {18, 11}, {15, 11},
{64, 33}, {160, 99}, {0, 1}, {0, 1}};
static const int ff_vc1_fps_nr[7] = {24, 25, 30, 50, 60, 48, 72};
static const int ff_vc1_fps_dr[2] = {1000, 1001};
static int readVC1Advanced(VC1Header *v, Common::BitStream8MSB *gb);
/**
* Decode Simple/Main Profiles sequence header
* @see Figure 7-8, p16-17
* @param v Parsed codec state
* @param gb Bit stream containing the codec sequence header
* @return Status
*/
// Sequence and entry-point headers
int readVC1Sequence(VC1Header *v, Common::BitStream8MSB *gb) {
v->profile = gb->getBits(2);
if (v->profile == PROFILE_COMPLEX) {
warning("WMV3 Complex Profile is not fully supported\n");
}
if (v->profile == PROFILE_ADVANCED) {
v->zz_8x4 = ff_vc1_adv_progressive_8x4_zz;
v->zz_4x8 = ff_vc1_adv_progressive_4x8_zz;
return readVC1Advanced(v, gb);
} else {
v->chromaformat = 1;
v->zz_8x4 = ff_wmv2_scantableA;
v->zz_4x8 = ff_wmv2_scantableB;
v->res_y411 = gb->getBit();
v->res_sprite = gb->getBit();
if (v->res_y411) {
warning("Old interlaced mode is not supported\n");
return -1;
}
}
// (fps-2)/4 (->30)
v->frmrtq_postproc = gb->getBits(3); // common
// (bitrate-32kbps)/64kbps
v->bitrtq_postproc = gb->getBits(5); // common
v->loop_filter = gb->getBit(); // common
if (v->loop_filter == 1 && v->profile == PROFILE_SIMPLE) {
warning("LOOPFILTER shall not be enabled in Simple Profile\n");
}
v->res_x8 = gb->getBit(); // reserved
v->multires = gb->getBit();
v->res_fasttx = gb->getBit();
v->fastuvmc = gb->getBit(); // common
if (!v->profile && !v->fastuvmc) {
warning("FASTUVMC unavailable in Simple Profile\n");
return -1;
}
v->extended_mv = gb->getBit(); // common
if (!v->profile && v->extended_mv) {
warning("Extended MVs unavailable in Simple Profile\n");
return -1;
}
v->dquant = gb->getBits(2); // common
v->vstransform = gb->getBit(); // common
v->res_transtab = gb->getBit();
if (v->res_transtab) {
warning("1 for reserved RES_TRANSTAB is forbidden\n");
return -1;
}
v->overlap = gb->getBit(); // common
v->resync_marker = gb->getBit();
v->rangered = gb->getBit();
if (v->rangered && v->profile == PROFILE_SIMPLE) {
warning("RANGERED should be set to 0 in Simple Profile\n");
}
v->max_b_frames = gb->getBits(3); // common
v->quantizer_mode = gb->getBits(2); // common
v->finterpflag = gb->getBit(); // common
if (v->res_sprite) {
int w = gb->getBits(11);
int h = gb->getBits(11);
int ret = setDimensions(v, w, h);
if (ret < 0) {
warning("Failed to set dimensions %d %d\n", w, h);
return ret;
}
gb->skip(5); // frame rate
v->res_x8 = gb->getBit();
if (gb->getBit()) { // something to do with DC VLC selection
warning("Unsupported sprite feature\n");
return -1;
}
gb->skip(3); // slice code
v->res_rtm_flag = 0;
} else {
v->res_rtm_flag = gb->getBit(); // reserved
}
// TODO: figure out what they mean (always 0x402F)
if (gb->pos() > gb->size())
return -1;
if (!v->res_fasttx)
gb->skip(16);
return 0;
}
static int readVC1Advanced(VC1Header *v, Common::BitStream8MSB *gb) {
v->res_rtm_flag = 1;
v->level = gb->getBits(3);
if (v->level >= 5) {
warning("Reserved LEVEL %i\n", v->level);
}
v->chromaformat = gb->getBits(2);
if (v->chromaformat != 1) {
warning("Only 4:2:0 chroma format supported\n");
return -1;
}
// (fps-2)/4 (->30)
v->frmrtq_postproc = gb->getBits(3); // common
// (bitrate-32kbps)/64kbps
v->bitrtq_postproc = gb->getBits(5); // common
v->postprocflag = gb->getBit(); // common
v->max_coded_width = (gb->getBits(12) + 1) << 1;
v->max_coded_height = (gb->getBits(12) + 1) << 1;
v->broadcast = gb->getBit();
v->interlace = gb->getBit();
v->tfcntrflag = gb->getBit();
v->finterpflag = gb->getBit();
gb->skip(1); // reserved
v->psf = gb->getBit();
if (v->psf) { // PsF, 6.1.13
warning("Progressive Segmented Frame mode: not supported (yet)\n");
return -1;
}
v->max_b_frames = 7;
if (gb->getBit()) { // Display Info - decoding is not affected by it
int w, h, ar = 0;
w = gb->getBits(14) + 1;
h = gb->getBits(14) + 1;
if (gb->getBit())
ar = gb->getBits(4);
if (ar && ar < 14) {
v->sample_aspect_ratio = ff_vc1_pixel_aspect[ar];
} else if (ar == 15) {
w = gb->getBits(8) + 1;
h = gb->getBits(8) + 1;
v->sample_aspect_ratio = VC1Ratio(w, h);
} else {
if (v->width > v->max_coded_width || v->height > v->max_coded_height) {
warning("VC-1: Huge resolution");
} else
reduceAspect(v->sample_aspect_ratio, v->height * w, v->width * h);
}
validateAspect(v);
if (gb->getBit()) { // framerate stuff
if (gb->getBit()) {
v->framerate.den = 32;
v->framerate.num = gb->getBits(16) + 1;
} else {
int nr, dr;
nr = gb->getBits(8);
dr = gb->getBits(4);
if (nr > 0 && nr < 8 && dr > 0 && dr < 3) {
v->framerate.den = ff_vc1_fps_dr[dr - 1];
v->framerate.num = ff_vc1_fps_nr[nr - 1] * 1000;
}
}
}
if (gb->getBit()) {
v->color_prim = gb->getBits(8);
v->transfer_char = gb->getBits(8);
v->matrix_coef = gb->getBits(8);
}
}
v->hrd_param_flag = gb->getBit();
if (v->hrd_param_flag) {
int i;
v->hrd_num_leaky_buckets = gb->getBits(5);
gb->skip(4); // bitrate exponent
gb->skip(4); // buffer size exponent
for (i = 0; i < v->hrd_num_leaky_buckets; i++) {
gb->skip(16); // hrd_rate[n]
gb->skip(16); // hrd_buffer[n]
}
}
return gb->pos() <= gb->size() ? 0 : -1;
}
int readVC1Entry(VC1Header *v, Common::BitStream8MSB *gb) {
int i;
int w, h;
int ret;
v->broken_link = gb->getBit();
v->closed_entry = gb->getBit();
v->panscanflag = gb->getBit();
v->refdist_flag = gb->getBit();
v->loop_filter = gb->getBit();
v->fastuvmc = gb->getBit();
v->extended_mv = gb->getBit();
v->dquant = gb->getBits(2);
v->vstransform = gb->getBit();
v->overlap = gb->getBit();
v->quantizer_mode = gb->getBits(2);
if (v->hrd_param_flag) {
for (i = 0; i < v->hrd_num_leaky_buckets; i++) {
gb->skip(8); // hrd_full[n]
}
}
if (gb->getBit()) {
w = (gb->getBits(12) + 1) << 1;
h = (gb->getBits(12) + 1) << 1;
} else {
w = v->max_coded_width;
h = v->max_coded_height;
}
if ((ret = setDimensions(v, w, h)) < 0) {
warning("Failed to set dimensions %d %d\n", w, h);
return ret;
}
if (v->extended_mv)
v->extended_dmv = gb->getBit();
if ((v->range_mapy_flag = gb->getBit())) {
warning("Luma scaling is not supported, expect wrong picture\n");
v->range_mapy = gb->getBits(3);
}
if ((v->range_mapuv_flag = gb->getBit())) {
warning("Chroma scaling is not supported, expect wrong picture\n");
v->range_mapuv = gb->getBits(3);
}
return gb->pos() <= gb->size() ? 0 : -1;
}
enum { IMODE_RAW, IMODE_NORM2, IMODE_DIFF2, IMODE_NORM6, IMODE_DIFF6, IMODE_ROWSKIP, IMODE_COLSKIP };
/* BitPlane IMODE - such a small table... */
static const uint32 vc1_imode_codes[7] = {0, 2, 1, 3, 1, 2, 3};
static const uint8 vc1_imode_bits[7] = {4, 2, 3, 2, 4, 3, 3};
/* Normal-2 imode */
static const uint32 vc1_norm2_codes[4] = {0, 4, 5, 3};
static const uint8 vc1_norm2_bits[4] = {1, 3, 3, 2};
static const uint32 vc1_norm6_codes[64] = {
0x001, 0x002, 0x003, 0x000, 0x004, 0x001, 0x002, 0x047, 0x005, 0x003, 0x004, 0x04B, 0x005, 0x04D, 0x04E, 0x30E,
0x006, 0x006, 0x007, 0x053, 0x008, 0x055, 0x056, 0x30D, 0x009, 0x059, 0x05A, 0x30C, 0x05C, 0x30B, 0x30A, 0x037,
0x007, 0x00A, 0x00B, 0x043, 0x00C, 0x045, 0x046, 0x309, 0x00D, 0x049, 0x04A, 0x308, 0x04C, 0x307, 0x306, 0x036,
0x00E, 0x051, 0x052, 0x305, 0x054, 0x304, 0x303, 0x035, 0x058, 0x302, 0x301, 0x034, 0x300, 0x033, 0x032, 0x007,
};
static const uint8 vc1_norm6_bits[64] = {
1, 4, 4, 8, 4, 8, 8, 10, 4, 8, 8, 10, 8, 10, 10, 13, 4, 8, 8, 10, 8, 10,
10, 13, 8, 10, 10, 13, 10, 13, 13, 9, 4, 8, 8, 10, 8, 10, 10, 13, 8, 10, 10, 13,
10, 13, 13, 9, 8, 10, 10, 13, 10, 13, 13, 9, 10, 13, 13, 9, 13, 9, 9, 6,
};
static void initCodes(uint16 *table, uint maxBits, const uint32 *codes, const uint8 *lengths, uint count) {
for (uint i = 0; i < (1U << maxBits); ++i)
table[i] = 0xffff;
for (uint i = 0; i < count; ++i) {
uint shift = maxBits - lengths[i];
uint start = codes[i] << shift;
for (uint j = 0; j < (1U << shift); ++j)
table[start + j] = (i << 4) | lengths[i];
}
}
static int readCode(Common::BitStream8MSB &bits, const uint16 *table, uint maxBits) {
uint16 entry = table[bits.peekBits(maxBits)];
if (entry == 0xffff)
return -1;
bits.skip(entry & 15);
if (bits.pos() > bits.size())
return -1;
return entry >> 4;
}
// Bitplane decoding
VC1Bitplane::VC1Bitplane() {
initCodes(_imode, 4, vc1_imode_codes, vc1_imode_bits, 7);
initCodes(_norm2, 3, vc1_norm2_codes, vc1_norm2_bits, 4);
initCodes(_norm6, 13, vc1_norm6_codes, vc1_norm6_bits, 64);
}
static void decode_rowskip(uint8 *plane, int width, int height, int stride, Common::BitStream8MSB *gb) {
int x, y;
for (y = 0; y < height; y++) {
if (!gb->getBit()) // rowskip
memset(plane, 0, width);
else
for (x = 0; x < width; x++)
plane[x] = gb->getBit();
plane += stride;
}
}
/** Decode columns by checking if they are skipped
* @param plane Buffer to store decoded bits
* @param[in] width Width of this buffer
* @param[in] height Height of this buffer
* @param[in] stride of this buffer
* @todo FIXME: Optimize
*/
static void decode_colskip(uint8 *plane, int width, int height, int stride, Common::BitStream8MSB *gb) {
int x, y;
for (x = 0; x < width; x++) {
if (!gb->getBit()) // colskip
for (y = 0; y < height; y++)
plane[y * stride] = 0;
else
for (y = 0; y < height; y++)
plane[y * stride] = gb->getBit();
plane++;
}
}
/** Decode a bitplane's bits
* @param data bitplane where to store the decode bits
* @param[out] raw_flag pointer to the flag indicating that this bitplane is not coded explicitly
* @param gb Bit stream containing the coded bitplane
* @return Status
* @todo FIXME: Optimize
*/
int VC1Bitplane::decode(uint8 *data, int *raw_flag, int width, int height, int stride,
Common::BitStream8MSB *gb) const {
if (!data || !raw_flag || width <= 0 || height <= 0 || stride < width)
return -1;
int imode, x, y, code, offset;
uint8 invert, *planep = data;
invert = gb->getBit();
imode = readCode(*gb, _imode, 4);
if (imode < 0)
return -1;
*raw_flag = 0;
switch (imode) {
case IMODE_RAW:
// Data is actually read in the MB layer (same for all tests == "raw")
*raw_flag = 1; // invert ignored
return gb->pos() <= gb->size() ? invert : -1;
case IMODE_DIFF2:
case IMODE_NORM2:
if ((height * width) & 1) {
*planep++ = gb->getBit();
y = offset = 1;
if (offset == width) {
offset = 0;
planep += stride - width;
}
} else
y = offset = 0;
// decode bitplane as one long line
for (; y < height * width; y += 2) {
code = readCode(*gb, _norm2, 3);
if (code < 0)
return -1;
*planep++ = code & 1;
offset++;
if (offset == width) {
offset = 0;
planep += stride - width;
}
*planep++ = code >> 1;
offset++;
if (offset == width) {
offset = 0;
planep += stride - width;
}
}
break;
case IMODE_DIFF6:
case IMODE_NORM6:
if (!(height % 3) && (width % 3)) { // use 2x3 decoding
for (y = 0; y < height; y += 3) {
for (x = width & 1; x < width; x += 2) {
code = readCode(*gb, _norm6, 13);
if (code < 0) {
return -1;
}
planep[x + 0] = (code >> 0) & 1;
planep[x + 1] = (code >> 1) & 1;
planep[x + 0 + stride] = (code >> 2) & 1;
planep[x + 1 + stride] = (code >> 3) & 1;
planep[x + 0 + stride * 2] = (code >> 4) & 1;
planep[x + 1 + stride * 2] = (code >> 5) & 1;
}
planep += stride * 3;
}
if (width & 1)
decode_colskip(data, 1, height, stride, gb);
} else { // 3x2
planep += (height & 1) * stride;
for (y = height & 1; y < height; y += 2) {
for (x = width % 3; x < width; x += 3) {
code = readCode(*gb, _norm6, 13);
if (code < 0) {
return -1;
}
planep[x + 0] = (code >> 0) & 1;
planep[x + 1] = (code >> 1) & 1;
planep[x + 2] = (code >> 2) & 1;
planep[x + 0 + stride] = (code >> 3) & 1;
planep[x + 1 + stride] = (code >> 4) & 1;
planep[x + 2 + stride] = (code >> 5) & 1;
}
planep += stride * 2;
}
x = width % 3;
if (x)
decode_colskip(data, x, height, stride, gb);
if (height & 1)
decode_rowskip(data + x, width - x, 1, stride, gb);
}
break;
case IMODE_ROWSKIP:
decode_rowskip(data, width, height, stride, gb);
break;
case IMODE_COLSKIP:
decode_colskip(data, width, height, stride, gb);
break;
default:
break;
}
/* Applying diff operator */
if (imode == IMODE_DIFF2 || imode == IMODE_DIFF6) {
planep = data;
planep[0] ^= invert;
for (x = 1; x < width; x++)
planep[x] ^= planep[x - 1];
for (y = 1; y < height; y++) {
planep += stride;
planep[0] ^= planep[-stride];
for (x = 1; x < width; x++) {
if (planep[x - 1] != planep[x - stride])
planep[x] ^= invert;
else
planep[x] ^= planep[x - 1];
}
}
} else if (invert) {
planep = data;
for (x = 0; x < stride * height; x++)
planep[x] = !planep[x]; // FIXME stride
}
return gb->pos() <= gb->size() ? (imode << 1) + invert : -1;
}
namespace VC1 {
const VLC *ff_msmp4_mb_i_vlc;
const VLC *ff_msmp4_dc_vlc[2][2];
/** Table for conversion between TTBLK and TTMB */
const int ff_vc1_ttblk_to_tt[3][8] = {
{TT_8X4, TT_4X8, TT_8X8, TT_4X4, TT_8X4_TOP, TT_8X4_BOTTOM, TT_4X8_RIGHT, TT_4X8_LEFT},
{TT_8X8, TT_4X8_RIGHT, TT_4X8_LEFT, TT_4X4, TT_8X4, TT_4X8, TT_8X4_BOTTOM, TT_8X4_TOP},
{TT_8X8, TT_4X8, TT_4X4, TT_8X4_BOTTOM, TT_4X8_RIGHT, TT_4X8_LEFT, TT_8X4, TT_8X4_TOP}};
const int ff_vc1_ttfrm_to_tt[4] = {TT_8X8, TT_8X4, TT_4X8, TT_4X4};
/** MV P mode - the 5th element is only used for mode 1 */
const uint8 ff_vc1_mv_pmode_table[2][5] = {
{MV_PMODE_1MV_HPEL_BILIN, MV_PMODE_1MV, MV_PMODE_1MV_HPEL, MV_PMODE_INTENSITY_COMP, MV_PMODE_MIXED_MV},
{MV_PMODE_1MV, MV_PMODE_MIXED_MV, MV_PMODE_1MV_HPEL, MV_PMODE_INTENSITY_COMP, MV_PMODE_1MV_HPEL_BILIN}};
const uint8 ff_vc1_mv_pmode_table2[2][4] = {
{MV_PMODE_1MV_HPEL_BILIN, MV_PMODE_1MV, MV_PMODE_1MV_HPEL, MV_PMODE_MIXED_MV},
{MV_PMODE_1MV, MV_PMODE_MIXED_MV, MV_PMODE_1MV_HPEL, MV_PMODE_1MV_HPEL_BILIN}};
/* MBMODE table for interlaced frame P-picture */
const uint8 ff_vc1_mbmode_intfrp[2][15][4] = {{/* 1: 4-MV, 0: non-4-MV */
/* Type, FIELDTX, 1-MV Differential present, Residuals (CBP) present */
/* Table 164 - Table 167 */
{MV_PMODE_INTFR_1MV, 0, 1, 1},
{MV_PMODE_INTFR_1MV, 1, 1, 1},
{MV_PMODE_INTFR_1MV, 0, 1, 0},
{MV_PMODE_INTFR_1MV, 0, 0, 1},
{MV_PMODE_INTFR_1MV, 1, 0, 1},
{MV_PMODE_INTFR_2MV_FIELD, 0, 0, 1},
{MV_PMODE_INTFR_2MV_FIELD, 1, 0, 1},
{MV_PMODE_INTFR_2MV_FIELD, 1, 0, 0},
{MV_PMODE_INTFR_INTRA, 0, 0, 0}},
{/* Table 160 - Table 163 */
{MV_PMODE_INTFR_1MV, 0, 1, 1},
{MV_PMODE_INTFR_1MV, 1, 1, 1},
{MV_PMODE_INTFR_1MV, 0, 1, 0},
{MV_PMODE_INTFR_1MV, 0, 0, 1},
{MV_PMODE_INTFR_1MV, 1, 0, 1},
{MV_PMODE_INTFR_2MV_FIELD, 0, 0, 1},
{MV_PMODE_INTFR_2MV_FIELD, 1, 0, 1},
{MV_PMODE_INTFR_2MV_FIELD, 1, 0, 0},
{MV_PMODE_INTFR_4MV, 0, 0, 1},
{MV_PMODE_INTFR_4MV, 1, 0, 1},
{MV_PMODE_INTFR_4MV, 0, 0, 0},
{MV_PMODE_INTFR_4MV_FIELD, 0, 0, 1},
{MV_PMODE_INTFR_4MV_FIELD, 1, 0, 1},
{MV_PMODE_INTFR_4MV_FIELD, 1, 0, 0},
{MV_PMODE_INTFR_INTRA, 0, 0, 0}}};
const int ff_vc1_fps_nr[7] = {24, 25, 30, 50, 60, 48, 72}, ff_vc1_fps_dr[2] = {1000, 1001};
const uint8 ff_vc1_pquant_table[3][32] = {
/* Implicit quantizer */
{0, 1, 2, 3, 4, 5, 6, 7, 8, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 29, 31},
/* Explicit quantizer, pquantizer uniform */
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
/* Explicit quantizer, pquantizer non-uniform */
{0, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 31}};
/** @name VC-1 VLC tables
* @todo TODO move this into the context
*/
//@{
const VLC *ff_vc1_imode_vlc;
const VLC *ff_vc1_norm2_vlc;
const VLC *ff_vc1_norm6_vlc;
const VLC *ff_vc1_ttmb_vlc[3];
const VLC *ff_vc1_mv_diff_vlc[4];
const VLC *ff_vc1_cbpcy_p_vlc[4];
const VLC *ff_vc1_icbpcy_vlc[8];
const VLC *ff_vc1_4mv_block_pattern_vlc[4];
const VLC *ff_vc1_2mv_block_pattern_vlc[4];
const VLC *ff_vc1_ttblk_vlc[3];
const VLC *ff_vc1_subblkpat_vlc[3];
const VLC *ff_vc1_intfr_4mv_mbmode_vlc[4];
const VLC *ff_vc1_intfr_non4mv_mbmode_vlc[4];
const VLC *ff_vc1_if_mmv_mbmode_vlc[8];
const VLC *ff_vc1_if_1mv_mbmode_vlc[8];
const VLC *ff_vc1_1ref_mvdata_vlc[4];
const VLC *ff_vc1_2ref_mvdata_vlc[8];
const VLC *ff_vc1_ac_coeff_table[8];
//@}
#if B_FRACTION_DEN == 840 // original bfraction from vc9data.h, not conforming to standard
/* bfraction is fractional, we scale to the GCD 3*5*7*8 = 840 */
const int16 ff_vc1_bfraction_lut[23] = {
420 /*1/2*/,
280 /*1/3*/,
560 /*2/3*/,
210 /*1/4*/,
630 /*3/4*/,
168 /*1/5*/,
336 /*2/5*/,
504 /*3/5*/,
672 /*4/5*/,
140 /*1/6*/,
700 /*5/6*/,
120 /*1/7*/,
240 /*2/7*/,
360 /*3/7*/,
480 /*4/7*/,
600 /*5/7*/,
720 /*6/7*/,
105 /*1/8*/,
315 /*3/8*/,
525 /*5/8*/,
735 /*7/8*/,
-1 /*inv.*/,
0 /*BI fm*/
};
#else
/* pre-computed scales for all bfractions and base=256 */
const int16 ff_vc1_bfraction_lut[23] = {
128 /*1/2*/,
85 /*1/3*/,
170 /*2/3*/,
64 /*1/4*/,
192 /*3/4*/,
51 /*1/5*/,
102 /*2/5*/,
153 /*3/5*/,
204 /*4/5*/,
43 /*1/6*/,
215 /*5/6*/,
37 /*1/7*/,
74 /*2/7*/,
111 /*3/7*/,
148 /*4/7*/,
185 /*5/7*/,
222 /*6/7*/,
32 /*1/8*/,
96 /*3/8*/,
160 /*5/8*/,
224 /*7/8*/,
-1 /*inv.*/,
0 /*BI fm*/
};
#endif
// Same as H.264
const VC1Ratio ff_vc1_pixel_aspect[16] = {{0, 1}, {1, 1}, {12, 11}, {10, 11}, {16, 11}, {40, 33},
{24, 11}, {20, 11}, {32, 11}, {80, 33}, {18, 11}, {15, 11},
{64, 33}, {160, 99}, {0, 1}, {0, 1}};
const uint8 ff_wmv3_dc_scale_table[32] = {0, 2, 4, 8, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21};
/* DC differentials low+hi-mo, p217 are the same as in msmpeg4data .h */
/* Table 232 */
const uint8 ff_vc1_simple_progressive_4x4_zz[16] = {0, 8, 16, 1, 9, 24, 17, 2, 10, 18, 25, 3, 11, 26, 19, 27};
const uint8 ff_vc1_adv_progressive_8x4_zz[32] = {/* Table 233 */
0, 8, 1, 16, 2, 9, 10, 3, 24, 17, 4, 11, 18, 12, 5, 19,
25, 13, 20, 26, 27, 6, 21, 28, 14, 22, 29, 7, 30, 15, 23, 31};
const uint8 ff_vc1_adv_progressive_4x8_zz[32] = {/* Table 234 */
0, 1, 8, 2, 9, 16, 17, 24, 10, 32, 25, 18, 40, 3, 33, 26,
48, 11, 56, 41, 34, 49, 57, 42, 19, 50, 27, 58, 35, 43, 51, 59};
const uint8 ff_vc1_adv_interlaced_8x8_zz[64] = {/* Table 235 */
0, 8, 1, 16, 24, 9, 2, 32, 40, 48, 56, 17, 10, 3, 25, 18,
11, 4, 33, 41, 49, 57, 26, 34, 42, 50, 58, 19, 12, 5, 27, 20,
13, 6, 35, 28, 21, 14, 7, 15, 22, 29, 36, 43, 51, 59, 60, 52,
44, 37, 30, 23, 31, 38, 45, 53, 61, 62, 54, 46, 39, 47, 55, 63};
const uint8 ff_vc1_adv_interlaced_8x4_zz[32] = {/* Table 236 */
0, 8, 16, 24, 1, 9, 2, 17, 25, 10, 3, 18, 26, 4, 11, 19,
12, 5, 13, 20, 27, 6, 21, 28, 14, 22, 29, 7, 30, 15, 23, 31};
const uint8 ff_vc1_adv_interlaced_4x8_zz[32] = {/* Table 237 */
0, 1, 2, 8, 16, 9, 24, 17, 10, 3, 32, 40, 48, 56, 25, 18,
33, 26, 41, 34, 49, 57, 11, 42, 19, 50, 27, 58, 35, 43, 51, 59};
const uint8 ff_vc1_adv_interlaced_4x4_zz[16] = {/* Table 238 */
0, 8, 16, 24, 1, 9, 17, 2, 25, 10, 18, 3, 26, 11, 19, 27};
/* DQScale as specified in 8.1.3.9 - almost identical to 0x40000/i */
const int32 ff_vc1_dqscale[63] = {
0x40000, 0x20000, 0x15555, 0x10000, 0xCCCD, 0xAAAB, 0x9249, 0x8000, 0x71C7, 0x6666, 0x5D17, 0x5555, 0x4EC5,
0x4925, 0x4444, 0x4000, 0x3C3C, 0x38E4, 0x35E5, 0x3333, 0x30C3, 0x2E8C, 0x2C86, 0x2AAB, 0x28F6, 0x2762,
0x25ED, 0x2492, 0x234F, 0x2222, 0x2108, 0x2000, 0x1F08, 0x1E1E, 0x1D42, 0x1C72, 0x1BAD, 0x1AF3, 0x1A42,
0x199A, 0x18FA, 0x1862, 0x17D0, 0x1746, 0x16C1, 0x1643, 0x15CA, 0x1555, 0x14E6, 0x147B, 0x1414, 0x13B1,
0x1352, 0x12F7, 0x129E, 0x1249, 0x11F7, 0x11A8, 0x115B, 0x1111, 0x10C9, 0x1084, 0x1041};
/* P Interlaced field picture MV predictor scaling values (Table 114) */
const uint16 ff_vc1_field_mvpred_scales[2][7][4] = {
// Refdist:
// 0 1 2 3 or greater
{
// current field is first
{128, 192, 213, 224}, // SCALEOPP
{512, 341, 307, 293}, // SCALESAME1
{219, 236, 242, 245}, // SCALESAME2
{32, 48, 53, 56}, // SCALEZONE1_X
{8, 12, 13, 14}, // SCALEZONE1_Y
{37, 20, 14, 11}, // ZONE1OFFSET_X
{10, 5, 4, 3} // ZONE1OFFSET_Y
},
{
// current field is second
{128, 64, 43, 32}, // SCALEOPP
{512, 1024, 1536, 2048}, // SCALESAME1
{219, 204, 200, 198}, // SCALESAME2
{32, 16, 11, 8}, // SCALEZONE1_X
{8, 4, 3, 2}, // SCALEZONE1_Y
{37, 52, 56, 58}, // ZONE1OFFSET_X
{10, 13, 14, 15} // ZONE1OFFSET_Y
}};
/* B Interlaced field picture backward MV predictor scaling values for first field (Table 115) */
const uint16 ff_vc1_b_field_mvpred_scales[7][4] = {
// BRFD:
// 0 1 2 3 or greater
{171, 205, 219, 228}, // SCALESAME
{384, 320, 299, 288}, // SCALEOPP1
{230, 239, 244, 246}, // SCALEOPP2
{43, 51, 55, 57}, // SCALEZONE1_X
{11, 13, 14, 14}, // SCALEZONE1_Y
{26, 17, 12, 10}, // ZONE1OFFSET_X
{7, 4, 3, 3} // ZONE1OFFSET_Y
};
const uint8 ff_wmv1_scantable[WMV1_SCANTABLE_COUNT][64] = {
{
0x00, 0x08, 0x01, 0x02, 0x09, 0x10, 0x18, 0x11, 0x0A, 0x03, 0x04, 0x0B, 0x12, 0x19, 0x20, 0x28,
0x30, 0x38, 0x29, 0x21, 0x1A, 0x13, 0x0C, 0x05, 0x06, 0x0D, 0x14, 0x1B, 0x22, 0x31, 0x39, 0x3A,
0x32, 0x2A, 0x23, 0x1C, 0x15, 0x0E, 0x07, 0x0F, 0x16, 0x1D, 0x24, 0x2B, 0x33, 0x3B, 0x3C, 0x34,
0x2C, 0x25, 0x1E, 0x17, 0x1F, 0x26, 0x2D, 0x35, 0x3D, 0x3E, 0x36, 0x2E, 0x27, 0x2F, 0x37, 0x3F,
},
{
0x00, 0x08, 0x01, 0x02, 0x09, 0x10, 0x18, 0x11, 0x0A, 0x03, 0x04, 0x0B, 0x12, 0x19, 0x20, 0x28,
0x21, 0x30, 0x1A, 0x13, 0x0C, 0x05, 0x06, 0x0D, 0x14, 0x1B, 0x22, 0x29, 0x38, 0x31, 0x39, 0x2A,
0x23, 0x1C, 0x15, 0x0E, 0x07, 0x0F, 0x16, 0x1D, 0x24, 0x2B, 0x32, 0x3A, 0x33, 0x3B, 0x2C, 0x25,
0x1E, 0x17, 0x1F, 0x26, 0x2D, 0x34, 0x3C, 0x35, 0x3D, 0x2E, 0x27, 0x2F, 0x36, 0x3E, 0x37, 0x3F,
},
{
0x00, 0x01, 0x08, 0x02, 0x03, 0x09, 0x10, 0x18, 0x11, 0x0A, 0x04, 0x05, 0x0B, 0x12, 0x19, 0x20,
0x28, 0x30, 0x21, 0x1A, 0x13, 0x0C, 0x06, 0x07, 0x0D, 0x14, 0x1B, 0x22, 0x29, 0x38, 0x31, 0x39,
0x2A, 0x23, 0x1C, 0x15, 0x0E, 0x0F, 0x16, 0x1D, 0x24, 0x2B, 0x32, 0x3A, 0x33, 0x2C, 0x25, 0x1E,
0x17, 0x1F, 0x26, 0x2D, 0x34, 0x3B, 0x3C, 0x35, 0x2E, 0x27, 0x2F, 0x36, 0x3D, 0x3E, 0x37, 0x3F,
},
{
0x00, 0x08, 0x10, 0x01, 0x18, 0x20, 0x28, 0x09, 0x02, 0x03, 0x0A, 0x11, 0x19, 0x30, 0x38, 0x29,
0x21, 0x1A, 0x12, 0x0B, 0x04, 0x05, 0x0C, 0x13, 0x1B, 0x22, 0x31, 0x39, 0x32, 0x2A, 0x23, 0x1C,
0x14, 0x0D, 0x06, 0x07, 0x0E, 0x15, 0x1D, 0x24, 0x2B, 0x33, 0x3A, 0x3B, 0x34, 0x2C, 0x25, 0x1E,
0x16, 0x0F, 0x17, 0x1F, 0x26, 0x2D, 0x3C, 0x35, 0x2E, 0x27, 0x2F, 0x36, 0x3D, 0x3E, 0x37, 0x3F,
}};
// VLC table initialization
void initTables() {
ff_vc1_norm2_vlc = makeVLC(4, vc1_norm2_bits, 1, 1, vc1_norm2_codes, 1, 1);
ff_vc1_norm6_vlc = makeVLC(64, vc1_norm6_bits, 1, 1, vc1_norm6_codes, 2, 2);
ff_vc1_imode_vlc = makeVLC(7, vc1_imode_bits, 1, 1, vc1_imode_codes, 1, 1);
for (int i = 0; i < 3; i++) {
ff_vc1_ttmb_vlc[i] = makeVLC(16, vc1_ttmb_bits[i], 1, 1, vc1_ttmb_codes[i], 2, 2);
ff_vc1_ttblk_vlc[i] = makeVLC(8, vc1_ttblk_bits[i], 1, 1, vc1_ttblk_codes[i], 1, 1);
ff_vc1_subblkpat_vlc[i] = makeVLC(15, vc1_subblkpat_bits[i], 1, 1, vc1_subblkpat_codes[i], 1, 1);
}
for (int i = 0; i < 4; i++) {
ff_vc1_4mv_block_pattern_vlc[i] =
makeVLC(16, vc1_4mv_block_pattern_bits[i], 1, 1, vc1_4mv_block_pattern_codes[i], 1, 1);
ff_vc1_cbpcy_p_vlc[i] = makeVLC(64, vc1_cbpcy_p_bits[i], 1, 1, vc1_cbpcy_p_codes[i], 2, 2);
ff_vc1_mv_diff_vlc[i] = makeVLC(73, vc1_mv_diff_bits[i], 1, 1, vc1_mv_diff_codes[i], 2, 2);
/* initialize 4MV MBMODE VLC tables for interlaced frame P picture */
ff_vc1_intfr_4mv_mbmode_vlc[i] =
makeVLC(15, vc1_intfr_4mv_mbmode_bits[i], 1, 1, vc1_intfr_4mv_mbmode_codes[i], 2, 2);
/* initialize NON-4MV MBMODE VLC tables for the same */
ff_vc1_intfr_non4mv_mbmode_vlc[i] =
makeVLC(9, vc1_intfr_non4mv_mbmode_bits[i], 1, 1, vc1_intfr_non4mv_mbmode_codes[i], 1, 1);
/* initialize interlaced MVDATA tables (1-Ref) */
ff_vc1_1ref_mvdata_vlc[i] = makeVLC(72, vc1_1ref_mvdata_bits[i], 1, 1, vc1_1ref_mvdata_codes[i], 4, 4);
/* Initialize 2MV Block pattern VLC tables */
ff_vc1_2mv_block_pattern_vlc[i] =
makeVLC(4, vc1_2mv_block_pattern_bits[i], 1, 1, vc1_2mv_block_pattern_codes[i], 1, 1);
}
for (int i = 0; i < 8; i++) {
ff_vc1_ac_coeff_table[i] =
makeVLC(ff_vc1_ac_sizes[i], &vc1_ac_tables[i][0][1], 8, 4, &vc1_ac_tables[i][0][0], 8, 4);
/* initialize interlaced MVDATA tables (2-Ref) */
ff_vc1_2ref_mvdata_vlc[i] = makeVLC(126, vc1_2ref_mvdata_bits[i], 1, 1, vc1_2ref_mvdata_codes[i], 4, 4);
/* Initialize interlaced CBPCY VLC tables (Table 124 - Table 131) */
ff_vc1_icbpcy_vlc[i] = makeVLC(63, vc1_icbpcy_p_bits[i], 1, 1, vc1_icbpcy_p_codes[i], 2, 2);
/* Initialize interlaced field picture MBMODE VLC tables */
ff_vc1_if_mmv_mbmode_vlc[i] = makeVLC(8, vc1_if_mmv_mbmode_bits[i], 1, 1, vc1_if_mmv_mbmode_codes[i], 1, 1);
ff_vc1_if_1mv_mbmode_vlc[i] = makeVLC(6, vc1_if_1mv_mbmode_bits[i], 1, 1, vc1_if_1mv_mbmode_codes[i], 1, 1);
}
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
ff_msmp4_dc_vlc[i][j] =
makeVLC(120, &ff_msmp4_dc_tables[i][j][0][1], 8, 4, &ff_msmp4_dc_tables[i][j][0][0], 8, 4);
ff_msmp4_mb_i_vlc = makeVLC(64, &ff_msmp4_mb_i_table[0][1], 4, 2, &ff_msmp4_mb_i_table[0][0], 4, 2);
}
// Scalar reconstruction helpers
static uint32 tableValue(const void *p, int size) {
if (size == 1)
return *(const uint8 *)p;
if (size == 2)
return READ_UINT16(p);
return READ_UINT32(p);
}
const VLC *makeVLC(int count, const void *lengths, int ls, int lz, const void *codes, int cs, int cz) {
VLC *v = new VLC;
v->nodes.push_back(VLC::Node());
for (int i = 0; i < count; ++i) {
int length = tableValue((const uint8 *)lengths + i * ls, lz);
if (!length)
continue;
uint32 code = tableValue((const uint8 *)codes + i * cs, cz);
int at = 0;
for (int k = length - 1; k >= 0; --k) {
int bit = (code >> k) & 1;
int next = v->nodes[at].child[bit];
if (next < 0) {
next = v->nodes.size();
v->nodes[at].child[bit] = next;
v->nodes.push_back(VLC::Node());
}
at = next;
}
assert(v->nodes[at].symbol == -1);
v->nodes[at].symbol = i;
}
return v;
}
int get_vlc2(Bits *b, const VLC *v) {
int at = 0;
if (!v)
return -1;
for (int k = 0; k < 32; ++k) {
if (v->nodes[at].symbol >= 0)
return v->nodes[at].symbol;
if (get_bits_left(b) <= 0)
return -1;
at = v->nodes[at].child[get_bits1(b)];
if (at < 0)
return -1;
}
return -1;
}
static void clearBlock(int16 *p) {
memset(p, 0, 64 * sizeof(*p));
}
static void clearBlocks(int16 *p) {
memset(p, 0, 6 * 64 * sizeof(*p));
}
template<int mode> static void clampBlock(const int16 *b, uint8 *d, ptrdiff_t stride) {
for (int y = 0; y < 8; ++y) {
for (int x = 0; x < 8; ++x)
d[x] = av_clip_uint8(b[y * 8 + x] + (mode == 1 ? 128 : mode == 2 ? d[x] : 0));
d += stride;
}
}
template<int width, int xy, bool round, bool average>
static void halfPixels(uint8 *d, const uint8 *s, ptrdiff_t stride, int h) {
putHalfPixels<width>(d, s, stride, h, xy, !round, average);
}
template<int width, bool average>
static void chromaPixels(uint8 *d, const uint8 *s, ptrdiff_t stride, int h, int x, int y) {
int a = (8 - x) * (8 - y), b = x * (8 - y), c = (8 - x) * y, e = x * y;
for (int row = 0; row < h; ++row) {
for (int col = 0; col < width; ++col) {
int value = (a * s[col] + b * s[col + 1] + c * s[col + stride] + e * s[col + stride + 1] + 32) >> 6;
d[col] = average ? (d[col] + value + 1) >> 1 : value;
}
d += stride;
s += stride;
}
}
static void edgePixels(uint8 *dst, const uint8 *src, ptrdiff_t ds, ptrdiff_t ss, int bw, int bh, int x, int y, int w,
int h) {
for (int row = 0; row < bh; ++row) {
int sy = CLIP(y + row, 0, h - 1) - y;
for (int col = 0; col < bw; ++col)
dst[col] = src[sy * ss + CLIP(x + col, 0, w - 1) - x];
dst += ds;
}
}
void initSupport(PictureState *s, ChromaDSP *c) {
s->bdsp.clear_block = clearBlock;
s->bdsp.clear_blocks = clearBlocks;
s->idsp.put_pixels_clamped = clampBlock<0>;
s->idsp.put_signed_pixels_clamped = clampBlock<1>;
s->idsp.add_pixels_clamped = clampBlock<2>;
s->vdsp.emulated_edge_mc = edgePixels;
#define H(w, i, xy) \
s->hdsp.put_pixels_tab[i][xy] = halfPixels<w, xy, true, false>; \
s->hdsp.put_no_rnd_pixels_tab[i][xy] = halfPixels<w, xy, false, false>; \
s->hdsp.avg_pixels_tab[i][xy] = halfPixels<w, xy, true, true>;
H(16, 0, 0)
H(16, 0, 1)
H(16, 0, 2)
H(16, 0, 3)
H(8, 1, 0)
H(8, 1, 1)
H(8, 1, 2)
H(8, 1, 3)
#undef H
s->hdsp.avg_no_rnd_pixels_tab[0] = halfPixels<16, 0, false, true>;
s->hdsp.avg_no_rnd_pixels_tab[1] = halfPixels<16, 1, false, true>;
s->hdsp.avg_no_rnd_pixels_tab[2] = halfPixels<16, 2, false, true>;
s->hdsp.avg_no_rnd_pixels_tab[3] = halfPixels<16, 3, false, true>;
c->put_h264_chroma_pixels_tab[0] = chromaPixels<8, false>;
c->put_h264_chroma_pixels_tab[1] = chromaPixels<4, false>;
c->put_h264_chroma_pixels_tab[2] = chromaPixels<2, false>;
c->avg_h264_chroma_pixels_tab[0] = chromaPixels<8, true>;
c->avg_h264_chroma_pixels_tab[1] = chromaPixels<4, true>;
c->avg_h264_chroma_pixels_tab[2] = chromaPixels<2, true>;
}
void ff_init_block_index(PictureState *s) {
const int linesize = s->cur_pic.linesize[0], uvlinesize = s->cur_pic.linesize[1];
s->block_index[0] = s->b8_stride * (s->mb_y * 2) - 2 + s->mb_x * 2;
s->block_index[1] = s->b8_stride * (s->mb_y * 2) - 1 + s->mb_x * 2;
s->block_index[2] = s->b8_stride * (s->mb_y * 2 + 1) - 2 + s->mb_x * 2;
s->block_index[3] = s->b8_stride * (s->mb_y * 2 + 1) - 1 + s->mb_x * 2;
s->block_index[4] = s->mb_stride * (s->mb_y + 1) + s->b8_stride * s->mb_height * 2 + s->mb_x - 1;
s->block_index[5] = s->mb_stride * (s->mb_y + s->mb_height + 2) + s->b8_stride * s->mb_height * 2 + s->mb_x - 1;
s->dest[0] = s->cur_pic.data[0] + (s->mb_x - 1) * 16 + s->mb_y * linesize * 16;
s->dest[1] = s->cur_pic.data[1] + (s->mb_x - 1) * 8 + s->mb_y * uvlinesize * 8;
s->dest[2] = s->cur_pic.data[2] + (s->mb_x - 1) * 8 + s->mb_y * uvlinesize * 8;
}
void ff_update_block_index(PictureState *s, int, int, int) {
for (int i = 0; i < 4; ++i)
s->block_index[i] += 2;
++s->block_index[4];
++s->block_index[5];
s->dest[0] += 16;
s->dest[1] += 8;
s->dest[2] += 8;
}
/**
* @file
* simpleidct in C.
*/
/* Based upon some commented-out C code from mpeg2dec (idct_mmx.c
* written by Aaron Holtzman <[email protected]>). */
static inline void idctRowCondDC_int16_8bit(int16 *row, int extra_shift) {
unsigned a0, a1, a2, a3, b0, b1, b2, b3;
// TODO: Add DC-only support for int32 input
if (!(READ_UINT32(row + 2) | READ_UINT32(row + 4) | READ_UINT32(row + 6) | row[1])) {
uint32 temp;
if (3 - extra_shift >= 0) {
temp = (row[0] * (1 << (3 - extra_shift))) & 0xffff;
} else {
temp = ((row[0] + (1 << (extra_shift - 3 - 1))) >> (extra_shift - 3)) & 0xffff;
}
temp += temp * (1 << 16);
WRITE_UINT32(row, temp);
WRITE_UINT32(row + 2, temp);
WRITE_UINT32(row + 4, temp);
WRITE_UINT32(row + 6, temp);
return;
}
a0 = ((unsigned)16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[0]) + (1 << (11 + extra_shift - 1));
a1 = a0;
a2 = a0;
a3 = a0;
a0 += (unsigned)21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[2];
a1 += (unsigned)8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[2];
a2 -= (unsigned)8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[2];
a3 -= (unsigned)21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[2];
b0 = ((22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[1]));
((b0) += (19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[3]));
b1 = ((19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[1]));
((b1) += (-4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[3]));
b2 = ((12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[1]));
((b2) += (-22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[3]));
b3 = ((4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[1]));
((b3) += (-12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[3]));
if (READ_UINT64(row + 4)) {
a0 += (unsigned)16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[4] +
(unsigned)8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[6];
a1 += (unsigned)-16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[4] -
(unsigned)21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[6];
a2 += (unsigned)-16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[4] +
(unsigned)21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[6];
a3 += (unsigned)16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[4] -
(unsigned)8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * row[6];
((b0) += (12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[5]));
((b0) += (4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[7]));
((b1) += (-22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[5]));
((b1) += (-12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[7]));
((b2) += (4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[5]));
((b2) += (19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[7]));
((b3) += (19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[5]));
((b3) += (-22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (row[7]));
}
row[0] = (int)(a0 + b0) >> (11 + extra_shift);
row[7] = (int)(a0 - b0) >> (11 + extra_shift);
row[1] = (int)(a1 + b1) >> (11 + extra_shift);
row[6] = (int)(a1 - b1) >> (11 + extra_shift);
row[2] = (int)(a2 + b2) >> (11 + extra_shift);
row[5] = (int)(a2 - b2) >> (11 + extra_shift);
row[3] = (int)(a3 + b3) >> (11 + extra_shift);
row[4] = (int)(a3 - b3) >> (11 + extra_shift);
}
static inline void idctSparseCol_int16_8bit(int16 *col) {
unsigned a0, a1, a2, a3, b0, b1, b2, b3;
do {
a0 = (unsigned)16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ *
(col[8 * 0] + ((1 << (20 - 1)) / 16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/));
a1 = a0;
a2 = a0;
a3 = a0;
a0 += (unsigned)21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 2];
a1 += (unsigned)8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 2];
a2 += (unsigned)-8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 2];
a3 += (unsigned)-21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 2];
b0 = ((22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 1]));
b1 = ((19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 1]));
b2 = ((12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 1]));
b3 = ((4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 1]));
((b0) += (19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 3]));
((b1) += (-4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 3]));
((b2) += (-22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 3]));
((b3) += (-12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 3]));
if (col[8 * 4]) {
a0 += (unsigned)16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 4];
a1 += (unsigned)-16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 4];
a2 += (unsigned)-16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 4];
a3 += (unsigned)16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 4];
}
if (col[8 * 5]) {
((b0) += (12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 5]));
((b1) += (-22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 5]));
((b2) += (4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 5]));
((b3) += (19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 5]));
}
if (col[8 * 6]) {
a0 += (unsigned)8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 6];
a1 += (unsigned)-21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 6];
a2 += (unsigned)21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 6];
a3 += (unsigned)-8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 6];
}
if (col[8 * 7]) {
((b0) += (4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 7]));
((b1) += (-12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 7]));
((b2) += (19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 7]));
((b3) += (-22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 7]));
}
} while (0);
col[0] = ((int)(a0 + b0) >> 20);
col[8] = ((int)(a1 + b1) >> 20);
col[16] = ((int)(a2 + b2) >> 20);
col[24] = ((int)(a3 + b3) >> 20);
col[32] = ((int)(a3 - b3) >> 20);
col[40] = ((int)(a2 - b2) >> 20);
col[48] = ((int)(a1 - b1) >> 20);
col[56] = ((int)(a0 - b0) >> 20);
}
static inline void idctSparseColPut_int16_8bit(uint8 *dest, ptrdiff_t line_size, int16 *col) {
unsigned a0, a1, a2, a3, b0, b1, b2, b3;
do {
a0 = (unsigned)16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ *
(col[8 * 0] + ((1 << (20 - 1)) / 16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/));
a1 = a0;
a2 = a0;
a3 = a0;
a0 += (unsigned)21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 2];
a1 += (unsigned)8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 2];
a2 += (unsigned)-8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 2];
a3 += (unsigned)-21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 2];
b0 = ((22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 1]));
b1 = ((19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 1]));
b2 = ((12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 1]));
b3 = ((4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 1]));
((b0) += (19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 3]));
((b1) += (-4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 3]));
((b2) += (-22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 3]));
((b3) += (-12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 3]));
if (col[8 * 4]) {
a0 += (unsigned)16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 4];
a1 += (unsigned)-16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 4];
a2 += (unsigned)-16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 4];
a3 += (unsigned)16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 4];
}
if (col[8 * 5]) {
((b0) += (12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 5]));
((b1) += (-22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 5]));
((b2) += (4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 5]));
((b3) += (19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 5]));
}
if (col[8 * 6]) {
a0 += (unsigned)8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 6];
a1 += (unsigned)-21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 6];
a2 += (unsigned)21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 6];
a3 += (unsigned)-8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 6];
}
if (col[8 * 7]) {
((b0) += (4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 7]));
((b1) += (-12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 7]));
((b2) += (19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 7]));
((b3) += (-22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 7]));
}
} while (0);
dest[0] = av_clip_uint8((int)(a0 + b0) >> 20);
dest += line_size;
dest[0] = av_clip_uint8((int)(a1 + b1) >> 20);
dest += line_size;
dest[0] = av_clip_uint8((int)(a2 + b2) >> 20);
dest += line_size;
dest[0] = av_clip_uint8((int)(a3 + b3) >> 20);
dest += line_size;
dest[0] = av_clip_uint8((int)(a3 - b3) >> 20);
dest += line_size;
dest[0] = av_clip_uint8((int)(a2 - b2) >> 20);
dest += line_size;
dest[0] = av_clip_uint8((int)(a1 - b1) >> 20);
dest += line_size;
dest[0] = av_clip_uint8((int)(a0 - b0) >> 20);
}
static inline void idctSparseColAdd_int16_8bit(uint8 *dest, ptrdiff_t line_size, int16 *col) {
unsigned a0, a1, a2, a3, b0, b1, b2, b3;
do {
a0 = (unsigned)16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ *
(col[8 * 0] + ((1 << (20 - 1)) / 16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/));
a1 = a0;
a2 = a0;
a3 = a0;
a0 += (unsigned)21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 2];
a1 += (unsigned)8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 2];
a2 += (unsigned)-8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 2];
a3 += (unsigned)-21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 2];
b0 = ((22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 1]));
b1 = ((19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 1]));
b2 = ((12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 1]));
b3 = ((4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 1]));
((b0) += (19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 3]));
((b1) += (-4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 3]));
((b2) += (-22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 3]));
((b3) += (-12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 3]));
if (col[8 * 4]) {
a0 += (unsigned)16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 4];
a1 += (unsigned)-16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 4];
a2 += (unsigned)-16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 4];
a3 += (unsigned)16383 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 4];
}
if (col[8 * 5]) {
((b0) += (12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 5]));
((b1) += (-22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 5]));
((b2) += (4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 5]));
((b3) += (19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 5]));
}
if (col[8 * 6]) {
a0 += (unsigned)8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 6];
a1 += (unsigned)-21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 6];
a2 += (unsigned)21407 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 6];
a3 += (unsigned)-8867 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/ * col[8 * 6];
}
if (col[8 * 7]) {
((b0) += (4520 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 7]));
((b1) += (-12873 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 7]));
((b2) += (19266 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 7]));
((b3) += (-22725 /*cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5*/) * (col[8 * 7]));
}
} while (0);
dest[0] = av_clip_uint8(dest[0] + ((int)(a0 + b0) >> 20));
dest += line_size;
dest[0] = av_clip_uint8(dest[0] + ((int)(a1 + b1) >> 20));
dest += line_size;
dest[0] = av_clip_uint8(dest[0] + ((int)(a2 + b2) >> 20));
dest += line_size;
dest[0] = av_clip_uint8(dest[0] + ((int)(a3 + b3) >> 20));
dest += line_size;
dest[0] = av_clip_uint8(dest[0] + ((int)(a3 - b3) >> 20));
dest += line_size;
dest[0] = av_clip_uint8(dest[0] + ((int)(a2 - b2) >> 20));
dest += line_size;
dest[0] = av_clip_uint8(dest[0] + ((int)(a1 - b1) >> 20));
dest += line_size;
dest[0] = av_clip_uint8(dest[0] + ((int)(a0 - b0) >> 20));
}
void ff_simple_idct_put_int16_8bit(uint8 *dest_, ptrdiff_t line_size, int16 *block_) {
int16 *block = (int16 *)block_;
uint8 *dest = (uint8 *)dest_;
int i;
line_size /= sizeof(uint8);
for (i = 0; i < 8; i++)
idctRowCondDC_int16_8bit(block + i * 8, 0);
for (i = 0; i < 8; i++)
idctSparseColPut_int16_8bit(dest + i, line_size, block + i);
}
void ff_simple_idct_add_int16_8bit(uint8 *dest_, ptrdiff_t line_size, int16 *block) {
uint8 *dest = (uint8 *)dest_;
int i;
line_size /= sizeof(uint8);
for (i = 0; i < 8; i++)
idctRowCondDC_int16_8bit(block + i * 8, 0);
for (i = 0; i < 8; i++)
idctSparseColAdd_int16_8bit(dest + i, line_size, block + i);
}
void ff_simple_idct_int16_8bit(int16 *block) {
int i;
for (i = 0; i < 8; i++)
idctRowCondDC_int16_8bit(block + i * 8, 0);
for (i = 0; i < 8; i++)
idctSparseCol_int16_8bit(block + i);
}
static inline void idct4col_add(uint8 *dest, ptrdiff_t line_size, const int16 *col) {
int c0, c1, c2, c3, a0, a1, a2, a3;
a0 = col[8 * 0];
a1 = col[8 * 1];
a2 = col[8 * 2];
a3 = col[8 * 3];
c0 = (a0 + a2) * ((int)((0.5) * M_SQRT2 * (1 << 12) + 0.5)) + (1 << ((4 + 1 + 12) - 1));
c2 = (a0 - a2) * ((int)((0.5) * M_SQRT2 * (1 << 12) + 0.5)) + (1 << ((4 + 1 + 12) - 1));
c1 = a1 * ((int)((0.6532814824) * M_SQRT2 * (1 << 12) + 0.5)) +
a3 * ((int)((0.2705980501) * M_SQRT2 * (1 << 12) + 0.5));
c3 = a1 * ((int)((0.2705980501) * M_SQRT2 * (1 << 12) + 0.5)) -
a3 * ((int)((0.6532814824) * M_SQRT2 * (1 << 12) + 0.5));
dest[0] = av_clip_uint8(dest[0] + ((c0 + c1) >> (4 + 1 + 12)));
dest += line_size;
dest[0] = av_clip_uint8(dest[0] + ((c2 + c3) >> (4 + 1 + 12)));
dest += line_size;
dest[0] = av_clip_uint8(dest[0] + ((c2 - c3) >> (4 + 1 + 12)));
dest += line_size;
dest[0] = av_clip_uint8(dest[0] + ((c0 - c1) >> (4 + 1 + 12)));
}
static inline void idct4row(int16 *row) {
unsigned c0, c1, c2, c3;
int a0, a1, a2, a3;
a0 = row[0];
a1 = row[1];
a2 = row[2];
a3 = row[3];
c0 = (a0 + a2) * ((int)((0.5) * M_SQRT2 * (1 << 15) + 0.5)) + (1 << (11 - 1));
c2 = (a0 - a2) * ((int)((0.5) * M_SQRT2 * (1 << 15) + 0.5)) + (1 << (11 - 1));
c1 = a1 * ((int)((0.6532814824) * M_SQRT2 * (1 << 15) + 0.5)) +
a3 * ((int)((0.2705980501) * M_SQRT2 * (1 << 15) + 0.5));
c3 = a1 * ((int)((0.2705980501) * M_SQRT2 * (1 << 15) + 0.5)) -
a3 * ((int)((0.6532814824) * M_SQRT2 * (1 << 15) + 0.5));
row[0] = (c0 + c1) >> 11;
row[1] = (c2 + c3) >> 11;
row[2] = (c2 - c3) >> 11;
row[3] = (c0 - c1) >> 11;
}
void ff_simple_idct84_add(uint8 *dest, ptrdiff_t line_size, int16 *block) {
int i;
/* IDCT8 on each line */
for (i = 0; i < 4; i++) {
idctRowCondDC_int16_8bit(block + i * 8, 0);
}
/* IDCT4 and store */
for (i = 0; i < 8; i++) {
idct4col_add(dest + i, line_size, block + i);
}
}
void ff_simple_idct48_add(uint8 *dest, ptrdiff_t line_size, int16 *block) {
int i;
/* IDCT4 on each line */
for (i = 0; i < 8; i++) {
idct4row(block + i * 8);
}
/* IDCT8 and store */
for (i = 0; i < 4; i++) {
idctSparseColAdd_int16_8bit(dest + i, line_size, block + i);
}
}
void ff_simple_idct44_add(uint8 *dest, ptrdiff_t line_size, int16 *block) {
int i;
/* IDCT4 on each line */
for (i = 0; i < 4; i++) {
idct4row(block + i * 8);
}
/* IDCT4 and store */
for (i = 0; i < 4; i++) {
idct4col_add(dest + i, line_size, block + i);
}
}
static void copy_block8(uint8 *d, const uint8 *s, ptrdiff_t ds, ptrdiff_t ss, int h) {
for (int y = 0; y < h; ++y) {
memcpy(d, s, 8);
d += ds;
s += ss;
}
}
static void copy_block9(uint8 *d, const uint8 *s, ptrdiff_t ds, ptrdiff_t ss, int h) {
for (int y = 0; y < h; ++y) {
memcpy(d, s, 9);
d += ds;
s += ss;
}
}
static void copy_block16(uint8 *d, const uint8 *s, ptrdiff_t ds, ptrdiff_t ss, int h) {
for (int y = 0; y < h; ++y) {
memcpy(d, s, 16);
d += ds;
s += ss;
}
}
static void copy_block17(uint8 *d, const uint8 *s, ptrdiff_t ds, ptrdiff_t ss, int h) {
for (int y = 0; y < h; ++y) {
memcpy(d, s, 17);
d += ds;
s += ss;
}
}
static void put_pixels8_8_c(uint8 *d, const uint8 *s, ptrdiff_t stride, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 8; ++x) {
int val = s[x];
d[x] = val;
}
d += stride;
s += stride;
}
}
static void put_pixels8_l2_8(uint8 *d, const uint8 *a, const uint8 *b, int ds, int as, int bs, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 8; ++x) {
int val = (a[x] + b[x] + 1) >> 1;
d[x] = val;
}
d += ds;
a += as;
b += bs;
}
}
static void put_pixels8_l4_8(uint8 *d, const uint8 *a, const uint8 *b, const uint8 *c, const uint8 *e, int ds, int as,
int bs, int cs, int es, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 8; ++x) {
int val = (a[x] + b[x] + c[x] + e[x] + 2) >> 2;
d[x] = val;
}
d += ds;
a += as;
b += bs;
c += cs;
e += es;
}
}
static void avg_pixels8_8_c(uint8 *d, const uint8 *s, ptrdiff_t stride, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 8; ++x) {
int val = s[x];
d[x] = (d[x] + val + 1) >> 1;
}
d += stride;
s += stride;
}
}
static void avg_pixels8_l2_8(uint8 *d, const uint8 *a, const uint8 *b, int ds, int as, int bs, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 8; ++x) {
int val = (a[x] + b[x] + 1) >> 1;
d[x] = (d[x] + val + 1) >> 1;
}
d += ds;
a += as;
b += bs;
}
}
static void avg_pixels8_l4_8(uint8 *d, const uint8 *a, const uint8 *b, const uint8 *c, const uint8 *e, int ds, int as,
int bs, int cs, int es, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 8; ++x) {
int val = (a[x] + b[x] + c[x] + e[x] + 2) >> 2;
d[x] = (d[x] + val + 1) >> 1;
}
d += ds;
a += as;
b += bs;
c += cs;
e += es;
}
}
static void put_no_rnd_pixels8_l2_8(uint8 *d, const uint8 *a, const uint8 *b, int ds, int as, int bs, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 8; ++x) {
int val = (a[x] + b[x] + 0) >> 1;
d[x] = val;
}
d += ds;
a += as;
b += bs;
}
}
static void put_no_rnd_pixels8_l4_8(uint8 *d, const uint8 *a, const uint8 *b, const uint8 *c, const uint8 *e, int ds,
int as, int bs, int cs, int es, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 8; ++x) {
int val = (a[x] + b[x] + c[x] + e[x] + 1) >> 2;
d[x] = val;
}
d += ds;
a += as;
b += bs;
c += cs;
e += es;
}
}
static void put_pixels16_8_c(uint8 *d, const uint8 *s, ptrdiff_t stride, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 16; ++x) {
int val = s[x];
d[x] = val;
}
d += stride;
s += stride;
}
}
static void put_pixels16_l2_8(uint8 *d, const uint8 *a, const uint8 *b, int ds, int as, int bs, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 16; ++x) {
int val = (a[x] + b[x] + 1) >> 1;
d[x] = val;
}
d += ds;
a += as;
b += bs;
}
}
static void put_pixels16_l4_8(uint8 *d, const uint8 *a, const uint8 *b, const uint8 *c, const uint8 *e, int ds, int as,
int bs, int cs, int es, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 16; ++x) {
int val = (a[x] + b[x] + c[x] + e[x] + 2) >> 2;
d[x] = val;
}
d += ds;
a += as;
b += bs;
c += cs;
e += es;
}
}
static void avg_pixels16_8_c(uint8 *d, const uint8 *s, ptrdiff_t stride, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 16; ++x) {
int val = s[x];
d[x] = (d[x] + val + 1) >> 1;
}
d += stride;
s += stride;
}
}
static void avg_pixels16_l2_8(uint8 *d, const uint8 *a, const uint8 *b, int ds, int as, int bs, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 16; ++x) {
int val = (a[x] + b[x] + 1) >> 1;
d[x] = (d[x] + val + 1) >> 1;
}
d += ds;
a += as;
b += bs;
}
}
static void avg_pixels16_l4_8(uint8 *d, const uint8 *a, const uint8 *b, const uint8 *c, const uint8 *e, int ds, int as,
int bs, int cs, int es, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 16; ++x) {
int val = (a[x] + b[x] + c[x] + e[x] + 2) >> 2;
d[x] = (d[x] + val + 1) >> 1;
}
d += ds;
a += as;
b += bs;
c += cs;
e += es;
}
}
static void put_no_rnd_pixels16_l2_8(uint8 *d, const uint8 *a, const uint8 *b, int ds, int as, int bs, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 16; ++x) {
int val = (a[x] + b[x] + 0) >> 1;
d[x] = val;
}
d += ds;
a += as;
b += bs;
}
}
static void put_no_rnd_pixels16_l4_8(uint8 *d, const uint8 *a, const uint8 *b, const uint8 *c, const uint8 *e, int ds,
int as, int bs, int cs, int es, int h) {
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 16; ++x) {
int val = (a[x] + b[x] + c[x] + e[x] + 1) >> 2;
d[x] = val;
}
d += ds;
a += as;
b += bs;
c += cs;
e += es;
}
}
#define QPEL_MC(r, OPNAME, RND, OP) \
static void OPNAME##mpeg4_qpel8_h_lowpass(uint8 *dst, const uint8 *src, int dstStride, int srcStride, int h) { \
const Crop cm; \
int i; \
\
for (i = 0; i < h; i++) { \
OP(dst[0], (src[0] + src[1]) * 20 - (src[0] + src[2]) * 6 + (src[1] + src[3]) * 3 - (src[2] + src[4])); \
OP(dst[1], (src[1] + src[2]) * 20 - (src[0] + src[3]) * 6 + (src[0] + src[4]) * 3 - (src[1] + src[5])); \
OP(dst[2], (src[2] + src[3]) * 20 - (src[1] + src[4]) * 6 + (src[0] + src[5]) * 3 - (src[0] + src[6])); \
OP(dst[3], (src[3] + src[4]) * 20 - (src[2] + src[5]) * 6 + (src[1] + src[6]) * 3 - (src[0] + src[7])); \
OP(dst[4], (src[4] + src[5]) * 20 - (src[3] + src[6]) * 6 + (src[2] + src[7]) * 3 - (src[1] + src[8])); \
OP(dst[5], (src[5] + src[6]) * 20 - (src[4] + src[7]) * 6 + (src[3] + src[8]) * 3 - (src[2] + src[8])); \
OP(dst[6], (src[6] + src[7]) * 20 - (src[5] + src[8]) * 6 + (src[4] + src[8]) * 3 - (src[3] + src[7])); \
OP(dst[7], (src[7] + src[8]) * 20 - (src[6] + src[8]) * 6 + (src[5] + src[7]) * 3 - (src[4] + src[6])); \
dst += dstStride; \
src += srcStride; \
} \
} \
\
static void OPNAME##mpeg4_qpel8_v_lowpass(uint8 *dst, const uint8 *src, int dstStride, int srcStride) { \
const Crop cm; \
const int w = 8; \
int i; \
\
for (i = 0; i < w; i++) { \
const int src0 = src[0 * srcStride]; \
const int src1 = src[1 * srcStride]; \
const int src2 = src[2 * srcStride]; \
const int src3 = src[3 * srcStride]; \
const int src4 = src[4 * srcStride]; \
const int src5 = src[5 * srcStride]; \
const int src6 = src[6 * srcStride]; \
const int src7 = src[7 * srcStride]; \
const int src8 = src[8 * srcStride]; \
OP(dst[0 * dstStride], (src0 + src1) * 20 - (src0 + src2) * 6 + (src1 + src3) * 3 - (src2 + src4)); \
OP(dst[1 * dstStride], (src1 + src2) * 20 - (src0 + src3) * 6 + (src0 + src4) * 3 - (src1 + src5)); \
OP(dst[2 * dstStride], (src2 + src3) * 20 - (src1 + src4) * 6 + (src0 + src5) * 3 - (src0 + src6)); \
OP(dst[3 * dstStride], (src3 + src4) * 20 - (src2 + src5) * 6 + (src1 + src6) * 3 - (src0 + src7)); \
OP(dst[4 * dstStride], (src4 + src5) * 20 - (src3 + src6) * 6 + (src2 + src7) * 3 - (src1 + src8)); \
OP(dst[5 * dstStride], (src5 + src6) * 20 - (src4 + src7) * 6 + (src3 + src8) * 3 - (src2 + src8)); \
OP(dst[6 * dstStride], (src6 + src7) * 20 - (src5 + src8) * 6 + (src4 + src8) * 3 - (src3 + src7)); \
OP(dst[7 * dstStride], (src7 + src8) * 20 - (src6 + src8) * 6 + (src5 + src7) * 3 - (src4 + src6)); \
dst++; \
src++; \
} \
} \
\
static void OPNAME##mpeg4_qpel16_h_lowpass(uint8 *dst, const uint8 *src, int dstStride, int srcStride, int h) { \
const Crop cm; \
int i; \
\
for (i = 0; i < h; i++) { \
OP(dst[0], (src[0] + src[1]) * 20 - (src[0] + src[2]) * 6 + (src[1] + src[3]) * 3 - (src[2] + src[4])); \
OP(dst[1], (src[1] + src[2]) * 20 - (src[0] + src[3]) * 6 + (src[0] + src[4]) * 3 - (src[1] + src[5])); \
OP(dst[2], (src[2] + src[3]) * 20 - (src[1] + src[4]) * 6 + (src[0] + src[5]) * 3 - (src[0] + src[6])); \
OP(dst[3], (src[3] + src[4]) * 20 - (src[2] + src[5]) * 6 + (src[1] + src[6]) * 3 - (src[0] + src[7])); \
OP(dst[4], (src[4] + src[5]) * 20 - (src[3] + src[6]) * 6 + (src[2] + src[7]) * 3 - (src[1] + src[8])); \
OP(dst[5], (src[5] + src[6]) * 20 - (src[4] + src[7]) * 6 + (src[3] + src[8]) * 3 - (src[2] + src[9])); \
OP(dst[6], (src[6] + src[7]) * 20 - (src[5] + src[8]) * 6 + (src[4] + src[9]) * 3 - (src[3] + src[10])); \
OP(dst[7], (src[7] + src[8]) * 20 - (src[6] + src[9]) * 6 + (src[5] + src[10]) * 3 - (src[4] + src[11])); \
OP(dst[8], (src[8] + src[9]) * 20 - (src[7] + src[10]) * 6 + (src[6] + src[11]) * 3 - (src[5] + src[12])); \
OP(dst[9], \
(src[9] + src[10]) * 20 - (src[8] + src[11]) * 6 + (src[7] + src[12]) * 3 - (src[6] + src[13])); \
OP(dst[10], \
(src[10] + src[11]) * 20 - (src[9] + src[12]) * 6 + (src[8] + src[13]) * 3 - (src[7] + src[14])); \
OP(dst[11], \
(src[11] + src[12]) * 20 - (src[10] + src[13]) * 6 + (src[9] + src[14]) * 3 - (src[8] + src[15])); \
OP(dst[12], \
(src[12] + src[13]) * 20 - (src[11] + src[14]) * 6 + (src[10] + src[15]) * 3 - (src[9] + src[16])); \
OP(dst[13], \
(src[13] + src[14]) * 20 - (src[12] + src[15]) * 6 + (src[11] + src[16]) * 3 - (src[10] + src[16])); \
OP(dst[14], \
(src[14] + src[15]) * 20 - (src[13] + src[16]) * 6 + (src[12] + src[16]) * 3 - (src[11] + src[15])); \
OP(dst[15], \
(src[15] + src[16]) * 20 - (src[14] + src[16]) * 6 + (src[13] + src[15]) * 3 - (src[12] + src[14])); \
dst += dstStride; \
src += srcStride; \
} \
} \
\
static void OPNAME##mpeg4_qpel16_v_lowpass(uint8 *dst, const uint8 *src, int dstStride, int srcStride) { \
const Crop cm; \
const int w = 16; \
int i; \
\
for (i = 0; i < w; i++) { \
const int src0 = src[0 * srcStride]; \
const int src1 = src[1 * srcStride]; \
const int src2 = src[2 * srcStride]; \
const int src3 = src[3 * srcStride]; \
const int src4 = src[4 * srcStride]; \
const int src5 = src[5 * srcStride]; \
const int src6 = src[6 * srcStride]; \
const int src7 = src[7 * srcStride]; \
const int src8 = src[8 * srcStride]; \
const int src9 = src[9 * srcStride]; \
const int src10 = src[10 * srcStride]; \
const int src11 = src[11 * srcStride]; \
const int src12 = src[12 * srcStride]; \
const int src13 = src[13 * srcStride]; \
const int src14 = src[14 * srcStride]; \
const int src15 = src[15 * srcStride]; \
const int src16 = src[16 * srcStride]; \
OP(dst[0 * dstStride], (src0 + src1) * 20 - (src0 + src2) * 6 + (src1 + src3) * 3 - (src2 + src4)); \
OP(dst[1 * dstStride], (src1 + src2) * 20 - (src0 + src3) * 6 + (src0 + src4) * 3 - (src1 + src5)); \
OP(dst[2 * dstStride], (src2 + src3) * 20 - (src1 + src4) * 6 + (src0 + src5) * 3 - (src0 + src6)); \
OP(dst[3 * dstStride], (src3 + src4) * 20 - (src2 + src5) * 6 + (src1 + src6) * 3 - (src0 + src7)); \
OP(dst[4 * dstStride], (src4 + src5) * 20 - (src3 + src6) * 6 + (src2 + src7) * 3 - (src1 + src8)); \
OP(dst[5 * dstStride], (src5 + src6) * 20 - (src4 + src7) * 6 + (src3 + src8) * 3 - (src2 + src9)); \
OP(dst[6 * dstStride], (src6 + src7) * 20 - (src5 + src8) * 6 + (src4 + src9) * 3 - (src3 + src10)); \
OP(dst[7 * dstStride], (src7 + src8) * 20 - (src6 + src9) * 6 + (src5 + src10) * 3 - (src4 + src11)); \
OP(dst[8 * dstStride], (src8 + src9) * 20 - (src7 + src10) * 6 + (src6 + src11) * 3 - (src5 + src12)); \
OP(dst[9 * dstStride], (src9 + src10) * 20 - (src8 + src11) * 6 + (src7 + src12) * 3 - (src6 + src13)); \
OP(dst[10 * dstStride], (src10 + src11) * 20 - (src9 + src12) * 6 + (src8 + src13) * 3 - (src7 + src14)); \
OP(dst[11 * dstStride], (src11 + src12) * 20 - (src10 + src13) * 6 + (src9 + src14) * 3 - (src8 + src15)); \
OP(dst[12 * dstStride], \
(src12 + src13) * 20 - (src11 + src14) * 6 + (src10 + src15) * 3 - (src9 + src16)); \
OP(dst[13 * dstStride], \
(src13 + src14) * 20 - (src12 + src15) * 6 + (src11 + src16) * 3 - (src10 + src16)); \
OP(dst[14 * dstStride], \
(src14 + src15) * 20 - (src13 + src16) * 6 + (src12 + src16) * 3 - (src11 + src15)); \
OP(dst[15 * dstStride], \
(src15 + src16) * 20 - (src14 + src16) * 6 + (src13 + src15) * 3 - (src12 + src14)); \
dst++; \
src++; \
} \
} \
\
static void OPNAME##qpel8_mc10_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 half[64]; \
\
put##RND##mpeg4_qpel8_h_lowpass(half, src, 8, stride, 8); \
OPNAME##pixels8_l2_8(dst, src, half, stride, stride, 8, 8); \
} \
\
static void OPNAME##qpel8_mc20_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
OPNAME##mpeg4_qpel8_h_lowpass(dst, src, stride, stride, 8); \
} \
\
static void OPNAME##qpel8_mc30_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 half[64]; \
\
put##RND##mpeg4_qpel8_h_lowpass(half, src, 8, stride, 8); \
OPNAME##pixels8_l2_8(dst, src + 1, half, stride, stride, 8, 8); \
} \
\
static void OPNAME##qpel8_mc01_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 half[64]; \
\
copy_block8(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_v_lowpass(half, full, 8, 16); \
OPNAME##pixels8_l2_8(dst, full, half, stride, 16, 8, 8); \
} \
\
static void OPNAME##qpel8_mc02_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
\
copy_block8(full, src, 16, stride, 9); \
OPNAME##mpeg4_qpel8_v_lowpass(dst, full, stride, 16); \
} \
\
static void OPNAME##qpel8_mc03_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 half[64]; \
\
copy_block8(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_v_lowpass(half, full, 8, 16); \
OPNAME##pixels8_l2_8(dst, full + 16, half, stride, 16, 8, 8); \
} \
\
void ff_##OPNAME##qpel8_mc11_old_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 halfH[72]; \
uint8 halfV[64]; \
uint8 halfHV[64]; \
\
copy_block9(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \
put##RND##mpeg4_qpel8_v_lowpass(halfV, full, 8, 16); \
put##RND##mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \
OPNAME##pixels8_l4_8(dst, full, halfH, halfV, halfHV, stride, 16, 8, 8, 8, 8); \
} \
\
static void OPNAME##qpel8_mc11_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 halfH[72]; \
uint8 halfHV[64]; \
\
copy_block9(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \
put##RND##pixels8_l2_8(halfH, halfH, full, 8, 8, 16, 9); \
put##RND##mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \
OPNAME##pixels8_l2_8(dst, halfH, halfHV, stride, 8, 8, 8); \
} \
\
void ff_##OPNAME##qpel8_mc31_old_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 halfH[72]; \
uint8 halfV[64]; \
uint8 halfHV[64]; \
\
copy_block9(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \
put##RND##mpeg4_qpel8_v_lowpass(halfV, full + 1, 8, 16); \
put##RND##mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \
OPNAME##pixels8_l4_8(dst, full + 1, halfH, halfV, halfHV, stride, 16, 8, 8, 8, 8); \
} \
\
static void OPNAME##qpel8_mc31_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 halfH[72]; \
uint8 halfHV[64]; \
\
copy_block9(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \
put##RND##pixels8_l2_8(halfH, halfH, full + 1, 8, 8, 16, 9); \
put##RND##mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \
OPNAME##pixels8_l2_8(dst, halfH, halfHV, stride, 8, 8, 8); \
} \
\
void ff_##OPNAME##qpel8_mc13_old_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 halfH[72]; \
uint8 halfV[64]; \
uint8 halfHV[64]; \
\
copy_block9(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \
put##RND##mpeg4_qpel8_v_lowpass(halfV, full, 8, 16); \
put##RND##mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \
OPNAME##pixels8_l4_8(dst, full + 16, halfH + 8, halfV, halfHV, stride, 16, 8, 8, 8, 8); \
} \
\
static void OPNAME##qpel8_mc13_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 halfH[72]; \
uint8 halfHV[64]; \
\
copy_block9(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \
put##RND##pixels8_l2_8(halfH, halfH, full, 8, 8, 16, 9); \
put##RND##mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \
OPNAME##pixels8_l2_8(dst, halfH + 8, halfHV, stride, 8, 8, 8); \
} \
\
void ff_##OPNAME##qpel8_mc33_old_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 halfH[72]; \
uint8 halfV[64]; \
uint8 halfHV[64]; \
\
copy_block9(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \
put##RND##mpeg4_qpel8_v_lowpass(halfV, full + 1, 8, 16); \
put##RND##mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \
OPNAME##pixels8_l4_8(dst, full + 17, halfH + 8, halfV, halfHV, stride, 16, 8, 8, 8, 8); \
} \
\
static void OPNAME##qpel8_mc33_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 halfH[72]; \
uint8 halfHV[64]; \
\
copy_block9(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \
put##RND##pixels8_l2_8(halfH, halfH, full + 1, 8, 8, 16, 9); \
put##RND##mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \
OPNAME##pixels8_l2_8(dst, halfH + 8, halfHV, stride, 8, 8, 8); \
} \
\
static void OPNAME##qpel8_mc21_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 halfH[72]; \
uint8 halfHV[64]; \
\
put##RND##mpeg4_qpel8_h_lowpass(halfH, src, 8, stride, 9); \
put##RND##mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \
OPNAME##pixels8_l2_8(dst, halfH, halfHV, stride, 8, 8, 8); \
} \
\
static void OPNAME##qpel8_mc23_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 halfH[72]; \
uint8 halfHV[64]; \
\
put##RND##mpeg4_qpel8_h_lowpass(halfH, src, 8, stride, 9); \
put##RND##mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \
OPNAME##pixels8_l2_8(dst, halfH + 8, halfHV, stride, 8, 8, 8); \
} \
\
void ff_##OPNAME##qpel8_mc12_old_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 halfH[72]; \
uint8 halfV[64]; \
uint8 halfHV[64]; \
\
copy_block9(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \
put##RND##mpeg4_qpel8_v_lowpass(halfV, full, 8, 16); \
put##RND##mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \
OPNAME##pixels8_l2_8(dst, halfV, halfHV, stride, 8, 8, 8); \
} \
\
static void OPNAME##qpel8_mc12_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 halfH[72]; \
\
copy_block9(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \
put##RND##pixels8_l2_8(halfH, halfH, full, 8, 8, 16, 9); \
OPNAME##mpeg4_qpel8_v_lowpass(dst, halfH, stride, 8); \
} \
\
void ff_##OPNAME##qpel8_mc32_old_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 halfH[72]; \
uint8 halfV[64]; \
uint8 halfHV[64]; \
\
copy_block9(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \
put##RND##mpeg4_qpel8_v_lowpass(halfV, full + 1, 8, 16); \
put##RND##mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \
OPNAME##pixels8_l2_8(dst, halfV, halfHV, stride, 8, 8, 8); \
} \
\
static void OPNAME##qpel8_mc32_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[16 * 9]; \
uint8 halfH[72]; \
\
copy_block9(full, src, 16, stride, 9); \
put##RND##mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \
put##RND##pixels8_l2_8(halfH, halfH, full + 1, 8, 8, 16, 9); \
OPNAME##mpeg4_qpel8_v_lowpass(dst, halfH, stride, 8); \
} \
\
static void OPNAME##qpel8_mc22_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 halfH[72]; \
\
put##RND##mpeg4_qpel8_h_lowpass(halfH, src, 8, stride, 9); \
OPNAME##mpeg4_qpel8_v_lowpass(dst, halfH, stride, 8); \
} \
\
static void OPNAME##qpel16_mc10_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 half[256]; \
\
put##RND##mpeg4_qpel16_h_lowpass(half, src, 16, stride, 16); \
OPNAME##pixels16_l2_8(dst, src, half, stride, stride, 16, 16); \
} \
\
static void OPNAME##qpel16_mc20_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
OPNAME##mpeg4_qpel16_h_lowpass(dst, src, stride, stride, 16); \
} \
\
static void OPNAME##qpel16_mc30_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 half[256]; \
\
put##RND##mpeg4_qpel16_h_lowpass(half, src, 16, stride, 16); \
OPNAME##pixels16_l2_8(dst, src + 1, half, stride, stride, 16, 16); \
} \
\
static void OPNAME##qpel16_mc01_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 half[256]; \
\
copy_block16(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_v_lowpass(half, full, 16, 24); \
OPNAME##pixels16_l2_8(dst, full, half, stride, 24, 16, 16); \
} \
\
static void OPNAME##qpel16_mc02_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
\
copy_block16(full, src, 24, stride, 17); \
OPNAME##mpeg4_qpel16_v_lowpass(dst, full, stride, 24); \
} \
\
static void OPNAME##qpel16_mc03_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 half[256]; \
\
copy_block16(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_v_lowpass(half, full, 16, 24); \
OPNAME##pixels16_l2_8(dst, full + 24, half, stride, 24, 16, 16); \
} \
\
void ff_##OPNAME##qpel16_mc11_old_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 halfH[272]; \
uint8 halfV[256]; \
uint8 halfHV[256]; \
\
copy_block17(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \
put##RND##mpeg4_qpel16_v_lowpass(halfV, full, 16, 24); \
put##RND##mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \
OPNAME##pixels16_l4_8(dst, full, halfH, halfV, halfHV, stride, 24, 16, 16, 16, 16); \
} \
\
static void OPNAME##qpel16_mc11_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 halfH[272]; \
uint8 halfHV[256]; \
\
copy_block17(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \
put##RND##pixels16_l2_8(halfH, halfH, full, 16, 16, 24, 17); \
put##RND##mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \
OPNAME##pixels16_l2_8(dst, halfH, halfHV, stride, 16, 16, 16); \
} \
\
void ff_##OPNAME##qpel16_mc31_old_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 halfH[272]; \
uint8 halfV[256]; \
uint8 halfHV[256]; \
\
copy_block17(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \
put##RND##mpeg4_qpel16_v_lowpass(halfV, full + 1, 16, 24); \
put##RND##mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \
OPNAME##pixels16_l4_8(dst, full + 1, halfH, halfV, halfHV, stride, 24, 16, 16, 16, 16); \
} \
\
static void OPNAME##qpel16_mc31_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 halfH[272]; \
uint8 halfHV[256]; \
\
copy_block17(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \
put##RND##pixels16_l2_8(halfH, halfH, full + 1, 16, 16, 24, 17); \
put##RND##mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \
OPNAME##pixels16_l2_8(dst, halfH, halfHV, stride, 16, 16, 16); \
} \
\
void ff_##OPNAME##qpel16_mc13_old_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 halfH[272]; \
uint8 halfV[256]; \
uint8 halfHV[256]; \
\
copy_block17(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \
put##RND##mpeg4_qpel16_v_lowpass(halfV, full, 16, 24); \
put##RND##mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \
OPNAME##pixels16_l4_8(dst, full + 24, halfH + 16, halfV, halfHV, stride, 24, 16, 16, 16, 16); \
} \
\
static void OPNAME##qpel16_mc13_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 halfH[272]; \
uint8 halfHV[256]; \
\
copy_block17(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \
put##RND##pixels16_l2_8(halfH, halfH, full, 16, 16, 24, 17); \
put##RND##mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \
OPNAME##pixels16_l2_8(dst, halfH + 16, halfHV, stride, 16, 16, 16); \
} \
\
void ff_##OPNAME##qpel16_mc33_old_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 halfH[272]; \
uint8 halfV[256]; \
uint8 halfHV[256]; \
\
copy_block17(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \
put##RND##mpeg4_qpel16_v_lowpass(halfV, full + 1, 16, 24); \
put##RND##mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \
OPNAME##pixels16_l4_8(dst, full + 25, halfH + 16, halfV, halfHV, stride, 24, 16, 16, 16, 16); \
} \
\
static void OPNAME##qpel16_mc33_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 halfH[272]; \
uint8 halfHV[256]; \
\
copy_block17(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \
put##RND##pixels16_l2_8(halfH, halfH, full + 1, 16, 16, 24, 17); \
put##RND##mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \
OPNAME##pixels16_l2_8(dst, halfH + 16, halfHV, stride, 16, 16, 16); \
} \
\
static void OPNAME##qpel16_mc21_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 halfH[272]; \
uint8 halfHV[256]; \
\
put##RND##mpeg4_qpel16_h_lowpass(halfH, src, 16, stride, 17); \
put##RND##mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \
OPNAME##pixels16_l2_8(dst, halfH, halfHV, stride, 16, 16, 16); \
} \
\
static void OPNAME##qpel16_mc23_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 halfH[272]; \
uint8 halfHV[256]; \
\
put##RND##mpeg4_qpel16_h_lowpass(halfH, src, 16, stride, 17); \
put##RND##mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \
OPNAME##pixels16_l2_8(dst, halfH + 16, halfHV, stride, 16, 16, 16); \
} \
\
void ff_##OPNAME##qpel16_mc12_old_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 halfH[272]; \
uint8 halfV[256]; \
uint8 halfHV[256]; \
\
copy_block17(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \
put##RND##mpeg4_qpel16_v_lowpass(halfV, full, 16, 24); \
put##RND##mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \
OPNAME##pixels16_l2_8(dst, halfV, halfHV, stride, 16, 16, 16); \
} \
\
static void OPNAME##qpel16_mc12_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 halfH[272]; \
\
copy_block17(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \
put##RND##pixels16_l2_8(halfH, halfH, full, 16, 16, 24, 17); \
OPNAME##mpeg4_qpel16_v_lowpass(dst, halfH, stride, 16); \
} \
\
void ff_##OPNAME##qpel16_mc32_old_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 halfH[272]; \
uint8 halfV[256]; \
uint8 halfHV[256]; \
\
copy_block17(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \
put##RND##mpeg4_qpel16_v_lowpass(halfV, full + 1, 16, 24); \
put##RND##mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \
OPNAME##pixels16_l2_8(dst, halfV, halfHV, stride, 16, 16, 16); \
} \
\
static void OPNAME##qpel16_mc32_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 full[24 * 17]; \
uint8 halfH[272]; \
\
copy_block17(full, src, 24, stride, 17); \
put##RND##mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \
put##RND##pixels16_l2_8(halfH, halfH, full + 1, 16, 16, 24, 17); \
OPNAME##mpeg4_qpel16_v_lowpass(dst, halfH, stride, 16); \
} \
\
static void OPNAME##qpel16_mc22_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) { \
uint8 halfH[272]; \
\
put##RND##mpeg4_qpel16_h_lowpass(halfH, src, 16, stride, 17); \
OPNAME##mpeg4_qpel16_v_lowpass(dst, halfH, stride, 16); \
}
#define op_avg(a, b) a = (((a) + cm[((b) + 16) >> 5] + 1) >> 1)
#define op_put(a, b) a = cm[((b) + 16) >> 5]
#define op_put_no_rnd(a, b) a = cm[((b) + 15) >> 5]
QPEL_MC(0, put_, _, op_put)
QPEL_MC(1, put_no_rnd_, _no_rnd_, op_put_no_rnd)
QPEL_MC(0, avg_, _, op_avg)
#undef op_avg
#undef op_put
#undef op_put_no_rnd
void ff_put_pixels8x8_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) {
put_pixels8_8_c(dst, src, stride, 8);
}
void ff_avg_pixels8x8_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) {
avg_pixels8_8_c(dst, src, stride, 8);
}
void ff_put_pixels16x16_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) {
put_pixels16_8_c(dst, src, stride, 16);
}
void ff_avg_pixels16x16_c(uint8 *dst, const uint8 *src, ptrdiff_t stride) {
avg_pixels16_8_c(dst, src, stride, 16);
}
#define put_qpel8_mc00_c ff_put_pixels8x8_c
#define avg_qpel8_mc00_c ff_avg_pixels8x8_c
#define put_qpel16_mc00_c ff_put_pixels16x16_c
#define avg_qpel16_mc00_c ff_avg_pixels16x16_c
#define put_no_rnd_qpel8_mc00_c ff_put_pixels8x8_c
#define put_no_rnd_qpel16_mc00_c ff_put_pixels16x16_c
void initQpel(QpelDSP *c) {
#define dspfunc(PFX, IDX, NUM) \
c->PFX##_pixels_tab[IDX][0] = PFX##NUM##_mc00_c; \
c->PFX##_pixels_tab[IDX][1] = PFX##NUM##_mc10_c; \
c->PFX##_pixels_tab[IDX][2] = PFX##NUM##_mc20_c; \
c->PFX##_pixels_tab[IDX][3] = PFX##NUM##_mc30_c; \
c->PFX##_pixels_tab[IDX][4] = PFX##NUM##_mc01_c; \
c->PFX##_pixels_tab[IDX][5] = PFX##NUM##_mc11_c; \
c->PFX##_pixels_tab[IDX][6] = PFX##NUM##_mc21_c; \
c->PFX##_pixels_tab[IDX][7] = PFX##NUM##_mc31_c; \
c->PFX##_pixels_tab[IDX][8] = PFX##NUM##_mc02_c; \
c->PFX##_pixels_tab[IDX][9] = PFX##NUM##_mc12_c; \
c->PFX##_pixels_tab[IDX][10] = PFX##NUM##_mc22_c; \
c->PFX##_pixels_tab[IDX][11] = PFX##NUM##_mc32_c; \
c->PFX##_pixels_tab[IDX][12] = PFX##NUM##_mc03_c; \
c->PFX##_pixels_tab[IDX][13] = PFX##NUM##_mc13_c; \
c->PFX##_pixels_tab[IDX][14] = PFX##NUM##_mc23_c; \
c->PFX##_pixels_tab[IDX][15] = PFX##NUM##_mc33_c
dspfunc(put_qpel, 0, 16);
dspfunc(put_qpel, 1, 8);
dspfunc(put_no_rnd_qpel, 0, 16);
dspfunc(put_no_rnd_qpel, 1, 8);
dspfunc(avg_qpel, 0, 16);
dspfunc(avg_qpel, 1, 8);
}
#undef QPEL_MC
#undef avg_qpel16_mc00_c
#undef avg_qpel8_mc00_c
#undef dspfunc
#undef put_no_rnd_qpel16_mc00_c
#undef put_no_rnd_qpel8_mc00_c
#undef put_qpel16_mc00_c
#undef put_qpel8_mc00_c
/*
* area positions, #3 is 1 pixel only, other are 8 pixels
* |66666666|
* 3|44444444|55555555|
* - -+--------+--------+
* 1 2|XXXXXXXX|
* 1 2|XXXXXXXX|
* 1 2|XXXXXXXX|
* 1 2|XXXXXXXX|
* 1 2|XXXXXXXX|
* 1 2|XXXXXXXX|
* 1 2|XXXXXXXX|
* 1 2|XXXXXXXX|
* ^-start
*/
#define area1 (0)
#define area2 (8)
#define area3 (8 + 8)
#define area4 (8 + 8 + 1)
#define area5 (8 + 8 + 1 + 8)
#define area6 (8 + 8 + 1 + 16)
/**
Collect statistics and prepare the edge pixels required by the other spatial compensation functions.
* @param src pointer to the beginning of the processed block
* @param dst pointer to emu_edge, edge pixels are stored the way other compensation routines do.
* @param linesize byte offset between 2 vertical pixels in the source image
* @param range pointer to the variable where the edge pixel range is to be stored (max-min values)
* @param psum pointer to the variable where the edge pixel sum is to be stored
* @param edges Informs this routine that the block is on an image border, so it has to interpolate the missing edge
pixels. and some of the edge pixels should be interpolated, the flag has the following meaning: 1 - mb_x==0 - first
block in the row, interpolate area #1,#2,#3; 2 - mb_y==0 - first row, interpolate area #3,#4,#5,#6; note: 1|2 -
mb_x==mb_y==0 - first block, use 0x80 value for all areas; 4 - mb_x>= (mb_width-1) last block in the row, interpolate
area #5;
-*/
static void x8_setup_spatial_compensation(const uint8 *src, uint8 *dst, ptrdiff_t stride, int *range, int *psum,
int edges) {
const uint8 *ptr;
int sum;
int i;
int min_pix, max_pix;
uint8 c;
if ((edges & 3) == 3) {
*psum = 0x80 * (8 + 1 + 8 + 2);
*range = 0;
memset(dst, 0x80, 16 + 1 + 16 + 8);
/* this triggers flat_dc for sure. flat_dc avoids all (other)
* prediction modes, but requires dc_level decoding. */
return;
}
min_pix = 256;
max_pix = -1;
sum = 0;
if (!(edges & 1)) { // (mb_x != 0) // there is previous block on this row
ptr = src - 1; // left column, area 2
for (i = 7; i >= 0; i--) {
c = *(ptr - 1); // area1, same mb as area2, no need to check
dst[area1 + i] = c;
c = *ptr;
sum += c;
min_pix = MIN(min_pix, int(c));
max_pix = MAX(max_pix, int(c));
dst[area2 + i] = c;
ptr += stride;
}
}
if (!(edges & 2)) { // (mb_y != 0) // there is row above
ptr = src - stride; // top line
for (i = 0; i < 8; i++) {
c = *(ptr + i);
sum += c;
min_pix = MIN(min_pix, int(c));
max_pix = MAX(max_pix, int(c));
}
if (edges & 4) { // last block on the row?
memset(dst + area5, c, 8); // set with last pixel fr
memcpy(dst + area4, ptr, 8);
} else {
memcpy(dst + area4, ptr, 16); // both area4 and 5
}
// area6 always present in the above block
memcpy(dst + area6, ptr - stride, 8);
}
// now calculate the stuff we need
if (edges & 3) { // mb_x ==0 || mb_y == 0) {
int avg = (sum + 4) >> 3;
if (edges & 1) // (mb_x == 0) { // implies mb_y !=0
memset(dst + area1, avg, 8 + 8 + 1); // areas 1, 2, 3 are averaged
else // implies y == 0 x != 0
memset(dst + area3, avg, 1 + 16 + 8); // areas 3, 4, 5, 6
sum += avg * 9;
} else {
// the edge pixel, in the top line and left column
uint8 c = *(src - 1 - stride);
dst[area3] = c;
sum += c;
// edge pixel is not part of min/max
}
*range = max_pix - min_pix;
sum += *(dst + area5) + *(dst + area5 + 1);
*psum = sum;
}
static const uint16 zero_prediction_weights[64 * 2] = {
640, 640, 669, 480, 708, 354, 748, 257, 792, 198, 760, 143, 808, 101, 772, 72, 480, 669, 537, 537, 598, 416,
661, 316, 719, 250, 707, 185, 768, 134, 745, 97, 354, 708, 416, 598, 488, 488, 564, 388, 634, 317, 642, 241,
716, 179, 706, 132, 257, 748, 316, 661, 388, 564, 469, 469, 543, 395, 571, 311, 655, 238, 660, 180, 198, 792,
250, 719, 317, 634, 395, 543, 469, 469, 507, 380, 597, 299, 616, 231, 161, 855, 206, 788, 266, 710, 340, 623,
411, 548, 455, 455, 548, 366, 576, 288, 122, 972, 159, 914, 211, 842, 276, 758, 341, 682, 389, 584, 483, 483,
520, 390, 110, 1172, 144, 1107, 193, 1028, 254, 932, 317, 846, 366, 731, 458, 611, 499, 499,
};
static void spatial_compensation_0(const uint8 *src, uint8 *dst, ptrdiff_t stride) {
int i, j;
int x, y;
unsigned int p; // power divided by 2
int a;
uint16 left_sum[2][8] = {{0}};
uint16 top_sum[2][8] = {{0}};
for (i = 0; i < 8; i++) {
a = src[area2 + 7 - i] << 4;
for (j = 0; j < 8; j++) {
p = abs(i - j);
left_sum[p & 1][j] += a >> (p >> 1);
}
}
for (i = 0; i < 8; i++) {
a = src[area4 + i] << 4;
for (j = 0; j < 8; j++) {
p = abs(i - j);
top_sum[p & 1][j] += a >> (p >> 1);
}
}
for (; i < 10; i++) {
a = src[area4 + i] << 4;
for (j = 5; j < 8; j++) {
p = abs(i - j);
top_sum[p & 1][j] += a >> (p >> 1);
}
}
for (; i < 12; i++) {
a = src[area4 + i] << 4;
for (j = 7; j < 8; j++) {
p = abs(i - j);
top_sum[p & 1][j] += a >> (p >> 1);
}
}
for (i = 0; i < 8; i++) {
top_sum[0][i] += (top_sum[1][i] * 181 + 128) >> 8; // 181 is sqrt(2)/2
left_sum[0][i] += (left_sum[1][i] * 181 + 128) >> 8;
}
for (y = 0; y < 8; y++) {
for (x = 0; x < 8; x++)
dst[x] = ((uint32)top_sum[0][x] * zero_prediction_weights[y * 16 + x * 2 + 0] +
(uint32)left_sum[0][y] * zero_prediction_weights[y * 16 + x * 2 + 1] + 0x8000) >>
16;
dst += stride;
}
}
static void spatial_compensation_1(const uint8 *src, uint8 *dst, ptrdiff_t stride) {
int x, y;
for (y = 0; y < 8; y++) {
for (x = 0; x < 8; x++)
dst[x] = src[area4 + MIN(2 * y + x + 2, 15)];
dst += stride;
}
}
static void spatial_compensation_2(const uint8 *src, uint8 *dst, ptrdiff_t stride) {
for (int y = 0; y < 8; y++) {
memcpy(dst, src + area4 + 1 + y, 8);
dst += stride;
}
}
static void spatial_compensation_3(const uint8 *src, uint8 *dst, ptrdiff_t stride) {
for (int y = 0; y < 8; y++) {
memcpy(dst, src + area4 + ((y + 1) >> 1), 8);
dst += stride;
}
}
static void spatial_compensation_4(const uint8 *src, uint8 *dst, ptrdiff_t stride) {
int x, y;
for (y = 0; y < 8; y++) {
for (x = 0; x < 8; x++)
dst[x] = (src[area4 + x] + src[area6 + x] + 1) >> 1;
dst += stride;
}
}
static void spatial_compensation_5(const uint8 *src, uint8 *dst, ptrdiff_t stride) {
int x, y;
for (y = 0; y < 8; y++) {
for (x = 0; x < 8; x++) {
if (2 * x - y < 0)
dst[x] = src[area2 + 9 + 2 * x - y];
else
dst[x] = src[area4 + x - ((y + 1) >> 1)];
}
dst += stride;
}
}
static void spatial_compensation_6(const uint8 *src, uint8 *dst, ptrdiff_t stride) {
for (int y = 0; y < 8; y++) {
memcpy(dst, src + area3 - y, 8);
dst += stride;
}
}
static void spatial_compensation_7(const uint8 *src, uint8 *dst, ptrdiff_t stride) {
int x, y;
for (y = 0; y < 8; y++) {
for (x = 0; x < 8; x++) {
if (x - 2 * y > 0)
dst[x] = (src[area3 - 1 + x - 2 * y] + src[area3 + x - 2 * y] + 1) >> 1;
else
dst[x] = src[area2 + 8 - y + (x >> 1)];
}
dst += stride;
}
}
static void spatial_compensation_8(const uint8 *src, uint8 *dst, ptrdiff_t stride) {
int x, y;
for (y = 0; y < 8; y++) {
for (x = 0; x < 8; x++)
dst[x] = (src[area1 + 7 - y] + src[area2 + 7 - y] + 1) >> 1;
dst += stride;
}
}
static void spatial_compensation_9(const uint8 *src, uint8 *dst, ptrdiff_t stride) {
int x, y;
for (y = 0; y < 8; y++) {
for (x = 0; x < 8; x++)
dst[x] = src[area2 + 6 - MIN(x + y, 6)];
dst += stride;
}
}
static void spatial_compensation_10(const uint8 *src, uint8 *dst, ptrdiff_t stride) {
int x, y;
for (y = 0; y < 8; y++) {
for (x = 0; x < 8; x++)
dst[x] = (src[area2 + 7 - y] * (8 - x) + src[area4 + x] * x + 4) >> 3;
dst += stride;
}
}
static void spatial_compensation_11(const uint8 *src, uint8 *dst, ptrdiff_t stride) {
int x, y;
for (y = 0; y < 8; y++) {
for (x = 0; x < 8; x++)
dst[x] = (src[area2 + 7 - y] * y + src[area4 + x] * (8 - y) + 4) >> 3;
dst += stride;
}
}
static void x8_loop_filter(uint8 *ptr, const ptrdiff_t a_stride, const ptrdiff_t b_stride, int quant) {
int i, t;
int p0, p1, p2, p3, p4, p5, p6, p7, p8, p9;
int ql = (quant + 10) >> 3;
for (i = 0; i < 8; i++, ptr += b_stride) {
p0 = ptr[-5 * a_stride];
p1 = ptr[-4 * a_stride];
p2 = ptr[-3 * a_stride];
p3 = ptr[-2 * a_stride];
p4 = ptr[-1 * a_stride];
p5 = ptr[0];
p6 = ptr[1 * a_stride];
p7 = ptr[2 * a_stride];
p8 = ptr[3 * a_stride];
p9 = ptr[4 * a_stride];
t = (ABS(p1 - p2) <= ql) + (ABS(p2 - p3) <= ql) + (ABS(p3 - p4) <= ql) + (ABS(p4 - p5) <= ql);
// You need at least 1 to be able to reach a total score of 6.
if (t > 0) {
t += (ABS(p5 - p6) <= ql) + (ABS(p6 - p7) <= ql) + (ABS(p7 - p8) <= ql) + (ABS(p8 - p9) <= ql) +
(ABS(p0 - p1) <= ql);
if (t >= 6) {
int min, max;
min = max = p1;
min = MIN(min, p3);
max = MAX(max, p3);
min = MIN(min, p5);
max = MAX(max, p5);
min = MIN(min, p8);
max = MAX(max, p8);
if (max - min < 2 * quant) { // early stop
min = MIN(min, p2);
max = MAX(max, p2);
min = MIN(min, p4);
max = MAX(max, p4);
min = MIN(min, p6);
max = MAX(max, p6);
min = MIN(min, p7);
max = MAX(max, p7);
if (max - min < 2 * quant) {
ptr[-2 * a_stride] = (4 * p2 + 3 * p3 + 1 * p7 + 4) >> 3;
ptr[-1 * a_stride] = (3 * p2 + 3 * p4 + 2 * p7 + 4) >> 3;
ptr[0] = (2 * p2 + 3 * p5 + 3 * p7 + 4) >> 3;
ptr[1 * a_stride] = (1 * p2 + 3 * p6 + 4 * p7 + 4) >> 3;
continue;
}
}
}
}
{
int x, x0, x1, x2;
int m;
x0 = (2 * p3 - 5 * p4 + 5 * p5 - 2 * p6 + 4) >> 3;
if (ABS(x0) < quant) {
x1 = (2 * p1 - 5 * p2 + 5 * p3 - 2 * p4 + 4) >> 3;
x2 = (2 * p5 - 5 * p6 + 5 * p7 - 2 * p8 + 4) >> 3;
x = ABS(x0) - MIN(ABS(x1), ABS(x2));
m = p4 - p5;
if (x > 0 && (m ^ x0) < 0) {
int32 sign;
sign = m >> 31;
m = (m ^ sign) - sign; // abs(m)
m >>= 1;
x = 5 * x >> 3;
if (x > m)
x = m;
x = (x ^ sign) - sign;
ptr[-1 * a_stride] -= x;
ptr[0] += x;
}
}
}
}
}
static void x8_h_loop_filter(uint8 *src, ptrdiff_t stride, int qscale) {
x8_loop_filter(src, stride, 1, qscale);
}
static void x8_v_loop_filter(uint8 *src, ptrdiff_t stride, int qscale) {
x8_loop_filter(src, 1, stride, qscale);
}
void ff_intrax8dsp_init(IntraX8DSPContext *dsp) {
dsp->h_loop_filter = x8_h_loop_filter;
dsp->v_loop_filter = x8_v_loop_filter;
dsp->setup_spatial_compensation = x8_setup_spatial_compensation;
dsp->spatial_compensation[0] = spatial_compensation_0;
dsp->spatial_compensation[1] = spatial_compensation_1;
dsp->spatial_compensation[2] = spatial_compensation_2;
dsp->spatial_compensation[3] = spatial_compensation_3;
dsp->spatial_compensation[4] = spatial_compensation_4;
dsp->spatial_compensation[5] = spatial_compensation_5;
dsp->spatial_compensation[6] = spatial_compensation_6;
dsp->spatial_compensation[7] = spatial_compensation_7;
dsp->spatial_compensation[8] = spatial_compensation_8;
dsp->spatial_compensation[9] = spatial_compensation_9;
dsp->spatial_compensation[10] = spatial_compensation_10;
dsp->spatial_compensation[11] = spatial_compensation_11;
}
#undef area1
#undef area2
#undef area3
#undef area4
#undef area5
#undef area6
static const uint8 x8_orient_lowquant_table[4][12][2] = {
{
/* Orient lowquant table 0 */
{0, 1},
{1, 3},
{2, 3},
{3, 4},
{4, 4},
{5, 6},
{7, 6},
{6, 5},
{8, 6},
{9, 6},
{10, 6},
{11, 6},
},
{
/* Orient lowquant table 1 */
{0, 5},
{1, 5},
{2, 5},
{6, 5},
{5, 4},
{8, 4},
{3, 2},
{4, 2},
{7, 3},
{9, 4},
{10, 5},
{11, 5},
},
{
/* Orient lowquant table 2 */
{0, 2},
{1, 2},
{2, 3},
{3, 3},
{4, 3},
{5, 6},
{6, 6},
{7, 5},
{8, 6},
{9, 6},
{10, 6},
{11, 6},
},
{
/* Orient lowquant table 3 */
{0, 3},
{1, 4},
{2, 4},
{3, 2},
{4, 2},
{5, 5},
{6, 5},
{7, 4},
{8, 5},
{9, 5},
{10, 5},
{11, 5},
},
};
static const uint8 x8_orient_highquant_table[2][12][2] = {
{
/* Orient highquant table 0 */
{0, 2},
{1, 2},
{2, 3},
{3, 3},
{4, 3},
{5, 6},
{7, 6},
{6, 5},
{8, 6},
{9, 6},
{10, 6},
{11, 6},
},
{
/* Orient highquant table 1 */
{0, 1},
{1, 2},
{2, 3},
{3, 5},
{4, 5},
{5, 7},
{7, 7},
{6, 6},
{8, 7},
{9, 7},
{10, 7},
{11, 7},
},
};
#define MAX_OR_VLC_BITS 7
static const uint8 x8_dc_quant_table[2][8][34][2] = {
{
{
/* DC highquant table 0 */
{0, 5}, {3, 5}, {1, 4}, {2, 4}, {4, 5}, {6, 5}, {5, 4}, {7, 5}, {8, 7},
{9, 7}, {10, 12}, {11, 12}, {12, 12}, {13, 12}, {14, 12}, {15, 12}, {16, 12}, {25, 12},
{26, 12}, {27, 12}, {28, 12}, {29, 12}, {30, 12}, {31, 12}, {32, 12}, {33, 12}, {24, 8},
{23, 7}, {17, 3}, {18, 2}, {19, 3}, {20, 4}, {21, 5}, {22, 5},
},
{
/* DC highquant table 1 */
{0, 3}, {1, 3}, {2, 3}, {3, 4}, {4, 4}, {5, 3}, {6, 4}, {7, 4}, {8, 6},
{9, 7}, {10, 7}, {11, 11}, {12, 11}, {13, 11}, {14, 11}, {15, 11}, {16, 11}, {25, 11},
{27, 11}, {28, 11}, {29, 11}, {30, 11}, {31, 11}, {32, 10}, {33, 10}, {23, 7}, {17, 6},
{18, 4}, {19, 5}, {20, 5}, {21, 6}, {24, 7}, {26, 7}, {22, 5},
},
{
/* DC highquant table 2 */
{0, 7}, {1, 7}, {2, 6}, {3, 7}, {5, 7}, {4, 6}, {6, 8}, {7, 8}, {8, 13},
{9, 13}, {10, 13}, {11, 13}, {12, 13}, {13, 13}, {14, 13}, {15, 13}, {16, 12}, {23, 12},
{24, 12}, {25, 12}, {26, 12}, {27, 12}, {28, 12}, {29, 12}, {30, 12}, {31, 12}, {32, 12},
{33, 12}, {22, 8}, {21, 6}, {20, 5}, {19, 3}, {18, 2}, {17, 1},
},
{
/* DC highquant table 3 */
{0, 4}, {3, 4}, {1, 3}, {2, 3}, {4, 4}, {8, 5}, {9, 5}, {5, 3}, {6, 3},
{7, 3}, {10, 7}, {11, 11}, {12, 11}, {13, 11}, {14, 11}, {15, 11}, {16, 11}, {25, 11},
{26, 11}, {27, 11}, {29, 11}, {30, 11}, {31, 11}, {32, 10}, {33, 10}, {18, 7}, {21, 7},
{17, 5}, {19, 6}, {20, 6}, {22, 7}, {23, 7}, {24, 7}, {28, 7},
},
{
/* DC highquant table 4 */
{0, 8}, {4, 9}, {6, 9}, {1, 7}, {2, 7}, {3, 7}, {5, 8}, {7, 14}, {8, 14},
{9, 14}, {10, 14}, {11, 14}, {12, 14}, {13, 14}, {14, 14}, {15, 13}, {16, 13}, {24, 13},
{25, 13}, {26, 13}, {27, 13}, {28, 13}, {29, 13}, {30, 13}, {31, 13}, {32, 13}, {33, 13},
{23, 9}, {22, 7}, {21, 6}, {20, 4}, {19, 3}, {17, 2}, {18, 1},
},
{
/* DC highquant table 5 */
{0, 7}, {1, 7}, {2, 6}, {3, 6}, {4, 6}, {5, 6}, {6, 6}, {7, 6}, {8, 6}, {9, 6}, {10, 6}, {11, 6},
{12, 6}, {13, 6}, {14, 6}, {15, 6}, {16, 6}, {17, 6}, {18, 6}, {19, 6}, {20, 6}, {21, 6}, {22, 6}, {23, 6},
{24, 6}, {25, 6}, {26, 6}, {28, 6}, {29, 6}, {30, 6}, {31, 6}, {32, 6}, {33, 6}, {27, 1},
},
{
/* DC highquant table 6 */
{0, 5}, {2, 5}, {1, 4}, {3, 5}, {4, 6}, {6, 6}, {5, 5}, {7, 6}, {8, 8},
{9, 8}, {10, 13}, {11, 13}, {12, 13}, {13, 13}, {14, 13}, {15, 13}, {16, 13}, {25, 13},
{26, 13}, {27, 13}, {28, 13}, {29, 13}, {30, 13}, {31, 13}, {32, 13}, {33, 13}, {24, 9},
{23, 8}, {17, 2}, {18, 2}, {19, 3}, {20, 4}, {21, 5}, {22, 5},
},
{
/* DC highquant table 7 */
{0, 7}, {1, 7}, {2, 7}, {3, 7}, {4, 7}, {5, 7}, {6, 7}, {7, 7}, {8, 7}, {9, 7}, {10, 7}, {11, 7},
{12, 7}, {13, 7}, {14, 7}, {15, 7}, {16, 7}, {19, 7}, {20, 7}, {21, 7}, {22, 7}, {23, 7}, {24, 7}, {25, 7},
{26, 7}, {27, 7}, {28, 7}, {29, 7}, {30, 7}, {31, 7}, {32, 7}, {33, 7}, {18, 2}, {17, 1},
},
},
{
{
/* DC lowquant table 0 */
{0, 5}, {2, 5}, {1, 4}, {3, 5}, {4, 5}, {5, 5}, {6, 6}, {7, 6}, {8, 8},
{9, 8}, {10, 13}, {11, 13}, {12, 13}, {13, 13}, {14, 13}, {15, 13}, {16, 13}, {25, 13},
{26, 13}, {27, 13}, {28, 13}, {29, 13}, {30, 13}, {31, 13}, {32, 13}, {33, 13}, {24, 9},
{23, 8}, {22, 6}, {21, 5}, {20, 4}, {19, 3}, {17, 2}, {18, 2},
},
{
/* DC lowquant table 1 */
{0, 4}, {3, 4}, {1, 3}, {2, 3}, {4, 4}, {6, 4}, {5, 3}, {7, 3}, {8, 4},
{9, 4}, {10, 5}, {11, 6}, {12, 9}, {13, 9}, {14, 13}, {15, 13}, {16, 13}, {25, 13},
{26, 13}, {27, 13}, {28, 12}, {29, 12}, {31, 12}, {32, 12}, {33, 12}, {21, 9}, {20, 7},
{17, 6}, {18, 6}, {19, 6}, {22, 7}, {23, 8}, {24, 9}, {30, 9},
},
{
/* DC lowquant table 2 */
{0, 4}, {3, 4}, {1, 3}, {2, 3}, {4, 4}, {5, 4}, {6, 4}, {7, 4}, {8, 6},
{9, 6}, {10, 7}, {11, 7}, {12, 12}, {13, 12}, {14, 12}, {15, 12}, {16, 12}, {25, 12},
{26, 12}, {27, 12}, {28, 12}, {29, 12}, {30, 12}, {31, 12}, {32, 11}, {33, 11}, {24, 8},
{23, 7}, {17, 4}, {18, 3}, {19, 4}, {20, 5}, {21, 6}, {22, 6},
},
{
/* DC lowquant table 3 */
{0, 4}, {6, 4}, {2, 3}, {1, 2}, {3, 3}, {4, 3}, {5, 3}, {7, 4}, {8, 6},
{9, 6}, {10, 7}, {11, 8}, {12, 14}, {13, 14}, {14, 14}, {15, 14}, {16, 13}, {21, 13},
{22, 13}, {23, 13}, {24, 13}, {25, 13}, {26, 13}, {27, 13}, {28, 13}, {29, 13}, {30, 13},
{31, 13}, {32, 13}, {33, 13}, {17, 9}, {18, 7}, {19, 8}, {20, 8},
},
{
/* DC lowquant table 4 */
{0, 7}, {1, 7}, {2, 7}, {3, 7}, {4, 7}, {5, 7}, {6, 7}, {7, 7}, {8, 7}, {9, 7}, {10, 7}, {11, 7},
{12, 7}, {13, 7}, {14, 7}, {15, 7}, {16, 7}, {19, 7}, {20, 7}, {21, 7}, {22, 7}, {23, 7}, {24, 7}, {25, 7},
{26, 7}, {27, 7}, {28, 7}, {29, 7}, {30, 7}, {31, 7}, {32, 7}, {33, 7}, {18, 2}, {17, 1},
},
{
/* DC lowquant table 5 */
{0, 5}, {2, 5}, {1, 4}, {3, 6}, {4, 6}, {5, 6}, {6, 7}, {8, 7}, {7, 6},
{9, 6}, {10, 8}, {12, 8}, {11, 7}, {13, 13}, {14, 13}, {15, 13}, {16, 13}, {23, 13},
{24, 13}, {25, 13}, {26, 13}, {27, 13}, {28, 13}, {29, 13}, {30, 13}, {31, 13}, {32, 13},
{33, 12}, {22, 9}, {21, 8}, {20, 7}, {17, 3}, {19, 3}, {18, 1},
},
{
/* DC lowquant table 6 */
{0, 4}, {4, 4}, {2, 3}, {1, 2}, {3, 3}, {5, 4}, {6, 5}, {7, 6}, {8, 7},
{9, 7}, {10, 8}, {11, 14}, {12, 14}, {15, 14}, {16, 14}, {23, 14}, {24, 14}, {25, 14},
{26, 14}, {27, 14}, {28, 14}, {29, 14}, {30, 14}, {31, 14}, {32, 14}, {33, 13}, {13, 10},
{14, 9}, {21, 8}, {22, 8}, {20, 6}, {19, 5}, {17, 4}, {18, 3},
},
{
/* DC lowquant table 7 */
{0, 6}, {1, 6}, {2, 6}, {3, 7}, {4, 7}, {5, 6}, {6, 6}, {7, 6}, {8, 7},
{9, 8}, {10, 8}, {11, 9}, {12, 10}, {13, 14}, {14, 14}, {15, 14}, {16, 14}, {24, 14},
{25, 14}, {26, 14}, {27, 14}, {28, 14}, {29, 14}, {30, 14}, {31, 14}, {32, 13}, {33, 13},
{23, 8}, {22, 7}, {21, 6}, {20, 5}, {19, 4}, {18, 2}, {17, 1},
},
},
};
#define MAX_DC_VLC_BITS 14
static const uint8 x8_ac_quant_table[2][2][8][77][2] = {
{
{
{
/* AC highquant table group 0, table 0 */
{0, 3}, {1, 4}, {2, 6}, {3, 6}, {4, 7}, {6, 15}, {8, 15}, {10, 15}, {12, 15}, {13, 15},
{14, 15}, {15, 14}, {34, 14}, {45, 14}, {46, 14}, {47, 14}, {49, 14}, {50, 14}, {51, 14}, {52, 14},
{53, 14}, {54, 14}, {55, 14}, {56, 14}, {57, 14}, {58, 14}, {60, 14}, {61, 14}, {62, 14}, {63, 14},
{64, 14}, {65, 14}, {67, 14}, {69, 14}, {70, 14}, {71, 14}, {72, 14}, {74, 14}, {75, 14}, {76, 14},
{9, 9}, {7, 8}, {5, 6}, {11, 9}, {18, 9}, {19, 9}, {22, 9}, {20, 7}, {17, 6}, {16, 5},
{21, 7}, {29, 8}, {33, 8}, {28, 6}, {27, 5}, {24, 3}, {23, 2}, {25, 4}, {26, 4}, {30, 7},
{32, 7}, {31, 6}, {35, 7}, {36, 7}, {37, 7}, {38, 9}, {41, 9}, {42, 8}, {39, 5}, {40, 6},
{43, 9}, {44, 9}, {48, 8}, {59, 9}, {66, 9}, {68, 9}, {73, 9},
},
{
/* AC highquant table group 0, table 1 */
{0, 3}, {1, 4}, {2, 4}, {3, 5}, {4, 6}, {5, 6}, {6, 6}, {7, 6}, {8, 7}, {9, 8},
{10, 8}, {11, 8}, {12, 8}, {13, 14}, {44, 14}, {47, 14}, {50, 14}, {51, 14}, {54, 14}, {55, 14},
{56, 14}, {63, 14}, {64, 14}, {67, 14}, {68, 14}, {69, 14}, {70, 14}, {72, 14}, {76, 14}, {14, 10},
{15, 10}, {45, 10}, {32, 8}, {16, 4}, {17, 5}, {18, 6}, {19, 7}, {31, 7}, {20, 5}, {21, 6},
{26, 6}, {22, 5}, {24, 5}, {23, 4}, {25, 5}, {27, 6}, {28, 6}, {29, 6}, {30, 6}, {33, 8},
{38, 8}, {34, 7}, {35, 7}, {36, 7}, {37, 7}, {39, 7}, {40, 7}, {41, 8}, {42, 8}, {43, 8},
{46, 9}, {49, 9}, {53, 8}, {58, 8}, {57, 6}, {48, 5}, {52, 5}, {59, 7}, {60, 8}, {61, 9},
{66, 9}, {62, 8}, {65, 8}, {71, 9}, {75, 9}, {74, 8}, {73, 5},
},
{
/* AC highquant table group 0, table 2 */
{0, 4}, {1, 5}, {2, 12}, {3, 12}, {4, 12}, {5, 12}, {6, 12}, {7, 12}, {8, 12}, {9, 12},
{10, 12}, {11, 12}, {12, 11}, {13, 11}, {14, 11}, {15, 11}, {16, 11}, {17, 11}, {18, 11}, {19, 11},
{20, 11}, {21, 11}, {22, 11}, {28, 11}, {29, 11}, {30, 11}, {31, 11}, {32, 11}, {33, 11}, {34, 11},
{35, 11}, {36, 11}, {37, 11}, {38, 11}, {40, 11}, {41, 11}, {42, 11}, {43, 11}, {44, 11}, {45, 11},
{46, 11}, {47, 11}, {48, 11}, {49, 11}, {50, 11}, {51, 11}, {52, 11}, {53, 11}, {54, 11}, {55, 11},
{56, 11}, {57, 11}, {58, 11}, {59, 11}, {60, 11}, {61, 11}, {62, 11}, {63, 11}, {64, 11}, {65, 11},
{66, 11}, {67, 11}, {68, 11}, {69, 11}, {70, 11}, {71, 11}, {72, 11}, {73, 11}, {74, 11}, {75, 11},
{76, 11}, {25, 5}, {26, 5}, {27, 5}, {39, 5}, {24, 2}, {23, 1},
},
{
/* AC highquant table group 0, table 3 */
{0, 8}, {1, 8}, {2, 8}, {3, 8}, {4, 8}, {5, 8}, {6, 8}, {7, 8}, {8, 8}, {9, 8}, {10, 8},
{11, 8}, {12, 8}, {13, 8}, {14, 8}, {15, 8}, {16, 8}, {17, 8}, {18, 8}, {19, 8}, {20, 8}, {21, 8},
{22, 8}, {24, 8}, {25, 7}, {26, 7}, {27, 7}, {28, 7}, {29, 7}, {30, 7}, {31, 7}, {32, 7}, {33, 7},
{34, 7}, {35, 7}, {36, 7}, {37, 7}, {38, 7}, {39, 7}, {40, 7}, {41, 7}, {42, 7}, {43, 7}, {44, 7},
{45, 7}, {46, 7}, {47, 7}, {48, 7}, {49, 7}, {50, 7}, {51, 7}, {52, 7}, {53, 7}, {54, 7}, {55, 7},
{56, 7}, {57, 7}, {58, 7}, {59, 7}, {60, 7}, {61, 7}, {62, 7}, {63, 7}, {64, 7}, {65, 7}, {66, 7},
{67, 7}, {68, 7}, {69, 7}, {70, 7}, {71, 7}, {72, 7}, {73, 7}, {74, 7}, {75, 7}, {76, 7}, {23, 1},
},
{
/* AC highquant table group 0, table 4 */
{0, 9}, {1, 9}, {2, 9}, {3, 9}, {4, 9}, {5, 9}, {6, 9}, {7, 9}, {8, 9}, {9, 9}, {10, 9},
{11, 9}, {12, 9}, {13, 9}, {14, 9}, {15, 9}, {16, 9}, {17, 9}, {18, 9}, {19, 9}, {20, 9}, {21, 9},
{22, 8}, {25, 8}, {26, 8}, {27, 8}, {28, 8}, {29, 8}, {30, 8}, {31, 8}, {32, 8}, {33, 8}, {34, 8},
{35, 8}, {36, 8}, {37, 8}, {38, 8}, {39, 8}, {40, 8}, {41, 8}, {42, 8}, {43, 8}, {44, 8}, {45, 8},
{46, 8}, {47, 8}, {48, 8}, {49, 8}, {50, 8}, {51, 8}, {52, 8}, {53, 8}, {54, 8}, {55, 8}, {56, 8},
{57, 8}, {58, 8}, {59, 8}, {60, 8}, {61, 8}, {62, 8}, {63, 8}, {64, 8}, {65, 8}, {66, 8}, {67, 8},
{68, 8}, {69, 8}, {70, 8}, {71, 8}, {72, 8}, {73, 8}, {74, 8}, {75, 8}, {76, 8}, {23, 2}, {24, 1},
},
{
/* AC highquant table group 0, table 5 */
{0, 10}, {1, 10}, {2, 10}, {3, 10}, {4, 10}, {5, 10}, {6, 10}, {7, 10}, {8, 10}, {9, 10},
{10, 10}, {11, 10}, {12, 10}, {13, 10}, {14, 10}, {15, 10}, {16, 10}, {17, 10}, {18, 10}, {19, 10},
{20, 9}, {21, 9}, {22, 9}, {25, 9}, {26, 9}, {28, 9}, {29, 9}, {30, 9}, {31, 9}, {32, 9},
{33, 9}, {34, 9}, {35, 9}, {36, 9}, {37, 9}, {38, 9}, {39, 9}, {40, 9}, {41, 9}, {42, 9},
{43, 9}, {44, 9}, {45, 9}, {46, 9}, {47, 9}, {48, 9}, {49, 9}, {50, 9}, {51, 9}, {52, 9},
{53, 9}, {54, 9}, {55, 9}, {56, 9}, {57, 9}, {58, 9}, {59, 9}, {60, 9}, {61, 9}, {62, 9},
{63, 9}, {64, 9}, {65, 9}, {66, 9}, {67, 9}, {68, 9}, {69, 9}, {70, 9}, {71, 9}, {72, 9},
{73, 9}, {74, 9}, {75, 9}, {76, 9}, {24, 3}, {27, 2}, {23, 1},
},
{
/* AC highquant table group 0, table 6 */
{0, 2}, {1, 4}, {2, 5}, {3, 5}, {4, 6}, {5, 6}, {6, 7}, {7, 8}, {8, 8}, {9, 8},
{10, 9}, {11, 9}, {12, 10}, {14, 10}, {13, 9}, {15, 15}, {42, 15}, {46, 15}, {50, 15}, {51, 15},
{55, 15}, {56, 14}, {59, 14}, {61, 14}, {62, 14}, {63, 14}, {64, 14}, {68, 14}, {69, 14}, {70, 14},
{71, 14}, {72, 14}, {75, 14}, {76, 14}, {43, 10}, {37, 9}, {17, 5}, {18, 6}, {19, 6}, {16, 3},
{20, 4}, {21, 7}, {24, 7}, {25, 7}, {26, 7}, {22, 5}, {23, 5}, {27, 8}, {30, 8}, {28, 7},
{29, 7}, {31, 8}, {32, 8}, {33, 8}, {34, 8}, {35, 8}, {36, 8}, {38, 8}, {39, 8}, {40, 8},
{41, 9}, {44, 10}, {45, 10}, {47, 10}, {54, 10}, {49, 9}, {58, 8}, {60, 10}, {66, 10}, {67, 10},
{74, 10}, {65, 8}, {48, 6}, {52, 4}, {53, 6}, {57, 6}, {73, 5},
},
{
/* AC highquant table group 0, table 7 */
{0, 3}, {1, 4}, {2, 5}, {3, 5}, {4, 6}, {5, 8}, {9, 13}, {12, 13}, {13, 13}, {14, 13},
{42, 13}, {45, 13}, {46, 13}, {47, 13}, {50, 13}, {51, 13}, {53, 13}, {54, 13}, {55, 13}, {56, 13},
{58, 13}, {61, 13}, {62, 13}, {63, 13}, {64, 13}, {66, 13}, {67, 13}, {68, 13}, {69, 13}, {70, 13},
{72, 12}, {74, 12}, {75, 12}, {76, 12}, {6, 7}, {7, 6}, {8, 7}, {10, 8}, {11, 8}, {15, 8},
{31, 8}, {18, 7}, {19, 6}, {17, 5}, {16, 4}, {20, 6}, {21, 7}, {36, 8}, {37, 8}, {22, 6},
{27, 6}, {23, 3}, {24, 5}, {25, 5}, {26, 4}, {28, 6}, {29, 6}, {30, 5}, {32, 6}, {33, 6},
{34, 6}, {35, 6}, {38, 7}, {40, 7}, {41, 7}, {43, 7}, {39, 5}, {44, 8}, {52, 8}, {48, 7},
{49, 7}, {57, 8}, {60, 8}, {59, 7}, {65, 8}, {71, 8}, {73, 6},
},
},
{
{
/* AC highquant table group 1, table 0 */
{0, 3}, {1, 4}, {2, 5}, {3, 5}, {4, 5}, {5, 5}, {6, 6}, {7, 7}, {9, 7}, {8, 6},
{10, 8}, {13, 8}, {11, 7}, {12, 7}, {14, 8}, {15, 9}, {41, 9}, {17, 6}, {18, 6}, {19, 7},
{21, 8}, {42, 9}, {43, 9}, {16, 4}, {20, 5}, {22, 6}, {26, 6}, {23, 4}, {24, 4}, {25, 5},
{27, 6}, {28, 6}, {29, 6}, {30, 7}, {31, 7}, {32, 7}, {33, 7}, {34, 7}, {35, 7}, {36, 7},
{37, 7}, {38, 7}, {39, 7}, {40, 7}, {44, 11}, {54, 14}, {55, 14}, {56, 14}, {64, 14}, {69, 14},
{70, 14}, {72, 14}, {76, 14}, {53, 10}, {45, 9}, {47, 8}, {46, 6}, {48, 5}, {49, 7}, {50, 9},
{51, 9}, {58, 10}, {67, 10}, {61, 9}, {52, 7}, {57, 7}, {59, 7}, {60, 8}, {62, 8}, {63, 7},
{65, 7}, {66, 7}, {68, 10}, {71, 10}, {74, 9}, {75, 8}, {73, 6},
},
{
/* AC highquant table group 1, table 1 */
{0, 2}, {1, 4}, {2, 5}, {3, 5}, {4, 6}, {5, 7}, {6, 7}, {7, 7}, {8, 8}, {9, 9},
{10, 9}, {11, 9}, {12, 9}, {13, 15}, {42, 15}, {44, 15}, {45, 15}, {46, 15}, {47, 15}, {50, 15},
{51, 15}, {56, 15}, {61, 15}, {62, 15}, {63, 15}, {64, 15}, {66, 15}, {67, 14}, {15, 11}, {14, 10},
{30, 9}, {19, 7}, {17, 5}, {18, 6}, {23, 6}, {16, 3}, {20, 4}, {21, 5}, {24, 7}, {25, 7},
{26, 8}, {27, 8}, {28, 7}, {22, 4}, {29, 8}, {31, 8}, {32, 9}, {33, 9}, {34, 9}, {35, 9},
{36, 10}, {37, 11}, {38, 11}, {39, 9}, {40, 9}, {41, 11}, {55, 11}, {43, 10}, {49, 8}, {54, 8},
{48, 6}, {53, 7}, {58, 8}, {59, 11}, {68, 14}, {69, 14}, {70, 14}, {71, 14}, {72, 14}, {74, 14},
{75, 14}, {76, 14}, {60, 10}, {65, 9}, {52, 4}, {57, 5}, {73, 5},
},
{
/* AC highquant table group 1, table 2 */
{0, 3}, {1, 4}, {2, 4}, {3, 5}, {4, 6}, {5, 7}, {7, 7}, {6, 6}, {8, 9}, {9, 9},
{10, 8}, {11, 15}, {13, 15}, {14, 15}, {15, 15}, {46, 15}, {47, 15}, {50, 15}, {51, 15}, {54, 14},
{55, 14}, {56, 14}, {62, 14}, {63, 14}, {64, 14}, {66, 14}, {67, 14}, {69, 14}, {70, 14}, {72, 14},
{76, 14}, {34, 10}, {12, 9}, {31, 8}, {17, 5}, {16, 3}, {18, 7}, {19, 7}, {21, 6}, {22, 5},
{20, 4}, {23, 4}, {24, 4}, {25, 5}, {26, 6}, {27, 6}, {28, 6}, {29, 6}, {30, 7}, {32, 7},
{33, 8}, {35, 8}, {36, 9}, {37, 10}, {38, 10}, {41, 9}, {42, 9}, {39, 6}, {40, 7}, {43, 8},
{44, 10}, {60, 10}, {45, 9}, {48, 7}, {49, 9}, {58, 9}, {53, 8}, {57, 6}, {52, 5}, {59, 9},
{61, 10}, {68, 10}, {65, 8}, {71, 9}, {75, 9}, {74, 8}, {73, 6},
},
{
/* AC highquant table group 1, table 3 */
{0, 3}, {1, 4}, {2, 5}, {3, 5}, {4, 6}, {5, 6}, {6, 7}, {7, 7}, {8, 6}, {9, 6},
{10, 7}, {11, 7}, {12, 9}, {13, 9}, {15, 8}, {14, 7}, {17, 6}, {16, 5}, {18, 9}, {42, 9},
{32, 8}, {19, 7}, {20, 6}, {21, 7}, {22, 7}, {27, 6}, {25, 5}, {23, 3}, {24, 3}, {26, 5},
{28, 6}, {29, 6}, {30, 7}, {31, 7}, {33, 8}, {34, 8}, {35, 8}, {41, 8}, {36, 7}, {38, 7},
{37, 6}, {39, 7}, {43, 14}, {44, 14}, {45, 14}, {50, 14}, {51, 14}, {53, 14}, {54, 13}, {55, 13},
{56, 13}, {58, 13}, {64, 13}, {67, 13}, {68, 13}, {69, 13}, {70, 13}, {71, 13}, {72, 13}, {74, 13},
{76, 13}, {47, 9}, {49, 8}, {40, 6}, {46, 7}, {48, 7}, {52, 8}, {57, 8}, {60, 7}, {59, 6},
{61, 9}, {75, 9}, {73, 8}, {63, 7}, {62, 6}, {65, 7}, {66, 7},
},
{
/* AC highquant table group 1, table 4 */
{0, 2}, {1, 4}, {2, 5}, {3, 5}, {4, 6}, {5, 6}, {6, 7}, {7, 7}, {8, 7}, {9, 8},
{10, 9}, {11, 9}, {12, 10}, {13, 10}, {14, 10}, {15, 15}, {50, 15}, {51, 15}, {54, 15}, {55, 15},
{56, 15}, {61, 15}, {64, 15}, {45, 12}, {47, 12}, {58, 12}, {32, 8}, {19, 7}, {18, 6}, {17, 5},
{16, 3}, {20, 4}, {21, 6}, {22, 6}, {24, 5}, {23, 4}, {25, 6}, {26, 6}, {27, 6}, {28, 7},
{29, 7}, {30, 7}, {31, 7}, {33, 8}, {34, 8}, {35, 8}, {36, 8}, {37, 8}, {38, 10}, {43, 10},
{41, 9}, {39, 7}, {40, 8}, {42, 9}, {44, 10}, {46, 10}, {49, 8}, {53, 9}, {59, 10}, {60, 10},
{48, 6}, {52, 6}, {57, 7}, {62, 12}, {67, 15}, {69, 15}, {70, 15}, {71, 15}, {72, 14}, {76, 14},
{63, 11}, {68, 12}, {74, 12}, {75, 11}, {66, 9}, {65, 8}, {73, 6},
},
{
/* AC highquant table group 1, table 5 */
{0, 3}, {1, 4}, {2, 4}, {3, 5}, {4, 5}, {5, 6}, {6, 7}, {7, 8}, {8, 11}, {10, 11},
{11, 10}, {9, 9}, {12, 11}, {13, 15}, {14, 15}, {15, 15}, {47, 15}, {49, 15}, {50, 15}, {51, 15},
{54, 15}, {55, 14}, {56, 14}, {58, 14}, {63, 14}, {38, 11}, {53, 11}, {37, 9}, {32, 8}, {19, 7},
{18, 6}, {16, 4}, {17, 5}, {20, 5}, {21, 7}, {31, 7}, {22, 6}, {25, 5}, {24, 4}, {23, 3},
{26, 5}, {27, 5}, {28, 5}, {29, 6}, {30, 6}, {33, 8}, {34, 8}, {35, 7}, {36, 8}, {41, 8},
{40, 7}, {39, 5}, {42, 8}, {44, 10}, {60, 10}, {45, 9}, {43, 7}, {46, 9}, {59, 9}, {61, 10},
{64, 14}, {67, 14}, {68, 14}, {69, 14}, {70, 14}, {72, 14}, {75, 14}, {76, 14}, {66, 11}, {62, 9},
{48, 7}, {52, 7}, {57, 7}, {65, 8}, {71, 9}, {74, 9}, {73, 7},
},
{
/* AC highquant table group 1, table 6 */
{0, 3}, {1, 4}, {2, 4}, {3, 5}, {4, 5}, {5, 5}, {6, 5}, {7, 6}, {8, 7}, {10, 7},
{9, 5}, {11, 13}, {13, 13}, {15, 13}, {29, 13}, {32, 13}, {33, 13}, {34, 12}, {37, 12}, {38, 12},
{40, 12}, {41, 12}, {42, 12}, {43, 12}, {44, 12}, {45, 12}, {50, 12}, {53, 12}, {54, 12}, {55, 12},
{56, 12}, {58, 12}, {60, 12}, {61, 12}, {62, 12}, {63, 12}, {64, 12}, {66, 12}, {67, 12}, {68, 12},
{69, 12}, {70, 12}, {71, 12}, {72, 12}, {74, 12}, {76, 12}, {12, 7}, {14, 7}, {18, 7}, {17, 6},
{19, 7}, {21, 7}, {16, 4}, {20, 5}, {22, 5}, {23, 6}, {24, 6}, {25, 7}, {27, 7}, {26, 6},
{28, 7}, {30, 7}, {31, 7}, {35, 7}, {36, 7}, {39, 7}, {47, 6}, {46, 5}, {49, 5}, {48, 4},
{51, 7}, {75, 7}, {57, 6}, {52, 5}, {59, 6}, {65, 6}, {73, 5},
},
{
/* AC highquant table group 1, table 7 */
{0, 3}, {1, 4}, {2, 5}, {3, 6}, {4, 6}, {5, 8}, {6, 8}, {7, 8}, {8, 11}, {9, 15},
{10, 15}, {11, 15}, {12, 15}, {13, 15}, {14, 15}, {15, 15}, {38, 15}, {46, 15}, {47, 15}, {50, 15},
{51, 15}, {53, 15}, {54, 15}, {55, 15}, {56, 15}, {37, 11}, {58, 15}, {61, 15}, {62, 15}, {63, 15},
{64, 15}, {66, 15}, {67, 15}, {68, 15}, {69, 15}, {70, 15}, {72, 14}, {75, 14}, {76, 14}, {19, 9},
{17, 6}, {18, 7}, {21, 8}, {22, 8}, {28, 6}, {16, 4}, {20, 5}, {25, 5}, {26, 5}, {27, 5},
{23, 2}, {24, 3}, {29, 6}, {30, 8}, {31, 8}, {32, 9}, {36, 9}, {33, 8}, {34, 7}, {35, 8},
{41, 8}, {40, 7}, {42, 9}, {44, 9}, {43, 8}, {39, 5}, {45, 9}, {49, 10}, {71, 10}, {48, 8},
{52, 8}, {57, 9}, {60, 9}, {59, 8}, {65, 9}, {74, 9}, {73, 7},
},
},
},
{
{
{
/* AC lowquant table group 0, table 0 */
{0, 2}, {1, 3}, {2, 4}, {3, 5}, {4, 6}, {5, 7}, {6, 7}, {7, 7}, {8, 9}, {12, 10},
{13, 10}, {9, 8}, {10, 8}, {11, 8}, {14, 10}, {15, 10}, {18, 9}, {19, 10}, {41, 10}, {40, 9},
{17, 7}, {21, 7}, {20, 6}, {16, 4}, {22, 7}, {32, 7}, {28, 6}, {25, 5}, {23, 4}, {24, 4},
{26, 5}, {27, 5}, {29, 6}, {30, 6}, {31, 6}, {33, 7}, {34, 7}, {35, 7}, {36, 7}, {37, 7},
{38, 7}, {39, 8}, {42, 14}, {43, 14}, {44, 14}, {45, 14}, {47, 14}, {49, 14}, {50, 14}, {51, 14},
{53, 14}, {54, 14}, {55, 14}, {56, 14}, {58, 14}, {63, 14}, {64, 14}, {65, 14}, {46, 10}, {48, 9},
{52, 8}, {57, 10}, {66, 14}, {67, 14}, {68, 14}, {69, 14}, {70, 14}, {71, 14}, {72, 13}, {73, 13},
{74, 13}, {75, 13}, {76, 13}, {62, 9}, {59, 7}, {60, 8}, {61, 8},
},
{
/* AC lowquant table group 0, table 1 */
{0, 3}, {1, 5}, {2, 7}, {5, 8}, {6, 8}, {3, 6}, {4, 6}, {7, 8}, {8, 14}, {9, 14},
{11, 14}, {12, 14}, {13, 14}, {14, 14}, {15, 14}, {18, 14}, {20, 14}, {21, 14}, {22, 14}, {41, 14},
{45, 14}, {46, 14}, {47, 14}, {49, 14}, {50, 14}, {51, 14}, {52, 13}, {53, 13}, {54, 13}, {55, 13},
{56, 13}, {57, 13}, {58, 13}, {60, 13}, {61, 13}, {62, 13}, {63, 13}, {64, 13}, {66, 13}, {67, 13},
{68, 13}, {69, 13}, {70, 13}, {71, 13}, {72, 13}, {73, 13}, {74, 13}, {75, 13}, {76, 13}, {10, 7},
{16, 6}, {17, 8}, {19, 8}, {30, 7}, {23, 2}, {24, 3}, {25, 5}, {29, 6}, {31, 7}, {32, 7},
{26, 4}, {27, 4}, {28, 4}, {33, 7}, {34, 8}, {40, 8}, {35, 7}, {42, 8}, {43, 8}, {36, 6},
{37, 6}, {38, 6}, {39, 6}, {44, 8}, {48, 8}, {65, 7}, {59, 6},
},
{
/* AC lowquant table group 0, table 2 */
{0, 2}, {1, 3}, {2, 3}, {3, 4}, {4, 5}, {5, 5}, {6, 6}, {7, 6}, {8, 7}, {9, 7},
{10, 7}, {11, 8}, {12, 8}, {13, 8}, {14, 9}, {15, 10}, {39, 16}, {40, 16}, {41, 15}, {43, 15},
{44, 15}, {45, 15}, {50, 15}, {51, 15}, {53, 15}, {42, 12}, {49, 12}, {54, 15}, {55, 15}, {56, 15},
{58, 15}, {64, 15}, {65, 15}, {66, 15}, {67, 15}, {18, 8}, {19, 9}, {21, 9}, {17, 6}, {20, 6},
{22, 8}, {38, 8}, {27, 7}, {16, 4}, {23, 5}, {24, 6}, {25, 6}, {26, 6}, {28, 7}, {29, 7},
{30, 7}, {31, 7}, {32, 7}, {33, 7}, {34, 7}, {35, 7}, {36, 7}, {37, 7}, {46, 8}, {47, 10},
{62, 11}, {63, 12}, {68, 15}, {69, 15}, {70, 15}, {71, 15}, {72, 15}, {74, 15}, {75, 15}, {76, 15},
{48, 9}, {52, 8}, {57, 9}, {73, 9}, {59, 7}, {60, 8}, {61, 8},
},
{
/* AC lowquant table group 0, table 3 */
{0, 2}, {1, 3}, {2, 4}, {3, 5}, {4, 5}, {5, 6}, {6, 6}, {7, 7}, {8, 7}, {9, 8},
{10, 8}, {11, 9}, {12, 9}, {13, 9}, {14, 10}, {15, 10}, {17, 5}, {18, 7}, {19, 7}, {21, 7},
{24, 7}, {16, 3}, {20, 4}, {22, 5}, {23, 6}, {25, 7}, {26, 7}, {27, 8}, {28, 8}, {29, 8},
{30, 8}, {31, 8}, {32, 8}, {33, 9}, {37, 9}, {34, 8}, {35, 8}, {36, 8}, {38, 11}, {40, 11},
{39, 10}, {41, 15}, {43, 15}, {44, 15}, {45, 15}, {50, 15}, {51, 15}, {64, 15}, {66, 15}, {49, 12},
{47, 11}, {42, 10}, {46, 9}, {55, 10}, {56, 11}, {63, 12}, {67, 15}, {68, 15}, {69, 15}, {70, 15},
{71, 15}, {72, 15}, {74, 14}, {48, 7}, {53, 7}, {52, 5}, {54, 8}, {58, 10}, {61, 10}, {62, 10},
{65, 11}, {75, 12}, {76, 12}, {57, 7}, {59, 8}, {60, 8}, {73, 7},
},
{
/* AC lowquant table group 0, table 4 */
{0, 3}, {1, 4}, {2, 4}, {3, 5}, {4, 6}, {5, 6}, {6, 6}, {7, 7}, {9, 7}, {8, 6},
{10, 8}, {11, 8}, {12, 8}, {13, 9}, {14, 9}, {15, 8}, {37, 8}, {31, 7}, {18, 6}, {17, 5},
{16, 4}, {19, 6}, {21, 6}, {22, 5}, {20, 4}, {23, 5}, {24, 6}, {25, 6}, {26, 6}, {27, 6},
{28, 6}, {29, 6}, {30, 6}, {32, 7}, {33, 7}, {34, 7}, {35, 7}, {36, 7}, {38, 11}, {50, 15},
{51, 15}, {55, 15}, {56, 15}, {64, 15}, {69, 15}, {70, 14}, {71, 14}, {72, 14}, {75, 14}, {76, 14},
{45, 10}, {42, 9}, {41, 8}, {39, 7}, {40, 7}, {43, 9}, {44, 9}, {46, 9}, {47, 10}, {58, 10},
{49, 8}, {54, 9}, {62, 10}, {66, 10}, {48, 6}, {53, 7}, {59, 7}, {52, 4}, {57, 6}, {60, 8},
{61, 8}, {63, 9}, {65, 9}, {67, 10}, {68, 10}, {74, 9}, {73, 5},
},
{
/* AC lowquant table group 0, table 5 */
{0, 2}, {1, 4}, {2, 5}, {3, 5}, {4, 6}, {5, 6}, {6, 7}, {7, 8}, {8, 8}, {9, 8},
{10, 9}, {11, 11}, {14, 11}, {13, 10}, {12, 8}, {15, 15}, {42, 15}, {50, 15}, {51, 15}, {62, 15},
{64, 15}, {67, 15}, {68, 15}, {69, 14}, {70, 14}, {71, 14}, {72, 14}, {38, 11}, {40, 10}, {33, 9},
{17, 5}, {18, 6}, {19, 7}, {24, 7}, {16, 3}, {20, 4}, {21, 6}, {23, 6}, {22, 5}, {25, 8},
{27, 8}, {26, 7}, {28, 7}, {29, 8}, {31, 8}, {30, 7}, {32, 8}, {34, 9}, {35, 9}, {36, 9},
{37, 9}, {39, 9}, {41, 11}, {44, 11}, {43, 10}, {45, 11}, {47, 11}, {46, 10}, {56, 9}, {49, 8},
{48, 6}, {54, 7}, {55, 7}, {53, 5}, {52, 4}, {57, 6}, {58, 8}, {59, 8}, {60, 10}, {61, 11},
{75, 11}, {63, 10}, {65, 10}, {66, 10}, {74, 10}, {76, 9}, {73, 5},
},
{
/* AC lowquant table group 0, table 6 */
{0, 2}, {1, 4}, {2, 5}, {3, 6}, {4, 6}, {5, 8}, {6, 9}, {7, 10}, {8, 10}, {9, 9},
{10, 15}, {11, 15}, {13, 15}, {15, 15}, {37, 15}, {46, 15}, {47, 15}, {49, 15}, {50, 15}, {51, 15},
{53, 15}, {54, 15}, {55, 15}, {56, 15}, {58, 15}, {60, 15}, {61, 15}, {62, 15}, {63, 15}, {64, 15},
{67, 15}, {68, 15}, {69, 15}, {70, 15}, {71, 15}, {72, 15}, {74, 14}, {75, 14}, {76, 14}, {12, 10},
{14, 10}, {36, 10}, {21, 9}, {18, 8}, {19, 8}, {22, 8}, {32, 8}, {17, 5}, {16, 4}, {20, 5},
{26, 5}, {25, 4}, {23, 3}, {24, 3}, {27, 6}, {28, 6}, {29, 7}, {30, 7}, {31, 7}, {33, 8},
{34, 9}, {38, 9}, {35, 8}, {41, 9}, {42, 10}, {45, 10}, {43, 8}, {44, 8}, {39, 6}, {40, 6},
{48, 9}, {57, 9}, {52, 8}, {59, 9}, {65, 10}, {66, 10}, {73, 8},
},
{
/* AC lowquant table group 0, table 7 */
{0, 4}, {1, 11}, {2, 11}, {3, 11}, {4, 11}, {5, 11}, {6, 11}, {7, 11}, {8, 11}, {9, 11},
{10, 11}, {11, 11}, {12, 11}, {13, 11}, {14, 11}, {15, 11}, {16, 11}, {17, 10}, {18, 10}, {19, 10},
{20, 10}, {21, 10}, {22, 10}, {25, 10}, {28, 10}, {29, 10}, {30, 10}, {31, 10}, {32, 10}, {33, 10},
{34, 10}, {35, 10}, {36, 10}, {37, 10}, {38, 10}, {39, 10}, {40, 10}, {41, 10}, {42, 10}, {43, 10},
{44, 10}, {45, 10}, {46, 10}, {47, 10}, {48, 10}, {49, 10}, {50, 10}, {51, 10}, {52, 10}, {53, 10},
{54, 10}, {55, 10}, {56, 10}, {57, 10}, {58, 10}, {59, 10}, {60, 10}, {61, 10}, {62, 10}, {63, 10},
{64, 10}, {65, 10}, {66, 10}, {67, 10}, {68, 10}, {69, 10}, {70, 10}, {71, 10}, {72, 10}, {73, 10},
{74, 10}, {75, 10}, {76, 10}, {26, 4}, {27, 4}, {24, 2}, {23, 1},
},
},
{
{
/* AC lowquant table group 1, table 0 */
{0, 3}, {1, 4}, {2, 4}, {3, 5}, {4, 6}, {5, 7}, {7, 8}, {8, 8}, {6, 6}, {9, 9},
{10, 10}, {14, 15}, {47, 15}, {49, 14}, {50, 14}, {51, 14}, {54, 14}, {55, 14}, {56, 14}, {58, 14},
{15, 11}, {11, 9}, {12, 9}, {13, 9}, {37, 9}, {32, 8}, {17, 5}, {16, 4}, {18, 6}, {19, 7},
{21, 7}, {20, 5}, {22, 5}, {25, 5}, {24, 4}, {23, 3}, {26, 5}, {27, 5}, {28, 5}, {29, 6},
{30, 6}, {31, 7}, {33, 8}, {34, 8}, {35, 8}, {36, 8}, {38, 10}, {44, 11}, {46, 11}, {45, 10},
{53, 10}, {41, 8}, {39, 6}, {40, 7}, {42, 8}, {43, 8}, {48, 7}, {57, 7}, {52, 6}, {59, 8},
{60, 9}, {61, 11}, {63, 11}, {62, 10}, {64, 14}, {67, 14}, {68, 14}, {69, 14}, {70, 14}, {71, 14},
{72, 14}, {76, 14}, {75, 11}, {66, 10}, {74, 9}, {65, 8}, {73, 6},
},
{
/* AC lowquant table group 1, table 1 */
{0, 2}, {1, 3}, {2, 4}, {3, 5}, {4, 6}, {5, 6}, {6, 7}, {7, 8}, {8, 8}, {9, 8},
{10, 9}, {11, 9}, {12, 11}, {13, 11}, {14, 11}, {15, 11}, {24, 9}, {23, 8}, {17, 5}, {18, 6},
{19, 7}, {25, 10}, {27, 10}, {26, 9}, {28, 10}, {29, 12}, {35, 12}, {34, 11}, {30, 10}, {31, 10},
{21, 6}, {32, 10}, {33, 10}, {36, 10}, {37, 12}, {38, 12}, {39, 15}, {40, 15}, {41, 15}, {42, 15},
{43, 14}, {44, 14}, {45, 14}, {51, 14}, {61, 14}, {64, 14}, {46, 11}, {47, 11}, {49, 10}, {50, 12},
{63, 12}, {59, 11}, {56, 10}, {48, 8}, {55, 8}, {16, 3}, {20, 4}, {22, 4}, {52, 4}, {53, 6},
{54, 7}, {58, 8}, {60, 10}, {62, 11}, {65, 14}, {66, 14}, {67, 14}, {68, 14}, {69, 14}, {70, 14},
{71, 14}, {72, 14}, {74, 11}, {75, 11}, {76, 10}, {57, 6}, {73, 6},
},
{
/* AC lowquant table group 1, table 2 */
{0, 3}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {5, 8}, {6, 8}, {7, 8}, {8, 10}, {10, 10},
{9, 9}, {11, 10}, {12, 16}, {15, 16}, {38, 16}, {44, 16}, {46, 15}, {47, 15}, {50, 15}, {51, 15},
{59, 15}, {60, 15}, {61, 15}, {62, 15}, {64, 15}, {68, 15}, {69, 15}, {70, 15}, {71, 15}, {72, 15},
{37, 11}, {13, 10}, {14, 10}, {19, 8}, {18, 6}, {17, 5}, {21, 5}, {23, 7}, {24, 9}, {25, 9},
{26, 9}, {27, 9}, {28, 9}, {29, 10}, {30, 10}, {31, 10}, {32, 10}, {33, 10}, {34, 10}, {35, 9},
{36, 10}, {39, 10}, {40, 11}, {42, 11}, {41, 10}, {43, 10}, {45, 11}, {63, 11}, {16, 3}, {20, 3},
{22, 4}, {48, 7}, {49, 9}, {65, 11}, {66, 11}, {67, 11}, {74, 11}, {56, 8}, {54, 6}, {55, 6},
{58, 7}, {75, 8}, {76, 8}, {52, 3}, {53, 4}, {57, 5}, {73, 5},
},
{
/* AC lowquant table group 1, table 3 */
{0, 2}, {1, 3}, {2, 4}, {3, 4}, {4, 5}, {5, 5}, {6, 6}, {7, 6}, {8, 6}, {9, 6},
{10, 7}, {11, 7}, {12, 8}, {13, 8}, {14, 8}, {15, 9}, {19, 9}, {17, 6}, {18, 7}, {21, 8},
{36, 8}, {16, 4}, {20, 6}, {22, 7}, {28, 7}, {23, 6}, {24, 6}, {25, 6}, {26, 6}, {27, 6},
{29, 7}, {30, 7}, {31, 7}, {32, 7}, {33, 7}, {34, 7}, {35, 7}, {37, 8}, {38, 9}, {39, 11},
{41, 15}, {42, 15}, {43, 15}, {44, 15}, {45, 15}, {51, 15}, {54, 15}, {55, 15}, {49, 12}, {40, 10},
{46, 7}, {47, 8}, {48, 8}, {50, 9}, {53, 9}, {56, 15}, {67, 15}, {68, 15}, {69, 15}, {70, 14},
{71, 14}, {72, 14}, {74, 14}, {75, 14}, {76, 14}, {58, 11}, {65, 11}, {66, 11}, {64, 9}, {52, 7},
{57, 8}, {61, 8}, {60, 7}, {59, 6}, {62, 8}, {73, 8}, {63, 7},
},
{
/* AC lowquant table group 1, table 4 */
{0, 2}, {1, 4}, {2, 5}, {3, 6}, {4, 6}, {5, 7}, {6, 7}, {7, 8}, {8, 8}, {9, 8},
{10, 9}, {11, 9}, {12, 10}, {13, 10}, {14, 14}, {69, 14}, {70, 14}, {72, 14}, {15, 12}, {44, 11},
{37, 10}, {29, 8}, {19, 7}, {18, 6}, {17, 5}, {21, 6}, {24, 6}, {16, 3}, {20, 4}, {22, 5},
{23, 5}, {25, 6}, {26, 6}, {27, 7}, {28, 7}, {30, 7}, {31, 8}, {32, 8}, {33, 8}, {34, 8},
{35, 8}, {36, 9}, {38, 10}, {43, 10}, {39, 7}, {40, 8}, {41, 9}, {42, 9}, {45, 9}, {46, 9},
{47, 10}, {50, 12}, {51, 12}, {62, 11}, {56, 9}, {48, 7}, {49, 8}, {54, 8}, {55, 8}, {58, 8},
{52, 4}, {53, 6}, {57, 6}, {59, 9}, {60, 10}, {61, 10}, {63, 10}, {64, 11}, {67, 11}, {65, 9},
{66, 9}, {68, 11}, {71, 11}, {76, 10}, {74, 9}, {75, 9}, {73, 6},
},
{
/* AC lowquant table group 1, table 5 */
{0, 2}, {1, 3}, {2, 4}, {3, 5}, {4, 5}, {5, 6}, {6, 6}, {7, 7}, {8, 7}, {9, 7},
{10, 8}, {11, 8}, {12, 8}, {13, 9}, {14, 10}, {39, 11}, {40, 12}, {41, 12}, {15, 9}, {37, 9},
{19, 8}, {18, 7}, {21, 7}, {17, 5}, {16, 3}, {20, 5}, {22, 6}, {24, 6}, {23, 5}, {25, 7},
{26, 7}, {27, 7}, {28, 8}, {29, 8}, {30, 7}, {31, 8}, {32, 8}, {33, 8}, {34, 8}, {35, 8},
{36, 8}, {38, 9}, {42, 15}, {44, 15}, {45, 15}, {56, 15}, {43, 13}, {51, 13}, {66, 13}, {58, 11},
{49, 10}, {46, 8}, {47, 9}, {50, 9}, {48, 8}, {53, 7}, {54, 9}, {55, 9}, {59, 8}, {52, 5},
{57, 7}, {60, 8}, {61, 8}, {62, 9}, {64, 11}, {65, 12}, {67, 15}, {68, 15}, {69, 15}, {70, 15},
{71, 15}, {72, 15}, {74, 14}, {75, 11}, {76, 11}, {63, 8}, {73, 7},
},
{
/* AC lowquant table group 1, table 6 */
{0, 3}, {1, 4}, {2, 4}, {3, 5}, {4, 5}, {5, 6}, {6, 6}, {7, 7}, {8, 8}, {9, 8},
{10, 8}, {11, 9}, {12, 9}, {13, 9}, {14, 11}, {15, 12}, {45, 12}, {38, 10}, {33, 8}, {16, 3},
{17, 5}, {18, 6}, {19, 7}, {27, 7}, {20, 4}, {21, 6}, {25, 6}, {22, 5}, {23, 4}, {24, 5},
{26, 6}, {28, 7}, {29, 7}, {30, 7}, {31, 7}, {32, 7}, {34, 8}, {35, 8}, {36, 9}, {41, 9},
{37, 8}, {39, 7}, {40, 8}, {42, 11}, {47, 15}, {50, 15}, {51, 15}, {56, 15}, {64, 15}, {67, 15},
{68, 15}, {69, 15}, {70, 14}, {71, 14}, {72, 14}, {76, 14}, {44, 10}, {43, 9}, {46, 9}, {54, 9},
{55, 11}, {63, 11}, {61, 10}, {58, 9}, {48, 6}, {49, 7}, {53, 7}, {52, 5}, {57, 6}, {59, 8},
{60, 9}, {62, 10}, {74, 10}, {65, 8}, {66, 9}, {75, 9}, {73, 5},
},
{
/* AC lowquant table group 1, table 7 */
{0, 2}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {5, 7}, {6, 8}, {7, 8}, {8, 9}, {9, 9},
{10, 9}, {11, 10}, {12, 15}, {13, 15}, {14, 15}, {15, 15}, {32, 15}, {36, 15}, {38, 15}, {41, 15},
{42, 15}, {45, 15}, {47, 15}, {50, 15}, {51, 15}, {61, 15}, {62, 14}, {34, 11}, {18, 6}, {17, 5},
{19, 7}, {23, 8}, {24, 8}, {21, 6}, {25, 9}, {26, 10}, {28, 10}, {27, 9}, {29, 9}, {30, 10},
{31, 10}, {33, 10}, {35, 11}, {40, 11}, {37, 10}, {43, 11}, {44, 11}, {39, 9}, {46, 11}, {60, 11},
{49, 10}, {56, 9}, {59, 9}, {63, 14}, {64, 14}, {67, 14}, {68, 14}, {69, 14}, {70, 14}, {71, 14},
{72, 14}, {74, 11}, {76, 10}, {48, 7}, {16, 3}, {20, 4}, {22, 4}, {52, 3}, {53, 5}, {54, 7},
{55, 7}, {58, 7}, {65, 9}, {66, 9}, {75, 8}, {57, 5}, {73, 5},
},
},
},
};
#define MAX_AC_VLC_BITS 16
#define W0 2048
#define W1 2841 /* 2048*sqrt (2)*cos (1*pi/16) */
#define W2 2676 /* 2048*sqrt (2)*cos (2*pi/16) */
#define W3 2408 /* 2048*sqrt (2)*cos (3*pi/16) */
#define W4 2048 /* 2048*sqrt (2)*cos (4*pi/16) */
#define W5 1609 /* 2048*sqrt (2)*cos (5*pi/16) */
#define W6 1108 /* 2048*sqrt (2)*cos (6*pi/16) */
#define W7 565 /* 2048*sqrt (2)*cos (7*pi/16) */
static void wmv2_idct_row(short *b) {
int s1, s2;
int a0, a1, a2, a3, a4, a5, a6, a7;
/* step 1 */
a1 = W1 * b[1] + W7 * b[7];
a7 = W7 * b[1] - W1 * b[7];
a5 = W5 * b[5] + W3 * b[3];
a3 = W3 * b[5] - W5 * b[3];
a2 = W2 * b[2] + W6 * b[6];
a6 = W6 * b[2] - W2 * b[6];
a0 = W0 * b[0] + W0 * b[4];
a4 = W0 * b[0] - W0 * b[4];
/* step 2 */
s1 = (int)(181U * (a1 - a5 + a7 - a3) + 128) >> 8; // 1, 3, 5, 7
s2 = (int)(181U * (a1 - a5 - a7 + a3) + 128) >> 8;
/* step 3 */
b[0] = (a0 + a2 + a1 + a5 + (1 << 7)) >> 8;
b[1] = (a4 + a6 + s1 + (1 << 7)) >> 8;
b[2] = (a4 - a6 + s2 + (1 << 7)) >> 8;
b[3] = (a0 - a2 + a7 + a3 + (1 << 7)) >> 8;
b[4] = (a0 - a2 - a7 - a3 + (1 << 7)) >> 8;
b[5] = (a4 - a6 - s2 + (1 << 7)) >> 8;
b[6] = (a4 + a6 - s1 + (1 << 7)) >> 8;
b[7] = (a0 + a2 - a1 - a5 + (1 << 7)) >> 8;
}
static void wmv2_idct_col(short *b) {
int s1, s2;
int a0, a1, a2, a3, a4, a5, a6, a7;
/* step 1, with extended precision */
a1 = (W1 * b[8 * 1] + W7 * b[8 * 7] + 4) >> 3;
a7 = (W7 * b[8 * 1] - W1 * b[8 * 7] + 4) >> 3;
a5 = (W5 * b[8 * 5] + W3 * b[8 * 3] + 4) >> 3;
a3 = (W3 * b[8 * 5] - W5 * b[8 * 3] + 4) >> 3;
a2 = (W2 * b[8 * 2] + W6 * b[8 * 6] + 4) >> 3;
a6 = (W6 * b[8 * 2] - W2 * b[8 * 6] + 4) >> 3;
a0 = (W0 * b[8 * 0] + W0 * b[8 * 4]) >> 3;
a4 = (W0 * b[8 * 0] - W0 * b[8 * 4]) >> 3;
/* step 2 */
s1 = (int)(181U * (a1 - a5 + a7 - a3) + 128) >> 8;
s2 = (int)(181U * (a1 - a5 - a7 + a3) + 128) >> 8;
/* step 3 */
b[8 * 0] = (a0 + a2 + a1 + a5 + (1 << 13)) >> 14;
b[8 * 1] = (a4 + a6 + s1 + (1 << 13)) >> 14;
b[8 * 2] = (a4 - a6 + s2 + (1 << 13)) >> 14;
b[8 * 3] = (a0 - a2 + a7 + a3 + (1 << 13)) >> 14;
b[8 * 4] = (a0 - a2 - a7 - a3 + (1 << 13)) >> 14;
b[8 * 5] = (a4 - a6 - s2 + (1 << 13)) >> 14;
b[8 * 6] = (a4 + a6 - s1 + (1 << 13)) >> 14;
b[8 * 7] = (a0 + a2 - a1 - a5 + (1 << 13)) >> 14;
}
static void wmv2_idct_add_c(uint8 *dest, ptrdiff_t line_size, int16 *block) {
int i;
for (i = 0; i < 64; i += 8)
wmv2_idct_row(block + i);
for (i = 0; i < 8; i++)
wmv2_idct_col(block + i);
for (i = 0; i < 8; i++) {
dest[0] = av_clip_uint8(dest[0] + block[0]);
dest[1] = av_clip_uint8(dest[1] + block[1]);
dest[2] = av_clip_uint8(dest[2] + block[2]);
dest[3] = av_clip_uint8(dest[3] + block[3]);
dest[4] = av_clip_uint8(dest[4] + block[4]);
dest[5] = av_clip_uint8(dest[5] + block[5]);
dest[6] = av_clip_uint8(dest[6] + block[6]);
dest[7] = av_clip_uint8(dest[7] + block[7]);
dest += line_size;
block += 8;
}
}
static const VLC *makeCanonicalVLC(int count, const uint8 table[][2]) {
uint32 codes[256], lengths[256];
uint64 code = 0;
for (int i = 0; i < count; ++i) {
int n = table[i][1];
codes[i] = code >> (32 - n);
lengths[i] = n;
code += uint64(1) << (32 - n);
}
VLC *v = const_cast<VLC *>(makeVLC(count, lengths, 4, 4, codes, 4, 4));
for (uint i = 0; i < v->nodes.size(); ++i)
if (v->nodes[i].symbol >= 0)
v->nodes[i].symbol = table[v->nodes[i].symbol][0];
return v;
}
#define VLC_BUFFER_SIZE 28150
#define MAX_TABLE_DEPTH(table_bits, max_bits) ((max_bits + table_bits - 1) / table_bits)
#define DC_VLC_BITS 9
#define OR_VLC_BITS 7
#define DC_VLC_MTD MAX_TABLE_DEPTH(DC_VLC_BITS, MAX_DC_VLC_BITS)
#define AC_VLC_MTD MAX_TABLE_DEPTH(AC_VLC_BITS, MAX_AC_VLC_BITS)
#define OR_VLC_MTD MAX_TABLE_DEPTH(OR_VLC_BITS, MAX_OR_VLC_BITS)
static const VLC *j_ac_vlc[2][2][8]; // [quant < 13], [intra / inter], [select]
static const VLC *j_dc_vlc[2][8]; // [quant], [select]
static const VLC *j_orient_vlc[2][4]; // [quant], [select]
static const VLC *x8_init_vlc(int nb_bits, int nb_codes, const uint8 table[][2]) {
return makeCanonicalVLC(nb_codes, table);
}
static void x8_vlc_init(void) {
int i;
// set ac tables
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 8; k++)
j_ac_vlc[i][j][k] = x8_init_vlc(AC_VLC_BITS, 77, x8_ac_quant_table[i][j][k]);
// set dc tables
for (int i = 0; i < 2; i++)
for (int j = 0; j < 8; j++)
j_dc_vlc[i][j] = x8_init_vlc(DC_VLC_BITS, 34, x8_dc_quant_table[i][j]);
// set orient tables
for (i = 0; i < 2; i++)
j_orient_vlc[0][i] = x8_init_vlc(OR_VLC_BITS, 12, x8_orient_highquant_table[i]);
for (i = 0; i < 4; i++)
j_orient_vlc[1][i] = x8_init_vlc(OR_VLC_BITS, 12, x8_orient_lowquant_table[i]);
}
static void x8_reset_vlc_tables(IntraX8Context *w) {
memset(w->j_dc_vlc_table, 0, sizeof(w->j_dc_vlc_table));
memset(w->j_ac_vlc_table, 0, sizeof(w->j_ac_vlc_table));
w->j_orient_vlc_table = NULL;
}
static inline void x8_select_ac_table(IntraX8Context *const w, int mode) {
int table_index;
assert(mode < 4);
if (w->j_ac_vlc_table[mode])
return;
table_index = get_bits(w->gb, 3);
// 2 modes use same tables
w->j_ac_vlc_table[mode] = j_ac_vlc[w->quant < 13][mode >> 1][table_index];
assert(w->j_ac_vlc_table[mode]);
}
static inline int x8_get_orient_vlc(IntraX8Context *w) {
if (!w->j_orient_vlc_table) {
int table_index = get_bits(w->gb, 1 + (w->quant < 13));
w->j_orient_vlc_table = j_orient_vlc[w->quant < 13][table_index];
}
return get_vlc2(w->gb, w->j_orient_vlc_table);
}
#define extra_bits(eb) (eb) // 3 bits
#define extra_run (0xFF << 8) // 1 bit
#define extra_level (0x00 << 8) // 1 bit
#define run_offset(r) ((r) << 16) // 6 bits
#define level_offset(l) ((l) << 24) // 5 bits
static const uint32 ac_decode_table[] = {
/* 46 */ extra_bits(3) | extra_run | run_offset(16) | level_offset(0),
/* 47 */ extra_bits(3) | extra_run | run_offset(24) | level_offset(0),
/* 48 */ extra_bits(2) | extra_run | run_offset(4) | level_offset(1),
/* 49 */ extra_bits(3) | extra_run | run_offset(8) | level_offset(1),
/* 50 */ extra_bits(5) | extra_run | run_offset(32) | level_offset(0),
/* 51 */ extra_bits(4) | extra_run | run_offset(16) | level_offset(1),
/* 52 */ extra_bits(2) | extra_level | run_offset(0) | level_offset(4),
/* 53 */ extra_bits(2) | extra_level | run_offset(0) | level_offset(8),
/* 54 */ extra_bits(2) | extra_level | run_offset(0) | level_offset(12),
/* 55 */ extra_bits(3) | extra_level | run_offset(0) | level_offset(16),
/* 56 */ extra_bits(3) | extra_level | run_offset(0) | level_offset(24),
/* 57 */ extra_bits(2) | extra_level | run_offset(1) | level_offset(3),
/* 58 */ extra_bits(3) | extra_level | run_offset(1) | level_offset(7),
/* 59 */ extra_bits(2) | extra_run | run_offset(16) | level_offset(0),
/* 60 */ extra_bits(2) | extra_run | run_offset(20) | level_offset(0),
/* 61 */ extra_bits(2) | extra_run | run_offset(24) | level_offset(0),
/* 62 */ extra_bits(2) | extra_run | run_offset(28) | level_offset(0),
/* 63 */ extra_bits(4) | extra_run | run_offset(32) | level_offset(0),
/* 64 */ extra_bits(4) | extra_run | run_offset(48) | level_offset(0),
/* 65 */ extra_bits(2) | extra_run | run_offset(4) | level_offset(1),
/* 66 */ extra_bits(3) | extra_run | run_offset(8) | level_offset(1),
/* 67 */ extra_bits(4) | extra_run | run_offset(16) | level_offset(1),
/* 68 */ extra_bits(2) | extra_level | run_offset(0) | level_offset(4),
/* 69 */ extra_bits(3) | extra_level | run_offset(0) | level_offset(8),
/* 70 */ extra_bits(4) | extra_level | run_offset(0) | level_offset(16),
/* 71 */ extra_bits(2) | extra_level | run_offset(1) | level_offset(3),
/* 72 */ extra_bits(3) | extra_level | run_offset(1) | level_offset(7),
};
#undef extra_bits
#undef extra_run
#undef extra_level
#undef run_offset
#undef level_offset
static void x8_get_ac_rlf(IntraX8Context *const w, const int mode, int *const run, int *const level, int *const final) {
int i, e;
// x8_select_ac_table(w, mode);
i = get_vlc2(w->gb, w->j_ac_vlc_table[mode]);
if (i < 46) { // [0-45]
int t, l;
if (i < 0) {
*level = *final = // prevent 'may be used uninitialized'
*run = 64; // this would cause error exit in the ac loop
return;
}
/*
* i == 0-15 r = 0-15 l = 0; r = i & %01111
* i == 16-19 r = 0-3 l = 1; r = i & %00011
* i == 20-21 r = 0-1 l = 2; r = i & %00001
* i == 22 r = 0 l = 3; r = i & %00000
*/
*final = t = i > 22;
i -= 23 * t;
/* l = lut_l[i / 2] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3 }[i >> 1];
* 11 10'01 01'00 00'00 00'00 00'00 00 => 0xE50000 */
l = (0xE50000 >> (i & 0x1E)) & 3; // 0x1E or ~1 or (i >> 1 << 1)
/* t = lut_mask[l] = { 0x0f, 0x03, 0x01, 0x00 }[l];
* as i < 256 the higher bits do not matter */
t = 0x01030F >> (l << 3);
*run = i & t;
*level = l;
} else if (i < 73) { // [46-72]
uint32 sm;
uint32 mask;
i -= 46;
sm = ac_decode_table[i];
e = get_bits(w->gb, sm & 0xF);
sm >>= 8; // 3 bits
mask = sm & 0xff;
sm >>= 8; // 1 bit
*run = (sm & 0xff) + (e & mask); // 6 bits
*level = (sm >> 8) + (e & ~mask); // 5 bits
*final = i > (58 - 46);
} else if (i < 75) { // [73-74]
static const uint8 crazy_mix_runlevel[32] = {
0x22, 0x32, 0x33, 0x53, 0x23, 0x42, 0x43, 0x63, 0x24, 0x52, 0x34, 0x73, 0x25, 0x62, 0x44, 0x83,
0x26, 0x72, 0x35, 0x54, 0x27, 0x82, 0x45, 0x64, 0x28, 0x92, 0x36, 0x74, 0x29, 0xa2, 0x46, 0x84,
};
*final = !(i & 1);
e = get_bits(w->gb, 5); // get the extra bits
*run = crazy_mix_runlevel[e] >> 4;
*level = crazy_mix_runlevel[e] & 0x0F;
} else {
*level = get_bits(w->gb, 7 - 3 * (i & 1));
*run = get_bits(w->gb, 6);
*final = get_bits1(w->gb);
}
return;
}
/* static const uint8 dc_extra_sbits[] = {
* 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
* }; */
static const uint8 dc_index_offset[] = {
0, 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
};
static int x8_get_dc_rlf(IntraX8Context *const w, const int mode, int *const level, int *const final) {
int i, e, c;
assert(mode < 3);
if (!w->j_dc_vlc_table[mode]) {
int table_index = get_bits(w->gb, 3);
// 4 modes, same table
w->j_dc_vlc_table[mode] = j_dc_vlc[w->quant < 13][table_index];
}
i = get_vlc2(w->gb, w->j_dc_vlc_table[mode]);
/* (i >= 17) { i -= 17; final =1; } */
c = i > 16;
*final = c;
i -= 17 * c;
if (i <= 0) {
*level = 0;
return -i;
}
c = (i + 1) >> 1; // hackish way to calculate dc_extra_sbits[]
c -= c > 1;
e = get_bits(w->gb, c); // get the extra bits
i = dc_index_offset[i] + (e >> 1);
e = -(e & 1); // 0, 0xffffff
*level = (i ^ e) - e; // (i ^ 0) - 0, (i ^ 0xff) - (-1)
return 0;
}
// end of huffman
static int x8_setup_spatial_predictor(IntraX8Context *const w, const int chroma) {
int range;
int sum;
int quant;
w->dsp.setup_spatial_compensation(w->dest[chroma], w->scratchpad, w->frame->linesize[chroma > 0], &range, &sum,
w->edges);
if (chroma) {
w->orient = w->chroma_orient;
quant = w->quant_dc_chroma;
} else {
quant = w->quant;
}
w->flat_dc = 0;
if (range < quant || range < 3) {
w->orient = 0;
// yep you read right, a +-1 idct error may break decoding!
if (range < 3) {
w->flat_dc = 1;
sum += 9;
// ((1 << 17) + 9) / (8 + 8 + 1 + 2) = 6899
w->predicted_dc = sum * 6899 >> 17;
}
}
if (chroma)
return 0;
assert(w->orient < 3);
if (range < 2 * w->quant) {
if ((w->edges & 3) == 0) {
if (w->orient == 1)
w->orient = 11;
if (w->orient == 2)
w->orient = 10;
} else {
w->orient = 0;
}
w->raw_orient = 0;
} else {
static const uint8 prediction_table[3][12] = {
{0, 8, 4, 10, 11, 2, 6, 9, 1, 3, 5, 7},
{4, 0, 8, 11, 10, 3, 5, 2, 6, 9, 1, 7},
{8, 0, 4, 10, 11, 1, 7, 2, 6, 9, 3, 5},
};
w->raw_orient = x8_get_orient_vlc(w);
if (w->raw_orient < 0)
return -1;
assert(w->raw_orient < 12);
assert(w->orient < 3);
w->orient = prediction_table[w->orient][w->raw_orient];
}
return 0;
}
static void x8_update_predictions(IntraX8Context *const w, const int orient, const int est_run) {
w->prediction_table[w->mb_x * 2 + (w->mb_y & 1)] = (est_run << 2) + 1 * (orient == 4) + 2 * (orient == 8);
/*
* y = 2n + 0 -> // 0 2 4
* y = 2n + 1 -> // 1 3 5
*/
}
static void x8_get_prediction_chroma(IntraX8Context *const w) {
w->edges = 1 * !(w->mb_x >> 1);
w->edges |= 2 * !(w->mb_y >> 1);
w->edges |= 4 * (w->mb_x >= (2 * w->mb_width - 1)); // mb_x for chroma would always be odd
w->raw_orient = 0;
// lut_co[8] = {inv,4,8,8, inv,4,8,8} <- => {1,1,0,0;1,1,0,0} => 0xCC
if (w->edges & 3) {
w->chroma_orient = 4 << ((0xCC >> w->edges) & 1);
return;
}
// block[x - 1][y | 1 - 1)]
w->chroma_orient = (w->prediction_table[2 * w->mb_x - 2] & 0x03) << 2;
}
static void x8_get_prediction(IntraX8Context *const w) {
int a, b, c, i;
w->edges = 1 * !w->mb_x;
w->edges |= 2 * !w->mb_y;
w->edges |= 4 * (w->mb_x >= (2 * w->mb_width - 1));
switch (w->edges & 3) {
case 0:
break;
case 1:
// take the one from the above block[0][y - 1]
w->est_run = w->prediction_table[!(w->mb_y & 1)] >> 2;
w->orient = 1;
return;
case 2:
// take the one from the previous block[x - 1][0]
w->est_run = w->prediction_table[2 * w->mb_x - 2] >> 2;
w->orient = 2;
return;
case 3:
w->est_run = 16;
w->orient = 0;
return;
}
// no edge cases
b = w->prediction_table[2 * w->mb_x + !(w->mb_y & 1)]; // block[x ][y - 1]
a = w->prediction_table[2 * w->mb_x - 2 + (w->mb_y & 1)]; // block[x - 1][y ]
c = w->prediction_table[2 * w->mb_x - 2 + !(w->mb_y & 1)]; // block[x - 1][y - 1]
w->est_run = MIN(b, a);
/* This condition has nothing to do with w->edges, even if it looks
* similar it would trigger if e.g. x = 3; y = 2;
* I guess somebody wrote something wrong and it became standard. */
if ((w->mb_x & w->mb_y) != 0)
w->est_run = MIN(c, w->est_run);
w->est_run >>= 2;
a &= 3;
b &= 3;
c &= 3;
i = (0xFFEAF4C4 >> (2 * b + 8 * a)) & 3;
if (i != 3)
w->orient = i;
else
w->orient = (0xFFEAD8 >> (2 * c + 8 * (w->quant > 12))) & 3;
/*
* lut1[b][a] = {
* ->{ 0, 1, 0, pad },
* { 0, 1, X, pad },
* { 2, 2, 2, pad }
* }
* pad 2 2 2;
* pad X 1 0;
* pad 0 1 0 <-
* -> 11 10 '10 10 '11 11'01 00 '11 00'01 00 => 0xEAF4C4
*
* lut2[q>12][c] = {
* ->{ 0, 2, 1, pad},
* { 2, 2, 2, pad}
* }
* pad 2 2 2;
* pad 1 2 0 <-
* -> 11 10'10 10 '11 01'10 00 => 0xEAD8
*/
}
static void x8_ac_compensation(IntraX8Context *const w, const int direction, const int dc_level) {
int t;
#define B(x, y) w->block[(x) + (y) * 8]
#define T(x) ((x) * dc_level + 0x8000) >> 16;
switch (direction) {
case 0:
t = T(3811); // h
B(1, 0) -= t;
B(0, 1) -= t;
t = T(487); // e
B(2, 0) -= t;
B(0, 2) -= t;
t = T(506); // f
B(3, 0) -= t;
B(0, 3) -= t;
t = T(135); // c
B(4, 0) -= t;
B(0, 4) -= t;
B(2, 1) += t;
B(1, 2) += t;
B(3, 1) += t;
B(1, 3) += t;
t = T(173); // d
B(5, 0) -= t;
B(0, 5) -= t;
t = T(61); // b
B(6, 0) -= t;
B(0, 6) -= t;
B(5, 1) += t;
B(1, 5) += t;
t = T(42); // a
B(7, 0) -= t;
B(0, 7) -= t;
B(4, 1) += t;
B(1, 4) += t;
B(4, 4) += t;
t = T(1084); // g
B(1, 1) += t;
break;
case 1:
B(0, 1) -= T(6269);
B(0, 3) -= T(708);
B(0, 5) -= T(172);
B(0, 7) -= T(73);
break;
case 2:
B(1, 0) -= T(6269);
B(3, 0) -= T(708);
B(5, 0) -= T(172);
B(7, 0) -= T(73);
break;
}
#undef B
#undef T
}
static void dsp_x8_put_solidcolor(const uint8 pix, uint8 *dst, const ptrdiff_t linesize) {
int k;
for (k = 0; k < 8; k++) {
memset(dst, pix, 8);
dst += linesize;
}
}
static const int16 quant_table[64] = {
256, 256, 256, 256, 256, 256, 259, 262, 265, 269, 272, 275, 278, 282, 285, 288, 292, 295, 299, 303, 306, 310,
314, 317, 321, 325, 329, 333, 337, 341, 345, 349, 353, 358, 362, 366, 371, 375, 379, 384, 389, 393, 398, 403,
408, 413, 417, 422, 428, 433, 438, 443, 448, 454, 459, 465, 470, 476, 482, 488, 493, 499, 505, 511,
};
static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma) {
uint8 *scantable;
int final, run, level;
int ac_mode, dc_mode, est_run, dc_level;
int pos, n;
int zeros_only;
int use_quant_matrix;
int sign;
assert(w->orient < 12);
w->bdsp.clear_block(w->block);
if (chroma)
dc_mode = 2;
else
dc_mode = !!w->est_run; // 0, 1
if (x8_get_dc_rlf(w, dc_mode, &dc_level, &final))
return -1;
n = 0;
zeros_only = 0;
if (!final) { // decode ac
use_quant_matrix = w->use_quant_matrix;
if (chroma) {
ac_mode = 1;
est_run = 64; // not used
} else {
if (w->raw_orient < 3)
use_quant_matrix = 0;
if (w->raw_orient > 4) {
ac_mode = 0;
est_run = 64;
} else {
if (w->est_run > 1) {
ac_mode = 2;
est_run = w->est_run;
} else {
ac_mode = 3;
est_run = 64;
}
}
}
x8_select_ac_table(w, ac_mode);
/* scantable_selector[12] = { 0, 2, 0, 1, 1, 1, 0, 2, 2, 0, 1, 2 }; <-
* -> 10'01' 00'10' 10'00' 01'01' 01'00' 10'00 => 0x928548 */
scantable = w->permutated_scantable[(0x928548 >> (2 * w->orient)) & 3];
pos = 0;
do {
n++;
if (n >= est_run) {
ac_mode = 3;
x8_select_ac_table(w, 3);
}
x8_get_ac_rlf(w, ac_mode, &run, &level, &final);
pos += run + 1;
if (pos > 63) {
// this also handles vlc error in x8_get_ac_rlf
return -1;
}
level = (level + 1) * w->dquant;
level += w->qsum;
sign = -get_bits1(w->gb);
level = (level ^ sign) - sign;
if (use_quant_matrix)
level = (level * quant_table[pos]) >> 8;
w->block[scantable[pos]] = level;
} while (!final);
} else { // DC only
if (w->flat_dc && ((unsigned)(dc_level + 1)) < 3) { // [-1; 1]
int32 divide_quant = !chroma ? w->divide_quant_dc_luma : w->divide_quant_dc_chroma;
int32 dc_quant = !chroma ? w->quant : w->quant_dc_chroma;
// original intent dc_level += predicted_dc/quant;
// but it got lost somewhere in the rounding
dc_level += (w->predicted_dc * divide_quant + (1 << 12)) >> 13;
dsp_x8_put_solidcolor(av_clip_uint8((dc_level * dc_quant + 4) >> 3), w->dest[chroma],
w->frame->linesize[!!chroma]);
goto block_placed;
}
zeros_only = dc_level == 0;
}
if (!chroma)
w->block[0] = dc_level * w->quant;
else
w->block[0] = dc_level * w->quant_dc_chroma;
// there is !zero_only check in the original, but dc_level check is enough
if ((unsigned int)(dc_level + 1) >= 3 && (w->edges & 3) != 3) {
int direction;
/* ac_comp_direction[orient] = { 0, 3, 3, 1, 1, 0, 0, 0, 2, 2, 2, 1 }; <-
* -> 01'10' 10'10' 00'00' 00'01' 01'11' 11'00 => 0x6A017C */
direction = (0x6A017C >> (w->orient * 2)) & 3;
if (direction != 3) {
x8_ac_compensation(w, direction, w->block[0]);
}
}
if (w->flat_dc) {
dsp_x8_put_solidcolor(w->predicted_dc, w->dest[chroma], w->frame->linesize[!!chroma]);
} else {
w->dsp.spatial_compensation[w->orient](w->scratchpad, w->dest[chroma], w->frame->linesize[!!chroma]);
}
if (!zeros_only)
w->idsp.idct_add(w->dest[chroma], w->frame->linesize[!!chroma], w->block);
block_placed:
if (!chroma)
x8_update_predictions(w, w->orient, n);
if (w->loopfilter) {
uint8 *ptr = w->dest[chroma];
ptrdiff_t linesize = w->frame->linesize[!!chroma];
if (!((w->edges & 2) || (zeros_only && (w->orient | 4) == 4)))
w->dsp.h_loop_filter(ptr, linesize, w->quant);
if (!((w->edges & 1) || (zeros_only && (w->orient | 8) == 8)))
w->dsp.v_loop_filter(ptr, linesize, w->quant);
}
return 0;
}
// FIXME maybe merge with ff_*
static void x8_init_block_index(IntraX8Context *w, Planes *frame) {
// not parent codec linesize as this would be wrong for field pics
// not that IntraX8 has interlacing support ;)
const ptrdiff_t linesize = frame->linesize[0];
const ptrdiff_t uvlinesize = frame->linesize[1];
w->dest[0] = frame->data[0];
w->dest[1] = frame->data[1];
w->dest[2] = frame->data[2];
w->dest[0] += w->mb_y * linesize << 3;
// chroma blocks are on add rows
w->dest[1] += (w->mb_y & ~1) * uvlinesize << 2;
w->dest[2] += (w->mb_y & ~1) * uvlinesize << 2;
}
int initX8(IntraX8Context *w, int16 block[64], int mb_width, int mb_height) {
w->mb_width = mb_width;
w->mb_height = mb_height;
w->block = block;
w->prediction_table = new uint8[mb_width * 4]();
w->idsp.idct_add = wmv2_idct_add_c;
memcpy(w->permutated_scantable[0], ff_wmv1_scantable[0], 64);
memcpy(w->permutated_scantable[1], ff_wmv1_scantable[2], 64);
memcpy(w->permutated_scantable[2], ff_wmv1_scantable[3], 64);
ff_intrax8dsp_init(&w->dsp);
PictureState state = {};
ChromaDSP chroma;
initSupport(&state, &chroma);
w->bdsp = state.bdsp;
static const bool initialized = (x8_vlc_init(), true);
(void)initialized;
return 0;
}
void endX8(IntraX8Context *w) {
delete[] w->prediction_table;
}
int ff_intrax8_decode_picture(IntraX8Context *w, Picture *pict, Bits *gb, int *mb_x, int *mb_y, int dquant,
int quant_offset, int loopfilter, int lowdelay) {
int mb_xy;
w->gb = gb;
w->dquant = dquant;
w->quant = dquant >> 1;
w->qsum = quant_offset;
w->frame = pict->f;
w->loopfilter = loopfilter;
w->use_quant_matrix = get_bits1(w->gb);
w->mb_x = *mb_x;
w->mb_y = *mb_y;
w->divide_quant_dc_luma = ((1 << 16) + (w->quant >> 1)) / w->quant;
if (w->quant < 5) {
w->quant_dc_chroma = w->quant;
w->divide_quant_dc_chroma = w->divide_quant_dc_luma;
} else {
w->quant_dc_chroma = w->quant + ((w->quant + 3) >> 3);
w->divide_quant_dc_chroma = ((1 << 16) + (w->quant_dc_chroma >> 1)) / w->quant_dc_chroma;
}
x8_reset_vlc_tables(w);
for (w->mb_y = 0; w->mb_y < w->mb_height * 2; w->mb_y++) {
x8_init_block_index(w, w->frame);
mb_xy = (w->mb_y >> 1) * (w->mb_width + 1);
if (get_bits_left(gb) < 1)
goto error;
for (w->mb_x = 0; w->mb_x < w->mb_width * 2; w->mb_x++) {
x8_get_prediction(w);
if (x8_setup_spatial_predictor(w, 0))
goto error;
if (x8_decode_intra_mb(w, 0))
goto error;
if (w->mb_x & w->mb_y & 1) {
x8_get_prediction_chroma(w);
/* when setting up chroma, no vlc is read,
* so no error condition can be reached */
x8_setup_spatial_predictor(w, 1);
if (x8_decode_intra_mb(w, 1))
goto error;
x8_setup_spatial_predictor(w, 2);
if (x8_decode_intra_mb(w, 2))
goto error;
w->dest[1] += 8;
w->dest[2] += 8;
pict->qscale_table[mb_xy] = w->quant;
mb_xy++;
}
w->dest[0] += 8;
}
}
error:
*mb_x = w->mb_x;
*mb_y = w->mb_y;
return 0;
}
#undef AC_VLC_MTD
#undef DC_VLC_BITS
#undef DC_VLC_MTD
#undef MAX_AC_VLC_BITS
#undef MAX_DC_VLC_BITS
#undef MAX_OR_VLC_BITS
#undef MAX_TABLE_DEPTH
#undef OR_VLC_BITS
#undef OR_VLC_MTD
#undef VLC_BUFFER_SIZE
#undef W0
#undef W1
#undef W2
#undef W3
#undef W4
#undef W5
#undef W6
#undef W7
static int bitplane_decoding(uint8 *data, int *raw, VC1Context *v) {
VC1Bitplane decoder;
int result =
decoder.decode(data, raw, v->s.mb_width, v->s.mb_height >> v->field_mode, v->s.mb_stride, v->gb.stream);
return result;
}
static int vop_dquant_decoding(VC1Context *v) {
Bits *const gb = &v->gb;
int pqdiff;
// variable size
if (v->dquant != 2) {
v->dquantfrm = get_bits1(gb);
if (!v->dquantfrm)
return 0;
v->dqprofile = get_bits(gb, 2);
switch (v->dqprofile) {
case DQPROFILE_SINGLE_EDGE:
case DQPROFILE_DOUBLE_EDGES:
v->dqsbedge = get_bits(gb, 2);
break;
case DQPROFILE_ALL_MBS:
v->dqbilevel = get_bits1(gb);
if (!v->dqbilevel) {
v->halfpq = 0;
return 0;
}
break;
default:
break; // Forbidden ?
}
}
pqdiff = get_bits(gb, 3);
if (pqdiff == 7)
v->altpq = get_bits(gb, 5);
else
v->altpq = v->pq + pqdiff + 1;
return 0;
}
/* fill lookup tables for intensity compensation */
#define INIT_LUT(lumscale, lumshift, luty, lutuv, chain) \
do { \
int scale, shift, i; \
if (!lumscale) { \
scale = -64; \
shift = (255 - lumshift * 2) * 64; \
if (lumshift > 31) \
shift += 128 << 6; \
} else { \
scale = lumscale + 32; \
if (lumshift > 31) \
shift = (lumshift - 64) * 64; \
else \
shift = lumshift << 6; \
} \
for (i = 0; i < 256; i++) { \
int iy = chain ? luty[i] : i; \
int iu = chain ? lutuv[i] : i; \
luty[i] = av_clip_uint8((scale * iy + shift + 32) >> 6); \
lutuv[i] = av_clip_uint8((scale * (iu - 128) + 128 * 64 + 32) >> 6); \
} \
} while (0)
static void rotate_luts(VC1Context *v) {
if (v->s.pict_type == AV_PICTURE_TYPE_BI || v->s.pict_type == AV_PICTURE_TYPE_B) {
v->curr_use_ic = &v->aux_use_ic;
v->curr_luty = v->aux_luty;
v->curr_lutuv = v->aux_lutuv;
} else {
#define ROTATE(DEF, L, N, C) \
do { \
DEF; \
memcpy(&tmp, L, sizeof(tmp)); \
memcpy(L, N, sizeof(tmp)); \
memcpy(N, &tmp, sizeof(tmp)); \
C = N; \
} while (0)
ROTATE(int tmp, &v->last_use_ic, &v->next_use_ic, v->curr_use_ic);
ROTATE(uint8 tmp[2][256], v->last_luty, v->next_luty, v->curr_luty);
ROTATE(uint8 tmp[2][256], v->last_lutuv, v->next_lutuv, v->curr_lutuv);
}
INIT_LUT(32, 0, v->curr_luty[0], v->curr_lutuv[0], 0);
INIT_LUT(32, 0, v->curr_luty[1], v->curr_lutuv[1], 0);
*v->curr_use_ic = 0;
}
static int read_bfraction(VC1Context *v, Bits *gb) {
int bfraction_lut_index = get_bits(gb, 3);
if (bfraction_lut_index == 7)
bfraction_lut_index = 7 + get_bits(gb, 4);
if (bfraction_lut_index == 21) {
warning("bfraction invalid\n");
return (-1);
}
v->bfraction_lut_index = bfraction_lut_index;
v->bfraction = ff_vc1_bfraction_lut[v->bfraction_lut_index];
return 0;
}
int ff_vc1_parse_frame_header(VC1Context *v, Bits *gb) {
int pqindex, lowquant, status;
v->field_mode = 0;
v->fcm = PROGRESSIVE;
if (v->finterpflag)
v->interpfrm = get_bits1(gb);
skip_bits(gb, 2); // framecnt unused
v->rangeredfrm = 0;
if (v->rangered)
v->rangeredfrm = get_bits1(gb);
if (get_bits1(gb)) {
v->s.pict_type = AV_PICTURE_TYPE_P;
} else {
if (v->max_b_frames && !get_bits1(gb)) {
v->s.pict_type = AV_PICTURE_TYPE_B;
} else
v->s.pict_type = AV_PICTURE_TYPE_I;
}
v->bi_type = 0;
if (v->s.pict_type == AV_PICTURE_TYPE_B) {
if (read_bfraction(v, gb) < 0)
return (-1);
if (v->bfraction == 0) {
v->s.pict_type = AV_PICTURE_TYPE_BI;
}
}
if (v->s.pict_type == AV_PICTURE_TYPE_I || v->s.pict_type == AV_PICTURE_TYPE_BI)
skip_bits(gb, 7); // skip buffer fullness
if (v->parse_only)
return 0;
/* calculate RND */
if (v->s.pict_type == AV_PICTURE_TYPE_I || v->s.pict_type == AV_PICTURE_TYPE_BI)
v->rnd = 1;
if (v->s.pict_type == AV_PICTURE_TYPE_P)
v->rnd ^= 1;
if (get_bits_left(gb) < 5)
return (-1);
/* Quantizer stuff */
pqindex = get_bits(gb, 5);
if (!pqindex)
return -1;
if (v->quantizer_mode == QUANT_FRAME_IMPLICIT)
v->pq = ff_vc1_pquant_table[0][pqindex];
else
v->pq = ff_vc1_pquant_table[1][pqindex];
v->pqindex = pqindex;
if (pqindex < 9)
v->halfpq = get_bits1(gb);
else
v->halfpq = 0;
switch (v->quantizer_mode) {
case QUANT_FRAME_IMPLICIT:
v->pquantizer = pqindex < 9;
break;
case QUANT_NON_UNIFORM:
v->pquantizer = 0;
break;
case QUANT_FRAME_EXPLICIT:
v->pquantizer = get_bits1(gb);
break;
default:
v->pquantizer = 1;
break;
}
v->dquantfrm = 0;
if (v->extended_mv == 1)
v->mvrange = get_unary(gb, 0, 3);
v->k_x = v->mvrange + 9 + (v->mvrange >> 1); // k_x can be 9 10 12 13
v->k_y = v->mvrange + 8; // k_y can be 8 9 10 11
v->range_x = 1 << (v->k_x - 1);
v->range_y = 1 << (v->k_y - 1);
if (v->multires && v->s.pict_type != AV_PICTURE_TYPE_B)
v->respic = get_bits(gb, 2);
if (v->res_x8 && (v->s.pict_type == AV_PICTURE_TYPE_I || v->s.pict_type == AV_PICTURE_TYPE_BI)) {
v->x8_type = get_bits1(gb);
} else
v->x8_type = 0;
if (v->first_pic_header_flag)
rotate_luts(v);
switch (v->s.pict_type) {
case AV_PICTURE_TYPE_P:
v->tt_index = (v->pq > 4) + (v->pq > 12);
lowquant = (v->pq > 12) ? 0 : 1;
v->mv_mode = ff_vc1_mv_pmode_table[lowquant][get_unary(gb, 1, 4)];
if (v->mv_mode == MV_PMODE_INTENSITY_COMP) {
v->mv_mode2 = ff_vc1_mv_pmode_table2[lowquant][get_unary(gb, 1, 3)];
v->lumscale = get_bits(gb, 6);
v->lumshift = get_bits(gb, 6);
v->last_use_ic = 1;
/* fill lookup tables for intensity compensation */
INIT_LUT(v->lumscale, v->lumshift, v->last_luty[0], v->last_lutuv[0], 1);
INIT_LUT(v->lumscale, v->lumshift, v->last_luty[1], v->last_lutuv[1], 1);
}
if (v->mv_mode == MV_PMODE_INTENSITY_COMP) {
v->s.quarter_sample = (v->mv_mode2 != MV_PMODE_1MV_HPEL && v->mv_mode2 != MV_PMODE_1MV_HPEL_BILIN);
v->s.mspel = (v->mv_mode2 != MV_PMODE_1MV_HPEL_BILIN);
} else {
v->s.quarter_sample = (v->mv_mode != MV_PMODE_1MV_HPEL && v->mv_mode != MV_PMODE_1MV_HPEL_BILIN);
v->s.mspel = (v->mv_mode != MV_PMODE_1MV_HPEL_BILIN);
}
if ((v->mv_mode == MV_PMODE_INTENSITY_COMP && v->mv_mode2 == MV_PMODE_MIXED_MV) ||
v->mv_mode == MV_PMODE_MIXED_MV) {
status = bitplane_decoding(v->mv_type_mb_plane, &v->mv_type_is_raw, v);
if (status < 0)
return -1;
} else {
v->mv_type_is_raw = 0;
memset(v->mv_type_mb_plane, 0, v->s.mb_stride * v->s.mb_height);
}
status = bitplane_decoding(v->s.mbskip_table, &v->skip_is_raw, v);
if (status < 0)
return -1;
if (get_bits_left(gb) < 4)
return (-1);
/* Hopefully this is correct for P-frames */
v->mv_table_index = get_bits(gb, 2); // but using ff_vc1_ tables
v->cbptab = get_bits(gb, 2);
v->cbpcy_vlc = ff_vc1_cbpcy_p_vlc[v->cbptab];
if (v->dquant) {
vop_dquant_decoding(v);
}
if (v->vstransform) {
v->ttmbf = get_bits1(gb);
if (v->ttmbf) {
v->ttfrm = ff_vc1_ttfrm_to_tt[get_bits(gb, 2)];
} else
v->ttfrm = 0; // FIXME Is that so ?
} else {
v->ttmbf = 1;
v->ttfrm = TT_8X8;
}
break;
case AV_PICTURE_TYPE_B:
v->tt_index = (v->pq > 4) + (v->pq > 12);
v->mv_mode = get_bits1(gb) ? MV_PMODE_1MV : MV_PMODE_1MV_HPEL_BILIN;
v->s.quarter_sample = (v->mv_mode == MV_PMODE_1MV);
v->s.mspel = v->s.quarter_sample;
status = bitplane_decoding(v->direct_mb_plane, &v->dmb_is_raw, v);
if (status < 0)
return -1;
status = bitplane_decoding(v->s.mbskip_table, &v->skip_is_raw, v);
if (status < 0)
return -1;
v->mv_table_index = get_bits(gb, 2);
v->cbptab = get_bits(gb, 2);
v->cbpcy_vlc = ff_vc1_cbpcy_p_vlc[v->cbptab];
if (v->dquant) {
vop_dquant_decoding(v);
}
if (v->vstransform) {
v->ttmbf = get_bits1(gb);
if (v->ttmbf) {
v->ttfrm = ff_vc1_ttfrm_to_tt[get_bits(gb, 2)];
} else
v->ttfrm = 0;
} else {
v->ttmbf = 1;
v->ttfrm = TT_8X8;
}
break;
}
if (!v->x8_type) {
/* AC Syntax */
v->c_ac_table_index = decode012(gb);
if (v->s.pict_type == AV_PICTURE_TYPE_I || v->s.pict_type == AV_PICTURE_TYPE_BI) {
v->y_ac_table_index = decode012(gb);
}
/* DC Syntax */
v->dc_table_index = get_bits1(gb);
}
if (v->s.pict_type == AV_PICTURE_TYPE_BI) {
v->s.pict_type = AV_PICTURE_TYPE_B;
v->bi_type = 1;
}
return 0;
}
int ff_vc1_parse_frame_header_adv(VC1Context *v, Bits *gb) {
int pqindex, lowquant;
int status;
int field_mode, fcm;
v->numref = 0;
v->p_frame_skipped = 0;
if (v->second_field) {
if (v->fcm != ILACE_FIELD || v->field_mode != 1)
return -1;
if (v->fptype & 4)
v->s.pict_type = (v->fptype & 1) ? AV_PICTURE_TYPE_BI : AV_PICTURE_TYPE_B;
else
v->s.pict_type = (v->fptype & 1) ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I;
v->s.cur_pic.ptr->f->pict_type = v->s.pict_type;
if (!v->pic_header_flag)
goto parse_common_info;
}
field_mode = 0;
if (v->interlace) {
fcm = decode012(gb);
if (fcm) {
if (fcm == ILACE_FIELD)
field_mode = 1;
}
} else {
fcm = PROGRESSIVE;
}
if (!v->first_pic_header_flag && v->field_mode != field_mode)
return (-1);
v->field_mode = field_mode;
v->fcm = fcm;
assert(v->s.mb_height == v->s.height + 15 >> 4 || v->s.mb_height == FFALIGN(v->s.height + 15 >> 4, 2));
if (v->field_mode) {
v->s.mb_height = FFALIGN(v->s.height + 15 >> 4, 2);
v->fptype = get_bits(gb, 3);
if (v->fptype & 4) // B-picture
v->s.pict_type = (v->fptype & 2) ? AV_PICTURE_TYPE_BI : AV_PICTURE_TYPE_B;
else
v->s.pict_type = (v->fptype & 2) ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I;
} else {
v->s.mb_height = v->s.height + 15 >> 4;
switch (get_unary(gb, 0, 4)) {
case 0:
v->s.pict_type = AV_PICTURE_TYPE_P;
break;
case 1:
v->s.pict_type = AV_PICTURE_TYPE_B;
break;
case 2:
v->s.pict_type = AV_PICTURE_TYPE_I;
break;
case 3:
v->s.pict_type = AV_PICTURE_TYPE_BI;
break;
case 4:
v->s.pict_type = AV_PICTURE_TYPE_P; // skipped pic
v->p_frame_skipped = 1;
break;
}
}
if (v->tfcntrflag)
skip_bits(gb, 8);
if (v->broadcast) {
if (!v->interlace || v->psf) {
v->rptfrm = get_bits(gb, 2);
} else {
v->tff = get_bits1(gb);
v->rff = get_bits1(gb);
}
} else {
v->tff = 1;
}
if (v->panscanflag) {
warning("Pan-scan");
//...
}
if (v->p_frame_skipped) {
return 0;
}
v->rnd = get_bits1(gb);
if (v->interlace)
v->uvsamp = get_bits1(gb);
if (v->field_mode) {
if (!v->refdist_flag)
v->refdist = 0;
else if ((v->s.pict_type != AV_PICTURE_TYPE_B) && (v->s.pict_type != AV_PICTURE_TYPE_BI)) {
v->refdist = get_bits(gb, 2);
if (v->refdist == 3)
v->refdist += get_unary(gb, 0, 14);
if (v->refdist > 16)
return (-1);
}
if ((v->s.pict_type == AV_PICTURE_TYPE_B) || (v->s.pict_type == AV_PICTURE_TYPE_BI)) {
if (read_bfraction(v, gb) < 0)
return (-1);
v->frfd = (v->bfraction * v->refdist) >> 8;
v->brfd = v->refdist - v->frfd - 1;
if (v->brfd < 0)
v->brfd = 0;
}
goto parse_common_info;
}
if (v->fcm == PROGRESSIVE) {
if (v->finterpflag)
v->interpfrm = get_bits1(gb);
if (v->s.pict_type == AV_PICTURE_TYPE_B) {
if (read_bfraction(v, gb) < 0)
return (-1);
if (v->bfraction == 0) {
v->s.pict_type = AV_PICTURE_TYPE_BI; /* XXX: should not happen here */
}
}
}
parse_common_info:
if (v->field_mode)
v->cur_field_type = !(v->tff ^ v->second_field);
pqindex = get_bits(gb, 5);
if (!pqindex)
return -1;
if (v->quantizer_mode == QUANT_FRAME_IMPLICIT)
v->pq = ff_vc1_pquant_table[0][pqindex];
else
v->pq = ff_vc1_pquant_table[1][pqindex];
v->pqindex = pqindex;
if (pqindex < 9)
v->halfpq = get_bits1(gb);
else
v->halfpq = 0;
switch (v->quantizer_mode) {
case QUANT_FRAME_IMPLICIT:
v->pquantizer = pqindex < 9;
break;
case QUANT_NON_UNIFORM:
v->pquantizer = 0;
break;
case QUANT_FRAME_EXPLICIT:
v->pquantizer = get_bits1(gb);
break;
default:
v->pquantizer = 1;
break;
}
v->dquantfrm = 0;
if (v->postprocflag)
v->postproc = get_bits(gb, 2);
if (v->parse_only)
return 0;
if (v->first_pic_header_flag)
rotate_luts(v);
switch (v->s.pict_type) {
case AV_PICTURE_TYPE_I:
case AV_PICTURE_TYPE_BI:
if (v->fcm == ILACE_FRAME) { // interlace frame picture
status = bitplane_decoding(v->fieldtx_plane, &v->fieldtx_is_raw, v);
if (status < 0)
return -1;
} else
v->fieldtx_is_raw = 0;
status = bitplane_decoding(v->acpred_plane, &v->acpred_is_raw, v);
if (status < 0)
return -1;
v->condover = CONDOVER_NONE;
if (v->overlap && v->pq <= 8) {
v->condover = decode012(gb);
if (v->condover == CONDOVER_SELECT) {
status = bitplane_decoding(v->over_flags_plane, &v->overflg_is_raw, v);
if (status < 0)
return -1;
}
}
break;
case AV_PICTURE_TYPE_P:
if (v->field_mode) {
v->numref = get_bits1(gb);
if (!v->numref) {
v->reffield = get_bits1(gb);
v->ref_field_type[0] = v->reffield ^ !v->cur_field_type;
}
}
if (v->extended_mv)
v->mvrange = get_unary(gb, 0, 3);
else
v->mvrange = 0;
if (v->interlace) {
if (v->extended_dmv)
v->dmvrange = get_unary(gb, 0, 3);
else
v->dmvrange = 0;
if (v->fcm == ILACE_FRAME) { // interlaced frame picture
v->fourmvswitch = get_bits1(gb);
v->intcomp = get_bits1(gb);
if (v->intcomp) {
v->lumscale = get_bits(gb, 6);
v->lumshift = get_bits(gb, 6);
INIT_LUT(v->lumscale, v->lumshift, v->last_luty[0], v->last_lutuv[0], 1);
INIT_LUT(v->lumscale, v->lumshift, v->last_luty[1], v->last_lutuv[1], 1);
v->last_use_ic = 1;
}
status = bitplane_decoding(v->s.mbskip_table, &v->skip_is_raw, v);
if (status < 0)
return -1;
v->mbmodetab = get_bits(gb, 2);
if (v->fourmvswitch)
v->mbmode_vlc = ff_vc1_intfr_4mv_mbmode_vlc[v->mbmodetab];
else
v->mbmode_vlc = ff_vc1_intfr_non4mv_mbmode_vlc[v->mbmodetab];
v->imvtab = get_bits(gb, 2);
v->imv_vlc = ff_vc1_1ref_mvdata_vlc[v->imvtab];
// interlaced p-picture cbpcy range is [1, 63]
v->icbptab = get_bits(gb, 3);
v->cbpcy_vlc = ff_vc1_icbpcy_vlc[v->icbptab];
v->twomvbptab = get_bits(gb, 2);
v->twomvbp_vlc = ff_vc1_2mv_block_pattern_vlc[v->twomvbptab];
if (v->fourmvswitch) {
v->fourmvbptab = get_bits(gb, 2);
v->fourmvbp_vlc = ff_vc1_4mv_block_pattern_vlc[v->fourmvbptab];
}
}
}
v->k_x = v->mvrange + 9 + (v->mvrange >> 1); // k_x can be 9 10 12 13
v->k_y = v->mvrange + 8; // k_y can be 8 9 10 11
v->range_x = 1 << (v->k_x - 1);
v->range_y = 1 << (v->k_y - 1);
v->tt_index = (v->pq > 4) + (v->pq > 12);
if (v->fcm != ILACE_FRAME) {
int mvmode;
mvmode = get_unary(gb, 1, 4);
lowquant = (v->pq > 12) ? 0 : 1;
v->mv_mode = ff_vc1_mv_pmode_table[lowquant][mvmode];
if (v->mv_mode == MV_PMODE_INTENSITY_COMP) {
int mvmode2;
mvmode2 = get_unary(gb, 1, 3);
v->mv_mode2 = ff_vc1_mv_pmode_table2[lowquant][mvmode2];
if (v->field_mode) {
v->intcompfield = decode210(gb) ^ 3;
} else
v->intcompfield = 3;
v->lumscale2 = v->lumscale = 32;
v->lumshift2 = v->lumshift = 0;
if (v->intcompfield & 1) {
v->lumscale = get_bits(gb, 6);
v->lumshift = get_bits(gb, 6);
}
if ((v->intcompfield & 2) && v->field_mode) {
v->lumscale2 = get_bits(gb, 6);
v->lumshift2 = get_bits(gb, 6);
} else if (!v->field_mode) {
v->lumscale2 = v->lumscale;
v->lumshift2 = v->lumshift;
}
if (v->field_mode && v->second_field) {
if (v->cur_field_type) {
INIT_LUT(v->lumscale, v->lumshift, v->curr_luty[v->cur_field_type ^ 1],
v->curr_lutuv[v->cur_field_type ^ 1], 0);
INIT_LUT(v->lumscale2, v->lumshift2, v->last_luty[v->cur_field_type],
v->last_lutuv[v->cur_field_type], 1);
} else {
INIT_LUT(v->lumscale2, v->lumshift2, v->curr_luty[v->cur_field_type ^ 1],
v->curr_lutuv[v->cur_field_type ^ 1], 0);
INIT_LUT(v->lumscale, v->lumshift, v->last_luty[v->cur_field_type],
v->last_lutuv[v->cur_field_type], 1);
}
v->next_use_ic = *v->curr_use_ic = 1;
} else {
INIT_LUT(v->lumscale, v->lumshift, v->last_luty[0], v->last_lutuv[0], 1);
INIT_LUT(v->lumscale2, v->lumshift2, v->last_luty[1], v->last_lutuv[1], 1);
}
v->last_use_ic = 1;
}
if (v->mv_mode == MV_PMODE_INTENSITY_COMP) {
v->s.quarter_sample = (v->mv_mode2 != MV_PMODE_1MV_HPEL && v->mv_mode2 != MV_PMODE_1MV_HPEL_BILIN);
v->s.mspel = (v->mv_mode2 != MV_PMODE_1MV_HPEL_BILIN);
} else {
v->s.quarter_sample = (v->mv_mode != MV_PMODE_1MV_HPEL && v->mv_mode != MV_PMODE_1MV_HPEL_BILIN);
v->s.mspel = (v->mv_mode != MV_PMODE_1MV_HPEL_BILIN);
}
}
if (v->fcm == PROGRESSIVE) { // progressive
if ((v->mv_mode == MV_PMODE_INTENSITY_COMP && v->mv_mode2 == MV_PMODE_MIXED_MV) ||
v->mv_mode == MV_PMODE_MIXED_MV) {
status = bitplane_decoding(v->mv_type_mb_plane, &v->mv_type_is_raw, v);
if (status < 0)
return -1;
} else {
v->mv_type_is_raw = 0;
memset(v->mv_type_mb_plane, 0, v->s.mb_stride * v->s.mb_height);
}
status = bitplane_decoding(v->s.mbskip_table, &v->skip_is_raw, v);
if (status < 0)
return -1;
/* Hopefully this is correct for P-frames */
v->mv_table_index = get_bits(gb, 2); // but using ff_vc1_ tables
v->cbptab = get_bits(gb, 2);
v->cbpcy_vlc = ff_vc1_cbpcy_p_vlc[v->cbptab];
} else if (v->fcm == ILACE_FRAME) { // frame interlaced
v->s.quarter_sample = 1;
v->s.mspel = 1;
} else { // field interlaced
v->mbmodetab = get_bits(gb, 3);
v->imvtab = get_bits(gb, 2 + v->numref);
if (!v->numref)
v->imv_vlc = ff_vc1_1ref_mvdata_vlc[v->imvtab];
else
v->imv_vlc = ff_vc1_2ref_mvdata_vlc[v->imvtab];
v->icbptab = get_bits(gb, 3);
v->cbpcy_vlc = ff_vc1_icbpcy_vlc[v->icbptab];
if ((v->mv_mode == MV_PMODE_INTENSITY_COMP && v->mv_mode2 == MV_PMODE_MIXED_MV) ||
v->mv_mode == MV_PMODE_MIXED_MV) {
v->fourmvbptab = get_bits(gb, 2);
v->fourmvbp_vlc = ff_vc1_4mv_block_pattern_vlc[v->fourmvbptab];
v->mbmode_vlc = ff_vc1_if_mmv_mbmode_vlc[v->mbmodetab];
} else {
v->mbmode_vlc = ff_vc1_if_1mv_mbmode_vlc[v->mbmodetab];
}
}
if (v->dquant) {
vop_dquant_decoding(v);
}
if (v->vstransform) {
v->ttmbf = get_bits1(gb);
if (v->ttmbf) {
v->ttfrm = ff_vc1_ttfrm_to_tt[get_bits(gb, 2)];
} else
v->ttfrm = 0; // FIXME Is that so ?
} else {
v->ttmbf = 1;
v->ttfrm = TT_8X8;
}
break;
case AV_PICTURE_TYPE_B:
if (v->fcm == ILACE_FRAME) {
if (read_bfraction(v, gb) < 0)
return (-1);
if (v->bfraction == 0) {
return -1;
}
}
if (v->extended_mv)
v->mvrange = get_unary(gb, 0, 3);
else
v->mvrange = 0;
v->k_x = v->mvrange + 9 + (v->mvrange >> 1); // k_x can be 9 10 12 13
v->k_y = v->mvrange + 8; // k_y can be 8 9 10 11
v->range_x = 1 << (v->k_x - 1);
v->range_y = 1 << (v->k_y - 1);
v->tt_index = (v->pq > 4) + (v->pq > 12);
if (v->field_mode) {
int mvmode;
if (v->extended_dmv)
v->dmvrange = get_unary(gb, 0, 3);
mvmode = get_unary(gb, 1, 3);
lowquant = (v->pq > 12) ? 0 : 1;
v->mv_mode = ff_vc1_mv_pmode_table2[lowquant][mvmode];
v->s.quarter_sample = (v->mv_mode == MV_PMODE_1MV || v->mv_mode == MV_PMODE_MIXED_MV);
v->s.mspel = (v->mv_mode != MV_PMODE_1MV_HPEL_BILIN);
status = bitplane_decoding(v->forward_mb_plane, &v->fmb_is_raw, v);
if (status < 0)
return -1;
v->mbmodetab = get_bits(gb, 3);
if (v->mv_mode == MV_PMODE_MIXED_MV)
v->mbmode_vlc = ff_vc1_if_mmv_mbmode_vlc[v->mbmodetab];
else
v->mbmode_vlc = ff_vc1_if_1mv_mbmode_vlc[v->mbmodetab];
v->imvtab = get_bits(gb, 3);
v->imv_vlc = ff_vc1_2ref_mvdata_vlc[v->imvtab];
v->icbptab = get_bits(gb, 3);
v->cbpcy_vlc = ff_vc1_icbpcy_vlc[v->icbptab];
if (v->mv_mode == MV_PMODE_MIXED_MV) {
v->fourmvbptab = get_bits(gb, 2);
v->fourmvbp_vlc = ff_vc1_4mv_block_pattern_vlc[v->fourmvbptab];
}
v->numref = 1; // interlaced field B pictures are always 2-ref
} else if (v->fcm == ILACE_FRAME) {
if (v->extended_dmv)
v->dmvrange = get_unary(gb, 0, 3);
if (get_bits1(gb)) /* intcomp - present but shall always be 0 */
warning("Intensity compensation set for B picture\n");
v->intcomp = 0;
v->mv_mode = MV_PMODE_1MV;
v->fourmvswitch = 0;
v->s.quarter_sample = 1;
v->s.mspel = 1;
status = bitplane_decoding(v->direct_mb_plane, &v->dmb_is_raw, v);
if (status < 0)
return -1;
status = bitplane_decoding(v->s.mbskip_table, &v->skip_is_raw, v);
if (status < 0)
return -1;
v->mbmodetab = get_bits(gb, 2);
v->mbmode_vlc = ff_vc1_intfr_non4mv_mbmode_vlc[v->mbmodetab];
v->imvtab = get_bits(gb, 2);
v->imv_vlc = ff_vc1_1ref_mvdata_vlc[v->imvtab];
// interlaced p/b-picture cbpcy range is [1, 63]
v->icbptab = get_bits(gb, 3);
v->cbpcy_vlc = ff_vc1_icbpcy_vlc[v->icbptab];
v->twomvbptab = get_bits(gb, 2);
v->twomvbp_vlc = ff_vc1_2mv_block_pattern_vlc[v->twomvbptab];
v->fourmvbptab = get_bits(gb, 2);
v->fourmvbp_vlc = ff_vc1_4mv_block_pattern_vlc[v->fourmvbptab];
} else {
v->mv_mode = get_bits1(gb) ? MV_PMODE_1MV : MV_PMODE_1MV_HPEL_BILIN;
v->s.quarter_sample = (v->mv_mode == MV_PMODE_1MV);
v->s.mspel = v->s.quarter_sample;
status = bitplane_decoding(v->direct_mb_plane, &v->dmb_is_raw, v);
if (status < 0)
return -1;
status = bitplane_decoding(v->s.mbskip_table, &v->skip_is_raw, v);
if (status < 0)
return -1;
v->mv_table_index = get_bits(gb, 2);
v->cbptab = get_bits(gb, 2);
v->cbpcy_vlc = ff_vc1_cbpcy_p_vlc[v->cbptab];
}
if (v->dquant) {
vop_dquant_decoding(v);
}
if (v->vstransform) {
v->ttmbf = get_bits1(gb);
if (v->ttmbf) {
v->ttfrm = ff_vc1_ttfrm_to_tt[get_bits(gb, 2)];
} else
v->ttfrm = 0;
} else {
v->ttmbf = 1;
v->ttfrm = TT_8X8;
}
break;
}
/* AC Syntax */
v->c_ac_table_index = decode012(gb);
if (v->s.pict_type == AV_PICTURE_TYPE_I || v->s.pict_type == AV_PICTURE_TYPE_BI) {
v->y_ac_table_index = decode012(gb);
} else if (v->fcm != PROGRESSIVE && !v->s.quarter_sample) {
v->range_x <<= 1;
v->range_y <<= 1;
}
/* DC Syntax */
v->dc_table_index = get_bits1(gb);
if ((v->s.pict_type == AV_PICTURE_TYPE_I || v->s.pict_type == AV_PICTURE_TYPE_BI) && v->dquant) {
vop_dquant_decoding(v);
}
v->bi_type = (v->s.pict_type == AV_PICTURE_TYPE_BI);
if (v->bi_type)
v->s.pict_type = AV_PICTURE_TYPE_B;
return 0;
}
#undef INIT_LUT
#undef ROTATE
static inline int scaleforsame_x(const VC1Context *v, int n /* MV */, int dir) {
int scaledvalue, refdist;
int scalesame1, scalesame2;
int scalezone1_x, zone1offset_x;
int table_index = dir ^ v->second_field;
if (v->s.pict_type != AV_PICTURE_TYPE_B)
refdist = v->refdist;
else
refdist = dir ? v->brfd : v->frfd;
if (refdist > 3)
refdist = 3;
scalesame1 = ff_vc1_field_mvpred_scales[table_index][1][refdist];
scalesame2 = ff_vc1_field_mvpred_scales[table_index][2][refdist];
scalezone1_x = ff_vc1_field_mvpred_scales[table_index][3][refdist];
zone1offset_x = ff_vc1_field_mvpred_scales[table_index][5][refdist];
if (ABS(n) > 255)
scaledvalue = n;
else {
if (ABS(n) < scalezone1_x)
scaledvalue = (n * scalesame1) >> 8;
else {
if (n < 0)
scaledvalue = ((n * scalesame2) >> 8) - zone1offset_x;
else
scaledvalue = ((n * scalesame2) >> 8) + zone1offset_x;
}
}
return av_clip(scaledvalue, -v->range_x, v->range_x - 1);
}
static inline int scaleforsame_y(const VC1Context *v, int n /* MV */, int dir) {
int scaledvalue, refdist;
int scalesame1, scalesame2;
int scalezone1_y, zone1offset_y;
int table_index = dir ^ v->second_field;
if (v->s.pict_type != AV_PICTURE_TYPE_B)
refdist = v->refdist;
else
refdist = dir ? v->brfd : v->frfd;
if (refdist > 3)
refdist = 3;
scalesame1 = ff_vc1_field_mvpred_scales[table_index][1][refdist];
scalesame2 = ff_vc1_field_mvpred_scales[table_index][2][refdist];
scalezone1_y = ff_vc1_field_mvpred_scales[table_index][4][refdist];
zone1offset_y = ff_vc1_field_mvpred_scales[table_index][6][refdist];
if (ABS(n) > 63)
scaledvalue = n;
else {
if (ABS(n) < scalezone1_y)
scaledvalue = (n * scalesame1) >> 8;
else {
if (n < 0)
scaledvalue = ((n * scalesame2) >> 8) - zone1offset_y;
else
scaledvalue = ((n * scalesame2) >> 8) + zone1offset_y;
}
}
if (v->cur_field_type && !v->ref_field_type[dir])
return av_clip(scaledvalue, -v->range_y / 2 + 1, v->range_y / 2);
else
return av_clip(scaledvalue, -v->range_y / 2, v->range_y / 2 - 1);
}
static inline int scaleforopp_x(const VC1Context *v, int n /* MV */) {
int scalezone1_x, zone1offset_x;
int scaleopp1, scaleopp2, brfd;
int scaledvalue;
brfd = MIN(v->brfd, 3);
scalezone1_x = ff_vc1_b_field_mvpred_scales[3][brfd];
zone1offset_x = ff_vc1_b_field_mvpred_scales[5][brfd];
scaleopp1 = ff_vc1_b_field_mvpred_scales[1][brfd];
scaleopp2 = ff_vc1_b_field_mvpred_scales[2][brfd];
if (ABS(n) > 255)
scaledvalue = n;
else {
if (ABS(n) < scalezone1_x)
scaledvalue = (n * scaleopp1) >> 8;
else {
if (n < 0)
scaledvalue = ((n * scaleopp2) >> 8) - zone1offset_x;
else
scaledvalue = ((n * scaleopp2) >> 8) + zone1offset_x;
}
}
return av_clip(scaledvalue, -v->range_x, v->range_x - 1);
}
static inline int scaleforopp_y(const VC1Context *v, int n /* MV */, int dir) {
int scalezone1_y, zone1offset_y;
int scaleopp1, scaleopp2, brfd;
int scaledvalue;
brfd = MIN(v->brfd, 3);
scalezone1_y = ff_vc1_b_field_mvpred_scales[4][brfd];
zone1offset_y = ff_vc1_b_field_mvpred_scales[6][brfd];
scaleopp1 = ff_vc1_b_field_mvpred_scales[1][brfd];
scaleopp2 = ff_vc1_b_field_mvpred_scales[2][brfd];
if (ABS(n) > 63)
scaledvalue = n;
else {
if (ABS(n) < scalezone1_y)
scaledvalue = (n * scaleopp1) >> 8;
else {
if (n < 0)
scaledvalue = ((n * scaleopp2) >> 8) - zone1offset_y;
else
scaledvalue = ((n * scaleopp2) >> 8) + zone1offset_y;
}
}
if (v->cur_field_type && !v->ref_field_type[dir]) {
return av_clip(scaledvalue, -v->range_y / 2 + 1, v->range_y / 2);
} else {
return av_clip(scaledvalue, -v->range_y / 2, v->range_y / 2 - 1);
}
}
static inline int scaleforsame(const VC1Context *v, int n /* MV */, int dim, int dir) {
int brfd, scalesame;
int hpel = 1 - v->s.quarter_sample;
n >>= hpel;
if (v->s.pict_type != AV_PICTURE_TYPE_B || v->second_field || !dir) {
if (dim)
n = scaleforsame_y(v, n, dir) * (1 << hpel);
else
n = scaleforsame_x(v, n, dir) * (1 << hpel);
return n;
}
brfd = MIN(v->brfd, 3);
scalesame = ff_vc1_b_field_mvpred_scales[0][brfd];
n = (n * scalesame >> 8) * (1 << hpel);
return n;
}
static inline int scaleforopp(const VC1Context *v, int n /* MV */, int dim, int dir) {
int refdist, scaleopp;
int hpel = 1 - v->s.quarter_sample;
n >>= hpel;
if (v->s.pict_type == AV_PICTURE_TYPE_B && !v->second_field && dir == 1) {
if (dim)
n = scaleforopp_y(v, n, dir) * (1 << hpel);
else
n = scaleforopp_x(v, n) * (1 << hpel);
return n;
}
if (v->s.pict_type != AV_PICTURE_TYPE_B)
refdist = v->refdist;
else
refdist = dir ? v->brfd : v->frfd;
refdist = MIN(refdist, 3);
scaleopp = ff_vc1_field_mvpred_scales[dir ^ v->second_field][0][refdist];
n = (n * scaleopp >> 8) * (1 << hpel);
return n;
}
/** Predict and set motion vector
*/
void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, int mv1, int r_x, int r_y, uint8 *is_intra,
int pred_flag, int dir) {
PictureState *s = &v->s;
int xy, wrap, off = 0;
int px, py;
int sum;
int mixedmv_pic, num_samefield = 0, num_oppfield = 0;
int opposite, a_f, b_f, c_f;
int16 field_predA[2];
int16 field_predB[2];
int16 field_predC[2];
int a_valid, b_valid, c_valid;
int hybridmv_thresh, y_bias = 0;
if (v->mv_mode == MV_PMODE_MIXED_MV ||
((v->mv_mode == MV_PMODE_INTENSITY_COMP) && (v->mv_mode2 == MV_PMODE_MIXED_MV)))
mixedmv_pic = 1;
else
mixedmv_pic = 0;
/* scale MV difference to be quad-pel */
if (!s->quarter_sample) {
dmv_x *= 2;
dmv_y *= 2;
}
wrap = s->b8_stride;
xy = s->block_index[n];
if (s->mb_intra) {
s->mv[0][n][0] = s->cur_pic.motion_val[0][xy + v->blocks_off][0] = 0;
s->mv[0][n][1] = s->cur_pic.motion_val[0][xy + v->blocks_off][1] = 0;
s->cur_pic.motion_val[1][xy + v->blocks_off][0] = 0;
s->cur_pic.motion_val[1][xy + v->blocks_off][1] = 0;
if (mv1) { /* duplicate motion data for 1-MV block */
s->cur_pic.motion_val[0][xy + 1 + v->blocks_off][0] = 0;
s->cur_pic.motion_val[0][xy + 1 + v->blocks_off][1] = 0;
s->cur_pic.motion_val[0][xy + wrap + v->blocks_off][0] = 0;
s->cur_pic.motion_val[0][xy + wrap + v->blocks_off][1] = 0;
s->cur_pic.motion_val[0][xy + wrap + 1 + v->blocks_off][0] = 0;
s->cur_pic.motion_val[0][xy + wrap + 1 + v->blocks_off][1] = 0;
v->luma_mv[s->mb_x][0] = v->luma_mv[s->mb_x][1] = 0;
s->cur_pic.motion_val[1][xy + 1 + v->blocks_off][0] = 0;
s->cur_pic.motion_val[1][xy + 1 + v->blocks_off][1] = 0;
s->cur_pic.motion_val[1][xy + wrap + v->blocks_off][0] = 0;
s->cur_pic.motion_val[1][xy + wrap + v->blocks_off][1] = 0;
s->cur_pic.motion_val[1][xy + wrap + 1 + v->blocks_off][0] = 0;
s->cur_pic.motion_val[1][xy + wrap + 1 + v->blocks_off][1] = 0;
}
return;
}
a_valid = !s->first_slice_line || (n == 2 || n == 3);
b_valid = a_valid;
c_valid = s->mb_x || (n == 1 || n == 3);
if (mv1) {
if (v->field_mode && mixedmv_pic)
off = (s->mb_x == (s->mb_width - 1)) ? -2 : 2;
else
off = (s->mb_x == (s->mb_width - 1)) ? -1 : 2;
b_valid = b_valid && s->mb_width > 1;
} else {
// in 4-MV mode different blocks have different B predictor position
switch (n) {
case 0:
if (v->res_rtm_flag)
off = s->mb_x ? -1 : 1;
else
off = s->mb_x ? -1 : 2 * s->mb_width - wrap - 1;
break;
case 1:
off = (s->mb_x == (s->mb_width - 1)) ? -1 : 1;
break;
case 2:
off = 1;
break;
case 3:
off = -1;
}
if (v->field_mode && s->mb_width == 1)
b_valid = b_valid && c_valid;
}
if (v->field_mode) {
a_valid = a_valid && !is_intra[xy - wrap];
b_valid = b_valid && !is_intra[xy - wrap + off];
c_valid = c_valid && !is_intra[xy - 1];
}
if (a_valid) {
const int16 *A = s->cur_pic.motion_val[dir][xy - wrap + v->blocks_off];
a_f = v->mv_f[dir][xy - wrap + v->blocks_off];
num_oppfield += a_f;
num_samefield += 1 - a_f;
field_predA[0] = A[0];
field_predA[1] = A[1];
} else {
field_predA[0] = field_predA[1] = 0;
a_f = 0;
}
if (b_valid) {
const int16 *B = s->cur_pic.motion_val[dir][xy - wrap + off + v->blocks_off];
b_f = v->mv_f[dir][xy - wrap + off + v->blocks_off];
num_oppfield += b_f;
num_samefield += 1 - b_f;
field_predB[0] = B[0];
field_predB[1] = B[1];
} else {
field_predB[0] = field_predB[1] = 0;
b_f = 0;
}
if (c_valid) {
const int16 *C = s->cur_pic.motion_val[dir][xy - 1 + v->blocks_off];
c_f = v->mv_f[dir][xy - 1 + v->blocks_off];
num_oppfield += c_f;
num_samefield += 1 - c_f;
field_predC[0] = C[0];
field_predC[1] = C[1];
} else {
field_predC[0] = field_predC[1] = 0;
c_f = 0;
}
if (v->field_mode) {
if (!v->numref)
// REFFIELD determines if the last field or the second-last field is
// to be used as reference
opposite = 1 - v->reffield;
else {
if (num_samefield <= num_oppfield)
opposite = 1 - pred_flag;
else
opposite = pred_flag;
}
} else
opposite = 0;
if (opposite) {
v->mv_f[dir][xy + v->blocks_off] = 1;
v->ref_field_type[dir] = !v->cur_field_type;
if (a_valid && !a_f) {
field_predA[0] = scaleforopp(v, field_predA[0], 0, dir);
field_predA[1] = scaleforopp(v, field_predA[1], 1, dir);
}
if (b_valid && !b_f) {
field_predB[0] = scaleforopp(v, field_predB[0], 0, dir);
field_predB[1] = scaleforopp(v, field_predB[1], 1, dir);
}
if (c_valid && !c_f) {
field_predC[0] = scaleforopp(v, field_predC[0], 0, dir);
field_predC[1] = scaleforopp(v, field_predC[1], 1, dir);
}
} else {
v->mv_f[dir][xy + v->blocks_off] = 0;
v->ref_field_type[dir] = v->cur_field_type;
if (a_valid && a_f) {
field_predA[0] = scaleforsame(v, field_predA[0], 0, dir);
field_predA[1] = scaleforsame(v, field_predA[1], 1, dir);
}
if (b_valid && b_f) {
field_predB[0] = scaleforsame(v, field_predB[0], 0, dir);
field_predB[1] = scaleforsame(v, field_predB[1], 1, dir);
}
if (c_valid && c_f) {
field_predC[0] = scaleforsame(v, field_predC[0], 0, dir);
field_predC[1] = scaleforsame(v, field_predC[1], 1, dir);
}
}
if (a_valid) {
px = field_predA[0];
py = field_predA[1];
} else if (c_valid) {
px = field_predC[0];
py = field_predC[1];
} else if (b_valid) {
px = field_predB[0];
py = field_predB[1];
} else {
px = 0;
py = 0;
}
if (num_samefield + num_oppfield > 1) {
px = mid_pred(field_predA[0], field_predB[0], field_predC[0]);
py = mid_pred(field_predA[1], field_predB[1], field_predC[1]);
}
/* Pullback MV as specified in 8.3.5.3.4 */
if (!v->field_mode) {
int qx, qy, X, Y;
int MV = mv1 ? -60 : -28;
qx = (s->mb_x << 6) + ((n == 1 || n == 3) ? 32 : 0);
qy = (s->mb_y << 6) + ((n == 2 || n == 3) ? 32 : 0);
X = (s->mb_width << 6) - 4;
Y = (s->mb_height << 6) - 4;
if (qx + px < MV)
px = MV - qx;
if (qy + py < MV)
py = MV - qy;
if (qx + px > X)
px = X - qx;
if (qy + py > Y)
py = Y - qy;
}
if (!v->field_mode || s->pict_type != AV_PICTURE_TYPE_B) {
/* Calculate hybrid prediction as specified in 8.3.5.3.5 (also 10.3.5.4.3.5) */
hybridmv_thresh = 32;
if (a_valid && c_valid) {
if (is_intra[xy - wrap])
sum = ABS(px) + ABS(py);
else
sum = ABS(px - field_predA[0]) + ABS(py - field_predA[1]);
if (sum > hybridmv_thresh) {
if (get_bits1(&v->gb)) { // read HYBRIDPRED bit
px = field_predA[0];
py = field_predA[1];
} else {
px = field_predC[0];
py = field_predC[1];
}
} else {
if (is_intra[xy - 1])
sum = ABS(px) + ABS(py);
else
sum = ABS(px - field_predC[0]) + ABS(py - field_predC[1]);
if (sum > hybridmv_thresh) {
if (get_bits1(&v->gb)) {
px = field_predA[0];
py = field_predA[1];
} else {
px = field_predC[0];
py = field_predC[1];
}
}
}
}
}
if (v->field_mode && v->numref)
r_y >>= 1;
if (v->field_mode && v->cur_field_type && v->ref_field_type[dir] == 0)
y_bias = 1;
/* store MV using signed modulus of MV range defined in 4.11 */
s->mv[dir][n][0] = s->cur_pic.motion_val[dir][xy + v->blocks_off][0] =
((px + dmv_x + r_x) & ((r_x << 1) - 1)) - r_x;
s->mv[dir][n][1] = s->cur_pic.motion_val[dir][xy + v->blocks_off][1] =
((py + dmv_y + r_y - y_bias) & ((r_y << 1) - 1)) - r_y + y_bias;
if (mv1) { /* duplicate motion data for 1-MV block */
s->cur_pic.motion_val[dir][xy + 1 + v->blocks_off][0] = s->cur_pic.motion_val[dir][xy + v->blocks_off][0];
s->cur_pic.motion_val[dir][xy + 1 + v->blocks_off][1] = s->cur_pic.motion_val[dir][xy + v->blocks_off][1];
s->cur_pic.motion_val[dir][xy + wrap + v->blocks_off][0] = s->cur_pic.motion_val[dir][xy + v->blocks_off][0];
s->cur_pic.motion_val[dir][xy + wrap + v->blocks_off][1] = s->cur_pic.motion_val[dir][xy + v->blocks_off][1];
s->cur_pic.motion_val[dir][xy + wrap + 1 + v->blocks_off][0] =
s->cur_pic.motion_val[dir][xy + v->blocks_off][0];
s->cur_pic.motion_val[dir][xy + wrap + 1 + v->blocks_off][1] =
s->cur_pic.motion_val[dir][xy + v->blocks_off][1];
v->mv_f[dir][xy + 1 + v->blocks_off] = v->mv_f[dir][xy + v->blocks_off];
v->mv_f[dir][xy + wrap + v->blocks_off] = v->mv_f[dir][xy + wrap + 1 + v->blocks_off] =
v->mv_f[dir][xy + v->blocks_off];
}
}
/** Predict and set motion vector for interlaced frame picture MBs
*/
void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y, int mvn, int r_x, int r_y, int dir) {
PictureState *s = &v->s;
int xy, wrap, off = 0;
int A[2], B[2], C[2];
int px = 0, py = 0;
int a_valid = 0, b_valid = 0, c_valid = 0;
int field_a, field_b, field_c; // 0: same, 1: opposite
int total_valid, num_samefield, num_oppfield;
int pos_c, pos_b, n_adj;
wrap = s->b8_stride;
xy = s->block_index[n];
if (s->mb_intra) {
s->mv[0][n][0] = s->cur_pic.motion_val[0][xy][0] = 0;
s->mv[0][n][1] = s->cur_pic.motion_val[0][xy][1] = 0;
s->cur_pic.motion_val[1][xy][0] = 0;
s->cur_pic.motion_val[1][xy][1] = 0;
if (mvn == 1) { /* duplicate motion data for 1-MV block */
s->cur_pic.motion_val[0][xy + 1][0] = 0;
s->cur_pic.motion_val[0][xy + 1][1] = 0;
s->cur_pic.motion_val[0][xy + wrap][0] = 0;
s->cur_pic.motion_val[0][xy + wrap][1] = 0;
s->cur_pic.motion_val[0][xy + wrap + 1][0] = 0;
s->cur_pic.motion_val[0][xy + wrap + 1][1] = 0;
v->luma_mv[s->mb_x][0] = v->luma_mv[s->mb_x][1] = 0;
s->cur_pic.motion_val[1][xy + 1][0] = 0;
s->cur_pic.motion_val[1][xy + 1][1] = 0;
s->cur_pic.motion_val[1][xy + wrap][0] = 0;
s->cur_pic.motion_val[1][xy + wrap][1] = 0;
s->cur_pic.motion_val[1][xy + wrap + 1][0] = 0;
s->cur_pic.motion_val[1][xy + wrap + 1][1] = 0;
}
return;
}
off = ((n == 0) || (n == 1)) ? 1 : -1;
/* predict A */
if (s->mb_x || (n == 1) || (n == 3)) {
if ((v->blk_mv_type[xy]) // current block (MB) has a field MV
|| (!v->blk_mv_type[xy] && !v->blk_mv_type[xy - 1])) { // or both have frame MV
A[0] = s->cur_pic.motion_val[dir][xy - 1][0];
A[1] = s->cur_pic.motion_val[dir][xy - 1][1];
a_valid = 1;
} else { // current block has frame mv and cand. has field MV (so average)
A[0] =
(s->cur_pic.motion_val[dir][xy - 1][0] + s->cur_pic.motion_val[dir][xy - 1 + off * wrap][0] + 1) >> 1;
A[1] =
(s->cur_pic.motion_val[dir][xy - 1][1] + s->cur_pic.motion_val[dir][xy - 1 + off * wrap][1] + 1) >> 1;
a_valid = 1;
}
if (!(n & 1) && v->is_intra[s->mb_x - 1]) {
a_valid = 0;
A[0] = A[1] = 0;
}
} else
A[0] = A[1] = 0;
/* Predict B and C */
B[0] = B[1] = C[0] = C[1] = 0;
if (n == 0 || n == 1 || v->blk_mv_type[xy]) {
if (!s->first_slice_line) {
if (!v->is_intra[s->mb_x - s->mb_stride]) {
b_valid = 1;
n_adj = n | 2;
pos_b = s->block_index[n_adj] - 2 * wrap;
if (v->blk_mv_type[pos_b] && v->blk_mv_type[xy]) {
n_adj = (n & 2) | (n & 1);
}
B[0] = s->cur_pic.motion_val[dir][s->block_index[n_adj] - 2 * wrap][0];
B[1] = s->cur_pic.motion_val[dir][s->block_index[n_adj] - 2 * wrap][1];
if (v->blk_mv_type[pos_b] && !v->blk_mv_type[xy]) {
B[0] = (B[0] + s->cur_pic.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap][0] + 1) >> 1;
B[1] = (B[1] + s->cur_pic.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap][1] + 1) >> 1;
}
}
if (s->mb_width > 1) {
if (!v->is_intra[s->mb_x - s->mb_stride + 1]) {
c_valid = 1;
n_adj = 2;
pos_c = s->block_index[2] - 2 * wrap + 2;
if (v->blk_mv_type[pos_c] && v->blk_mv_type[xy]) {
n_adj = n & 2;
}
C[0] = s->cur_pic.motion_val[dir][s->block_index[n_adj] - 2 * wrap + 2][0];
C[1] = s->cur_pic.motion_val[dir][s->block_index[n_adj] - 2 * wrap + 2][1];
if (v->blk_mv_type[pos_c] && !v->blk_mv_type[xy]) {
C[0] =
(1 + C[0] + (s->cur_pic.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap + 2][0])) >> 1;
C[1] =
(1 + C[1] + (s->cur_pic.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap + 2][1])) >> 1;
}
if (s->mb_x == s->mb_width - 1) {
if (!v->is_intra[s->mb_x - s->mb_stride - 1]) {
c_valid = 1;
n_adj = 3;
pos_c = s->block_index[3] - 2 * wrap - 2;
if (v->blk_mv_type[pos_c] && v->blk_mv_type[xy]) {
n_adj = n | 1;
}
C[0] = s->cur_pic.motion_val[dir][s->block_index[n_adj] - 2 * wrap - 2][0];
C[1] = s->cur_pic.motion_val[dir][s->block_index[n_adj] - 2 * wrap - 2][1];
if (v->blk_mv_type[pos_c] && !v->blk_mv_type[xy]) {
C[0] =
(1 + C[0] + s->cur_pic.motion_val[dir][s->block_index[1] - 2 * wrap - 2][0]) >> 1;
C[1] =
(1 + C[1] + s->cur_pic.motion_val[dir][s->block_index[1] - 2 * wrap - 2][1]) >> 1;
}
} else
c_valid = 0;
}
}
}
}
} else {
pos_b = s->block_index[1];
b_valid = 1;
B[0] = s->cur_pic.motion_val[dir][pos_b][0];
B[1] = s->cur_pic.motion_val[dir][pos_b][1];
pos_c = s->block_index[0];
c_valid = 1;
C[0] = s->cur_pic.motion_val[dir][pos_c][0];
C[1] = s->cur_pic.motion_val[dir][pos_c][1];
}
total_valid = a_valid + b_valid + c_valid;
// check if predictor A is out of bounds
if (!s->mb_x && !(n == 1 || n == 3)) {
A[0] = A[1] = 0;
}
// check if predictor B is out of bounds
if ((s->first_slice_line && v->blk_mv_type[xy]) || (s->first_slice_line && !(n & 2))) {
B[0] = B[1] = C[0] = C[1] = 0;
}
if (!v->blk_mv_type[xy]) {
if (s->mb_width == 1) {
px = B[0];
py = B[1];
} else {
if (total_valid >= 2) {
px = mid_pred(A[0], B[0], C[0]);
py = mid_pred(A[1], B[1], C[1]);
} else if (total_valid) {
if (a_valid) {
px = A[0];
py = A[1];
} else if (b_valid) {
px = B[0];
py = B[1];
} else {
px = C[0];
py = C[1];
}
}
}
} else {
if (a_valid)
field_a = (A[1] & 4) ? 1 : 0;
else
field_a = 0;
if (b_valid)
field_b = (B[1] & 4) ? 1 : 0;
else
field_b = 0;
if (c_valid)
field_c = (C[1] & 4) ? 1 : 0;
else
field_c = 0;
num_oppfield = field_a + field_b + field_c;
num_samefield = total_valid - num_oppfield;
if (total_valid == 3) {
if ((num_samefield == 3) || (num_oppfield == 3)) {
px = mid_pred(A[0], B[0], C[0]);
py = mid_pred(A[1], B[1], C[1]);
} else if (num_samefield >= num_oppfield) {
/* take one MV from same field set depending on priority
the check for B may not be necessary */
px = !field_a ? A[0] : B[0];
py = !field_a ? A[1] : B[1];
} else {
px = field_a ? A[0] : B[0];
py = field_a ? A[1] : B[1];
}
} else if (total_valid == 2) {
if (num_samefield >= num_oppfield) {
if (!field_a && a_valid) {
px = A[0];
py = A[1];
} else if (!field_b && b_valid) {
px = B[0];
py = B[1];
} else /*if (c_valid)*/ {
assert(c_valid);
px = C[0];
py = C[1];
}
} else {
if (field_a && a_valid) {
px = A[0];
py = A[1];
} else /*if (field_b && b_valid)*/ {
assert(field_b && b_valid);
px = B[0];
py = B[1];
}
}
} else if (total_valid == 1) {
px = (a_valid) ? A[0] : ((b_valid) ? B[0] : C[0]);
py = (a_valid) ? A[1] : ((b_valid) ? B[1] : C[1]);
}
}
/* store MV using signed modulus of MV range defined in 4.11 */
s->mv[dir][n][0] = s->cur_pic.motion_val[dir][xy][0] = ((px + dmv_x + r_x) & ((r_x << 1) - 1)) - r_x;
s->mv[dir][n][1] = s->cur_pic.motion_val[dir][xy][1] = ((py + dmv_y + r_y) & ((r_y << 1) - 1)) - r_y;
if (mvn == 1) { /* duplicate motion data for 1-MV block */
s->cur_pic.motion_val[dir][xy + 1][0] = s->cur_pic.motion_val[dir][xy][0];
s->cur_pic.motion_val[dir][xy + 1][1] = s->cur_pic.motion_val[dir][xy][1];
s->cur_pic.motion_val[dir][xy + wrap][0] = s->cur_pic.motion_val[dir][xy][0];
s->cur_pic.motion_val[dir][xy + wrap][1] = s->cur_pic.motion_val[dir][xy][1];
s->cur_pic.motion_val[dir][xy + wrap + 1][0] = s->cur_pic.motion_val[dir][xy][0];
s->cur_pic.motion_val[dir][xy + wrap + 1][1] = s->cur_pic.motion_val[dir][xy][1];
} else if (mvn == 2) { /* duplicate motion data for 2-Field MV block */
s->cur_pic.motion_val[dir][xy + 1][0] = s->cur_pic.motion_val[dir][xy][0];
s->cur_pic.motion_val[dir][xy + 1][1] = s->cur_pic.motion_val[dir][xy][1];
s->mv[dir][n + 1][0] = s->mv[dir][n][0];
s->mv[dir][n + 1][1] = s->mv[dir][n][1];
}
}
void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], int direct, int mvtype) {
PictureState *s = &v->s;
int xy, wrap;
int px, py;
int sum;
int r_x, r_y;
const uint8 *is_intra = v->mb_type;
assert(!v->field_mode);
r_x = v->range_x;
r_y = v->range_y;
/* scale MV difference to be quad-pel */
if (!s->quarter_sample) {
dmv_x[0] *= 2;
dmv_y[0] *= 2;
dmv_x[1] *= 2;
dmv_y[1] *= 2;
}
wrap = s->b8_stride;
xy = s->block_index[0];
if (s->mb_intra) {
s->cur_pic.motion_val[0][xy][0] = s->cur_pic.motion_val[0][xy][1] = s->cur_pic.motion_val[1][xy][0] =
s->cur_pic.motion_val[1][xy][1] = 0;
return;
}
if (direct && s->next_pic.ptr->field_picture)
warning("Mixed frame/field direct mode not supported\n");
s->mv[0][0][0] = scale_mv(s->next_pic.motion_val[1][xy][0], v->bfraction, 0, s->quarter_sample);
s->mv[0][0][1] = scale_mv(s->next_pic.motion_val[1][xy][1], v->bfraction, 0, s->quarter_sample);
s->mv[1][0][0] = scale_mv(s->next_pic.motion_val[1][xy][0], v->bfraction, 1, s->quarter_sample);
s->mv[1][0][1] = scale_mv(s->next_pic.motion_val[1][xy][1], v->bfraction, 1, s->quarter_sample);
/* Pullback predicted motion vectors as specified in 8.4.5.4 */
s->mv[0][0][0] = av_clip(s->mv[0][0][0], -60 - (s->mb_x << 6), (s->mb_width << 6) - 4 - (s->mb_x << 6));
s->mv[0][0][1] = av_clip(s->mv[0][0][1], -60 - (s->mb_y << 6), (s->mb_height << 6) - 4 - (s->mb_y << 6));
s->mv[1][0][0] = av_clip(s->mv[1][0][0], -60 - (s->mb_x << 6), (s->mb_width << 6) - 4 - (s->mb_x << 6));
s->mv[1][0][1] = av_clip(s->mv[1][0][1], -60 - (s->mb_y << 6), (s->mb_height << 6) - 4 - (s->mb_y << 6));
if (direct) {
s->cur_pic.motion_val[0][xy][0] = s->mv[0][0][0];
s->cur_pic.motion_val[0][xy][1] = s->mv[0][0][1];
s->cur_pic.motion_val[1][xy][0] = s->mv[1][0][0];
s->cur_pic.motion_val[1][xy][1] = s->mv[1][0][1];
return;
}
if ((mvtype == BMV_TYPE_FORWARD) || (mvtype == BMV_TYPE_INTERPOLATED)) {
int16 *C = s->cur_pic.motion_val[0][xy - 2];
const int16 *A = s->cur_pic.motion_val[0][xy - wrap * 2];
int off = (s->mb_x == (s->mb_width - 1)) ? -2 : 2;
const int16 *B = s->cur_pic.motion_val[0][xy - wrap * 2 + off];
if (!s->mb_x)
C[0] = C[1] = 0;
if (!s->first_slice_line) { // predictor A is not out of bounds
if (s->mb_width == 1) {
px = A[0];
py = A[1];
} else {
px = mid_pred(A[0], B[0], C[0]);
py = mid_pred(A[1], B[1], C[1]);
}
} else if (s->mb_x) { // predictor C is not out of bounds
px = C[0];
py = C[1];
} else {
px = py = 0;
}
/* Pullback MV as specified in 8.3.5.3.4 */
{
int qx, qy, X, Y;
int sh = v->profile < PROFILE_ADVANCED ? 5 : 6;
int MV = 4 - (1 << sh);
qx = (s->mb_x << sh);
qy = (s->mb_y << sh);
X = (s->mb_width << sh) - 4;
Y = (s->mb_height << sh) - 4;
if (qx + px < MV)
px = MV - qx;
if (qy + py < MV)
py = MV - qy;
if (qx + px > X)
px = X - qx;
if (qy + py > Y)
py = Y - qy;
}
/* Calculate hybrid prediction as specified in 8.3.5.3.5 */
if (0 && !s->first_slice_line && s->mb_x) {
if (is_intra[xy - wrap])
sum = ABS(px) + ABS(py);
else
sum = ABS(px - A[0]) + ABS(py - A[1]);
if (sum > 32) {
if (get_bits1(&v->gb)) {
px = A[0];
py = A[1];
} else {
px = C[0];
py = C[1];
}
} else {
if (is_intra[xy - 2])
sum = ABS(px) + ABS(py);
else
sum = ABS(px - C[0]) + ABS(py - C[1]);
if (sum > 32) {
if (get_bits1(&v->gb)) {
px = A[0];
py = A[1];
} else {
px = C[0];
py = C[1];
}
}
}
}
/* store MV using signed modulus of MV range defined in 4.11 */
s->mv[0][0][0] = ((px + dmv_x[0] + r_x) & ((r_x << 1) - 1)) - r_x;
s->mv[0][0][1] = ((py + dmv_y[0] + r_y) & ((r_y << 1) - 1)) - r_y;
}
if ((mvtype == BMV_TYPE_BACKWARD) || (mvtype == BMV_TYPE_INTERPOLATED)) {
int16 *C = s->cur_pic.motion_val[1][xy - 2];
const int16 *A = s->cur_pic.motion_val[1][xy - wrap * 2];
int off = (s->mb_x == (s->mb_width - 1)) ? -2 : 2;
const int16 *B = s->cur_pic.motion_val[1][xy - wrap * 2 + off];
if (!s->mb_x)
C[0] = C[1] = 0;
if (!s->first_slice_line) { // predictor A is not out of bounds
if (s->mb_width == 1) {
px = A[0];
py = A[1];
} else {
px = mid_pred(A[0], B[0], C[0]);
py = mid_pred(A[1], B[1], C[1]);
}
} else if (s->mb_x) { // predictor C is not out of bounds
px = C[0];
py = C[1];
} else {
px = py = 0;
}
/* Pullback MV as specified in 8.3.5.3.4 */
{
int qx, qy, X, Y;
int sh = v->profile < PROFILE_ADVANCED ? 5 : 6;
int MV = 4 - (1 << sh);
qx = (s->mb_x << sh);
qy = (s->mb_y << sh);
X = (s->mb_width << sh) - 4;
Y = (s->mb_height << sh) - 4;
if (qx + px < MV)
px = MV - qx;
if (qy + py < MV)
py = MV - qy;
if (qx + px > X)
px = X - qx;
if (qy + py > Y)
py = Y - qy;
}
/* Calculate hybrid prediction as specified in 8.3.5.3.5 */
if (0 && !s->first_slice_line && s->mb_x) {
if (is_intra[xy - wrap])
sum = ABS(px) + ABS(py);
else
sum = ABS(px - A[0]) + ABS(py - A[1]);
if (sum > 32) {
if (get_bits1(&v->gb)) {
px = A[0];
py = A[1];
} else {
px = C[0];
py = C[1];
}
} else {
if (is_intra[xy - 2])
sum = ABS(px) + ABS(py);
else
sum = ABS(px - C[0]) + ABS(py - C[1]);
if (sum > 32) {
if (get_bits1(&v->gb)) {
px = A[0];
py = A[1];
} else {
px = C[0];
py = C[1];
}
}
}
}
/* store MV using signed modulus of MV range defined in 4.11 */
s->mv[1][0][0] = ((px + dmv_x[1] + r_x) & ((r_x << 1) - 1)) - r_x;
s->mv[1][0][1] = ((py + dmv_y[1] + r_y) & ((r_y << 1) - 1)) - r_y;
}
s->cur_pic.motion_val[0][xy][0] = s->mv[0][0][0];
s->cur_pic.motion_val[0][xy][1] = s->mv[0][0][1];
s->cur_pic.motion_val[1][xy][0] = s->mv[1][0][0];
s->cur_pic.motion_val[1][xy][1] = s->mv[1][0][1];
}
void ff_vc1_pred_b_mv_intfi(VC1Context *v, int n, int *dmv_x, int *dmv_y, int mv1, int *pred_flag) {
int dir = (v->bmvtype == BMV_TYPE_BACKWARD) ? 1 : 0;
PictureState *s = &v->s;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
if (v->bmvtype == BMV_TYPE_DIRECT) {
int total_opp, k, f;
if (s->next_pic.mb_type[mb_pos + v->mb_off] != MB_TYPE_INTRA) {
s->mv[0][0][0] = scale_mv(s->next_pic.motion_val[1][s->block_index[0] + v->blocks_off][0], v->bfraction, 0,
s->quarter_sample);
s->mv[0][0][1] = scale_mv(s->next_pic.motion_val[1][s->block_index[0] + v->blocks_off][1], v->bfraction, 0,
s->quarter_sample);
s->mv[1][0][0] = scale_mv(s->next_pic.motion_val[1][s->block_index[0] + v->blocks_off][0], v->bfraction, 1,
s->quarter_sample);
s->mv[1][0][1] = scale_mv(s->next_pic.motion_val[1][s->block_index[0] + v->blocks_off][1], v->bfraction, 1,
s->quarter_sample);
total_opp = v->mv_f_next[0][s->block_index[0] + v->blocks_off] +
v->mv_f_next[0][s->block_index[1] + v->blocks_off] +
v->mv_f_next[0][s->block_index[2] + v->blocks_off] +
v->mv_f_next[0][s->block_index[3] + v->blocks_off];
f = (total_opp > 2) ? 1 : 0;
} else {
s->mv[0][0][0] = s->mv[0][0][1] = 0;
s->mv[1][0][0] = s->mv[1][0][1] = 0;
f = 0;
}
v->ref_field_type[0] = v->ref_field_type[1] = v->cur_field_type ^ f;
for (k = 0; k < 4; k++) {
s->cur_pic.motion_val[0][s->block_index[k] + v->blocks_off][0] = s->mv[0][0][0];
s->cur_pic.motion_val[0][s->block_index[k] + v->blocks_off][1] = s->mv[0][0][1];
s->cur_pic.motion_val[1][s->block_index[k] + v->blocks_off][0] = s->mv[1][0][0];
s->cur_pic.motion_val[1][s->block_index[k] + v->blocks_off][1] = s->mv[1][0][1];
v->mv_f[0][s->block_index[k] + v->blocks_off] = f;
v->mv_f[1][s->block_index[k] + v->blocks_off] = f;
}
return;
}
if (v->bmvtype == BMV_TYPE_INTERPOLATED) {
ff_vc1_pred_mv(v, 0, dmv_x[0], dmv_y[0], 1, v->range_x, v->range_y, v->mb_type, pred_flag[0], 0);
ff_vc1_pred_mv(v, 0, dmv_x[1], dmv_y[1], 1, v->range_x, v->range_y, v->mb_type, pred_flag[1], 1);
return;
}
if (dir) { // backward
ff_vc1_pred_mv(v, n, dmv_x[1], dmv_y[1], mv1, v->range_x, v->range_y, v->mb_type, pred_flag[1], 1);
if (n == 3 || mv1) {
ff_vc1_pred_mv(v, 0, dmv_x[0], dmv_y[0], 1, v->range_x, v->range_y, v->mb_type, 0, 0);
}
} else { // forward
ff_vc1_pred_mv(v, n, dmv_x[0], dmv_y[0], mv1, v->range_x, v->range_y, v->mb_type, pred_flag[0], 0);
if (n == 3 || mv1) {
ff_vc1_pred_mv(v, 0, dmv_x[1], dmv_y[1], 1, v->range_x, v->range_y, v->mb_type, 0, 1);
}
}
}
static inline void vc1_h_overlap_filter(VC1Context *v, int16 (*left_block)[64], int16 (*right_block)[64],
int left_fieldtx, int right_fieldtx, int block_num) {
switch (block_num) {
case 0:
v->vc1dsp.vc1_h_s_overlap(
left_block[2], right_block[0], left_fieldtx ^ right_fieldtx ? 16 - 8 * left_fieldtx : 8,
left_fieldtx ^ right_fieldtx ? 16 - 8 * right_fieldtx : 8, left_fieldtx || right_fieldtx ? 0 : 1);
break;
case 1:
v->vc1dsp.vc1_h_s_overlap(right_block[0], right_block[2], 8, 8, right_fieldtx ? 0 : 1);
break;
case 2:
v->vc1dsp.vc1_h_s_overlap(!left_fieldtx && right_fieldtx ? left_block[2] + 8 : left_block[3],
left_fieldtx && !right_fieldtx ? right_block[0] + 8 : right_block[1],
left_fieldtx ^ right_fieldtx ? 16 - 8 * left_fieldtx : 8,
left_fieldtx ^ right_fieldtx ? 16 - 8 * right_fieldtx : 8,
left_fieldtx || right_fieldtx ? 2 : 1);
break;
case 3:
v->vc1dsp.vc1_h_s_overlap(right_block[1], right_block[3], 8, 8, right_fieldtx ? 2 : 1);
break;
case 4:
case 5:
v->vc1dsp.vc1_h_s_overlap(left_block[block_num], right_block[block_num], 8, 8, 1);
break;
}
}
static inline void vc1_v_overlap_filter(VC1Context *v, int16 (*top_block)[64], int16 (*bottom_block)[64],
int block_num) {
switch (block_num) {
case 0:
v->vc1dsp.vc1_v_s_overlap(top_block[1], bottom_block[0]);
break;
case 1:
v->vc1dsp.vc1_v_s_overlap(top_block[3], bottom_block[2]);
break;
case 2:
v->vc1dsp.vc1_v_s_overlap(bottom_block[0], bottom_block[1]);
break;
case 3:
v->vc1dsp.vc1_v_s_overlap(bottom_block[2], bottom_block[3]);
break;
case 4:
case 5:
v->vc1dsp.vc1_v_s_overlap(top_block[block_num], bottom_block[block_num]);
break;
}
}
void ff_vc1_i_overlap_filter(VC1Context *v) {
PictureState *s = &v->s;
int16(*topleft_blk)[64], (*top_blk)[64], (*left_blk)[64], (*cur_blk)[64];
int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
int i;
topleft_blk = v->block[v->topleft_blk_idx];
top_blk = v->block[v->top_blk_idx];
left_blk = v->block[v->left_blk_idx];
cur_blk = v->block[v->cur_blk_idx];
/* Within a MB, the horizontal overlap always runs before the vertical.
* To accomplish that, we run the H on the left and internal vertical
* borders of the currently decoded MB. Then, we wait for the next overlap
* iteration to do H overlap on the right edge of this MB, before moving
* over and running the V overlap on the top and internal horizontal
* borders. Therefore, the H overlap trails by one MB col and the
* V overlap trails by one MB row. This is reflected in the time at which
* we run the put_pixels loop, i.e. delayed by one row and one column. */
for (i = 0; i < block_count; i++) {
if (s->mb_x == 0 && (i & 5) != 1)
continue;
if (v->pq >= 9 || (v->profile == PROFILE_ADVANCED &&
(v->condover == CONDOVER_ALL ||
(v->over_flags_plane[mb_pos] && ((i & 5) == 1 || v->over_flags_plane[mb_pos - 1])))))
vc1_h_overlap_filter(v, s->mb_x ? left_blk : cur_blk, cur_blk,
v->fcm == ILACE_FRAME && s->mb_x && v->fieldtx_plane[mb_pos - 1],
v->fcm == ILACE_FRAME && v->fieldtx_plane[mb_pos], i);
}
if (v->fcm != ILACE_FRAME)
for (i = 0; i < block_count; i++) {
if (s->first_slice_line && !(i & 2))
continue;
if (s->mb_x &&
(v->pq >= 9 ||
(v->profile == PROFILE_ADVANCED &&
(v->condover == CONDOVER_ALL ||
(v->over_flags_plane[mb_pos - 1] && ((i & 2) || v->over_flags_plane[mb_pos - 1 - s->mb_stride]))))))
vc1_v_overlap_filter(v, s->first_slice_line ? left_blk : topleft_blk, left_blk, i);
if (s->mb_x == s->mb_width - 1 &&
(v->pq >= 9 ||
(v->profile == PROFILE_ADVANCED &&
(v->condover == CONDOVER_ALL ||
(v->over_flags_plane[mb_pos] && ((i & 2) || v->over_flags_plane[mb_pos - s->mb_stride]))))))
vc1_v_overlap_filter(v, s->first_slice_line ? cur_blk : top_blk, cur_blk, i);
}
}
void ff_vc1_p_overlap_filter(VC1Context *v) {
PictureState *s = &v->s;
int16(*topleft_blk)[64], (*top_blk)[64], (*left_blk)[64], (*cur_blk)[64];
int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
int i;
topleft_blk = v->block[v->topleft_blk_idx];
top_blk = v->block[v->top_blk_idx];
left_blk = v->block[v->left_blk_idx];
cur_blk = v->block[v->cur_blk_idx];
for (i = 0; i < block_count; i++) {
if (s->mb_x == 0 && (i & 5) != 1)
continue;
if (v->mb_type[s->block_index[i]] && v->mb_type[s->block_index[i] - 1])
vc1_h_overlap_filter(v, s->mb_x ? left_blk : cur_blk, cur_blk,
v->fcm == ILACE_FRAME && s->mb_x && v->fieldtx_plane[mb_pos - 1],
v->fcm == ILACE_FRAME && v->fieldtx_plane[mb_pos], i);
}
if (v->fcm != ILACE_FRAME)
for (i = 0; i < block_count; i++) {
if (s->first_slice_line && !(i & 2))
continue;
if (s->mb_x && v->mb_type[s->block_index[i] - 2 + (i > 3)] &&
v->mb_type[s->block_index[i] - s->block_wrap[i] - 2 + (i > 3)])
vc1_v_overlap_filter(v, s->first_slice_line ? left_blk : topleft_blk, left_blk, i);
if (s->mb_x == s->mb_width - 1)
if (v->mb_type[s->block_index[i]] && v->mb_type[s->block_index[i] - s->block_wrap[i]])
vc1_v_overlap_filter(v, s->first_slice_line ? cur_blk : top_blk, cur_blk, i);
}
}
#define LEFT_EDGE (1 << 0)
#define RIGHT_EDGE (1 << 1)
#define TOP_EDGE (1 << 2)
#define BOTTOM_EDGE (1 << 3)
static inline void vc1_i_h_loop_filter(VC1Context *v, uint8 *dest, uint32 flags, int block_num) {
PictureState *s = &v->s;
int pq = v->pq;
uint8 *dst;
if (block_num & 2)
return;
if (!(flags & LEFT_EDGE) || (block_num & 5) == 1) {
if (block_num > 3)
dst = dest;
else
dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8;
if (v->fcm == ILACE_FRAME)
if (block_num > 3) {
v->vc1dsp.vc1_h_loop_filter4(dst, 2 * s->uvlinesize, pq);
v->vc1dsp.vc1_h_loop_filter4(dst + s->uvlinesize, 2 * s->uvlinesize, pq);
} else {
v->vc1dsp.vc1_h_loop_filter8(dst, 2 * s->linesize, pq);
v->vc1dsp.vc1_h_loop_filter8(dst + s->linesize, 2 * s->linesize, pq);
}
else if (block_num > 3)
v->vc1dsp.vc1_h_loop_filter8(dst, s->uvlinesize, pq);
else
v->vc1dsp.vc1_h_loop_filter16(dst, s->linesize, pq);
}
}
static inline void vc1_i_v_loop_filter(VC1Context *v, uint8 *dest, uint32 flags, uint8 fieldtx, int block_num) {
PictureState *s = &v->s;
int pq = v->pq;
uint8 *dst;
if ((block_num & 5) == 1)
return;
if (!(flags & TOP_EDGE) || block_num & 2) {
if (block_num > 3)
dst = dest;
else
dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8;
if (v->fcm == ILACE_FRAME) {
if (block_num > 3) {
v->vc1dsp.vc1_v_loop_filter8(dst, 2 * s->uvlinesize, pq);
v->vc1dsp.vc1_v_loop_filter8(dst + s->uvlinesize, 2 * s->uvlinesize, pq);
} else if (block_num < 2 || !fieldtx) {
v->vc1dsp.vc1_v_loop_filter16(dst, 2 * s->linesize, pq);
v->vc1dsp.vc1_v_loop_filter16(dst + s->linesize, 2 * s->linesize, pq);
}
} else if (block_num > 3)
v->vc1dsp.vc1_v_loop_filter8(dst, s->uvlinesize, pq);
else
v->vc1dsp.vc1_v_loop_filter16(dst, s->linesize, pq);
}
}
void ff_vc1_i_loop_filter(VC1Context *v) {
PictureState *s = &v->s;
int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
uint8 *dest, fieldtx;
uint32 flags = 0;
int i;
/* Within a MB, the vertical loop filter always runs before the horizontal.
* To accomplish that, we run the V loop filter on top and internal
* horizontal borders of the last overlap filtered MB. Then, we wait for
* the loop filter iteration on the next row to do V loop filter on the
* bottom edge of this MB, before moving over and running the H loop
* filter on the left and internal vertical borders. Therefore, the loop
* filter trails by one row and one column relative to the overlap filter
* and two rows and two columns relative to the decoding loop. */
if (!s->first_slice_line) {
dest = s->dest[0] - 16 * s->linesize - 16;
flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0;
if (s->mb_x) {
fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride - 1];
for (i = 0; i < block_count; i++)
vc1_i_v_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, flags, fieldtx, i);
}
if (s->mb_x == v->end_mb_x - 1) {
dest += 16;
fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride];
for (i = 0; i < block_count; i++)
vc1_i_v_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, flags, fieldtx, i);
}
}
if (s->mb_y == s->end_mb_y - 1) {
dest = s->dest[0] - 16;
flags = s->first_slice_line ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE;
if (s->mb_x) {
fieldtx = v->fieldtx_plane[mb_pos - 1];
for (i = 0; i < block_count; i++)
vc1_i_v_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, flags, fieldtx, i);
}
if (s->mb_x == v->end_mb_x - 1) {
dest += 16;
fieldtx = v->fieldtx_plane[mb_pos];
for (i = 0; i < block_count; i++)
vc1_i_v_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, flags, fieldtx, i);
}
}
if (s->mb_y >= s->start_mb_y + 2) {
dest = s->dest[0] - 32 * s->linesize - 16;
if (s->mb_x) {
flags = s->mb_x == 1 ? LEFT_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 8 : dest, flags, i);
}
if (s->mb_x == v->end_mb_x - 1) {
dest += 16;
flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE;
for (i = 0; i < block_count; i++)
vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize : dest, flags, i);
}
}
if (s->mb_y == s->end_mb_y - 1) {
if (s->mb_y >= s->start_mb_y + 1) {
dest = s->dest[0] - 16 * s->linesize - 16;
if (s->mb_x) {
flags = s->mb_x == 1 ? LEFT_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, flags, i);
}
if (s->mb_x == v->end_mb_x - 1) {
flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE;
dest += 16;
for (i = 0; i < block_count; i++)
vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, flags, i);
}
}
dest = s->dest[0] - 16;
if (s->mb_x) {
flags = s->mb_x == 1 ? LEFT_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, flags, i);
}
if (s->mb_x == v->end_mb_x - 1) {
dest += 16;
flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE;
for (i = 0; i < block_count; i++)
vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, flags, i);
}
}
}
static inline void vc1_p_h_loop_filter(VC1Context *v, uint8 *dest, uint32 *cbp, uint8 *is_intra, int16 (*mv)[2],
uint8 *mv_f, int *ttblk, uint32 flags, int block_num) {
PictureState *s = &v->s;
int pq = v->pq;
uint32 left_cbp = cbp[0] >> (block_num * 4), right_cbp;
uint8 left_is_intra, right_is_intra;
int tt;
int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize;
uint8 *dst;
if (block_num > 3)
dst = dest;
else
dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8;
if (!(flags & RIGHT_EDGE) || !(block_num & 5)) {
left_is_intra = is_intra[0] & (1 << block_num);
if (block_num > 3) {
right_is_intra = is_intra[1] & (1 << block_num);
right_cbp = cbp[1] >> (block_num * 4);
} else if (block_num & 1) {
right_is_intra = is_intra[1] & (1 << block_num - 1);
right_cbp = cbp[1] >> ((block_num - 1) * 4);
} else {
right_is_intra = is_intra[0] & (1 << block_num + 1);
right_cbp = cbp[0] >> ((block_num + 1) * 4);
}
if (left_is_intra || right_is_intra || mv[0][0] != mv[1][0] || mv[0][1] != mv[1][1] ||
(v->fcm == ILACE_FIELD && mv_f[0] != mv_f[1]))
v->vc1dsp.vc1_h_loop_filter8(dst + 8, linesize, pq);
else {
idx = (left_cbp | (right_cbp >> 1)) & 5;
if (idx & 1)
v->vc1dsp.vc1_h_loop_filter4(dst + 4 * linesize + 8, linesize, pq);
if (idx & 4)
v->vc1dsp.vc1_h_loop_filter4(dst + 8, linesize, pq);
}
}
tt = ttblk[0] >> (block_num * 4) & 0xf;
if (tt == TT_4X4 || tt == TT_4X8) {
if (left_cbp & 3)
v->vc1dsp.vc1_h_loop_filter4(dst + 4 * linesize + 4, linesize, pq);
if (left_cbp & 12)
v->vc1dsp.vc1_h_loop_filter4(dst + 4, linesize, pq);
}
}
static inline void vc1_p_v_loop_filter(VC1Context *v, uint8 *dest, const uint32 *cbp, const uint8 *is_intra,
int16 (*mv)[2], const uint8 *mv_f, const int *ttblk, uint32 flags,
int block_num) {
PictureState *s = &v->s;
int pq = v->pq;
uint32 top_cbp = cbp[0] >> (block_num * 4), bottom_cbp;
uint8 top_is_intra, bottom_is_intra;
int tt;
int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize;
uint8 *dst;
if (block_num > 3)
dst = dest;
else
dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8;
if (!(flags & BOTTOM_EDGE) || block_num < 2) {
top_is_intra = is_intra[0] & (1 << block_num);
if (block_num > 3) {
bottom_is_intra = is_intra[s->mb_stride] & (1 << block_num);
bottom_cbp = cbp[s->mb_stride] >> (block_num * 4);
} else if (block_num < 2) {
bottom_is_intra = is_intra[0] & (1 << block_num + 2);
bottom_cbp = cbp[0] >> ((block_num + 2) * 4);
} else {
bottom_is_intra = is_intra[s->mb_stride] & (1 << block_num - 2);
bottom_cbp = cbp[s->mb_stride] >> ((block_num - 2) * 4);
}
if (top_is_intra || bottom_is_intra || mv[0][0] != mv[block_num > 3 ? s->mb_stride : s->b8_stride][0] ||
mv[0][1] != mv[block_num > 3 ? s->mb_stride : s->b8_stride][1] ||
(v->fcm == ILACE_FIELD && mv_f[0] != mv_f[block_num > 3 ? s->mb_stride : s->b8_stride]))
v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, linesize, pq);
else {
idx = (top_cbp | (bottom_cbp >> 2)) & 3;
if (idx & 1)
v->vc1dsp.vc1_v_loop_filter4(dst + 8 * linesize + 4, linesize, pq);
if (idx & 2)
v->vc1dsp.vc1_v_loop_filter4(dst + 8 * linesize, linesize, pq);
}
}
tt = ttblk[0] >> (block_num * 4) & 0xf;
if (tt == TT_4X4 || tt == TT_8X4) {
if (top_cbp & 5)
v->vc1dsp.vc1_v_loop_filter4(dst + 4 * linesize + 4, linesize, pq);
if (top_cbp & 10)
v->vc1dsp.vc1_v_loop_filter4(dst + 4 * linesize, linesize, pq);
}
}
void ff_vc1_p_loop_filter(VC1Context *v) {
PictureState *s = &v->s;
int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6;
uint8 *dest;
uint32 *cbp;
uint8 *is_intra;
int16(*uvmv)[2];
int *ttblk;
uint32 flags;
int i;
/* Within a MB, the vertical loop filter always runs before the horizontal.
* To accomplish that, we run the V loop filter on all applicable
* horizontal borders of the MB above the last overlap filtered MB. Then,
* we wait for the next loop filter iteration to do H loop filter on all
* applicable vertical borders of this MB. Therefore, the loop filter
* trails by one row and one column relative to the overlap filter and two
* rows and two columns relative to the decoding loop. */
if (s->mb_y >= s->start_mb_y + 2) {
if (s->mb_x) {
dest = s->dest[0] - 32 * s->linesize - 16;
cbp = &v->cbp[s->mb_x - 2 * s->mb_stride - 1];
is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride - 1];
uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride - 1];
ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 1];
flags = s->mb_y == s->start_mb_y + 2 ? TOP_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_p_v_loop_filter(
v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 8 : dest, cbp, is_intra,
i > 3 ? uvmv : &s->cur_pic.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride - 1 + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off],
ttblk, flags, i);
}
if (s->mb_x == s->mb_width - 1) {
dest = s->dest[0] - 32 * s->linesize;
cbp = &v->cbp[s->mb_x - 2 * s->mb_stride];
is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride];
uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride];
ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride];
flags = s->mb_y == s->start_mb_y + 2 ? TOP_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_p_v_loop_filter(
v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize : dest, cbp, is_intra,
i > 3 ? uvmv : &s->cur_pic.motion_val[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off],
ttblk, flags, i);
}
}
if (s->mb_y == s->end_mb_y - 1) {
if (s->mb_x) {
if (s->mb_y >= s->start_mb_y + 1) {
dest = s->dest[0] - 16 * s->linesize - 16;
cbp = &v->cbp[s->mb_x - s->mb_stride - 1];
is_intra = &v->is_intra[s->mb_x - s->mb_stride - 1];
uvmv = &v->luma_mv[s->mb_x - s->mb_stride - 1];
ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1];
flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_p_v_loop_filter(
v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, cbp, is_intra,
i > 3 ? uvmv
: &s->cur_pic.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride - 1 + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off],
ttblk, flags, i);
}
dest = s->dest[0] - 16;
cbp = &v->cbp[s->mb_x - 1];
is_intra = &v->is_intra[s->mb_x - 1];
uvmv = &v->luma_mv[s->mb_x - 1];
ttblk = &v->ttblk[s->mb_x - 1];
flags = s->mb_y == s->start_mb_y ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE;
for (i = 0; i < block_count; i++)
vc1_p_v_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, cbp, is_intra,
i > 3 ? uvmv : &s->cur_pic.motion_val[0][s->block_index[i] - 2 + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - 1 + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 2 + v->blocks_off],
ttblk, flags, i);
}
if (s->mb_x == s->mb_width - 1) {
if (s->mb_y >= s->start_mb_y + 1) {
dest = s->dest[0] - 16 * s->linesize;
cbp = &v->cbp[s->mb_x - s->mb_stride];
is_intra = &v->is_intra[s->mb_x - s->mb_stride];
uvmv = &v->luma_mv[s->mb_x - s->mb_stride];
ttblk = &v->ttblk[s->mb_x - s->mb_stride];
flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_p_v_loop_filter(
v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, cbp, is_intra,
i > 3 ? uvmv : &s->cur_pic.motion_val[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off],
ttblk, flags, i);
}
dest = s->dest[0];
cbp = &v->cbp[s->mb_x];
is_intra = &v->is_intra[s->mb_x];
uvmv = &v->luma_mv[s->mb_x];
ttblk = &v->ttblk[s->mb_x];
flags = s->mb_y == s->start_mb_y ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE;
for (i = 0; i < block_count; i++)
vc1_p_v_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, cbp, is_intra,
i > 3 ? uvmv : &s->cur_pic.motion_val[0][s->block_index[i] + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] + v->mb_off]
: &v->mv_f[0][s->block_index[i] + v->blocks_off],
ttblk, flags, i);
}
}
if (s->mb_y >= s->start_mb_y + 2) {
if (s->mb_x >= 2) {
dest = s->dest[0] - 32 * s->linesize - 32;
cbp = &v->cbp[s->mb_x - 2 * s->mb_stride - 2];
is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride - 2];
uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride - 2];
ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 2];
flags = s->mb_x == 2 ? LEFT_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_p_h_loop_filter(
v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 16 : dest, cbp, is_intra,
i > 3 ? uvmv : &s->cur_pic.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 4 + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride - 2 + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride - 4 + v->blocks_off],
ttblk, flags, i);
}
if (s->mb_x == s->mb_width - 1) {
if (s->mb_x >= 1) {
dest = s->dest[0] - 32 * s->linesize - 16;
cbp = &v->cbp[s->mb_x - 2 * s->mb_stride - 1];
is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride - 1];
uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride - 1];
ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 1];
flags = s->mb_x == 1 ? LEFT_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_p_h_loop_filter(
v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 8 : dest, cbp, is_intra,
i > 3 ? uvmv
: &s->cur_pic.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride - 1 + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off],
ttblk, flags, i);
}
dest = s->dest[0] - 32 * s->linesize;
cbp = &v->cbp[s->mb_x - 2 * s->mb_stride];
is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride];
uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride];
ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride];
flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE;
for (i = 0; i < block_count; i++)
vc1_p_h_loop_filter(
v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize : dest, cbp, is_intra,
i > 3 ? uvmv : &s->cur_pic.motion_val[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off],
ttblk, flags, i);
}
}
if (s->mb_y == s->end_mb_y - 1) {
if (s->mb_y >= s->start_mb_y + 1) {
if (s->mb_x >= 2) {
dest = s->dest[0] - 16 * s->linesize - 32;
cbp = &v->cbp[s->mb_x - s->mb_stride - 2];
is_intra = &v->is_intra[s->mb_x - s->mb_stride - 2];
uvmv = &v->luma_mv[s->mb_x - s->mb_stride - 2];
ttblk = &v->ttblk[s->mb_x - s->mb_stride - 2];
flags = s->mb_x == 2 ? LEFT_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_p_h_loop_filter(
v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 16 : dest, cbp, is_intra,
i > 3 ? uvmv
: &s->cur_pic.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 4 + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride - 2 + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride - 4 + v->blocks_off],
ttblk, flags, i);
}
if (s->mb_x == s->mb_width - 1) {
if (s->mb_x >= 1) {
dest = s->dest[0] - 16 * s->linesize - 16;
cbp = &v->cbp[s->mb_x - s->mb_stride - 1];
is_intra = &v->is_intra[s->mb_x - s->mb_stride - 1];
uvmv = &v->luma_mv[s->mb_x - s->mb_stride - 1];
ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1];
flags = s->mb_x == 1 ? LEFT_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_p_h_loop_filter(
v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, cbp, is_intra,
i > 3 ? uvmv
: &s->cur_pic.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride - 1 + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off],
ttblk, flags, i);
}
dest = s->dest[0] - 16 * s->linesize;
cbp = &v->cbp[s->mb_x - s->mb_stride];
is_intra = &v->is_intra[s->mb_x - s->mb_stride];
uvmv = &v->luma_mv[s->mb_x - s->mb_stride];
ttblk = &v->ttblk[s->mb_x - s->mb_stride];
flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE;
for (i = 0; i < block_count; i++)
vc1_p_h_loop_filter(
v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, cbp, is_intra,
i > 3 ? uvmv : &s->cur_pic.motion_val[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off],
ttblk, flags, i);
}
}
if (s->mb_x >= 2) {
dest = s->dest[0] - 32;
cbp = &v->cbp[s->mb_x - 2];
is_intra = &v->is_intra[s->mb_x - 2];
uvmv = &v->luma_mv[s->mb_x - 2];
ttblk = &v->ttblk[s->mb_x - 2];
flags = s->mb_x == 2 ? LEFT_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_p_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 16 : dest, cbp, is_intra,
i > 3 ? uvmv : &s->cur_pic.motion_val[0][s->block_index[i] - 4 + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - 2 + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 4 + v->blocks_off],
ttblk, flags, i);
}
if (s->mb_x == s->mb_width - 1) {
if (s->mb_x >= 1) {
dest = s->dest[0] - 16;
cbp = &v->cbp[s->mb_x - 1];
is_intra = &v->is_intra[s->mb_x - 1];
uvmv = &v->luma_mv[s->mb_x - 1];
ttblk = &v->ttblk[s->mb_x - 1];
flags = s->mb_x == 1 ? LEFT_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_p_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, cbp, is_intra,
i > 3 ? uvmv : &s->cur_pic.motion_val[0][s->block_index[i] - 2 + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] - 1 + v->mb_off]
: &v->mv_f[0][s->block_index[i] - 2 + v->blocks_off],
ttblk, flags, i);
}
dest = s->dest[0];
cbp = &v->cbp[s->mb_x];
is_intra = &v->is_intra[s->mb_x];
uvmv = &v->luma_mv[s->mb_x];
ttblk = &v->ttblk[s->mb_x];
flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE;
for (i = 0; i < block_count; i++)
vc1_p_h_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, cbp, is_intra,
i > 3 ? uvmv : &s->cur_pic.motion_val[0][s->block_index[i] + v->blocks_off],
i > 3 ? &v->mv_f[0][s->block_index[i] + v->mb_off]
: &v->mv_f[0][s->block_index[i] + v->blocks_off],
ttblk, flags, i);
}
}
}
static inline void vc1_p_h_intfr_loop_filter(VC1Context *v, uint8 *dest, const int *ttblk, uint32 flags, uint8 fieldtx,
int block_num) {
PictureState *s = &v->s;
int pq = v->pq;
int tt;
int linesize = block_num > 3 ? s->uvlinesize : s->linesize;
uint8 *dst;
if (block_num > 3)
dst = dest;
else
dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8;
tt = ttblk[0] >> (block_num * 4) & 0xf;
if (block_num < 4) {
if (fieldtx) {
if (block_num < 2) {
if (tt == TT_4X4 || tt == TT_4X8)
v->vc1dsp.vc1_h_loop_filter8(dst + 4, 2 * linesize, pq);
if (!(flags & RIGHT_EDGE) || block_num == 0)
v->vc1dsp.vc1_h_loop_filter8(dst + 8, 2 * linesize, pq);
} else {
if (tt == TT_4X4 || tt == TT_4X8)
v->vc1dsp.vc1_h_loop_filter8(dst - 7 * linesize + 4, 2 * linesize, pq);
if (!(flags & RIGHT_EDGE) || block_num == 2)
v->vc1dsp.vc1_h_loop_filter8(dst - 7 * linesize + 8, 2 * linesize, pq);
}
} else {
if (tt == TT_4X4 || tt == TT_4X8) {
v->vc1dsp.vc1_h_loop_filter4(dst + 4, 2 * linesize, pq);
v->vc1dsp.vc1_h_loop_filter4(dst + linesize + 4, 2 * linesize, pq);
}
if (!(flags & RIGHT_EDGE) || !(block_num & 5)) {
v->vc1dsp.vc1_h_loop_filter4(dst + 8, 2 * linesize, pq);
v->vc1dsp.vc1_h_loop_filter4(dst + linesize + 8, 2 * linesize, pq);
}
}
} else {
if (tt == TT_4X4 || tt == TT_4X8) {
v->vc1dsp.vc1_h_loop_filter4(dst + 4, 2 * linesize, pq);
v->vc1dsp.vc1_h_loop_filter4(dst + linesize + 4, 2 * linesize, pq);
}
if (!(flags & RIGHT_EDGE)) {
v->vc1dsp.vc1_h_loop_filter4(dst + 8, 2 * linesize, pq);
v->vc1dsp.vc1_h_loop_filter4(dst + linesize + 8, 2 * linesize, pq);
}
}
}
static inline void vc1_p_v_intfr_loop_filter(VC1Context *v, uint8 *dest, const int *ttblk, uint32 flags, uint8 fieldtx,
int block_num) {
PictureState *s = &v->s;
int pq = v->pq;
int tt;
int linesize = block_num > 3 ? s->uvlinesize : s->linesize;
uint8 *dst;
if (block_num > 3)
dst = dest;
else
dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8;
tt = ttblk[0] >> (block_num * 4) & 0xf;
if (block_num < 4) {
if (fieldtx) {
if (block_num < 2) {
if (tt == TT_4X4 || tt == TT_8X4)
v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, 2 * linesize, pq);
if (!(flags & BOTTOM_EDGE))
v->vc1dsp.vc1_v_loop_filter8(dst + 16 * linesize, 2 * linesize, pq);
} else {
if (tt == TT_4X4 || tt == TT_8X4)
v->vc1dsp.vc1_v_loop_filter8(dst + linesize, 2 * linesize, pq);
if (!(flags & BOTTOM_EDGE))
v->vc1dsp.vc1_v_loop_filter8(dst + 9 * linesize, 2 * linesize, pq);
}
} else {
if (block_num < 2) {
if (!(flags & TOP_EDGE) && (tt == TT_4X4 || tt == TT_8X4)) {
v->vc1dsp.vc1_v_loop_filter8(dst + 4 * linesize, 2 * linesize, pq);
v->vc1dsp.vc1_v_loop_filter8(dst + 5 * linesize, 2 * linesize, pq);
}
v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, 2 * linesize, pq);
v->vc1dsp.vc1_v_loop_filter8(dst + 9 * linesize, 2 * linesize, pq);
} else if (!(flags & BOTTOM_EDGE)) {
if (tt == TT_4X4 || tt == TT_8X4) {
v->vc1dsp.vc1_v_loop_filter8(dst + 4 * linesize, 2 * linesize, pq);
v->vc1dsp.vc1_v_loop_filter8(dst + 5 * linesize, 2 * linesize, pq);
}
v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, 2 * linesize, pq);
v->vc1dsp.vc1_v_loop_filter8(dst + 9 * linesize, 2 * linesize, pq);
}
}
} else {
if (!(flags & BOTTOM_EDGE)) {
if (!(flags & TOP_EDGE) && (tt == TT_4X4 || tt == TT_8X4)) {
v->vc1dsp.vc1_v_loop_filter8(dst + 4 * linesize, 2 * linesize, pq);
v->vc1dsp.vc1_v_loop_filter8(dst + 5 * linesize, 2 * linesize, pq);
}
v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, 2 * linesize, pq);
v->vc1dsp.vc1_v_loop_filter8(dst + 9 * linesize, 2 * linesize, pq);
}
}
}
void ff_vc1_p_intfr_loop_filter(VC1Context *v) {
PictureState *s = &v->s;
int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
uint8 *dest;
int *ttblk;
uint32 flags;
uint8 fieldtx;
int i;
/* Within a MB, the vertical loop filter always runs before the horizontal.
* To accomplish that, we run the V loop filter on all applicable
* horizontal borders of the MB above the last overlap filtered MB. Then,
* we wait for the loop filter iteration on the next row and next column to
* do H loop filter on all applicable vertical borders of this MB.
* Therefore, the loop filter trails by two rows and one column relative to
* the overlap filter and two rows and two columns relative to the decoding
* loop. */
if (s->mb_x) {
if (s->mb_y >= s->start_mb_y + 1) {
dest = s->dest[0] - 16 * s->linesize - 16;
ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1];
flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0;
fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride - 1];
for (i = 0; i < block_count; i++)
vc1_p_v_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, ttblk, flags,
fieldtx, i);
}
}
if (s->mb_x == s->mb_width - 1) {
if (s->mb_y >= s->start_mb_y + 1) {
dest = s->dest[0] - 16 * s->linesize;
ttblk = &v->ttblk[s->mb_x - s->mb_stride];
flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0;
fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride];
for (i = 0; i < block_count; i++)
vc1_p_v_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, ttblk, flags, fieldtx,
i);
}
}
if (s->mb_y == s->end_mb_y - 1) {
if (s->mb_x) {
dest = s->dest[0] - 16;
ttblk = &v->ttblk[s->mb_x - 1];
flags = s->mb_y == s->start_mb_y ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE;
fieldtx = v->fieldtx_plane[mb_pos - 1];
for (i = 0; i < block_count; i++)
vc1_p_v_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, ttblk, flags, fieldtx, i);
}
if (s->mb_x == s->mb_width - 1) {
dest = s->dest[0];
ttblk = &v->ttblk[s->mb_x];
flags = s->mb_y == s->start_mb_y ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE;
fieldtx = v->fieldtx_plane[mb_pos];
for (i = 0; i < block_count; i++)
vc1_p_v_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, ttblk, flags, fieldtx, i);
}
}
if (s->mb_y >= s->start_mb_y + 2) {
if (s->mb_x >= 2) {
dest = s->dest[0] - 32 * s->linesize - 32;
ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 2];
flags = s->mb_x == 2 ? LEFT_EDGE : 0;
fieldtx = v->fieldtx_plane[mb_pos - 2 * s->mb_stride - 2];
for (i = 0; i < block_count; i++)
vc1_p_h_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 16 : dest, ttblk, flags,
fieldtx, i);
}
if (s->mb_x == s->mb_width - 1) {
if (s->mb_x >= 1) {
dest = s->dest[0] - 32 * s->linesize - 16;
ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 1];
flags = s->mb_x == 1 ? LEFT_EDGE : 0;
fieldtx = v->fieldtx_plane[mb_pos - 2 * s->mb_stride - 1];
for (i = 0; i < block_count; i++)
vc1_p_h_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 8 : dest, ttblk, flags,
fieldtx, i);
}
dest = s->dest[0] - 32 * s->linesize;
ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride];
flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE;
fieldtx = v->fieldtx_plane[mb_pos - 2 * s->mb_stride];
for (i = 0; i < block_count; i++)
vc1_p_h_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize : dest, ttblk, flags, fieldtx,
i);
}
}
if (s->mb_y == s->end_mb_y - 1) {
if (s->mb_y >= s->start_mb_y + 1) {
if (s->mb_x >= 2) {
dest = s->dest[0] - 16 * s->linesize - 32;
ttblk = &v->ttblk[s->mb_x - s->mb_stride - 2];
flags = s->mb_x == 2 ? LEFT_EDGE : 0;
fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride - 2];
for (i = 0; i < block_count; i++)
vc1_p_h_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 16 : dest, ttblk, flags,
fieldtx, i);
}
if (s->mb_x == s->mb_width - 1) {
if (s->mb_x >= 1) {
dest = s->dest[0] - 16 * s->linesize - 16;
ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1];
flags = s->mb_x == 1 ? LEFT_EDGE : 0;
fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride - 1];
for (i = 0; i < block_count; i++)
vc1_p_h_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, ttblk,
flags, fieldtx, i);
}
dest = s->dest[0] - 16 * s->linesize;
ttblk = &v->ttblk[s->mb_x - s->mb_stride];
flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE;
fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride];
for (i = 0; i < block_count; i++)
vc1_p_h_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, ttblk, flags,
fieldtx, i);
}
}
if (s->mb_x >= 2) {
dest = s->dest[0] - 32;
ttblk = &v->ttblk[s->mb_x - 2];
flags = s->mb_x == 2 ? LEFT_EDGE : 0;
fieldtx = v->fieldtx_plane[mb_pos - 2];
for (i = 0; i < block_count; i++)
vc1_p_h_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] - 16 : dest, ttblk, flags, fieldtx, i);
}
if (s->mb_x == s->mb_width - 1) {
if (s->mb_x >= 1) {
dest = s->dest[0] - 16;
ttblk = &v->ttblk[s->mb_x - 1];
flags = s->mb_x == 1 ? LEFT_EDGE : 0;
fieldtx = v->fieldtx_plane[mb_pos - 1];
for (i = 0; i < block_count; i++)
vc1_p_h_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, ttblk, flags, fieldtx, i);
}
dest = s->dest[0];
ttblk = &v->ttblk[s->mb_x];
flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE;
fieldtx = v->fieldtx_plane[mb_pos];
for (i = 0; i < block_count; i++)
vc1_p_h_intfr_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, ttblk, flags, fieldtx, i);
}
}
}
static inline void vc1_b_h_intfi_loop_filter(VC1Context *v, uint8 *dest, const uint32 *cbp, const int *ttblk,
uint32 flags, int block_num) {
PictureState *s = &v->s;
int pq = v->pq;
uint8 *dst;
uint32 block_cbp = cbp[0] >> (block_num * 4);
int tt;
int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize;
if (block_num > 3)
dst = dest;
else
dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8;
if (!(flags & RIGHT_EDGE) || !(block_num & 5)) {
v->vc1dsp.vc1_h_loop_filter8(dst + 8, linesize, pq);
}
tt = ttblk[0] >> (block_num * 4) & 0xf;
if (tt == TT_4X4 || tt == TT_4X8) {
idx = (block_cbp | (block_cbp >> 1)) & 5;
if (idx & 1)
v->vc1dsp.vc1_h_loop_filter4(dst + 4 * linesize + 4, linesize, pq);
if (idx & 4)
v->vc1dsp.vc1_h_loop_filter4(dst + 4, linesize, pq);
}
}
static inline void vc1_b_v_intfi_loop_filter(VC1Context *v, uint8 *dest, const uint32 *cbp, const int *ttblk,
uint32 flags, int block_num) {
PictureState *s = &v->s;
int pq = v->pq;
uint8 *dst;
uint32 block_cbp = cbp[0] >> (block_num * 4);
int tt;
int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize;
if (block_num > 3)
dst = dest;
else
dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8;
if (!(flags & BOTTOM_EDGE) || block_num < 2)
v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, linesize, pq);
tt = ttblk[0] >> (block_num * 4) & 0xf;
if (tt == TT_4X4 || tt == TT_8X4) {
idx = (block_cbp | (block_cbp >> 2)) & 3;
if (idx & 1)
v->vc1dsp.vc1_v_loop_filter4(dst + 4 * linesize + 4, linesize, pq);
if (idx & 2)
v->vc1dsp.vc1_v_loop_filter4(dst + 4 * linesize, linesize, pq);
}
}
void ff_vc1_b_intfi_loop_filter(VC1Context *v) {
PictureState *s = &v->s;
int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6;
uint8 *dest;
const uint32 *cbp;
int *ttblk;
uint32 flags = 0;
int i;
/* Within a MB, the vertical loop filter always runs before the horizontal.
* To accomplish that, we run the V loop filter on all applicable
* horizontal borders of the MB above the currently decoded MB. Then,
* we wait for the next loop filter iteration to do H loop filter on all
* applicable vertical borders of this MB. Therefore, the loop filter
* trails by one row and one column relative to the decoding loop. */
if (!s->first_slice_line) {
dest = s->dest[0] - 16 * s->linesize;
cbp = &v->cbp[s->mb_x - s->mb_stride];
ttblk = &v->ttblk[s->mb_x - s->mb_stride];
flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_b_v_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, cbp, ttblk, flags, i);
}
if (s->mb_y == s->end_mb_y - 1) {
dest = s->dest[0];
cbp = &v->cbp[s->mb_x];
ttblk = &v->ttblk[s->mb_x];
flags = s->first_slice_line ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE;
for (i = 0; i < block_count; i++)
vc1_b_v_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, cbp, ttblk, flags, i);
}
if (!s->first_slice_line) {
dest = s->dest[0] - 16 * s->linesize - 16;
cbp = &v->cbp[s->mb_x - s->mb_stride - 1];
ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1];
if (s->mb_x) {
flags = s->mb_x == 1 ? LEFT_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_b_h_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, cbp, ttblk, flags,
i);
}
if (s->mb_x == s->mb_width - 1) {
dest += 16;
cbp++;
ttblk++;
flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE;
for (i = 0; i < block_count; i++)
vc1_b_h_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, cbp, ttblk, flags, i);
}
}
if (s->mb_y == s->end_mb_y - 1) {
dest = s->dest[0] - 16;
cbp = &v->cbp[s->mb_x - 1];
ttblk = &v->ttblk[s->mb_x - 1];
if (s->mb_x) {
flags = s->mb_x == 1 ? LEFT_EDGE : 0;
for (i = 0; i < block_count; i++)
vc1_b_h_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, cbp, ttblk, flags, i);
}
if (s->mb_x == s->mb_width - 1) {
dest += 16;
cbp++;
ttblk++;
flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE;
for (i = 0; i < block_count; i++)
vc1_b_h_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, cbp, ttblk, flags, i);
}
}
}
#undef BOTTOM_EDGE
#undef LEFT_EDGE
#undef RIGHT_EDGE
#undef TOP_EDGE
static inline void vc1_scale_luma(uint8 *srcY, int k, int linesize) {
int i, j;
for (j = 0; j < k; j++) {
for (i = 0; i < k; i++)
srcY[i] = ((srcY[i] - 128) >> 1) + 128;
srcY += linesize;
}
}
static inline void vc1_scale_chroma(uint8 *srcU, uint8 *srcV, int k, int uvlinesize) {
int i, j;
for (j = 0; j < k; j++) {
for (i = 0; i < k; i++) {
srcU[i] = ((srcU[i] - 128) >> 1) + 128;
srcV[i] = ((srcV[i] - 128) >> 1) + 128;
}
srcU += uvlinesize;
srcV += uvlinesize;
}
}
static inline void vc1_lut_scale_luma(uint8 *srcY, const uint8 *lut1, const uint8 *lut2, int k, int linesize) {
int i, j;
for (j = 0; j < k; j += 2) {
for (i = 0; i < k; i++)
srcY[i] = lut1[srcY[i]];
srcY += linesize;
if (j + 1 == k)
break;
for (i = 0; i < k; i++)
srcY[i] = lut2[srcY[i]];
srcY += linesize;
}
}
static inline void vc1_lut_scale_chroma(uint8 *srcU, uint8 *srcV, const uint8 *lut1, const uint8 *lut2, int k,
int uvlinesize) {
int i, j;
for (j = 0; j < k; j += 2) {
for (i = 0; i < k; i++) {
srcU[i] = lut1[srcU[i]];
srcV[i] = lut1[srcV[i]];
}
srcU += uvlinesize;
srcV += uvlinesize;
if (j + 1 == k)
break;
for (i = 0; i < k; i++) {
srcU[i] = lut2[srcU[i]];
srcV[i] = lut2[srcV[i]];
}
srcU += uvlinesize;
srcV += uvlinesize;
}
}
static const uint8 popcount4[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
static inline int get_luma_mv(VC1Context *v, int dir, int16 *tx, int16 *ty) {
PictureState *s = &v->s;
int idx = v->mv_f[dir][s->block_index[0] + v->blocks_off] | (v->mv_f[dir][s->block_index[1] + v->blocks_off] << 1) |
(v->mv_f[dir][s->block_index[2] + v->blocks_off] << 2) |
(v->mv_f[dir][s->block_index[3] + v->blocks_off] << 3);
static const uint8 index2[16] = {0, 0, 0, 0x23, 0, 0x13, 0x03, 0, 0, 0x12, 0x02, 0, 0x01, 0, 0, 0};
int opp_count = popcount4[idx];
switch (opp_count) {
case 0:
case 4:
*tx = median4(s->mv[dir][0][0], s->mv[dir][1][0], s->mv[dir][2][0], s->mv[dir][3][0]);
*ty = median4(s->mv[dir][0][1], s->mv[dir][1][1], s->mv[dir][2][1], s->mv[dir][3][1]);
break;
case 1:
*tx = mid_pred(s->mv[dir][idx < 2][0], s->mv[dir][1 + (idx < 4)][0], s->mv[dir][2 + (idx < 8)][0]);
*ty = mid_pred(s->mv[dir][idx < 2][1], s->mv[dir][1 + (idx < 4)][1], s->mv[dir][2 + (idx < 8)][1]);
break;
case 3:
*tx = mid_pred(s->mv[dir][idx > 0xd][0], s->mv[dir][1 + (idx > 0xb)][0], s->mv[dir][2 + (idx > 0x7)][0]);
*ty = mid_pred(s->mv[dir][idx > 0xd][1], s->mv[dir][1 + (idx > 0xb)][1], s->mv[dir][2 + (idx > 0x7)][1]);
break;
case 2:
*tx = (s->mv[dir][index2[idx] >> 4][0] + s->mv[dir][index2[idx] & 0xf][0]) / 2;
*ty = (s->mv[dir][index2[idx] >> 4][1] + s->mv[dir][index2[idx] & 0xf][1]) / 2;
break;
}
return opp_count;
}
static inline int get_chroma_mv(VC1Context *v, int dir, int16 *tx, int16 *ty) {
PictureState *s = &v->s;
int idx = !v->mb_type[s->block_index[0]] | (!v->mb_type[s->block_index[1]] << 1) |
(!v->mb_type[s->block_index[2]] << 2) | (!v->mb_type[s->block_index[3]] << 3);
static const uint8 index2[16] = {0, 0, 0, 0x01, 0, 0x02, 0x12, 0, 0, 0x03, 0x13, 0, 0x23, 0, 0, 0};
int valid_count = popcount4[idx];
switch (valid_count) {
case 4:
*tx = median4(s->mv[dir][0][0], s->mv[dir][1][0], s->mv[dir][2][0], s->mv[dir][3][0]);
*ty = median4(s->mv[dir][0][1], s->mv[dir][1][1], s->mv[dir][2][1], s->mv[dir][3][1]);
break;
case 3:
*tx = mid_pred(s->mv[dir][idx > 0xd][0], s->mv[dir][1 + (idx > 0xb)][0], s->mv[dir][2 + (idx > 0x7)][0]);
*ty = mid_pred(s->mv[dir][idx > 0xd][1], s->mv[dir][1 + (idx > 0xb)][1], s->mv[dir][2 + (idx > 0x7)][1]);
break;
case 2:
*tx = (s->mv[dir][index2[idx] >> 4][0] + s->mv[dir][index2[idx] & 0xf][0]) / 2;
*ty = (s->mv[dir][index2[idx] >> 4][1] + s->mv[dir][index2[idx] & 0xf][1]) / 2;
break;
default:
return 0;
}
return valid_count;
}
/** Do motion compensation over 1 macroblock
* Mostly adapted hpel_motion and qpel_motion from mpegvideo.c
*/
void ff_vc1_mc_1mv(VC1Context *v, int dir) {
PictureState *s = &v->s;
ChromaDSP *h264chroma = &v->h264chroma;
uint8 *srcY, *srcU, *srcV;
int dxy, mx, my, uvmx, uvmy, src_x, src_y, uvsrc_x, uvsrc_y;
int v_edge_pos = s->v_edge_pos >> v->field_mode;
int i;
const uint8(*luty)[256], (*lutuv)[256];
int use_ic;
int interlace;
int linesize, uvlinesize;
if ((!v->field_mode || (v->ref_field_type[dir] == 1 && v->cur_field_type == 1)) && !v->s.last_pic.data[0])
return;
linesize = s->cur_pic.ptr->f->linesize[0];
uvlinesize = s->cur_pic.ptr->f->linesize[1];
mx = s->mv[dir][0][0];
my = s->mv[dir][0][1];
// store motion vectors for further use in B-frames
if (s->pict_type == AV_PICTURE_TYPE_P) {
for (i = 0; i < 4; i++) {
s->cur_pic.motion_val[1][s->block_index[i] + v->blocks_off][0] = mx;
s->cur_pic.motion_val[1][s->block_index[i] + v->blocks_off][1] = my;
}
}
uvmx = (mx + ((mx & 3) == 3)) >> 1;
uvmy = (my + ((my & 3) == 3)) >> 1;
v->luma_mv[s->mb_x][0] = uvmx;
v->luma_mv[s->mb_x][1] = uvmy;
if (v->field_mode && v->cur_field_type != v->ref_field_type[dir]) {
my = my - 2 + 4 * v->cur_field_type;
uvmy = uvmy - 2 + 4 * v->cur_field_type;
}
// fastuvmc shall be ignored for interlaced frame picture
if (v->fastuvmc && (v->fcm != ILACE_FRAME)) {
uvmx = uvmx + ((uvmx < 0) ? (uvmx & 1) : -(uvmx & 1));
uvmy = uvmy + ((uvmy < 0) ? (uvmy & 1) : -(uvmy & 1));
}
if (!dir) {
if (v->field_mode && (v->cur_field_type != v->ref_field_type[dir]) && v->second_field) {
srcY = s->cur_pic.data[0];
srcU = s->cur_pic.data[1];
srcV = s->cur_pic.data[2];
luty = v->curr_luty;
lutuv = v->curr_lutuv;
use_ic = *v->curr_use_ic;
interlace = 1;
} else {
srcY = s->last_pic.data[0];
srcU = s->last_pic.data[1];
srcV = s->last_pic.data[2];
luty = v->last_luty;
lutuv = v->last_lutuv;
use_ic = v->last_use_ic;
interlace = v->last_interlaced;
}
} else {
srcY = s->next_pic.data[0];
srcU = s->next_pic.data[1];
srcV = s->next_pic.data[2];
luty = v->next_luty;
lutuv = v->next_lutuv;
use_ic = v->next_use_ic;
interlace = v->next_interlaced;
}
if (!srcY || !srcU) {
warning("Referenced frame missing.\n");
return;
}
src_x = s->mb_x * 16 + (mx >> 2);
src_y = s->mb_y * 16 + (my >> 2);
uvsrc_x = s->mb_x * 8 + (uvmx >> 2);
uvsrc_y = s->mb_y * 8 + (uvmy >> 2);
if (v->profile != PROFILE_ADVANCED) {
src_x = av_clip(src_x, -16, s->mb_width * 16);
src_y = av_clip(src_y, -16, s->mb_height * 16);
uvsrc_x = av_clip(uvsrc_x, -8, s->mb_width * 8);
uvsrc_y = av_clip(uvsrc_y, -8, s->mb_height * 8);
} else {
src_x = av_clip(src_x, -17, s->avctx->coded_width);
uvsrc_x = av_clip(uvsrc_x, -8, s->avctx->coded_width >> 1);
if (v->fcm == ILACE_FRAME) {
src_y = av_clip(src_y, -18 + (src_y & 1), s->avctx->coded_height + (src_y & 1));
uvsrc_y = av_clip(uvsrc_y, -8 + (uvsrc_y & 1), (s->avctx->coded_height >> 1) + (uvsrc_y & 1));
} else {
src_y = av_clip(src_y, -18, s->avctx->coded_height + 1);
uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1);
}
}
srcY += src_y * s->linesize + src_x;
srcU += uvsrc_y * s->uvlinesize + uvsrc_x;
srcV += uvsrc_y * s->uvlinesize + uvsrc_x;
if (v->field_mode && v->ref_field_type[dir]) {
srcY += linesize;
srcU += uvlinesize;
srcV += uvlinesize;
}
/* for grayscale we should not try to read from unknown area */
if (CONFIG_GRAY && s->avctx->flags & AV_CODEC_FLAG_GRAY) {
srcU = s->sc.edge_emu_buffer + 18 * s->linesize;
srcV = s->sc.edge_emu_buffer + 18 * s->linesize;
}
if (v->rangeredfrm || use_ic || s->h_edge_pos < 22 || v_edge_pos < 22 ||
(unsigned)(src_x - s->mspel) > s->h_edge_pos - (mx & 3) - 16 - s->mspel * 3 ||
(unsigned)(src_y - 1) > v_edge_pos - (my & 3) - 16 - 3) {
uint8 *ubuf = s->sc.edge_emu_buffer + 19 * s->linesize;
uint8 *vbuf = ubuf + 9 * s->uvlinesize;
const int k = 17 + s->mspel * 2;
srcY -= s->mspel * (1 + s->linesize);
if (interlace) {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcY, linesize << 1, linesize << 1, k,
v->field_mode ? k : k + 1 >> 1, src_x - s->mspel,
src_y - s->mspel >> !v->field_mode, s->h_edge_pos, s->v_edge_pos >> 1);
if (!v->field_mode)
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + linesize, srcY + linesize, linesize << 1,
linesize << 1, k, k >> 1, src_x - s->mspel, src_y - s->mspel + 1 >> 1,
s->h_edge_pos, s->v_edge_pos >> 1);
} else
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcY, linesize, linesize, k,
v->field_mode ? (k << 1) - 1 : k, src_x - s->mspel,
v->field_mode ? 2 * (src_y - s->mspel) + v->ref_field_type[dir] : src_y - s->mspel,
s->h_edge_pos, s->v_edge_pos);
srcY = s->sc.edge_emu_buffer;
if (interlace) {
s->vdsp.emulated_edge_mc(ubuf, srcU, uvlinesize << 1, uvlinesize << 1, 9, v->field_mode ? 9 : 5, uvsrc_x,
uvsrc_y >> !v->field_mode, s->h_edge_pos >> 1, s->v_edge_pos >> 2);
s->vdsp.emulated_edge_mc(vbuf, srcV, uvlinesize << 1, uvlinesize << 1, 9, v->field_mode ? 9 : 5, uvsrc_x,
uvsrc_y >> !v->field_mode, s->h_edge_pos >> 1, s->v_edge_pos >> 2);
if (!v->field_mode) {
s->vdsp.emulated_edge_mc(ubuf + uvlinesize, srcU + uvlinesize, uvlinesize << 1, uvlinesize << 1, 9, 4,
uvsrc_x, uvsrc_y + 1 >> 1, s->h_edge_pos >> 1, s->v_edge_pos >> 2);
s->vdsp.emulated_edge_mc(vbuf + uvlinesize, srcV + uvlinesize, uvlinesize << 1, uvlinesize << 1, 9, 4,
uvsrc_x, uvsrc_y + 1 >> 1, s->h_edge_pos >> 1, s->v_edge_pos >> 2);
}
} else {
s->vdsp.emulated_edge_mc(ubuf, srcU, uvlinesize, uvlinesize, 9, v->field_mode ? 17 : 9, uvsrc_x,
v->field_mode ? 2 * uvsrc_y + v->ref_field_type[dir] : uvsrc_y, s->h_edge_pos >> 1,
s->v_edge_pos >> 1);
s->vdsp.emulated_edge_mc(vbuf, srcV, uvlinesize, uvlinesize, 9, v->field_mode ? 17 : 9, uvsrc_x,
v->field_mode ? 2 * uvsrc_y + v->ref_field_type[dir] : uvsrc_y, s->h_edge_pos >> 1,
s->v_edge_pos >> 1);
}
srcU = ubuf;
srcV = vbuf;
/* if we deal with range reduction we need to scale source blocks */
if (v->rangeredfrm) {
vc1_scale_luma(srcY, k, s->linesize);
vc1_scale_chroma(srcU, srcV, 9, s->uvlinesize);
}
/* if we deal with intensity compensation we need to scale source blocks */
if (use_ic) {
vc1_lut_scale_luma(srcY, luty[v->field_mode ? v->ref_field_type[dir] : ((0 + src_y - s->mspel) & 1)],
luty[v->field_mode ? v->ref_field_type[dir] : ((1 + src_y - s->mspel) & 1)], k,
s->linesize);
vc1_lut_scale_chroma(srcU, srcV, lutuv[v->field_mode ? v->ref_field_type[dir] : ((0 + uvsrc_y) & 1)],
lutuv[v->field_mode ? v->ref_field_type[dir] : ((1 + uvsrc_y) & 1)], 9, s->uvlinesize);
}
srcY += s->mspel * (1 + s->linesize);
}
if (s->mspel) {
dxy = ((my & 3) << 2) | (mx & 3);
v->vc1dsp.put_vc1_mspel_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize, v->rnd);
} else { // hpel mc - always used for luma
dxy = (my & 2) | ((mx & 2) >> 1);
if (!v->rnd)
s->hdsp.put_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize, 16);
else
s->hdsp.put_no_rnd_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize, 16);
}
if (CONFIG_GRAY && s->avctx->flags & AV_CODEC_FLAG_GRAY)
return;
/* Chroma MC always uses qpel bilinear */
uvmx = (uvmx & 3) << 1;
uvmy = (uvmy & 3) << 1;
if (!v->rnd) {
h264chroma->put_h264_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
h264chroma->put_h264_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
} else {
v->vc1dsp.put_no_rnd_vc1_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
v->vc1dsp.put_no_rnd_vc1_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
}
if (v->field_mode) {
v->mv_f[dir][s->block_index[4] + v->mb_off] = v->cur_field_type != v->ref_field_type[dir];
v->mv_f[dir][s->block_index[5] + v->mb_off] = v->cur_field_type != v->ref_field_type[dir];
}
}
/** Do motion compensation for 4-MV macroblock - luminance block
*/
void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg) {
PictureState *s = &v->s;
uint8 *srcY;
int dxy, mx, my, src_x, src_y;
int off;
int fieldmv = (v->fcm == ILACE_FRAME) ? v->blk_mv_type[s->block_index[n]] : 0;
int v_edge_pos = s->v_edge_pos >> v->field_mode;
const uint8(*luty)[256];
int use_ic;
int interlace;
int linesize;
if ((!v->field_mode || (v->ref_field_type[dir] == 1 && v->cur_field_type == 1)) && !v->s.last_pic.data[0])
return;
linesize = s->cur_pic.ptr->f->linesize[0];
mx = s->mv[dir][n][0];
my = s->mv[dir][n][1];
if (!dir) {
if (v->field_mode && (v->cur_field_type != v->ref_field_type[dir]) && v->second_field) {
srcY = s->cur_pic.data[0];
luty = v->curr_luty;
use_ic = *v->curr_use_ic;
interlace = 1;
} else {
srcY = s->last_pic.data[0];
luty = v->last_luty;
use_ic = v->last_use_ic;
interlace = v->last_interlaced;
}
} else {
srcY = s->next_pic.data[0];
luty = v->next_luty;
use_ic = v->next_use_ic;
interlace = v->next_interlaced;
}
if (!srcY) {
warning("Referenced frame missing.\n");
return;
}
if (v->field_mode) {
if (v->cur_field_type != v->ref_field_type[dir])
my = my - 2 + 4 * v->cur_field_type;
}
if (s->pict_type == AV_PICTURE_TYPE_P && n == 3 && v->field_mode) {
int opp_count = get_luma_mv(v, 0, &s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][0],
&s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][1]);
int k, f = opp_count > 2;
for (k = 0; k < 4; k++)
v->mv_f[1][s->block_index[k] + v->blocks_off] = f;
}
if (v->fcm == ILACE_FRAME) { // not sure if needed for other types of picture
int qx, qy;
int width = s->avctx->coded_width;
int height = s->avctx->coded_height >> 1;
if (s->pict_type == AV_PICTURE_TYPE_P) {
s->cur_pic.motion_val[1][s->block_index[n] + v->blocks_off][0] = mx;
s->cur_pic.motion_val[1][s->block_index[n] + v->blocks_off][1] = my;
}
qx = (s->mb_x * 16) + (mx >> 2);
qy = (s->mb_y * 8) + (my >> 3);
if (qx < -17)
mx -= 4 * (qx + 17);
else if (qx > width)
mx -= 4 * (qx - width);
if (qy < -18)
my -= 8 * (qy + 18);
else if (qy > height + 1)
my -= 8 * (qy - height - 1);
}
if ((v->fcm == ILACE_FRAME) && fieldmv)
off = ((n > 1) ? s->linesize : 0) + (n & 1) * 8;
else
off = s->linesize * 4 * (n & 2) + (n & 1) * 8;
src_x = s->mb_x * 16 + (n & 1) * 8 + (mx >> 2);
if (!fieldmv)
src_y = s->mb_y * 16 + (n & 2) * 4 + (my >> 2);
else
src_y = s->mb_y * 16 + ((n > 1) ? 1 : 0) + (my >> 2);
if (v->profile != PROFILE_ADVANCED) {
src_x = av_clip(src_x, -16, s->mb_width * 16);
src_y = av_clip(src_y, -16, s->mb_height * 16);
} else {
src_x = av_clip(src_x, -17, s->avctx->coded_width);
if (v->fcm == ILACE_FRAME)
src_y = av_clip(src_y, -18 + (src_y & 1), s->avctx->coded_height + (src_y & 1));
else
src_y = av_clip(src_y, -18, s->avctx->coded_height + 1);
}
srcY += src_y * s->linesize + src_x;
if (v->field_mode && v->ref_field_type[dir])
srcY += linesize;
if (v->rangeredfrm || use_ic || s->h_edge_pos < 13 || v_edge_pos < 23 ||
(unsigned)(src_x - s->mspel) > s->h_edge_pos - (mx & 3) - 8 - s->mspel * 2 ||
(unsigned)(src_y - (s->mspel << fieldmv)) > v_edge_pos - (my & 3) - ((8 + s->mspel * 2) << fieldmv)) {
const int k = 9 + s->mspel * 2;
srcY -= s->mspel * (1 + (s->linesize << fieldmv));
/* check emulate edge stride and offset */
if (interlace) {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcY, linesize << 1, linesize << 1, k,
v->field_mode ? k : (k << fieldmv) + 1 >> 1, src_x - s->mspel,
src_y - (s->mspel << fieldmv) >> !v->field_mode, s->h_edge_pos,
s->v_edge_pos >> 1);
if (!v->field_mode && !fieldmv)
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + linesize, srcY + linesize, linesize << 1,
linesize << 1, k, k >> 1, src_x - s->mspel, src_y - s->mspel + 1 >> 1,
s->h_edge_pos, s->v_edge_pos >> 1);
} else
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcY, linesize, linesize, k,
v->field_mode ? (k << 1) - 1 : k << fieldmv, src_x - s->mspel,
v->field_mode ? 2 * (src_y - s->mspel) + v->ref_field_type[dir]
: src_y - (s->mspel << fieldmv),
s->h_edge_pos, s->v_edge_pos);
srcY = s->sc.edge_emu_buffer;
/* if we deal with range reduction we need to scale source blocks */
if (v->rangeredfrm) {
vc1_scale_luma(srcY, k, s->linesize << fieldmv);
}
/* if we deal with intensity compensation we need to scale source blocks */
if (use_ic) {
vc1_lut_scale_luma(
srcY,
luty[v->field_mode ? v->ref_field_type[dir] : (((0 << fieldmv) + src_y - (s->mspel << fieldmv)) & 1)],
luty[v->field_mode ? v->ref_field_type[dir] : (((1 << fieldmv) + src_y - (s->mspel << fieldmv)) & 1)],
k, s->linesize << fieldmv);
}
srcY += s->mspel * (1 + (s->linesize << fieldmv));
}
if (s->mspel) {
dxy = ((my & 3) << 2) | (mx & 3);
if (avg)
v->vc1dsp.avg_vc1_mspel_pixels_tab[1][dxy](s->dest[0] + off, srcY, s->linesize << fieldmv, v->rnd);
else
v->vc1dsp.put_vc1_mspel_pixels_tab[1][dxy](s->dest[0] + off, srcY, s->linesize << fieldmv, v->rnd);
} else { // hpel mc - always used for luma
dxy = (my & 2) | ((mx & 2) >> 1);
if (!v->rnd)
s->hdsp.put_pixels_tab[1][dxy](s->dest[0] + off, srcY, s->linesize, 8);
else
s->hdsp.put_no_rnd_pixels_tab[1][dxy](s->dest[0] + off, srcY, s->linesize, 8);
}
}
/** Do motion compensation for 4-MV macroblock - both chroma blocks
*/
void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir) {
PictureState *s = &v->s;
ChromaDSP *h264chroma = &v->h264chroma;
uint8 *srcU, *srcV;
int uvmx, uvmy, uvsrc_x, uvsrc_y;
int16 tx, ty;
int chroma_ref_type;
int v_edge_pos = s->v_edge_pos >> v->field_mode;
const uint8(*lutuv)[256];
int use_ic;
int interlace;
int uvlinesize;
if (!v->field_mode && !v->s.last_pic.data[0])
return;
if (CONFIG_GRAY && s->avctx->flags & AV_CODEC_FLAG_GRAY)
return;
/* calculate chroma MV vector from four luma MVs */
if (!v->field_mode || !v->numref) {
int valid_count = get_chroma_mv(v, dir, &tx, &ty);
if (!valid_count) {
s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][0] = 0;
s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][1] = 0;
v->luma_mv[s->mb_x][0] = v->luma_mv[s->mb_x][1] = 0;
return; // no need to do MC for intra blocks
}
chroma_ref_type = v->ref_field_type[dir];
} else {
int opp_count = get_luma_mv(v, dir, &tx, &ty);
chroma_ref_type = v->cur_field_type ^ (opp_count > 2);
}
if (v->field_mode && chroma_ref_type == 1 && v->cur_field_type == 1 && !v->s.last_pic.data[0])
return;
s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][0] = tx;
s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][1] = ty;
uvlinesize = s->cur_pic.ptr->f->linesize[1];
uvmx = (tx + ((tx & 3) == 3)) >> 1;
uvmy = (ty + ((ty & 3) == 3)) >> 1;
v->luma_mv[s->mb_x][0] = uvmx;
v->luma_mv[s->mb_x][1] = uvmy;
if (v->fastuvmc) {
uvmx = uvmx + ((uvmx < 0) ? (uvmx & 1) : -(uvmx & 1));
uvmy = uvmy + ((uvmy < 0) ? (uvmy & 1) : -(uvmy & 1));
}
// Field conversion bias
if (v->cur_field_type != chroma_ref_type)
uvmy += 2 - 4 * chroma_ref_type;
uvsrc_x = s->mb_x * 8 + (uvmx >> 2);
uvsrc_y = s->mb_y * 8 + (uvmy >> 2);
if (v->profile != PROFILE_ADVANCED) {
uvsrc_x = av_clip(uvsrc_x, -8, s->mb_width * 8);
uvsrc_y = av_clip(uvsrc_y, -8, s->mb_height * 8);
} else {
uvsrc_x = av_clip(uvsrc_x, -8, s->avctx->coded_width >> 1);
uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1);
}
if (!dir) {
if (v->field_mode && (v->cur_field_type != chroma_ref_type) && v->second_field) {
srcU = s->cur_pic.data[1];
srcV = s->cur_pic.data[2];
lutuv = v->curr_lutuv;
use_ic = *v->curr_use_ic;
interlace = 1;
} else {
srcU = s->last_pic.data[1];
srcV = s->last_pic.data[2];
lutuv = v->last_lutuv;
use_ic = v->last_use_ic;
interlace = v->last_interlaced;
}
} else {
srcU = s->next_pic.data[1];
srcV = s->next_pic.data[2];
lutuv = v->next_lutuv;
use_ic = v->next_use_ic;
interlace = v->next_interlaced;
}
if (!srcU) {
warning("Referenced frame missing.\n");
return;
}
srcU += uvsrc_y * s->uvlinesize + uvsrc_x;
srcV += uvsrc_y * s->uvlinesize + uvsrc_x;
if (v->field_mode) {
if (chroma_ref_type) {
srcU += uvlinesize;
srcV += uvlinesize;
}
}
if (v->rangeredfrm || use_ic || s->h_edge_pos < 18 || v_edge_pos < 18 ||
(unsigned)uvsrc_x > (s->h_edge_pos >> 1) - 9 || (unsigned)uvsrc_y > (v_edge_pos >> 1) - 9) {
if (interlace) {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcU, uvlinesize << 1, uvlinesize << 1, 9,
v->field_mode ? 9 : 5, uvsrc_x, uvsrc_y >> !v->field_mode, s->h_edge_pos >> 1,
s->v_edge_pos >> 2);
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16, srcV, uvlinesize << 1, uvlinesize << 1, 9,
v->field_mode ? 9 : 5, uvsrc_x, uvsrc_y >> !v->field_mode, s->h_edge_pos >> 1,
s->v_edge_pos >> 2);
if (!v->field_mode) {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + uvlinesize, srcU + uvlinesize, uvlinesize << 1,
uvlinesize << 1, 9, 4, uvsrc_x, uvsrc_y + 1 >> 1, s->h_edge_pos >> 1,
s->v_edge_pos >> 2);
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16 + uvlinesize, srcV + uvlinesize, uvlinesize << 1,
uvlinesize << 1, 9, 4, uvsrc_x, uvsrc_y + 1 >> 1, s->h_edge_pos >> 1,
s->v_edge_pos >> 2);
}
} else {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcU, uvlinesize, uvlinesize, 9, v->field_mode ? 17 : 9,
uvsrc_x, v->field_mode ? 2 * uvsrc_y + chroma_ref_type : uvsrc_y,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
s->vdsp.emulated_edge_mc(
s->sc.edge_emu_buffer + 16, srcV, uvlinesize, uvlinesize, 9, v->field_mode ? 17 : 9, uvsrc_x,
v->field_mode ? 2 * uvsrc_y + chroma_ref_type : uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
}
srcU = s->sc.edge_emu_buffer;
srcV = s->sc.edge_emu_buffer + 16;
/* if we deal with range reduction we need to scale source blocks */
if (v->rangeredfrm) {
vc1_scale_chroma(srcU, srcV, 9, s->uvlinesize);
}
/* if we deal with intensity compensation we need to scale source blocks */
if (use_ic) {
vc1_lut_scale_chroma(srcU, srcV, lutuv[v->field_mode ? chroma_ref_type : ((0 + uvsrc_y) & 1)],
lutuv[v->field_mode ? chroma_ref_type : ((1 + uvsrc_y) & 1)], 9, s->uvlinesize);
}
}
/* Chroma MC always uses qpel bilinear */
uvmx = (uvmx & 3) << 1;
uvmy = (uvmy & 3) << 1;
if (!v->rnd) {
h264chroma->put_h264_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
h264chroma->put_h264_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
} else {
v->vc1dsp.put_no_rnd_vc1_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
v->vc1dsp.put_no_rnd_vc1_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
}
if (v->field_mode) {
v->mv_f[dir][s->block_index[4] + v->mb_off] = v->cur_field_type != chroma_ref_type;
v->mv_f[dir][s->block_index[5] + v->mb_off] = v->cur_field_type != chroma_ref_type;
}
}
/** Do motion compensation for 4-MV interlaced frame chroma macroblock (both U and V)
*/
void ff_vc1_mc_4mv_chroma4(VC1Context *v, int dir, int dir2, int avg) {
PictureState *s = &v->s;
ChromaDSP *h264chroma = &v->h264chroma;
uint8 *srcU, *srcV;
int uvsrc_x, uvsrc_y;
int uvmx_field[4], uvmy_field[4];
int i, off, tx, ty;
int fieldmv = v->blk_mv_type[s->block_index[0]];
static const uint8 s_rndtblfield[16] = {0, 0, 1, 2, 4, 4, 5, 6, 2, 2, 3, 8, 6, 6, 7, 12};
int v_dist = fieldmv ? 1 : 4; // vertical offset for lower sub-blocks
int v_edge_pos = s->v_edge_pos >> 1;
int use_ic;
int interlace;
int uvlinesize;
const uint8(*lutuv)[256];
if (CONFIG_GRAY && s->avctx->flags & AV_CODEC_FLAG_GRAY)
return;
uvlinesize = s->cur_pic.ptr->f->linesize[1];
for (i = 0; i < 4; i++) {
int d = i < 2 ? dir : dir2;
tx = s->mv[d][i][0];
uvmx_field[i] = (tx + ((tx & 3) == 3)) >> 1;
ty = s->mv[d][i][1];
if (fieldmv)
uvmy_field[i] = (ty >> 4) * 8 + s_rndtblfield[ty & 0xF];
else
uvmy_field[i] = (ty + ((ty & 3) == 3)) >> 1;
}
for (i = 0; i < 4; i++) {
off = (i & 1) * 4 + ((i & 2) ? v_dist * s->uvlinesize : 0);
uvsrc_x = s->mb_x * 8 + (i & 1) * 4 + (uvmx_field[i] >> 2);
uvsrc_y = s->mb_y * 8 + ((i & 2) ? v_dist : 0) + (uvmy_field[i] >> 2);
// FIXME: implement proper pull-back (see vc1cropmv.c, vc1CROPMV_ChromaPullBack())
uvsrc_x = av_clip(uvsrc_x, -8, s->avctx->coded_width >> 1);
if (v->fcm == ILACE_FRAME)
uvsrc_y = av_clip(uvsrc_y, -8 + (uvsrc_y & 1), (s->avctx->coded_height >> 1) + (uvsrc_y & 1));
else
uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1);
if (i < 2 ? dir : dir2) {
srcU = s->next_pic.data[1];
srcV = s->next_pic.data[2];
lutuv = v->next_lutuv;
use_ic = v->next_use_ic;
interlace = v->next_interlaced;
} else {
srcU = s->last_pic.data[1];
srcV = s->last_pic.data[2];
lutuv = v->last_lutuv;
use_ic = v->last_use_ic;
interlace = v->last_interlaced;
}
if (!srcU)
return;
srcU += uvsrc_y * s->uvlinesize + uvsrc_x;
srcV += uvsrc_y * s->uvlinesize + uvsrc_x;
uvmx_field[i] = (uvmx_field[i] & 3) << 1;
uvmy_field[i] = (uvmy_field[i] & 3) << 1;
if (use_ic || s->h_edge_pos < 10 || v_edge_pos < (5 << fieldmv) ||
(unsigned)uvsrc_x > (s->h_edge_pos >> 1) - 5 || (unsigned)uvsrc_y > v_edge_pos - (5 << fieldmv)) {
if (interlace) {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcU, uvlinesize << 1, uvlinesize << 1, 5,
(5 << fieldmv) + 1 >> 1, uvsrc_x, uvsrc_y >> 1, s->h_edge_pos >> 1,
s->v_edge_pos >> 2);
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16, srcV, uvlinesize << 1, uvlinesize << 1, 5,
(5 << fieldmv) + 1 >> 1, uvsrc_x, uvsrc_y >> 1, s->h_edge_pos >> 1,
s->v_edge_pos >> 2);
if (!fieldmv) {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + uvlinesize, srcU + uvlinesize, uvlinesize << 1,
uvlinesize << 1, 5, 2, uvsrc_x, uvsrc_y + 1 >> 1, s->h_edge_pos >> 1,
s->v_edge_pos >> 2);
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16 + uvlinesize, srcV + uvlinesize,
uvlinesize << 1, uvlinesize << 1, 5, 2, uvsrc_x, uvsrc_y + 1 >> 1,
s->h_edge_pos >> 1, s->v_edge_pos >> 2);
}
} else {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcU, uvlinesize, uvlinesize, 5, 5 << fieldmv, uvsrc_x,
uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16, srcV, uvlinesize, uvlinesize, 5, 5 << fieldmv,
uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
}
srcU = s->sc.edge_emu_buffer;
srcV = s->sc.edge_emu_buffer + 16;
/* if we deal with intensity compensation we need to scale source blocks */
if (use_ic) {
vc1_lut_scale_chroma(srcU, srcV, lutuv[(uvsrc_y + (0 << fieldmv)) & 1],
lutuv[(uvsrc_y + (1 << fieldmv)) & 1], 5, s->uvlinesize << fieldmv);
}
}
if (avg) {
if (!v->rnd) {
h264chroma->avg_h264_chroma_pixels_tab[1](s->dest[1] + off, srcU, s->uvlinesize << fieldmv, 4,
uvmx_field[i], uvmy_field[i]);
h264chroma->avg_h264_chroma_pixels_tab[1](s->dest[2] + off, srcV, s->uvlinesize << fieldmv, 4,
uvmx_field[i], uvmy_field[i]);
} else {
v->vc1dsp.avg_no_rnd_vc1_chroma_pixels_tab[1](s->dest[1] + off, srcU, s->uvlinesize << fieldmv, 4,
uvmx_field[i], uvmy_field[i]);
v->vc1dsp.avg_no_rnd_vc1_chroma_pixels_tab[1](s->dest[2] + off, srcV, s->uvlinesize << fieldmv, 4,
uvmx_field[i], uvmy_field[i]);
}
} else {
if (!v->rnd) {
h264chroma->put_h264_chroma_pixels_tab[1](s->dest[1] + off, srcU, s->uvlinesize << fieldmv, 4,
uvmx_field[i], uvmy_field[i]);
h264chroma->put_h264_chroma_pixels_tab[1](s->dest[2] + off, srcV, s->uvlinesize << fieldmv, 4,
uvmx_field[i], uvmy_field[i]);
} else {
v->vc1dsp.put_no_rnd_vc1_chroma_pixels_tab[1](s->dest[1] + off, srcU, s->uvlinesize << fieldmv, 4,
uvmx_field[i], uvmy_field[i]);
v->vc1dsp.put_no_rnd_vc1_chroma_pixels_tab[1](s->dest[2] + off, srcV, s->uvlinesize << fieldmv, 4,
uvmx_field[i], uvmy_field[i]);
}
}
}
}
/** Motion compensation for direct or interpolated blocks in B-frames
*/
void ff_vc1_interp_mc(VC1Context *v) {
PictureState *s = &v->s;
ChromaDSP *h264chroma = &v->h264chroma;
uint8 *srcY, *srcU, *srcV;
int dxy, mx, my, uvmx, uvmy, src_x, src_y, uvsrc_x, uvsrc_y;
int v_edge_pos = s->v_edge_pos >> v->field_mode;
int use_ic = v->next_use_ic;
int interlace = v->next_interlaced;
int linesize, uvlinesize;
if (!v->field_mode && !v->s.next_pic.data[0])
return;
linesize = s->cur_pic.ptr->f->linesize[0];
uvlinesize = s->cur_pic.ptr->f->linesize[1];
mx = s->mv[1][0][0];
my = s->mv[1][0][1];
uvmx = (mx + ((mx & 3) == 3)) >> 1;
uvmy = (my + ((my & 3) == 3)) >> 1;
if (v->field_mode && v->cur_field_type != v->ref_field_type[1]) {
my = my - 2 + 4 * v->cur_field_type;
uvmy = uvmy - 2 + 4 * v->cur_field_type;
}
if (v->fastuvmc) {
uvmx = uvmx + ((uvmx < 0) ? -(uvmx & 1) : (uvmx & 1));
uvmy = uvmy + ((uvmy < 0) ? -(uvmy & 1) : (uvmy & 1));
}
srcY = s->next_pic.data[0];
srcU = s->next_pic.data[1];
srcV = s->next_pic.data[2];
src_x = s->mb_x * 16 + (mx >> 2);
src_y = s->mb_y * 16 + (my >> 2);
uvsrc_x = s->mb_x * 8 + (uvmx >> 2);
uvsrc_y = s->mb_y * 8 + (uvmy >> 2);
if (v->profile != PROFILE_ADVANCED) {
src_x = av_clip(src_x, -16, s->mb_width * 16);
src_y = av_clip(src_y, -16, s->mb_height * 16);
uvsrc_x = av_clip(uvsrc_x, -8, s->mb_width * 8);
uvsrc_y = av_clip(uvsrc_y, -8, s->mb_height * 8);
} else {
src_x = av_clip(src_x, -17, s->avctx->coded_width);
uvsrc_x = av_clip(uvsrc_x, -8, s->avctx->coded_width >> 1);
if (v->fcm == ILACE_FRAME) {
src_y = av_clip(src_y, -18 + (src_y & 1), s->avctx->coded_height + (src_y & 1));
uvsrc_y = av_clip(uvsrc_y, -8 + (uvsrc_y & 1), (s->avctx->coded_height >> 1) + (uvsrc_y & 1));
} else {
src_y = av_clip(src_y, -18, s->avctx->coded_height + 1);
uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1);
}
}
srcY += src_y * s->linesize + src_x;
srcU += uvsrc_y * s->uvlinesize + uvsrc_x;
srcV += uvsrc_y * s->uvlinesize + uvsrc_x;
if (v->field_mode && v->ref_field_type[1]) {
srcY += linesize;
srcU += uvlinesize;
srcV += uvlinesize;
}
/* for grayscale we should not try to read from unknown area */
if (CONFIG_GRAY && s->avctx->flags & AV_CODEC_FLAG_GRAY) {
srcU = s->sc.edge_emu_buffer + 18 * s->linesize;
srcV = s->sc.edge_emu_buffer + 18 * s->linesize;
}
if (v->rangeredfrm || s->h_edge_pos < 22 || v_edge_pos < 22 || use_ic ||
(unsigned)(src_x - 1) > s->h_edge_pos - (mx & 3) - 16 - 3 ||
(unsigned)(src_y - 1) > v_edge_pos - (my & 3) - 16 - 3) {
uint8 *ubuf = s->sc.edge_emu_buffer + 19 * s->linesize;
uint8 *vbuf = ubuf + 9 * s->uvlinesize;
const int k = 17 + s->mspel * 2;
srcY -= s->mspel * (1 + s->linesize);
if (interlace) {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcY, linesize << 1, linesize << 1, k,
v->field_mode ? k : (k + 1 >> 1), src_x - s->mspel,
src_y - s->mspel >> !v->field_mode, s->h_edge_pos, s->v_edge_pos >> 1);
if (!v->field_mode)
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + linesize, srcY + linesize, linesize << 1,
linesize << 1, k, k >> 1, src_x - s->mspel, src_y - s->mspel + 1 >> 1,
s->h_edge_pos, s->v_edge_pos >> 1);
} else
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcY, linesize, linesize, k,
v->field_mode ? (k << 1) - 1 : k, src_x - s->mspel,
v->field_mode ? 2 * (src_y - s->mspel) + v->ref_field_type[1] : src_y - s->mspel,
s->h_edge_pos, s->v_edge_pos);
srcY = s->sc.edge_emu_buffer;
if (interlace) {
s->vdsp.emulated_edge_mc(ubuf, srcU, uvlinesize << 1, uvlinesize << 1, 9, v->field_mode ? 9 : 5, uvsrc_x,
uvsrc_y >> !v->field_mode, s->h_edge_pos >> 1, s->v_edge_pos >> 2);
s->vdsp.emulated_edge_mc(vbuf, srcV, uvlinesize << 1, uvlinesize << 1, 9, v->field_mode ? 9 : 5, uvsrc_x,
uvsrc_y >> !v->field_mode, s->h_edge_pos >> 1, s->v_edge_pos >> 2);
if (!v->field_mode) {
s->vdsp.emulated_edge_mc(ubuf + uvlinesize, srcU + uvlinesize, uvlinesize << 1, uvlinesize << 1, 9, 4,
uvsrc_x, uvsrc_y + 1 >> 1, s->h_edge_pos >> 1, s->v_edge_pos >> 2);
s->vdsp.emulated_edge_mc(vbuf + uvlinesize, srcV + uvlinesize, uvlinesize << 1, uvlinesize << 1, 9, 4,
uvsrc_x, uvsrc_y + 1 >> 1, s->h_edge_pos >> 1, s->v_edge_pos >> 2);
}
} else {
s->vdsp.emulated_edge_mc(ubuf, srcU, uvlinesize, uvlinesize, 9, v->field_mode ? 17 : 9, uvsrc_x,
v->field_mode ? 2 * uvsrc_y + v->ref_field_type[1] : uvsrc_y, s->h_edge_pos >> 1,
s->v_edge_pos >> 1);
s->vdsp.emulated_edge_mc(vbuf, srcV, uvlinesize, uvlinesize, 9, v->field_mode ? 17 : 9, uvsrc_x,
v->field_mode ? 2 * uvsrc_y + v->ref_field_type[1] : uvsrc_y, s->h_edge_pos >> 1,
s->v_edge_pos >> 1);
}
srcU = ubuf;
srcV = vbuf;
/* if we deal with range reduction we need to scale source blocks */
if (v->rangeredfrm) {
vc1_scale_luma(srcY, k, s->linesize);
vc1_scale_chroma(srcU, srcV, 9, s->uvlinesize);
}
if (use_ic) {
const uint8(*luty)[256] = v->next_luty;
const uint8(*lutuv)[256] = v->next_lutuv;
vc1_lut_scale_luma(srcY, luty[v->field_mode ? v->ref_field_type[1] : ((0 + src_y - s->mspel) & 1)],
luty[v->field_mode ? v->ref_field_type[1] : ((1 + src_y - s->mspel) & 1)], k,
s->linesize);
vc1_lut_scale_chroma(srcU, srcV, lutuv[v->field_mode ? v->ref_field_type[1] : ((0 + uvsrc_y) & 1)],
lutuv[v->field_mode ? v->ref_field_type[1] : ((1 + uvsrc_y) & 1)], 9, s->uvlinesize);
}
srcY += s->mspel * (1 + s->linesize);
}
if (s->mspel) {
dxy = ((my & 3) << 2) | (mx & 3);
v->vc1dsp.avg_vc1_mspel_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize, v->rnd);
} else { // hpel mc
dxy = (my & 2) | ((mx & 2) >> 1);
if (!v->rnd)
s->hdsp.avg_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize, 16);
else
s->hdsp.avg_no_rnd_pixels_tab[dxy](s->dest[0], srcY, s->linesize, 16);
}
if (CONFIG_GRAY && s->avctx->flags & AV_CODEC_FLAG_GRAY)
return;
/* Chroma MC always uses qpel bilinear */
uvmx = (uvmx & 3) << 1;
uvmy = (uvmy & 3) << 1;
if (!v->rnd) {
h264chroma->avg_h264_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
h264chroma->avg_h264_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
} else {
v->vc1dsp.avg_no_rnd_vc1_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
v->vc1dsp.avg_no_rnd_vc1_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
}
}
// offset tables for interlaced picture MVDATA decoding
static const uint8 offset_table[2][9] = {
{0, 1, 2, 4, 8, 16, 32, 64, 128},
{0, 1, 3, 7, 15, 31, 63, 127, 255},
};
// mapping table for internal block representation
static const int block_map[6] = {0, 2, 1, 3, 4, 5};
/***********************************************************************/
/**
* @name VC-1 Bitplane decoding
* @see 8.7, p56
* @{
*/
static inline void init_block_index(VC1Context *v) {
PictureState *s = &v->s;
ff_init_block_index(s);
if (v->field_mode && !(v->second_field ^ v->tff)) {
s->dest[0] += s->cur_pic.ptr->f->linesize[0];
s->dest[1] += s->cur_pic.ptr->f->linesize[1];
s->dest[2] += s->cur_pic.ptr->f->linesize[2];
}
}
static inline void update_block_index(PictureState *s) {
/* VC1 is always 420 except when using AV_CODEC_FLAG_GRAY
* (or a HWAccel). Shall we inline this value? */
ff_update_block_index(s, 8, 0, s->chroma_x_shift);
}
/** @} */ // Bitplane group
static void vc1_put_blocks_clamped(VC1Context *v, int put_signed) {
PictureState *s = &v->s;
uint8 *dest;
int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6;
int fieldtx = 0;
int i;
/* The put pixels loop is one MB row and one MB column behind the decoding
* loop because we can only put pixels when overlap filtering is done. For
* interlaced frame pictures, however, the put pixels loop is only one
* column behind the decoding loop as interlaced frame pictures only need
* horizontal overlap filtering. */
if (!s->first_slice_line && v->fcm != ILACE_FRAME) {
if (s->mb_x) {
for (i = 0; i < block_count; i++) {
if (i > 3 ? v->mb_type[s->block_index[i] - s->block_wrap[i] - 1]
: v->mb_type[s->block_index[i] - 2 * s->block_wrap[i] - 2]) {
dest = s->dest[0] + ((i & 2) - 4) * 4 * s->linesize + ((i & 1) - 2) * 8;
if (put_signed)
s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][block_map[i]],
i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest,
i > 3 ? s->uvlinesize : s->linesize);
else
s->idsp.put_pixels_clamped(v->block[v->topleft_blk_idx][block_map[i]],
i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest,
i > 3 ? s->uvlinesize : s->linesize);
}
}
}
if (s->mb_x == v->end_mb_x - 1) {
for (i = 0; i < block_count; i++) {
if (i > 3 ? v->mb_type[s->block_index[i] - s->block_wrap[i]]
: v->mb_type[s->block_index[i] - 2 * s->block_wrap[i]]) {
dest = s->dest[0] + ((i & 2) - 4) * 4 * s->linesize + (i & 1) * 8;
if (put_signed)
s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][block_map[i]],
i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest,
i > 3 ? s->uvlinesize : s->linesize);
else
s->idsp.put_pixels_clamped(v->block[v->top_blk_idx][block_map[i]],
i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest,
i > 3 ? s->uvlinesize : s->linesize);
}
}
}
}
if (s->mb_y == s->end_mb_y - 1 || v->fcm == ILACE_FRAME) {
if (s->mb_x) {
if (v->fcm == ILACE_FRAME)
fieldtx = v->fieldtx_plane[s->mb_y * s->mb_stride + s->mb_x - 1];
for (i = 0; i < block_count; i++) {
if (i > 3 ? v->mb_type[s->block_index[i] - 1] : v->mb_type[s->block_index[i] - 2]) {
if (fieldtx)
dest = s->dest[0] + ((i & 2) >> 1) * s->linesize + ((i & 1) - 2) * 8;
else
dest = s->dest[0] + (i & 2) * 4 * s->linesize + ((i & 1) - 2) * 8;
if (put_signed)
s->idsp.put_signed_pixels_clamped(v->block[v->left_blk_idx][block_map[i]],
i > 3 ? s->dest[i - 3] - 8 : dest,
i > 3 ? s->uvlinesize : s->linesize << fieldtx);
else
s->idsp.put_pixels_clamped(v->block[v->left_blk_idx][block_map[i]],
i > 3 ? s->dest[i - 3] - 8 : dest,
i > 3 ? s->uvlinesize : s->linesize << fieldtx);
}
}
}
if (s->mb_x == v->end_mb_x - 1) {
if (v->fcm == ILACE_FRAME)
fieldtx = v->fieldtx_plane[s->mb_y * s->mb_stride + s->mb_x];
for (i = 0; i < block_count; i++) {
if (v->mb_type[s->block_index[i]]) {
if (fieldtx)
dest = s->dest[0] + ((i & 2) >> 1) * s->linesize + (i & 1) * 8;
else
dest = s->dest[0] + (i & 2) * 4 * s->linesize + (i & 1) * 8;
if (put_signed)
s->idsp.put_signed_pixels_clamped(v->block[v->cur_blk_idx][block_map[i]],
i > 3 ? s->dest[i - 3] : dest,
i > 3 ? s->uvlinesize : s->linesize << fieldtx);
else
s->idsp.put_pixels_clamped(v->block[v->cur_blk_idx][block_map[i]],
i > 3 ? s->dest[i - 3] : dest,
i > 3 ? s->uvlinesize : s->linesize << fieldtx);
}
}
}
}
}
#define inc_blk_idx(idx) \
do { \
idx++; \
if (idx >= v->n_allocated_blks) \
idx = 0; \
} while (0)
/***********************************************************************/
/**
* @name VC-1 Block-level functions
* @see 7.1.4, p91 and 8.1.1.7, p(1)04
* @{
*/
/**
* @def GET_MQUANT
* @brief Get macroblock-level quantizer scale
*/
#define GET_MQUANT() \
if (v->dquantfrm) { \
int edges = 0; \
if (v->dqprofile == DQPROFILE_ALL_MBS) { \
if (v->dqbilevel) { \
mquant = (get_bits1(gb)) ? -v->altpq : v->pq; \
} else { \
mqdiff = get_bits(gb, 3); \
if (mqdiff != 7) \
mquant = -v->pq - mqdiff; \
else \
mquant = -get_bits(gb, 5); \
} \
} \
if (v->dqprofile == DQPROFILE_SINGLE_EDGE) \
edges = 1 << v->dqsbedge; \
else if (v->dqprofile == DQPROFILE_DOUBLE_EDGES) \
edges = (3 << v->dqsbedge) % 15; \
else if (v->dqprofile == DQPROFILE_FOUR_EDGES) \
edges = 15; \
if ((edges & 1) && !s->mb_x) \
mquant = -v->altpq; \
if ((edges & 2) && !s->mb_y) \
mquant = -v->altpq; \
if ((edges & 4) && s->mb_x == (s->mb_width - 1)) \
mquant = -v->altpq; \
if ((edges & 8) && s->mb_y == ((s->mb_height >> v->field_mode) - 1)) \
mquant = -v->altpq; \
if (!mquant || mquant > 31 || mquant < -31) { \
warning("Overriding invalid mquant %d\n", mquant); \
mquant = 1; \
} \
}
/**
* @def GET_MVDATA(_dmv_x, _dmv_y)
* @brief Get MV differentials
* @see MVDATA decoding from 8.3.5.2, p(1)20
* @param _dmv_x Horizontal differential for decoded MV
* @param _dmv_y Vertical differential for decoded MV
*/
#define GET_MVDATA(_dmv_x, _dmv_y) \
index = 1 + get_vlc2(gb, ff_vc1_mv_diff_vlc[v->mv_table_index]); \
if (index > 36) { \
mb_has_coeffs = 1; \
index -= 37; \
} else \
mb_has_coeffs = 0; \
s->mb_intra = 0; \
if (!index) { \
_dmv_x = _dmv_y = 0; \
} else if (index == 35) { \
_dmv_x = get_bits(gb, v->k_x - 1 + s->quarter_sample); \
_dmv_y = get_bits(gb, v->k_y - 1 + s->quarter_sample); \
} else if (index == 36) { \
_dmv_x = 0; \
_dmv_y = 0; \
s->mb_intra = 1; \
} else { \
index1 = index % 6; \
_dmv_x = offset_table[1][index1]; \
val = size_table[index1] - (!s->quarter_sample && index1 == 5); \
if (val > 0) { \
val = get_bits(gb, val); \
sign = 0 - (val & 1); \
_dmv_x = (sign ^ ((val >> 1) + _dmv_x)) - sign; \
} \
\
index1 = index / 6; \
_dmv_y = offset_table[1][index1]; \
val = size_table[index1] - (!s->quarter_sample && index1 == 5); \
if (val > 0) { \
val = get_bits(gb, val); \
sign = 0 - (val & 1); \
_dmv_y = (sign ^ ((val >> 1) + _dmv_y)) - sign; \
} \
}
static inline void get_mvdata_interlaced(VC1Context *v, int *dmv_x, int *dmv_y, int *pred_flag) {
int index, index1;
int extend_x, extend_y;
Bits *const gb = &v->gb;
int esc;
int val, sign;
if (v->numref) {
esc = 125;
} else {
esc = 71;
}
extend_x = v->dmvrange & 1;
extend_y = (v->dmvrange >> 1) & 1;
index = get_vlc2(gb, v->imv_vlc);
if (index == esc) {
*dmv_x = get_bits(gb, v->k_x);
*dmv_y = get_bits(gb, v->k_y);
if (v->numref) {
if (pred_flag)
*pred_flag = *dmv_y & 1;
*dmv_y = (*dmv_y + (*dmv_y & 1)) >> 1;
}
} else {
assert(index < esc);
index1 = (index + 1) % 9;
if (index1 != 0) {
val = get_bits(gb, index1 + extend_x);
sign = 0 - (val & 1);
*dmv_x = (sign ^ ((val >> 1) + offset_table[extend_x][index1])) - sign;
} else
*dmv_x = 0;
index1 = (index + 1) / 9;
if (index1 > v->numref) {
val = get_bits(gb, (index1 >> v->numref) + extend_y);
sign = 0 - (val & 1);
*dmv_y = (sign ^ ((val >> 1) + offset_table[extend_y][index1 >> v->numref])) - sign;
} else
*dmv_y = 0;
if (v->numref && pred_flag)
*pred_flag = index1 & 1;
}
}
/** Reconstruct motion vector for B-frame and do motion compensation
*/
static inline void vc1_b_mc(VC1Context *v, int dmv_x[2], int dmv_y[2], int direct, int mode) {
if (direct) {
ff_vc1_mc_1mv(v, 0);
ff_vc1_interp_mc(v);
return;
}
if (mode == BMV_TYPE_INTERPOLATED) {
ff_vc1_mc_1mv(v, 0);
ff_vc1_interp_mc(v);
return;
}
ff_vc1_mc_1mv(v, (mode == BMV_TYPE_BACKWARD));
}
/** Get predicted DC value for I-frames only
* prediction dir: left=0, top=1
* @param s PictureState
* @param overlap flag indicating that overlap filtering is used
* @param pq integer part of picture quantizer
* @param[in] n block index in the current MB
* @param dc_val_ptr Pointer to DC predictor
* @param dir_ptr Prediction direction for use in AC prediction
*/
static inline int vc1_i_pred_dc(PictureState *s, int overlap, int pq, int n, int16 **dc_val_ptr, int *dir_ptr) {
int a, b, c, wrap, pred, scale;
int16 *dc_val;
static const uint16 dcpred[32] = {65535, 1024, 512, 341, 256, 205, 171, 146, 128, 114, 102, 93, 85, 79, 73, 68,
64, 60, 57, 54, 51, 49, 47, 45, 43, 41, 39, 38, 37, 35, 34, 33};
/* find prediction - wmv3_dc_scale always used here in fact */
scale = s->y_dc_scale;
wrap = s->block_wrap[n];
dc_val = s->dc_val + s->block_index[n];
/* B A
* C X
*/
c = dc_val[-1];
b = dc_val[-1 - wrap];
a = dc_val[-wrap];
if (pq < 9 || !overlap) {
/* Set outer values */
if (s->first_slice_line && (n != 2 && n != 3))
b = a = dcpred[scale];
if (s->mb_x == 0 && (n != 1 && n != 3))
b = c = dcpred[scale];
} else {
/* Set outer values */
if (s->first_slice_line && (n != 2 && n != 3))
b = a = 0;
if (s->mb_x == 0 && (n != 1 && n != 3))
b = c = 0;
}
if (abs(a - b) <= abs(b - c)) {
pred = c;
*dir_ptr = 1; // left
} else {
pred = a;
*dir_ptr = 0; // top
}
/* update predictor */
*dc_val_ptr = &dc_val[0];
return pred;
}
/** Get predicted DC value
* prediction dir: left=0, top=1
* @param s PictureState
* @param overlap flag indicating that overlap filtering is used
* @param pq integer part of picture quantizer
* @param[in] n block index in the current MB
* @param a_avail flag indicating top block availability
* @param c_avail flag indicating left block availability
* @param dc_val_ptr Pointer to DC predictor
* @param dir_ptr Prediction direction for use in AC prediction
*/
static inline int ff_vc1_pred_dc(PictureState *s, int overlap, int pq, int n, int a_avail, int c_avail,
int16 **dc_val_ptr, int *dir_ptr) {
int a, b, c, wrap, pred;
int16 *dc_val;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
int q1, q2 = 0;
int dqscale_index;
/* scale predictors if needed */
q1 = ABS(s->cur_pic.qscale_table[mb_pos]);
dqscale_index = ff_wmv3_dc_scale_table[q1] - 1;
if (dqscale_index < 0)
return 0;
wrap = s->block_wrap[n];
dc_val = s->dc_val + s->block_index[n];
/* B A
* C X
*/
c = dc_val[-1];
b = dc_val[-1 - wrap];
a = dc_val[-wrap];
if (c_avail && (n != 1 && n != 3)) {
q2 = ABS(s->cur_pic.qscale_table[mb_pos - 1]);
if (q2 && q2 != q1)
c = (int)((unsigned)c * ff_wmv3_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18;
}
if (a_avail && (n != 2 && n != 3)) {
q2 = ABS(s->cur_pic.qscale_table[mb_pos - s->mb_stride]);
if (q2 && q2 != q1)
a = (int)((unsigned)a * ff_wmv3_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18;
}
if (a_avail && c_avail && (n != 3)) {
int off = mb_pos;
if (n != 1)
off--;
if (n != 2)
off -= s->mb_stride;
q2 = ABS(s->cur_pic.qscale_table[off]);
if (q2 && q2 != q1)
b = (int)((unsigned)b * ff_wmv3_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18;
}
if (c_avail && (!a_avail || abs(a - b) <= abs(b - c))) {
pred = c;
*dir_ptr = 1; // left
} else if (a_avail) {
pred = a;
*dir_ptr = 0; // top
} else {
pred = 0;
*dir_ptr = 1; // left
}
/* update predictor */
*dc_val_ptr = &dc_val[0];
return pred;
}
/** @} */ // Block group
/**
* @name VC1 Macroblock-level functions in Simple/Main Profiles
* @see 7.1.4, p91 and 8.1.1.7, p(1)04
* @{
*/
static inline int vc1_coded_block_pred(PictureState *const s, int n, int diff) {
int xy, wrap, pred, a, b, c;
xy = s->block_index[n];
wrap = s->b8_stride;
/* B C
* A X
*/
a = s->coded_block[xy - 1];
b = s->coded_block[xy - 1 - wrap];
c = s->coded_block[xy - wrap];
if (b == c) {
pred = a;
} else {
pred = c;
}
/* store value */
s->coded_block[xy] = pred ^ diff;
return pred ^ diff;
}
/**
* Decode one AC coefficient
* @param v The VC1 context
* @param last Last coefficient
* @param skip How much zero coefficients to skip
* @param value Decoded AC coefficient value
* @param codingset set of VLC to decode data
* @see 8.1.3.4
*/
static int vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip, int *value, int codingset) {
Bits *const gb = &v->gb;
int index, run, level, lst, sign;
index = get_vlc2(gb, ff_vc1_ac_coeff_table[codingset]);
if (index < 0)
return index;
if (index != ff_vc1_ac_sizes[codingset] - 1) {
run = vc1_index_decode_table[codingset][index][0];
level = vc1_index_decode_table[codingset][index][1];
lst = index >= vc1_last_decode_table[codingset] || get_bits_left(gb) < 0;
sign = get_bits1(gb);
} else {
int escape = decode210(gb);
if (escape != 2) {
index = get_vlc2(gb, ff_vc1_ac_coeff_table[codingset]);
if (index >= ff_vc1_ac_sizes[codingset] - 1U)
return (-1);
run = vc1_index_decode_table[codingset][index][0];
level = vc1_index_decode_table[codingset][index][1];
lst = index >= vc1_last_decode_table[codingset];
if (escape == 0) {
if (lst)
level += vc1_last_delta_level_table[codingset][run];
else
level += vc1_delta_level_table[codingset][run];
} else {
if (lst)
run += vc1_last_delta_run_table[codingset][level] + 1;
else
run += vc1_delta_run_table[codingset][level] + 1;
}
sign = get_bits1(gb);
} else {
lst = get_bits1(gb);
if (v->esc3_level_length == 0) {
if (v->pq < 8 || v->dquantfrm) { // table 59
v->esc3_level_length = get_bits(gb, 3);
if (!v->esc3_level_length)
v->esc3_level_length = get_bits(gb, 2) + 8;
} else { // table 60
v->esc3_level_length = get_unary(gb, 1, 6) + 2;
}
v->esc3_run_length = 3 + get_bits(gb, 2);
}
run = get_bits(gb, v->esc3_run_length);
sign = get_bits1(gb);
level = get_bits(gb, v->esc3_level_length);
}
}
*last = lst;
*skip = run;
*value = (level ^ -sign) + sign;
return 0;
}
/** Decode intra block in intra frames - should be faster than decode_intra_block
* @param v VC1Context
* @param block block to decode
* @param[in] n subblock index
* @param coded are AC coeffs present or not
* @param codingset set of VLC to decode data
*/
static int vc1_decode_i_block(VC1Context *v, int16 block[64], int n, int coded, int codingset) {
Bits *const gb = &v->gb;
PictureState *s = &v->s;
int dc_pred_dir = 0; /* Direction of the DC prediction used */
int16 *dc_val;
int16 *ac_val, *ac_val2;
int dcdiff, scale;
/* Get DC differential */
dcdiff = get_vlc2(gb, ff_msmp4_dc_vlc[v->dc_table_index][n >= 4]);
if (dcdiff) {
const int m = (v->pq == 1 || v->pq == 2) ? 3 - v->pq : 0;
if (dcdiff == 119 /* ESC index value */) {
dcdiff = get_bits(gb, 8 + m);
} else {
if (m)
dcdiff = (dcdiff << m) + get_bits(gb, m) - ((1 << m) - 1);
}
if (get_bits1(gb))
dcdiff = -dcdiff;
}
/* Prediction */
dcdiff += vc1_i_pred_dc(&v->s, v->overlap, v->pq, n, &dc_val, &dc_pred_dir);
*dc_val = dcdiff;
/* Store the quantized DC coeff, used for prediction */
block[0] = dcdiff * s->y_dc_scale;
ac_val = s->ac_val[s->block_index[n]];
ac_val2 = ac_val;
if (dc_pred_dir) // left
ac_val -= 16;
else // top
ac_val -= 16 * s->block_wrap[n];
scale = v->pq * 2 + v->halfpq;
// AC Decoding
if (coded) {
int last = 0, skip, value;
const uint8 *zz_table;
int k;
if (v->s.ac_pred) {
if (!dc_pred_dir)
zz_table = v->zz_8x8[2];
else
zz_table = v->zz_8x8[3];
} else
zz_table = v->zz_8x8[1];
for (int i = 1; !last; ++i) {
int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, codingset);
if (ret < 0)
return ret;
i += skip;
if (i > 63)
break;
block[zz_table[i]] = value;
}
/* apply AC prediction if needed */
if (s->ac_pred) {
int sh;
if (dc_pred_dir) { // left
sh = v->left_blk_sh;
} else { // top
sh = v->top_blk_sh;
ac_val += 8;
}
for (k = 1; k < 8; k++)
block[k << sh] += ac_val[k];
}
/* save AC coeffs for further prediction */
for (k = 1; k < 8; k++) {
ac_val2[k] = block[k << v->left_blk_sh];
ac_val2[k + 8] = block[k << v->top_blk_sh];
}
/* scale AC coeffs */
for (k = 1; k < 64; k++)
if (block[k]) {
block[k] *= scale;
if (!v->pquantizer)
block[k] += (block[k] < 0) ? -v->pq : v->pq;
}
} else {
int k;
memset(ac_val2, 0, 16 * 2);
/* apply AC prediction if needed */
if (s->ac_pred) {
int sh;
if (dc_pred_dir) { // left
sh = v->left_blk_sh;
} else { // top
sh = v->top_blk_sh;
ac_val += 8;
ac_val2 += 8;
}
memcpy(ac_val2, ac_val, 8 * 2);
for (k = 1; k < 8; k++) {
block[k << sh] = ac_val[k] * scale;
if (!v->pquantizer && block[k << sh])
block[k << sh] += (block[k << sh] < 0) ? -v->pq : v->pq;
}
}
}
return 0;
}
/** Decode intra block in intra frames - should be faster than decode_intra_block
* @param v VC1Context
* @param block block to decode
* @param[in] n subblock number
* @param coded are AC coeffs present or not
* @param codingset set of VLC to decode data
* @param mquant quantizer value for this macroblock
*/
static int vc1_decode_i_block_adv(VC1Context *v, int16 block[64], int n, int coded, int codingset, int mquant) {
Bits *const gb = &v->gb;
PictureState *s = &v->s;
int dc_pred_dir = 0; /* Direction of the DC prediction used */
int16 *dc_val = NULL;
int16 *ac_val, *ac_val2;
int dcdiff;
int a_avail = v->a_avail, c_avail = v->c_avail;
int use_pred = s->ac_pred;
int scale;
int q1, q2 = 0;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
int quant = ABS(mquant);
/* Get DC differential */
dcdiff = get_vlc2(gb, ff_msmp4_dc_vlc[v->dc_table_index][n >= 4]);
if (dcdiff) {
const int m = (quant == 1 || quant == 2) ? 3 - quant : 0;
if (dcdiff == 119 /* ESC index value */) {
dcdiff = get_bits(gb, 8 + m);
} else {
if (m)
dcdiff = (dcdiff << m) + get_bits(gb, m) - ((1 << m) - 1);
}
if (get_bits1(gb))
dcdiff = -dcdiff;
}
/* Prediction */
dcdiff += ff_vc1_pred_dc(&v->s, v->overlap, quant, n, v->a_avail, v->c_avail, &dc_val, &dc_pred_dir);
*dc_val = dcdiff;
/* Store the quantized DC coeff, used for prediction */
block[0] = dcdiff * s->y_dc_scale;
/* check if AC is needed at all */
if (!a_avail && !c_avail)
use_pred = 0;
scale = quant * 2 + ((mquant < 0) ? 0 : v->halfpq);
ac_val = s->ac_val[s->block_index[n]];
ac_val2 = ac_val;
if (dc_pred_dir) // left
ac_val -= 16;
else // top
ac_val -= 16 * s->block_wrap[n];
q1 = s->cur_pic.qscale_table[mb_pos];
if (n == 3)
q2 = q1;
else if (dc_pred_dir) {
if (n == 1)
q2 = q1;
else if (c_avail && mb_pos)
q2 = s->cur_pic.qscale_table[mb_pos - 1];
} else {
if (n == 2)
q2 = q1;
else if (a_avail && mb_pos >= s->mb_stride)
q2 = s->cur_pic.qscale_table[mb_pos - s->mb_stride];
}
// AC Decoding
if (coded) {
int last = 0, skip, value;
const uint8 *zz_table;
int k;
if (v->s.ac_pred) {
if (!use_pred && v->fcm == ILACE_FRAME) {
zz_table = v->zzi_8x8;
} else {
if (!dc_pred_dir) // top
zz_table = v->zz_8x8[2];
else // left
zz_table = v->zz_8x8[3];
}
} else {
if (v->fcm != ILACE_FRAME)
zz_table = v->zz_8x8[1];
else
zz_table = v->zzi_8x8;
}
for (int i = 1; !last; ++i) {
int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, codingset);
if (ret < 0)
return ret;
i += skip;
if (i > 63)
break;
block[zz_table[i]] = value;
}
/* apply AC prediction if needed */
if (use_pred) {
int sh;
if (dc_pred_dir) { // left
sh = v->left_blk_sh;
} else { // top
sh = v->top_blk_sh;
ac_val += 8;
}
/* scale predictors if needed*/
q1 = ABS(q1) * 2 + ((q1 < 0) ? 0 : v->halfpq) - 1;
if (q1 < 1)
return (-1);
if (q2)
q2 = ABS(q2) * 2 + ((q2 < 0) ? 0 : v->halfpq) - 1;
if (q2 && q1 != q2) {
for (k = 1; k < 8; k++)
block[k << sh] += (int)(ac_val[k] * (unsigned)q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18;
} else {
for (k = 1; k < 8; k++)
block[k << sh] += ac_val[k];
}
}
/* save AC coeffs for further prediction */
for (k = 1; k < 8; k++) {
ac_val2[k] = block[k << v->left_blk_sh];
ac_val2[k + 8] = block[k << v->top_blk_sh];
}
/* scale AC coeffs */
for (k = 1; k < 64; k++)
if (block[k]) {
block[k] *= scale;
if (!v->pquantizer)
block[k] += (block[k] < 0) ? -quant : quant;
}
} else { // no AC coeffs
int k;
memset(ac_val2, 0, 16 * 2);
/* apply AC prediction if needed */
if (use_pred) {
int sh;
if (dc_pred_dir) { // left
sh = v->left_blk_sh;
} else { // top
sh = v->top_blk_sh;
ac_val += 8;
ac_val2 += 8;
}
memcpy(ac_val2, ac_val, 8 * 2);
q1 = ABS(q1) * 2 + ((q1 < 0) ? 0 : v->halfpq) - 1;
if (q1 < 1)
return (-1);
if (q2)
q2 = ABS(q2) * 2 + ((q2 < 0) ? 0 : v->halfpq) - 1;
if (q2 && q1 != q2) {
for (k = 1; k < 8; k++)
ac_val2[k] = (int)(ac_val2[k] * q2 * (unsigned)ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18;
}
for (k = 1; k < 8; k++) {
block[k << sh] = ac_val2[k] * scale;
if (!v->pquantizer && block[k << sh])
block[k << sh] += (block[k << sh] < 0) ? -quant : quant;
}
}
}
return 0;
}
/** Decode intra block in inter frames - more generic version than vc1_decode_i_block
* @param v VC1Context
* @param block block to decode
* @param[in] n subblock index
* @param coded are AC coeffs present or not
* @param mquant block quantizer
* @param codingset set of VLC to decode data
*/
static int vc1_decode_intra_block(VC1Context *v, int16 block[64], int n, int coded, int mquant, int codingset) {
Bits *const gb = &v->gb;
PictureState *s = &v->s;
int dc_pred_dir = 0; /* Direction of the DC prediction used */
int16 *dc_val = NULL;
int16 *ac_val, *ac_val2;
int dcdiff;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
int a_avail = v->a_avail, c_avail = v->c_avail;
int use_pred = s->ac_pred;
int scale;
int q1, q2 = 0;
int quant = ABS(mquant);
s->bdsp.clear_block(block);
/* XXX: Guard against dumb values of mquant */
quant = av_clip_uintp2(quant, 5);
/* Set DC scale - y and c use the same so we only set y */
s->y_dc_scale = ff_wmv3_dc_scale_table[quant];
/* Get DC differential */
dcdiff = get_vlc2(gb, ff_msmp4_dc_vlc[v->dc_table_index][n >= 4]);
if (dcdiff) {
const int m = (quant == 1 || quant == 2) ? 3 - quant : 0;
if (dcdiff == 119 /* ESC index value */) {
dcdiff = get_bits(gb, 8 + m);
} else {
if (m)
dcdiff = (dcdiff << m) + get_bits(gb, m) - ((1 << m) - 1);
}
if (get_bits1(gb))
dcdiff = -dcdiff;
}
/* Prediction */
dcdiff += ff_vc1_pred_dc(&v->s, v->overlap, quant, n, a_avail, c_avail, &dc_val, &dc_pred_dir);
*dc_val = dcdiff;
/* Store the quantized DC coeff, used for prediction */
block[0] = dcdiff * s->y_dc_scale;
// AC Decoding
/* check if AC is needed at all and adjust direction if needed */
if (!a_avail)
dc_pred_dir = 1;
if (!c_avail)
dc_pred_dir = 0;
if (!a_avail && !c_avail)
use_pred = 0;
ac_val = s->ac_val[s->block_index[n]];
ac_val2 = ac_val;
scale = quant * 2 + ((mquant < 0) ? 0 : v->halfpq);
if (dc_pred_dir) // left
ac_val -= 16;
else // top
ac_val -= 16 * s->block_wrap[n];
q1 = s->cur_pic.qscale_table[mb_pos];
if (dc_pred_dir && c_avail && mb_pos)
q2 = s->cur_pic.qscale_table[mb_pos - 1];
if (!dc_pred_dir && a_avail && mb_pos >= s->mb_stride)
q2 = s->cur_pic.qscale_table[mb_pos - s->mb_stride];
if (dc_pred_dir && n == 1)
q2 = q1;
if (!dc_pred_dir && n == 2)
q2 = q1;
if (n == 3)
q2 = q1;
if (coded) {
int last = 0, skip, value;
int k;
for (int i = 1; !last; ++i) {
int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, codingset);
if (ret < 0)
return ret;
i += skip;
if (i > 63)
break;
if (v->fcm == PROGRESSIVE)
block[v->zz_8x8[0][i]] = value;
else {
if (use_pred && (v->fcm == ILACE_FRAME)) {
if (!dc_pred_dir) // top
block[v->zz_8x8[2][i]] = value;
else // left
block[v->zz_8x8[3][i]] = value;
} else {
block[v->zzi_8x8[i]] = value;
}
}
}
/* apply AC prediction if needed */
if (use_pred) {
/* scale predictors if needed*/
q1 = ABS(q1) * 2 + ((q1 < 0) ? 0 : v->halfpq) - 1;
if (q1 < 1)
return (-1);
if (q2)
q2 = ABS(q2) * 2 + ((q2 < 0) ? 0 : v->halfpq) - 1;
if (q2 && q1 != q2) {
if (dc_pred_dir) { // left
for (k = 1; k < 8; k++)
block[k << v->left_blk_sh] +=
(int)(ac_val[k] * q2 * (unsigned)ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18;
} else { // top
for (k = 1; k < 8; k++)
block[k << v->top_blk_sh] +=
(int)(ac_val[k + 8] * q2 * (unsigned)ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18;
}
} else {
if (dc_pred_dir) { // left
for (k = 1; k < 8; k++)
block[k << v->left_blk_sh] += ac_val[k];
} else { // top
for (k = 1; k < 8; k++)
block[k << v->top_blk_sh] += ac_val[k + 8];
}
}
}
/* save AC coeffs for further prediction */
for (k = 1; k < 8; k++) {
ac_val2[k] = block[k << v->left_blk_sh];
ac_val2[k + 8] = block[k << v->top_blk_sh];
}
/* scale AC coeffs */
for (k = 1; k < 64; k++)
if (block[k]) {
block[k] *= scale;
if (!v->pquantizer)
block[k] += (block[k] < 0) ? -quant : quant;
}
} else { // no AC coeffs
int k;
memset(ac_val2, 0, 16 * 2);
if (dc_pred_dir) { // left
if (use_pred) {
memcpy(ac_val2, ac_val, 8 * 2);
q1 = ABS(q1) * 2 + ((q1 < 0) ? 0 : v->halfpq) - 1;
if (q1 < 1)
return (-1);
if (q2)
q2 = ABS(q2) * 2 + ((q2 < 0) ? 0 : v->halfpq) - 1;
if (q2 && q1 != q2) {
for (k = 1; k < 8; k++)
ac_val2[k] = (int)(ac_val2[k] * (unsigned)q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18;
}
}
} else { // top
if (use_pred) {
memcpy(ac_val2 + 8, ac_val + 8, 8 * 2);
q1 = ABS(q1) * 2 + ((q1 < 0) ? 0 : v->halfpq) - 1;
if (q1 < 1)
return (-1);
if (q2)
q2 = ABS(q2) * 2 + ((q2 < 0) ? 0 : v->halfpq) - 1;
if (q2 && q1 != q2) {
for (k = 1; k < 8; k++)
ac_val2[k + 8] = (int)(ac_val2[k + 8] * (unsigned)q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18;
}
}
}
/* apply AC prediction if needed */
if (use_pred) {
if (dc_pred_dir) { // left
for (k = 1; k < 8; k++) {
block[k << v->left_blk_sh] = ac_val2[k] * scale;
if (!v->pquantizer && block[k << v->left_blk_sh])
block[k << v->left_blk_sh] += (block[k << v->left_blk_sh] < 0) ? -quant : quant;
}
} else { // top
for (k = 1; k < 8; k++) {
block[k << v->top_blk_sh] = ac_val2[k + 8] * scale;
if (!v->pquantizer && block[k << v->top_blk_sh])
block[k << v->top_blk_sh] += (block[k << v->top_blk_sh] < 0) ? -quant : quant;
}
}
}
}
return 0;
}
/** Decode P block
*/
static int vc1_decode_p_block(VC1Context *v, int16 block[64], int n, int mquant, int ttmb, int first_block, uint8 *dst,
int linesize, int skip_block, int *ttmb_out) {
PictureState *s = &v->s;
Bits *const gb = &v->gb;
int i, j;
int subblkpat = 0;
int scale, off, idx, last, skip, value;
int ttblk = ttmb & 7;
int pat = 0;
int quant = ABS(mquant);
s->bdsp.clear_block(block);
if (ttmb == -1) {
ttblk = ff_vc1_ttblk_to_tt[v->tt_index][get_vlc2(gb, ff_vc1_ttblk_vlc[v->tt_index])];
}
if (ttblk == TT_4X4) {
subblkpat = ~(get_vlc2(gb, ff_vc1_subblkpat_vlc[v->tt_index]) + 1);
}
if ((ttblk != TT_8X8 && ttblk != TT_4X4) &&
((v->ttmbf || (ttmb != -1 && (ttmb & 8) && !first_block)) || (!v->res_rtm_flag && !first_block))) {
subblkpat = decode012(gb);
if (subblkpat)
subblkpat ^= 3; // swap decoded pattern bits
if (ttblk == TT_8X4_TOP || ttblk == TT_8X4_BOTTOM)
ttblk = TT_8X4;
if (ttblk == TT_4X8_RIGHT || ttblk == TT_4X8_LEFT)
ttblk = TT_4X8;
}
scale = quant * 2 + ((mquant < 0) ? 0 : v->halfpq);
// convert transforms like 8X4_TOP to generic TT and SUBBLKPAT
if (ttblk == TT_8X4_TOP || ttblk == TT_8X4_BOTTOM) {
subblkpat = 2 - (ttblk == TT_8X4_TOP);
ttblk = TT_8X4;
}
if (ttblk == TT_4X8_RIGHT || ttblk == TT_4X8_LEFT) {
subblkpat = 2 - (ttblk == TT_4X8_LEFT);
ttblk = TT_4X8;
}
switch (ttblk) {
case TT_8X8:
pat = 0xF;
i = 0;
last = 0;
while (!last) {
int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, v->codingset2);
if (ret < 0)
return ret;
i += skip;
if (i > 63)
break;
if (!v->fcm)
idx = v->zz_8x8[0][i++];
else
idx = v->zzi_8x8[i++];
block[idx] = value * scale;
if (!v->pquantizer)
block[idx] += (block[idx] < 0) ? -quant : quant;
}
if (!skip_block) {
if (i == 1)
v->vc1dsp.vc1_inv_trans_8x8_dc(dst, linesize, block);
else {
v->vc1dsp.vc1_inv_trans_8x8(block);
s->idsp.add_pixels_clamped(block, dst, linesize);
}
}
break;
case TT_4X4:
pat = ~subblkpat & 0xF;
for (j = 0; j < 4; j++) {
last = subblkpat & (1 << (3 - j));
i = 0;
off = (j & 1) * 4 + (j & 2) * 16;
while (!last) {
int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, v->codingset2);
if (ret < 0)
return ret;
i += skip;
if (i > 15)
break;
if (!v->fcm)
idx = ff_vc1_simple_progressive_4x4_zz[i++];
else
idx = ff_vc1_adv_interlaced_4x4_zz[i++];
block[idx + off] = value * scale;
if (!v->pquantizer)
block[idx + off] += (block[idx + off] < 0) ? -quant : quant;
}
if (!(subblkpat & (1 << (3 - j))) && !skip_block) {
if (i == 1)
v->vc1dsp.vc1_inv_trans_4x4_dc(dst + (j & 1) * 4 + (j & 2) * 2 * linesize, linesize, block + off);
else
v->vc1dsp.vc1_inv_trans_4x4(dst + (j & 1) * 4 + (j & 2) * 2 * linesize, linesize, block + off);
}
}
break;
case TT_8X4:
pat = ~((subblkpat & 2) * 6 + (subblkpat & 1) * 3) & 0xF;
for (j = 0; j < 2; j++) {
last = subblkpat & (1 << (1 - j));
i = 0;
off = j * 32;
while (!last) {
int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, v->codingset2);
if (ret < 0)
return ret;
i += skip;
if (i > 31)
break;
if (!v->fcm)
idx = v->zz_8x4[i++] + off;
else
idx = ff_vc1_adv_interlaced_8x4_zz[i++] + off;
block[idx] = value * scale;
if (!v->pquantizer)
block[idx] += (block[idx] < 0) ? -quant : quant;
}
if (!(subblkpat & (1 << (1 - j))) && !skip_block) {
if (i == 1)
v->vc1dsp.vc1_inv_trans_8x4_dc(dst + j * 4 * linesize, linesize, block + off);
else
v->vc1dsp.vc1_inv_trans_8x4(dst + j * 4 * linesize, linesize, block + off);
}
}
break;
case TT_4X8:
pat = ~(subblkpat * 5) & 0xF;
for (j = 0; j < 2; j++) {
last = subblkpat & (1 << (1 - j));
i = 0;
off = j * 4;
while (!last) {
int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, v->codingset2);
if (ret < 0)
return ret;
i += skip;
if (i > 31)
break;
if (!v->fcm)
idx = v->zz_4x8[i++] + off;
else
idx = ff_vc1_adv_interlaced_4x8_zz[i++] + off;
block[idx] = value * scale;
if (!v->pquantizer)
block[idx] += (block[idx] < 0) ? -quant : quant;
}
if (!(subblkpat & (1 << (1 - j))) && !skip_block) {
if (i == 1)
v->vc1dsp.vc1_inv_trans_4x8_dc(dst + j * 4, linesize, block + off);
else
v->vc1dsp.vc1_inv_trans_4x8(dst + j * 4, linesize, block + off);
}
}
break;
}
if (ttmb_out)
*ttmb_out |= ttblk << (n * 4);
return pat;
}
/** @} */ // Macroblock group
static const uint8 size_table[6] = {0, 2, 3, 4, 5, 8};
/** Decode one P-frame MB
*/
static int vc1_decode_p_mb(VC1Context *v) {
PictureState *s = &v->s;
Bits *const gb = &v->gb;
int i, j;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
int cbp; /* cbp decoding stuff */
int mqdiff, mquant; /* MB quantization */
int ttmb = v->ttfrm; /* MB Transform type */
int mb_has_coeffs = 1; /* last_flag */
int dmv_x, dmv_y; /* Differential MV components */
int index, index1; /* LUT indexes */
int val, sign; /* temp values */
int first_block = 1;
int dst_idx, off;
int skipped, fourmv;
int block_cbp = 0, pat, block_tt = 0, block_intra = 0;
int ret;
mquant = v->pq; /* lossy initialization */
if (v->mv_type_is_raw)
fourmv = get_bits1(gb);
else
fourmv = v->mv_type_mb_plane[mb_pos];
if (v->skip_is_raw)
skipped = get_bits1(gb);
else
skipped = v->s.mbskip_table[mb_pos];
if (!fourmv) { /* 1MV mode */
if (!skipped) {
GET_MVDATA(dmv_x, dmv_y);
if (s->mb_intra) {
s->cur_pic.motion_val[1][s->block_index[0]][0] = 0;
s->cur_pic.motion_val[1][s->block_index[0]][1] = 0;
}
s->cur_pic.mb_type[mb_pos] = s->mb_intra ? MB_TYPE_INTRA : MB_TYPE_16x16;
ff_vc1_pred_mv(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type, 0, 0);
/* FIXME Set DC val for inter block ? */
if (s->mb_intra && !mb_has_coeffs) {
GET_MQUANT();
s->ac_pred = get_bits1(gb);
cbp = 0;
} else if (mb_has_coeffs) {
if (s->mb_intra)
s->ac_pred = get_bits1(gb);
cbp = get_vlc2(gb, v->cbpcy_vlc);
GET_MQUANT();
} else {
mquant = v->pq;
cbp = 0;
}
s->cur_pic.qscale_table[mb_pos] = mquant;
if (!v->ttmbf && !s->mb_intra && mb_has_coeffs)
ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index]);
if (!s->mb_intra)
ff_vc1_mc_1mv(v, 0);
dst_idx = 0;
for (i = 0; i < 6; i++) {
s->dc_val[s->block_index[i]] = 0;
dst_idx += i >> 2;
val = ((cbp >> (5 - i)) & 1);
off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize);
v->mb_type[s->block_index[i]] = s->mb_intra;
if (s->mb_intra) {
/* check if prediction blocks A and C are available */
v->a_avail = v->c_avail = 0;
if (i == 2 || i == 3 || !s->first_slice_line)
v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]];
if (i == 1 || i == 3 || s->mb_x)
v->c_avail = v->mb_type[s->block_index[i] - 1];
ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant,
(i & 4) ? v->codingset2 : v->codingset);
if (ret < 0)
return ret;
if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[i]]);
if (v->rangeredfrm)
for (j = 0; j < 64; j++)
v->block[v->cur_blk_idx][block_map[i]][j] *= 2;
block_cbp |= 0xF << (i << 2);
block_intra |= 1 << i;
} else if (val) {
pat =
vc1_decode_p_block(v, v->block[v->cur_blk_idx][block_map[i]], i, mquant, ttmb, first_block,
s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize,
CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt);
if (pat < 0)
return pat;
block_cbp |= pat << (i << 2);
if (!v->ttmbf && ttmb < 8)
ttmb = -1;
first_block = 0;
}
}
} else { // skipped
s->mb_intra = 0;
for (i = 0; i < 6; i++) {
v->mb_type[s->block_index[i]] = 0;
s->dc_val[s->block_index[i]] = 0;
}
s->cur_pic.mb_type[mb_pos] = MB_TYPE_SKIP;
s->cur_pic.qscale_table[mb_pos] = 0;
ff_vc1_pred_mv(v, 0, 0, 0, 1, v->range_x, v->range_y, v->mb_type, 0, 0);
ff_vc1_mc_1mv(v, 0);
}
} else { // 4MV mode
if (!skipped /* unskipped MB */) {
int intra_count = 0, coded_inter = 0;
int is_intra[6], is_coded[6];
/* Get CBPCY */
cbp = get_vlc2(gb, v->cbpcy_vlc);
for (i = 0; i < 6; i++) {
val = ((cbp >> (5 - i)) & 1);
s->dc_val[s->block_index[i]] = 0;
s->mb_intra = 0;
if (i < 4) {
dmv_x = dmv_y = 0;
s->mb_intra = 0;
mb_has_coeffs = 0;
if (val) {
GET_MVDATA(dmv_x, dmv_y);
}
ff_vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type, 0, 0);
if (!s->mb_intra)
ff_vc1_mc_4mv_luma(v, i, 0, 0);
intra_count += s->mb_intra;
is_intra[i] = s->mb_intra;
is_coded[i] = mb_has_coeffs;
}
if (i & 4) {
is_intra[i] = (intra_count >= 3);
is_coded[i] = val;
}
if (i == 4)
ff_vc1_mc_4mv_chroma(v, 0);
v->mb_type[s->block_index[i]] = is_intra[i];
if (!coded_inter)
coded_inter = !is_intra[i] & is_coded[i];
}
// if there are no coded blocks then don't do anything more
dst_idx = 0;
if (!intra_count && !coded_inter)
goto end;
GET_MQUANT();
s->cur_pic.qscale_table[mb_pos] = mquant;
/* test if block is intra and has pred */
{
int intrapred = 0;
for (i = 0; i < 6; i++)
if (is_intra[i]) {
if (((!s->first_slice_line || (i == 2 || i == 3)) &&
v->mb_type[s->block_index[i] - s->block_wrap[i]]) ||
((s->mb_x || (i == 1 || i == 3)) && v->mb_type[s->block_index[i] - 1])) {
intrapred = 1;
break;
}
}
if (intrapred)
s->ac_pred = get_bits1(gb);
else
s->ac_pred = 0;
}
if (!v->ttmbf && coded_inter)
ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index]);
for (i = 0; i < 6; i++) {
dst_idx += i >> 2;
off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize);
s->mb_intra = is_intra[i];
if (is_intra[i]) {
/* check if prediction blocks A and C are available */
v->a_avail = v->c_avail = 0;
if (i == 2 || i == 3 || !s->first_slice_line)
v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]];
if (i == 1 || i == 3 || s->mb_x)
v->c_avail = v->mb_type[s->block_index[i] - 1];
ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, is_coded[i], mquant,
(i & 4) ? v->codingset2 : v->codingset);
if (ret < 0)
return ret;
if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[i]]);
if (v->rangeredfrm)
for (j = 0; j < 64; j++)
v->block[v->cur_blk_idx][block_map[i]][j] *= 2;
block_cbp |= 0xF << (i << 2);
block_intra |= 1 << i;
} else if (is_coded[i]) {
pat =
vc1_decode_p_block(v, v->block[v->cur_blk_idx][block_map[i]], i, mquant, ttmb, first_block,
s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize,
CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt);
if (pat < 0)
return pat;
block_cbp |= pat << (i << 2);
if (!v->ttmbf && ttmb < 8)
ttmb = -1;
first_block = 0;
}
}
} else { // skipped MB
s->mb_intra = 0;
s->cur_pic.qscale_table[mb_pos] = 0;
for (i = 0; i < 6; i++) {
v->mb_type[s->block_index[i]] = 0;
s->dc_val[s->block_index[i]] = 0;
}
for (i = 0; i < 4; i++) {
ff_vc1_pred_mv(v, i, 0, 0, 0, v->range_x, v->range_y, v->mb_type, 0, 0);
ff_vc1_mc_4mv_luma(v, i, 0, 0);
}
ff_vc1_mc_4mv_chroma(v, 0);
s->cur_pic.qscale_table[mb_pos] = 0;
}
}
end:
if (v->overlap && v->pq >= 9)
ff_vc1_p_overlap_filter(v);
vc1_put_blocks_clamped(v, 1);
v->cbp[s->mb_x] = block_cbp;
v->ttblk[s->mb_x] = block_tt;
v->is_intra[s->mb_x] = block_intra;
return 0;
}
/* Decode one macroblock in an interlaced frame p picture */
static int vc1_decode_p_mb_intfr(VC1Context *v) {
PictureState *s = &v->s;
Bits *const gb = &v->gb;
int i;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
int cbp = 0; /* cbp decoding stuff */
int mqdiff, mquant; /* MB quantization */
int ttmb = v->ttfrm; /* MB Transform type */
int mb_has_coeffs = 1; /* last_flag */
int dmv_x, dmv_y; /* Differential MV components */
int val; /* temp value */
int first_block = 1;
int dst_idx, off;
int skipped, fourmv = 0, twomv = 0;
int block_cbp = 0, pat, block_tt = 0;
int idx_mbmode = 0, mvbp;
int fieldtx;
int ret;
mquant = v->pq; /* Lossy initialization */
if (v->skip_is_raw)
skipped = get_bits1(gb);
else
skipped = v->s.mbskip_table[mb_pos];
if (!skipped) {
if (v->fourmvswitch)
idx_mbmode = get_vlc2(gb, v->mbmode_vlc); // try getting this done
else
idx_mbmode = get_vlc2(gb, v->mbmode_vlc); // in a single line
switch (ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][0]) {
/* store the motion vector type in a flag (useful later) */
case MV_PMODE_INTFR_4MV:
fourmv = 1;
v->blk_mv_type[s->block_index[0]] = 0;
v->blk_mv_type[s->block_index[1]] = 0;
v->blk_mv_type[s->block_index[2]] = 0;
v->blk_mv_type[s->block_index[3]] = 0;
break;
case MV_PMODE_INTFR_4MV_FIELD:
fourmv = 1;
v->blk_mv_type[s->block_index[0]] = 1;
v->blk_mv_type[s->block_index[1]] = 1;
v->blk_mv_type[s->block_index[2]] = 1;
v->blk_mv_type[s->block_index[3]] = 1;
break;
case MV_PMODE_INTFR_2MV_FIELD:
twomv = 1;
v->blk_mv_type[s->block_index[0]] = 1;
v->blk_mv_type[s->block_index[1]] = 1;
v->blk_mv_type[s->block_index[2]] = 1;
v->blk_mv_type[s->block_index[3]] = 1;
break;
case MV_PMODE_INTFR_1MV:
v->blk_mv_type[s->block_index[0]] = 0;
v->blk_mv_type[s->block_index[1]] = 0;
v->blk_mv_type[s->block_index[2]] = 0;
v->blk_mv_type[s->block_index[3]] = 0;
break;
}
if (ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][0] == MV_PMODE_INTFR_INTRA) { // intra MB
for (i = 0; i < 4; i++) {
s->cur_pic.motion_val[1][s->block_index[i]][0] = 0;
s->cur_pic.motion_val[1][s->block_index[i]][1] = 0;
}
v->is_intra[s->mb_x] = 0x3f; // Set the bitfield to all 1.
s->mb_intra = 1;
s->cur_pic.mb_type[mb_pos] = MB_TYPE_INTRA;
fieldtx = v->fieldtx_plane[mb_pos] = get_bits1(gb);
mb_has_coeffs = get_bits1(gb);
if (mb_has_coeffs)
cbp = 1 + get_vlc2(gb, v->cbpcy_vlc);
v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb);
GET_MQUANT();
s->cur_pic.qscale_table[mb_pos] = mquant;
/* Set DC scale - y and c use the same so we only set y */
s->y_dc_scale = ff_wmv3_dc_scale_table[ABS(mquant)];
dst_idx = 0;
for (i = 0; i < 6; i++) {
v->a_avail = v->c_avail = 0;
v->mb_type[s->block_index[i]] = 1;
s->dc_val[s->block_index[i]] = 0;
dst_idx += i >> 2;
val = ((cbp >> (5 - i)) & 1);
if (i == 2 || i == 3 || !s->first_slice_line)
v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]];
if (i == 1 || i == 3 || s->mb_x)
v->c_avail = v->mb_type[s->block_index[i] - 1];
ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant,
(i & 4) ? v->codingset2 : v->codingset);
if (ret < 0)
return ret;
if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[i]]);
block_cbp |= 0xf << (i << 2);
}
} else { // inter MB
mb_has_coeffs = ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][3];
if (mb_has_coeffs)
cbp = 1 + get_vlc2(gb, v->cbpcy_vlc);
if (ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][0] == MV_PMODE_INTFR_2MV_FIELD) {
v->twomvbp = get_vlc2(gb, v->twomvbp_vlc);
} else {
if ((ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][0] == MV_PMODE_INTFR_4MV) ||
(ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][0] == MV_PMODE_INTFR_4MV_FIELD)) {
v->fourmvbp = get_vlc2(gb, v->fourmvbp_vlc);
}
}
s->mb_intra = v->is_intra[s->mb_x] = 0;
for (i = 0; i < 6; i++)
v->mb_type[s->block_index[i]] = 0;
fieldtx = v->fieldtx_plane[mb_pos] = ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][1];
/* for all motion vector read MVDATA and motion compensate each block */
dst_idx = 0;
if (fourmv) {
mvbp = v->fourmvbp;
for (i = 0; i < 4; i++) {
dmv_x = dmv_y = 0;
if (mvbp & (8 >> i))
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
ff_vc1_pred_mv_intfr(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, 0);
ff_vc1_mc_4mv_luma(v, i, 0, 0);
}
ff_vc1_mc_4mv_chroma4(v, 0, 0, 0);
} else if (twomv) {
mvbp = v->twomvbp;
dmv_x = dmv_y = 0;
if (mvbp & 2) {
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
}
ff_vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 2, v->range_x, v->range_y, 0);
ff_vc1_mc_4mv_luma(v, 0, 0, 0);
ff_vc1_mc_4mv_luma(v, 1, 0, 0);
dmv_x = dmv_y = 0;
if (mvbp & 1) {
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
}
ff_vc1_pred_mv_intfr(v, 2, dmv_x, dmv_y, 2, v->range_x, v->range_y, 0);
ff_vc1_mc_4mv_luma(v, 2, 0, 0);
ff_vc1_mc_4mv_luma(v, 3, 0, 0);
ff_vc1_mc_4mv_chroma4(v, 0, 0, 0);
} else {
mvbp = ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][2];
dmv_x = dmv_y = 0;
if (mvbp) {
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
}
ff_vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, 0);
ff_vc1_mc_1mv(v, 0);
}
if (cbp)
GET_MQUANT(); // p. 227
s->cur_pic.qscale_table[mb_pos] = mquant;
if (!v->ttmbf && cbp)
ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index]);
for (i = 0; i < 6; i++) {
s->dc_val[s->block_index[i]] = 0;
dst_idx += i >> 2;
val = ((cbp >> (5 - i)) & 1);
if (!fieldtx)
off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize);
else
off = (i & 4) ? 0 : ((i & 1) * 8 + ((i > 1) * s->linesize));
if (val) {
pat =
vc1_decode_p_block(v, v->block[v->cur_blk_idx][block_map[i]], i, mquant, ttmb, first_block,
s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : (s->linesize << fieldtx),
CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt);
if (pat < 0)
return pat;
block_cbp |= pat << (i << 2);
if (!v->ttmbf && ttmb < 8)
ttmb = -1;
first_block = 0;
}
}
}
} else { // skipped
s->mb_intra = v->is_intra[s->mb_x] = 0;
for (i = 0; i < 6; i++) {
v->mb_type[s->block_index[i]] = 0;
s->dc_val[s->block_index[i]] = 0;
}
s->cur_pic.mb_type[mb_pos] = MB_TYPE_SKIP;
s->cur_pic.qscale_table[mb_pos] = 0;
v->blk_mv_type[s->block_index[0]] = 0;
v->blk_mv_type[s->block_index[1]] = 0;
v->blk_mv_type[s->block_index[2]] = 0;
v->blk_mv_type[s->block_index[3]] = 0;
ff_vc1_pred_mv_intfr(v, 0, 0, 0, 1, v->range_x, v->range_y, 0);
ff_vc1_mc_1mv(v, 0);
v->fieldtx_plane[mb_pos] = 0;
}
if (v->overlap && v->pq >= 9)
ff_vc1_p_overlap_filter(v);
vc1_put_blocks_clamped(v, 1);
v->cbp[s->mb_x] = block_cbp;
v->ttblk[s->mb_x] = block_tt;
return 0;
}
static int vc1_decode_p_mb_intfi(VC1Context *v) {
PictureState *s = &v->s;
Bits *const gb = &v->gb;
int i;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
int cbp = 0; /* cbp decoding stuff */
int mqdiff, mquant; /* MB quantization */
int ttmb = v->ttfrm; /* MB Transform type */
int mb_has_coeffs = 1; /* last_flag */
int dmv_x, dmv_y; /* Differential MV components */
int val; /* temp values */
int first_block = 1;
int dst_idx, off;
int pred_flag = 0;
int block_cbp = 0, pat, block_tt = 0;
int idx_mbmode = 0;
int ret;
mquant = v->pq; /* Lossy initialization */
idx_mbmode = get_vlc2(gb, v->mbmode_vlc);
if (idx_mbmode <= 1) { // intra MB
v->is_intra[s->mb_x] = 0x3f; // Set the bitfield to all 1.
s->mb_intra = 1;
s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][0] = 0;
s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][1] = 0;
s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA;
GET_MQUANT();
s->cur_pic.qscale_table[mb_pos] = mquant;
/* Set DC scale - y and c use the same so we only set y */
s->y_dc_scale = ff_wmv3_dc_scale_table[ABS(mquant)];
v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb);
mb_has_coeffs = idx_mbmode & 1;
if (mb_has_coeffs)
cbp = 1 + get_vlc2(gb, v->cbpcy_vlc);
dst_idx = 0;
for (i = 0; i < 6; i++) {
v->a_avail = v->c_avail = 0;
v->mb_type[s->block_index[i]] = 1;
s->dc_val[s->block_index[i]] = 0;
dst_idx += i >> 2;
val = ((cbp >> (5 - i)) & 1);
if (i == 2 || i == 3 || !s->first_slice_line)
v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]];
if (i == 1 || i == 3 || s->mb_x)
v->c_avail = v->mb_type[s->block_index[i] - 1];
ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant,
(i & 4) ? v->codingset2 : v->codingset);
if (ret < 0)
return ret;
if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[i]]);
block_cbp |= 0xf << (i << 2);
}
} else {
s->mb_intra = v->is_intra[s->mb_x] = 0;
s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_16x16;
for (i = 0; i < 6; i++)
v->mb_type[s->block_index[i]] = 0;
if (idx_mbmode <= 5) { // 1-MV
dmv_x = dmv_y = pred_flag = 0;
if (idx_mbmode & 1) {
get_mvdata_interlaced(v, &dmv_x, &dmv_y, &pred_flag);
}
ff_vc1_pred_mv(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type, pred_flag, 0);
ff_vc1_mc_1mv(v, 0);
mb_has_coeffs = !(idx_mbmode & 2);
} else { // 4-MV
v->fourmvbp = get_vlc2(gb, v->fourmvbp_vlc);
for (i = 0; i < 4; i++) {
dmv_x = dmv_y = pred_flag = 0;
if (v->fourmvbp & (8 >> i))
get_mvdata_interlaced(v, &dmv_x, &dmv_y, &pred_flag);
ff_vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type, pred_flag, 0);
ff_vc1_mc_4mv_luma(v, i, 0, 0);
}
ff_vc1_mc_4mv_chroma(v, 0);
mb_has_coeffs = idx_mbmode & 1;
}
if (mb_has_coeffs)
cbp = 1 + get_vlc2(gb, v->cbpcy_vlc);
if (cbp) {
GET_MQUANT();
}
s->cur_pic.qscale_table[mb_pos] = mquant;
if (!v->ttmbf && cbp) {
ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index]);
}
dst_idx = 0;
for (i = 0; i < 6; i++) {
s->dc_val[s->block_index[i]] = 0;
dst_idx += i >> 2;
val = ((cbp >> (5 - i)) & 1);
off = (i & 4) ? 0 : (i & 1) * 8 + (i & 2) * 4 * s->linesize;
if (val) {
pat = vc1_decode_p_block(v, v->block[v->cur_blk_idx][block_map[i]], i, mquant, ttmb, first_block,
s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize,
CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt);
if (pat < 0)
return pat;
block_cbp |= pat << (i << 2);
if (!v->ttmbf && ttmb < 8)
ttmb = -1;
first_block = 0;
}
}
}
if (v->overlap && v->pq >= 9)
ff_vc1_p_overlap_filter(v);
vc1_put_blocks_clamped(v, 1);
v->cbp[s->mb_x] = block_cbp;
v->ttblk[s->mb_x] = block_tt;
return 0;
}
/** Decode one B-frame MB (in Main profile)
*/
static int vc1_decode_b_mb(VC1Context *v) {
PictureState *s = &v->s;
Bits *const gb = &v->gb;
int i, j;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
int cbp = 0; /* cbp decoding stuff */
int mqdiff, mquant; /* MB quantization */
int ttmb = v->ttfrm; /* MB Transform type */
int mb_has_coeffs = 0; /* last_flag */
int index, index1; /* LUT indexes */
int val, sign; /* temp values */
int first_block = 1;
int dst_idx, off;
int skipped, direct;
int dmv_x[2], dmv_y[2];
int bmvtype = BMV_TYPE_BACKWARD;
int ret;
mquant = v->pq; /* lossy initialization */
s->mb_intra = 0;
if (v->dmb_is_raw)
direct = get_bits1(gb);
else
direct = v->direct_mb_plane[mb_pos];
if (v->skip_is_raw)
skipped = get_bits1(gb);
else
skipped = v->s.mbskip_table[mb_pos];
dmv_x[0] = dmv_x[1] = dmv_y[0] = dmv_y[1] = 0;
for (i = 0; i < 6; i++) {
v->mb_type[s->block_index[i]] = 0;
s->dc_val[s->block_index[i]] = 0;
}
s->cur_pic.qscale_table[mb_pos] = 0;
if (!direct) {
if (!skipped) {
GET_MVDATA(dmv_x[0], dmv_y[0]);
dmv_x[1] = dmv_x[0];
dmv_y[1] = dmv_y[0];
}
if (skipped || !s->mb_intra) {
bmvtype = decode012(gb);
switch (bmvtype) {
case 0:
bmvtype = (v->bfraction >= (B_FRACTION_DEN / 2)) ? BMV_TYPE_BACKWARD : BMV_TYPE_FORWARD;
break;
case 1:
bmvtype = (v->bfraction >= (B_FRACTION_DEN / 2)) ? BMV_TYPE_FORWARD : BMV_TYPE_BACKWARD;
break;
case 2:
bmvtype = BMV_TYPE_INTERPOLATED;
dmv_x[0] = dmv_y[0] = 0;
}
}
}
for (i = 0; i < 6; i++)
v->mb_type[s->block_index[i]] = s->mb_intra;
if (skipped) {
if (direct)
bmvtype = BMV_TYPE_INTERPOLATED;
ff_vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype);
vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype);
return 0;
}
if (direct) {
cbp = get_vlc2(gb, v->cbpcy_vlc);
GET_MQUANT();
s->mb_intra = 0;
s->cur_pic.qscale_table[mb_pos] = mquant;
if (!v->ttmbf)
ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index]);
dmv_x[0] = dmv_y[0] = dmv_x[1] = dmv_y[1] = 0;
ff_vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype);
vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype);
} else {
if (!mb_has_coeffs && !s->mb_intra) {
/* no coded blocks - effectively skipped */
ff_vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype);
vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype);
return 0;
}
if (s->mb_intra && !mb_has_coeffs) {
GET_MQUANT();
s->cur_pic.qscale_table[mb_pos] = mquant;
s->ac_pred = get_bits1(gb);
cbp = 0;
ff_vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype);
} else {
if (bmvtype == BMV_TYPE_INTERPOLATED) {
GET_MVDATA(dmv_x[0], dmv_y[0]);
if (!mb_has_coeffs) {
/* interpolated skipped block */
ff_vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype);
vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype);
return 0;
}
}
ff_vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype);
if (!s->mb_intra) {
vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype);
}
if (s->mb_intra)
s->ac_pred = get_bits1(gb);
cbp = get_vlc2(gb, v->cbpcy_vlc);
GET_MQUANT();
s->cur_pic.qscale_table[mb_pos] = mquant;
if (!v->ttmbf && !s->mb_intra && mb_has_coeffs)
ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index]);
}
}
dst_idx = 0;
for (i = 0; i < 6; i++) {
s->dc_val[s->block_index[i]] = 0;
dst_idx += i >> 2;
val = ((cbp >> (5 - i)) & 1);
off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize);
v->mb_type[s->block_index[i]] = s->mb_intra;
if (s->mb_intra) {
/* check if prediction blocks A and C are available */
v->a_avail = v->c_avail = 0;
if (i == 2 || i == 3 || !s->first_slice_line)
v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]];
if (i == 1 || i == 3 || s->mb_x)
v->c_avail = v->mb_type[s->block_index[i] - 1];
ret = vc1_decode_intra_block(v, v->blocks[i], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset);
if (ret < 0)
return ret;
if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(v->blocks[i]);
if (v->rangeredfrm)
for (j = 0; j < 64; j++)
v->blocks[i][j] *= 2;
s->idsp.put_signed_pixels_clamped(v->blocks[i], s->dest[dst_idx] + off,
i & 4 ? s->uvlinesize : s->linesize);
} else if (val) {
int pat = vc1_decode_p_block(v, v->blocks[i], i, mquant, ttmb, first_block, s->dest[dst_idx] + off,
(i & 4) ? s->uvlinesize : s->linesize,
CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), NULL);
if (pat < 0)
return pat;
if (!v->ttmbf && ttmb < 8)
ttmb = -1;
first_block = 0;
}
}
return 0;
}
/** Decode one B-frame MB (in interlaced field B picture)
*/
static int vc1_decode_b_mb_intfi(VC1Context *v) {
PictureState *s = &v->s;
Bits *const gb = &v->gb;
int i, j;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
int cbp = 0; /* cbp decoding stuff */
int mqdiff, mquant; /* MB quantization */
int ttmb = v->ttfrm; /* MB Transform type */
int mb_has_coeffs = 0; /* last_flag */
int val; /* temp value */
int first_block = 1;
int dst_idx, off;
int fwd;
int dmv_x[2], dmv_y[2], pred_flag[2];
int bmvtype = BMV_TYPE_BACKWARD;
int block_cbp = 0, pat, block_tt = 0;
int idx_mbmode;
int ret;
mquant = v->pq; /* Lossy initialization */
s->mb_intra = 0;
idx_mbmode = get_vlc2(gb, v->mbmode_vlc);
if (idx_mbmode <= 1) { // intra MB
v->is_intra[s->mb_x] = 0x3f; // Set the bitfield to all 1.
s->mb_intra = 1;
s->cur_pic.motion_val[1][s->block_index[0]][0] = 0;
s->cur_pic.motion_val[1][s->block_index[0]][1] = 0;
s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA;
GET_MQUANT();
s->cur_pic.qscale_table[mb_pos] = mquant;
/* Set DC scale - y and c use the same so we only set y */
s->y_dc_scale = ff_wmv3_dc_scale_table[ABS(mquant)];
v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb);
mb_has_coeffs = idx_mbmode & 1;
if (mb_has_coeffs)
cbp = 1 + get_vlc2(gb, v->cbpcy_vlc);
dst_idx = 0;
for (i = 0; i < 6; i++) {
v->a_avail = v->c_avail = 0;
v->mb_type[s->block_index[i]] = 1;
s->dc_val[s->block_index[i]] = 0;
dst_idx += i >> 2;
val = ((cbp >> (5 - i)) & 1);
if (i == 2 || i == 3 || !s->first_slice_line)
v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]];
if (i == 1 || i == 3 || s->mb_x)
v->c_avail = v->mb_type[s->block_index[i] - 1];
ret = vc1_decode_intra_block(v, v->blocks[i], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset);
if (ret < 0)
return ret;
if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(v->blocks[i]);
if (v->rangeredfrm)
for (j = 0; j < 64; j++)
v->blocks[i][j] <<= 1;
off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize);
s->idsp.put_signed_pixels_clamped(v->blocks[i], s->dest[dst_idx] + off,
(i & 4) ? s->uvlinesize : s->linesize);
}
} else {
s->mb_intra = v->is_intra[s->mb_x] = 0;
s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_16x16;
for (i = 0; i < 6; i++)
v->mb_type[s->block_index[i]] = 0;
if (v->fmb_is_raw)
fwd = v->forward_mb_plane[mb_pos] = get_bits1(gb);
else
fwd = v->forward_mb_plane[mb_pos];
if (idx_mbmode <= 5) { // 1-MV
int interpmvp = 0;
dmv_x[0] = dmv_x[1] = dmv_y[0] = dmv_y[1] = 0;
pred_flag[0] = pred_flag[1] = 0;
if (fwd)
bmvtype = BMV_TYPE_FORWARD;
else {
bmvtype = decode012(gb);
switch (bmvtype) {
case 0:
bmvtype = BMV_TYPE_BACKWARD;
break;
case 1:
bmvtype = BMV_TYPE_DIRECT;
break;
case 2:
bmvtype = BMV_TYPE_INTERPOLATED;
interpmvp = get_bits1(gb);
}
}
v->bmvtype = bmvtype;
if (bmvtype != BMV_TYPE_DIRECT && idx_mbmode & 1) {
get_mvdata_interlaced(v, &dmv_x[bmvtype == BMV_TYPE_BACKWARD], &dmv_y[bmvtype == BMV_TYPE_BACKWARD],
&pred_flag[bmvtype == BMV_TYPE_BACKWARD]);
}
if (interpmvp) {
get_mvdata_interlaced(v, &dmv_x[1], &dmv_y[1], &pred_flag[1]);
}
if (bmvtype == BMV_TYPE_DIRECT) {
dmv_x[0] = dmv_y[0] = pred_flag[0] = 0;
dmv_x[1] = dmv_y[1] = pred_flag[0] = 0;
if (!s->next_pic.ptr->field_picture) {
warning("Mixed field/frame direct mode not supported\n");
return (-1);
}
}
ff_vc1_pred_b_mv_intfi(v, 0, dmv_x, dmv_y, 1, pred_flag);
vc1_b_mc(v, dmv_x, dmv_y, (bmvtype == BMV_TYPE_DIRECT), bmvtype);
mb_has_coeffs = !(idx_mbmode & 2);
} else { // 4-MV
if (fwd)
bmvtype = BMV_TYPE_FORWARD;
v->bmvtype = bmvtype;
v->fourmvbp = get_vlc2(gb, v->fourmvbp_vlc);
for (i = 0; i < 4; i++) {
dmv_x[0] = dmv_y[0] = pred_flag[0] = 0;
dmv_x[1] = dmv_y[1] = pred_flag[1] = 0;
if (v->fourmvbp & (8 >> i)) {
get_mvdata_interlaced(v, &dmv_x[bmvtype == BMV_TYPE_BACKWARD], &dmv_y[bmvtype == BMV_TYPE_BACKWARD],
&pred_flag[bmvtype == BMV_TYPE_BACKWARD]);
}
ff_vc1_pred_b_mv_intfi(v, i, dmv_x, dmv_y, 0, pred_flag);
ff_vc1_mc_4mv_luma(v, i, bmvtype == BMV_TYPE_BACKWARD, 0);
}
ff_vc1_mc_4mv_chroma(v, bmvtype == BMV_TYPE_BACKWARD);
mb_has_coeffs = idx_mbmode & 1;
}
if (mb_has_coeffs)
cbp = 1 + get_vlc2(gb, v->cbpcy_vlc);
if (cbp) {
GET_MQUANT();
}
s->cur_pic.qscale_table[mb_pos] = mquant;
if (!v->ttmbf && cbp) {
ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index]);
}
dst_idx = 0;
for (i = 0; i < 6; i++) {
s->dc_val[s->block_index[i]] = 0;
dst_idx += i >> 2;
val = ((cbp >> (5 - i)) & 1);
off = (i & 4) ? 0 : (i & 1) * 8 + (i & 2) * 4 * s->linesize;
if (val) {
pat = vc1_decode_p_block(v, v->blocks[i], i, mquant, ttmb, first_block, s->dest[dst_idx] + off,
(i & 4) ? s->uvlinesize : s->linesize,
CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt);
if (pat < 0)
return pat;
block_cbp |= pat << (i << 2);
if (!v->ttmbf && ttmb < 8)
ttmb = -1;
first_block = 0;
}
}
}
v->cbp[s->mb_x] = block_cbp;
v->ttblk[s->mb_x] = block_tt;
return 0;
}
/** Decode one B-frame MB (in interlaced frame B picture)
*/
static int vc1_decode_b_mb_intfr(VC1Context *v) {
PictureState *s = &v->s;
Bits *const gb = &v->gb;
int i, j;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
int cbp = 0; /* cbp decoding stuff */
int mqdiff, mquant; /* MB quantization */
int ttmb = v->ttfrm; /* MB Transform type */
int mvsw = 0; /* motion vector switch */
int mb_has_coeffs = 1; /* last_flag */
int dmv_x, dmv_y; /* Differential MV components */
int val; /* temp value */
int first_block = 1;
int dst_idx, off;
int skipped, direct, twomv = 0;
int block_cbp = 0, pat, block_tt = 0;
int idx_mbmode = 0, mvbp;
int stride_y, fieldtx;
int bmvtype = BMV_TYPE_BACKWARD;
int dir, dir2;
int ret;
mquant = v->pq; /* Lossy initialization */
s->mb_intra = 0;
if (v->skip_is_raw)
skipped = get_bits1(gb);
else
skipped = v->s.mbskip_table[mb_pos];
if (!skipped) {
idx_mbmode = get_vlc2(gb, v->mbmode_vlc);
if (ff_vc1_mbmode_intfrp[0][idx_mbmode][0] == MV_PMODE_INTFR_2MV_FIELD) {
twomv = 1;
v->blk_mv_type[s->block_index[0]] = 1;
v->blk_mv_type[s->block_index[1]] = 1;
v->blk_mv_type[s->block_index[2]] = 1;
v->blk_mv_type[s->block_index[3]] = 1;
} else {
v->blk_mv_type[s->block_index[0]] = 0;
v->blk_mv_type[s->block_index[1]] = 0;
v->blk_mv_type[s->block_index[2]] = 0;
v->blk_mv_type[s->block_index[3]] = 0;
}
}
if (ff_vc1_mbmode_intfrp[0][idx_mbmode][0] == MV_PMODE_INTFR_INTRA) { // intra MB
for (i = 0; i < 4; i++) {
s->mv[0][i][0] = s->cur_pic.motion_val[0][s->block_index[i]][0] = 0;
s->mv[0][i][1] = s->cur_pic.motion_val[0][s->block_index[i]][1] = 0;
s->mv[1][i][0] = s->cur_pic.motion_val[1][s->block_index[i]][0] = 0;
s->mv[1][i][1] = s->cur_pic.motion_val[1][s->block_index[i]][1] = 0;
}
v->is_intra[s->mb_x] = 0x3f; // Set the bitfield to all 1.
s->mb_intra = 1;
s->cur_pic.mb_type[mb_pos] = MB_TYPE_INTRA;
fieldtx = v->fieldtx_plane[mb_pos] = get_bits1(gb);
mb_has_coeffs = get_bits1(gb);
if (mb_has_coeffs)
cbp = 1 + get_vlc2(gb, v->cbpcy_vlc);
v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb);
GET_MQUANT();
s->cur_pic.qscale_table[mb_pos] = mquant;
/* Set DC scale - y and c use the same so we only set y */
s->y_dc_scale = ff_wmv3_dc_scale_table[ABS(mquant)];
dst_idx = 0;
for (i = 0; i < 6; i++) {
v->a_avail = v->c_avail = 0;
v->mb_type[s->block_index[i]] = 1;
s->dc_val[s->block_index[i]] = 0;
dst_idx += i >> 2;
val = ((cbp >> (5 - i)) & 1);
if (i == 2 || i == 3 || !s->first_slice_line)
v->a_avail = v->mb_type[s->block_index[i] - s->block_wrap[i]];
if (i == 1 || i == 3 || s->mb_x)
v->c_avail = v->mb_type[s->block_index[i] - 1];
ret = vc1_decode_intra_block(v, v->blocks[i], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset);
if (ret < 0)
return ret;
if (CONFIG_GRAY && i > 3 && (s->avctx->flags & AV_CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(v->blocks[i]);
if (i < 4) {
stride_y = s->linesize << fieldtx;
off =
(fieldtx) ? ((i & 1) * 8) + ((i & 2) >> 1) * s->linesize : (i & 1) * 8 + 4 * (i & 2) * s->linesize;
} else {
stride_y = s->uvlinesize;
off = 0;
}
s->idsp.put_signed_pixels_clamped(v->blocks[i], s->dest[dst_idx] + off, stride_y);
}
} else {
s->mb_intra = v->is_intra[s->mb_x] = 0;
if (v->dmb_is_raw)
direct = get_bits1(gb);
else
direct = v->direct_mb_plane[mb_pos];
if (direct) {
if (s->next_pic.ptr->field_picture)
warning("Mixed frame/field direct mode not supported\n");
s->mv[0][0][0] = s->cur_pic.motion_val[0][s->block_index[0]][0] =
scale_mv(s->next_pic.motion_val[1][s->block_index[0]][0], v->bfraction, 0, s->quarter_sample);
s->mv[0][0][1] = s->cur_pic.motion_val[0][s->block_index[0]][1] =
scale_mv(s->next_pic.motion_val[1][s->block_index[0]][1], v->bfraction, 0, s->quarter_sample);
s->mv[1][0][0] = s->cur_pic.motion_val[1][s->block_index[0]][0] =
scale_mv(s->next_pic.motion_val[1][s->block_index[0]][0], v->bfraction, 1, s->quarter_sample);
s->mv[1][0][1] = s->cur_pic.motion_val[1][s->block_index[0]][1] =
scale_mv(s->next_pic.motion_val[1][s->block_index[0]][1], v->bfraction, 1, s->quarter_sample);
if (twomv) {
s->mv[0][2][0] = s->cur_pic.motion_val[0][s->block_index[2]][0] =
scale_mv(s->next_pic.motion_val[1][s->block_index[2]][0], v->bfraction, 0, s->quarter_sample);
s->mv[0][2][1] = s->cur_pic.motion_val[0][s->block_index[2]][1] =
scale_mv(s->next_pic.motion_val[1][s->block_index[2]][1], v->bfraction, 0, s->quarter_sample);
s->mv[1][2][0] = s->cur_pic.motion_val[1][s->block_index[2]][0] =
scale_mv(s->next_pic.motion_val[1][s->block_index[2]][0], v->bfraction, 1, s->quarter_sample);
s->mv[1][2][1] = s->cur_pic.motion_val[1][s->block_index[2]][1] =
scale_mv(s->next_pic.motion_val[1][s->block_index[2]][1], v->bfraction, 1, s->quarter_sample);
for (i = 1; i < 4; i += 2) {
s->mv[0][i][0] = s->cur_pic.motion_val[0][s->block_index[i]][0] = s->mv[0][i - 1][0];
s->mv[0][i][1] = s->cur_pic.motion_val[0][s->block_index[i]][1] = s->mv[0][i - 1][1];
s->mv[1][i][0] = s->cur_pic.motion_val[1][s->block_index[i]][0] = s->mv[1][i - 1][0];
s->mv[1][i][1] = s->cur_pic.motion_val[1][s->block_index[i]][1] = s->mv[1][i - 1][1];
}
} else {
for (i = 1; i < 4; i++) {
s->mv[0][i][0] = s->cur_pic.motion_val[0][s->block_index[i]][0] = s->mv[0][0][0];
s->mv[0][i][1] = s->cur_pic.motion_val[0][s->block_index[i]][1] = s->mv[0][0][1];
s->mv[1][i][0] = s->cur_pic.motion_val[1][s->block_index[i]][0] = s->mv[1][0][0];
s->mv[1][i][1] = s->cur_pic.motion_val[1][s->block_index[i]][1] = s->mv[1][0][1];
}
}
}
if (!direct) {
if (skipped || !s->mb_intra) {
bmvtype = decode012(gb);
switch (bmvtype) {
case 0:
bmvtype = (v->bfraction >= (B_FRACTION_DEN / 2)) ? BMV_TYPE_BACKWARD : BMV_TYPE_FORWARD;
break;
case 1:
bmvtype = (v->bfraction >= (B_FRACTION_DEN / 2)) ? BMV_TYPE_FORWARD : BMV_TYPE_BACKWARD;
break;
case 2:
bmvtype = BMV_TYPE_INTERPOLATED;
}
}
if (twomv && bmvtype != BMV_TYPE_INTERPOLATED)
mvsw = get_bits1(gb);
}
if (!skipped) { // inter MB
mb_has_coeffs = ff_vc1_mbmode_intfrp[0][idx_mbmode][3];
if (mb_has_coeffs)
cbp = 1 + get_vlc2(gb, v->cbpcy_vlc);
if (!direct) {
if (bmvtype == BMV_TYPE_INTERPOLATED && twomv) {
v->fourmvbp = get_vlc2(gb, v->fourmvbp_vlc);
} else if (bmvtype == BMV_TYPE_INTERPOLATED || twomv) {
v->twomvbp = get_vlc2(gb, v->twomvbp_vlc);
}
}
for (i = 0; i < 6; i++)
v->mb_type[s->block_index[i]] = 0;
fieldtx = v->fieldtx_plane[mb_pos] = ff_vc1_mbmode_intfrp[0][idx_mbmode][1];
/* for all motion vector read MVDATA and motion compensate each block */
dst_idx = 0;
if (direct) {
if (twomv) {
for (i = 0; i < 4; i++) {
ff_vc1_mc_4mv_luma(v, i, 0, 0);
ff_vc1_mc_4mv_luma(v, i, 1, 1);
}
ff_vc1_mc_4mv_chroma4(v, 0, 0, 0);
ff_vc1_mc_4mv_chroma4(v, 1, 1, 1);
} else {
ff_vc1_mc_1mv(v, 0);
ff_vc1_interp_mc(v);
}
} else if (twomv && bmvtype == BMV_TYPE_INTERPOLATED) {
mvbp = v->fourmvbp;
for (i = 0; i < 4; i++) {
dir = i == 1 || i == 3;
dmv_x = dmv_y = 0;
val = ((mvbp >> (3 - i)) & 1);
if (val)
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
j = i > 1 ? 2 : 0;
ff_vc1_pred_mv_intfr(v, j, dmv_x, dmv_y, 2, v->range_x, v->range_y, dir);
ff_vc1_mc_4mv_luma(v, j, dir, dir);
ff_vc1_mc_4mv_luma(v, j + 1, dir, dir);
}
ff_vc1_mc_4mv_chroma4(v, 0, 0, 0);
ff_vc1_mc_4mv_chroma4(v, 1, 1, 1);
} else if (bmvtype == BMV_TYPE_INTERPOLATED) {
mvbp = v->twomvbp;
dmv_x = dmv_y = 0;
if (mvbp & 2)
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
ff_vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, 0);
ff_vc1_mc_1mv(v, 0);
dmv_x = dmv_y = 0;
if (mvbp & 1)
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
ff_vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, 1);
ff_vc1_interp_mc(v);
} else if (twomv) {
dir = bmvtype == BMV_TYPE_BACKWARD;
dir2 = dir;
if (mvsw)
dir2 = !dir;
mvbp = v->twomvbp;
dmv_x = dmv_y = 0;
if (mvbp & 2)
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
ff_vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 2, v->range_x, v->range_y, dir);
dmv_x = dmv_y = 0;
if (mvbp & 1)
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
ff_vc1_pred_mv_intfr(v, 2, dmv_x, dmv_y, 2, v->range_x, v->range_y, dir2);
if (mvsw) {
for (i = 0; i < 2; i++) {
s->mv[dir][i + 2][0] = s->mv[dir][i][0] = s->cur_pic.motion_val[dir][s->block_index[i + 2]][0] =
s->cur_pic.motion_val[dir][s->block_index[i]][0];
s->mv[dir][i + 2][1] = s->mv[dir][i][1] = s->cur_pic.motion_val[dir][s->block_index[i + 2]][1] =
s->cur_pic.motion_val[dir][s->block_index[i]][1];
s->mv[dir2][i + 2][0] = s->mv[dir2][i][0] = s->cur_pic.motion_val[dir2][s->block_index[i]][0] =
s->cur_pic.motion_val[dir2][s->block_index[i + 2]][0];
s->mv[dir2][i + 2][1] = s->mv[dir2][i][1] = s->cur_pic.motion_val[dir2][s->block_index[i]][1] =
s->cur_pic.motion_val[dir2][s->block_index[i + 2]][1];
}
} else {
ff_vc1_pred_mv_intfr(v, 0, 0, 0, 2, v->range_x, v->range_y, !dir);
ff_vc1_pred_mv_intfr(v, 2, 0, 0, 2, v->range_x, v->range_y, !dir);
}
ff_vc1_mc_4mv_luma(v, 0, dir, 0);
ff_vc1_mc_4mv_luma(v, 1, dir, 0);
ff_vc1_mc_4mv_luma(v, 2, dir2, 0);
ff_vc1_mc_4mv_luma(v, 3, dir2, 0);
ff_vc1_mc_4mv_chroma4(v, dir, dir2, 0);
} else {
dir = bmvtype == BMV_TYPE_BACKWARD;
mvbp = ff_vc1_mbmode_intfrp[0][idx_mbmode][2];
dmv_x = dmv_y = 0;
if (mvbp)
get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
ff_vc1_pred_mv_intfr(v, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, dir);
v->blk_mv_type[s->block_index[0]] = 1;
v->blk_mv_type[s->block_index[1]] = 1;
v->blk_mv_type[s->block_index[2]] = 1;
v->blk_mv_type[s->block_index[3]] = 1;
ff_vc1_pred_mv_intfr(v, 0, 0, 0, 2, v->range_x, v->range_y, !dir);
for (i = 0; i < 2; i++) {
s->mv[!dir][i + 2][0] = s->mv[!dir][i][0] = s->cur_pic.motion_val[!dir][s->block_index[i + 2]][0] =
s->cur_pic.motion_val[!dir][s->block_index[i]][0];
s->mv[!dir][i + 2][1] = s->mv[!dir][i][1] = s->cur_pic.motion_val[!dir][s->block_index[i + 2]][1] =
s->cur_pic.motion_val[!dir][s->block_index[i]][1];
}
ff_vc1_mc_1mv(v, dir);
}
if (cbp)
GET_MQUANT(); // p. 227
s->cur_pic.qscale_table[mb_pos] = mquant;
if (!v->ttmbf && cbp)
ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index]);
for (i = 0; i < 6; i++) {
s->dc_val[s->block_index[i]] = 0;
dst_idx += i >> 2;
val = ((cbp >> (5 - i)) & 1);
if (!fieldtx)
off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize);
else
off = (i & 4) ? 0 : ((i & 1) * 8 + ((i > 1) * s->linesize));
if (val) {
pat =
vc1_decode_p_block(v, v->blocks[i], i, mquant, ttmb, first_block, s->dest[dst_idx] + off,
(i & 4) ? s->uvlinesize : (s->linesize << fieldtx),
CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt);
if (pat < 0)
return pat;
block_cbp |= pat << (i << 2);
if (!v->ttmbf && ttmb < 8)
ttmb = -1;
first_block = 0;
}
}
} else { // skipped
dir = 0;
for (i = 0; i < 6; i++) {
v->mb_type[s->block_index[i]] = 0;
s->dc_val[s->block_index[i]] = 0;
}
s->cur_pic.mb_type[mb_pos] = MB_TYPE_SKIP;
s->cur_pic.qscale_table[mb_pos] = 0;
v->blk_mv_type[s->block_index[0]] = 0;
v->blk_mv_type[s->block_index[1]] = 0;
v->blk_mv_type[s->block_index[2]] = 0;
v->blk_mv_type[s->block_index[3]] = 0;
if (!direct) {
if (bmvtype == BMV_TYPE_INTERPOLATED) {
ff_vc1_pred_mv_intfr(v, 0, 0, 0, 1, v->range_x, v->range_y, 0);
ff_vc1_pred_mv_intfr(v, 0, 0, 0, 1, v->range_x, v->range_y, 1);
} else {
dir = bmvtype == BMV_TYPE_BACKWARD;
ff_vc1_pred_mv_intfr(v, 0, 0, 0, 1, v->range_x, v->range_y, dir);
if (mvsw) {
int dir2 = dir;
if (mvsw)
dir2 = !dir;
for (i = 0; i < 2; i++) {
s->mv[dir][i + 2][0] = s->mv[dir][i][0] =
s->cur_pic.motion_val[dir][s->block_index[i + 2]][0] =
s->cur_pic.motion_val[dir][s->block_index[i]][0];
s->mv[dir][i + 2][1] = s->mv[dir][i][1] =
s->cur_pic.motion_val[dir][s->block_index[i + 2]][1] =
s->cur_pic.motion_val[dir][s->block_index[i]][1];
s->mv[dir2][i + 2][0] = s->mv[dir2][i][0] =
s->cur_pic.motion_val[dir2][s->block_index[i]][0] =
s->cur_pic.motion_val[dir2][s->block_index[i + 2]][0];
s->mv[dir2][i + 2][1] = s->mv[dir2][i][1] =
s->cur_pic.motion_val[dir2][s->block_index[i]][1] =
s->cur_pic.motion_val[dir2][s->block_index[i + 2]][1];
}
} else {
v->blk_mv_type[s->block_index[0]] = 1;
v->blk_mv_type[s->block_index[1]] = 1;
v->blk_mv_type[s->block_index[2]] = 1;
v->blk_mv_type[s->block_index[3]] = 1;
ff_vc1_pred_mv_intfr(v, 0, 0, 0, 2, v->range_x, v->range_y, !dir);
for (i = 0; i < 2; i++) {
s->mv[!dir][i + 2][0] = s->mv[!dir][i][0] =
s->cur_pic.motion_val[!dir][s->block_index[i + 2]][0] =
s->cur_pic.motion_val[!dir][s->block_index[i]][0];
s->mv[!dir][i + 2][1] = s->mv[!dir][i][1] =
s->cur_pic.motion_val[!dir][s->block_index[i + 2]][1] =
s->cur_pic.motion_val[!dir][s->block_index[i]][1];
}
}
}
}
ff_vc1_mc_1mv(v, dir);
if (direct || bmvtype == BMV_TYPE_INTERPOLATED) {
ff_vc1_interp_mc(v);
}
v->fieldtx_plane[mb_pos] = 0;
}
}
v->cbp[s->mb_x] = block_cbp;
v->ttblk[s->mb_x] = block_tt;
return 0;
}
/** Decode blocks of I-frame
*/
static void vc1_decode_i_blocks(VC1Context *v) {
int k, j;
PictureState *s = &v->s;
int cbp, val;
int mb_pos;
/* select coding mode used for VLC tables selection */
switch (v->y_ac_table_index) {
case 0:
v->codingset = (v->pqindex <= 8) ? CS_HIGH_RATE_INTRA : CS_LOW_MOT_INTRA;
break;
case 1:
v->codingset = CS_HIGH_MOT_INTRA;
break;
case 2:
v->codingset = CS_MID_RATE_INTRA;
break;
}
switch (v->c_ac_table_index) {
case 0:
v->codingset2 = (v->pqindex <= 8) ? CS_HIGH_RATE_INTER : CS_LOW_MOT_INTER;
break;
case 1:
v->codingset2 = CS_HIGH_MOT_INTER;
break;
case 2:
v->codingset2 = CS_MID_RATE_INTER;
break;
}
/* Set DC scale - y and c use the same so we only set y */
s->y_dc_scale = ff_wmv3_dc_scale_table[v->pq];
// do frame decode
s->mb_x = s->mb_y = 0;
s->mb_intra = 1;
s->first_slice_line = 1;
for (s->mb_y = s->start_mb_y; s->mb_y < s->end_mb_y; s->mb_y++) {
s->mb_x = 0;
init_block_index(v);
for (; s->mb_x < v->end_mb_x; s->mb_x++) {
update_block_index(s);
s->bdsp.clear_blocks(v->block[v->cur_blk_idx][0]);
mb_pos = s->mb_x + s->mb_y * s->mb_width;
s->cur_pic.mb_type[mb_pos] = MB_TYPE_INTRA;
s->cur_pic.qscale_table[mb_pos] = v->pq;
for (int i = 0; i < 4; i++) {
s->cur_pic.motion_val[1][s->block_index[i]][0] = 0;
s->cur_pic.motion_val[1][s->block_index[i]][1] = 0;
}
// do actual MB decoding and displaying
cbp = get_vlc2(&v->gb, ff_msmp4_mb_i_vlc);
v->s.ac_pred = get_bits1(&v->gb);
for (k = 0; k < 6; k++) {
v->mb_type[s->block_index[k]] = 1;
val = ((cbp >> (5 - k)) & 1);
if (k < 4)
val = vc1_coded_block_pred(&v->s, k, val);
cbp |= val << (5 - k);
vc1_decode_i_block(v, v->block[v->cur_blk_idx][block_map[k]], k, val,
(k < 4) ? v->codingset : v->codingset2);
if (CONFIG_GRAY && k > 3 && (s->avctx->flags & AV_CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[k]]);
}
if (v->overlap && v->pq >= 9) {
ff_vc1_i_overlap_filter(v);
if (v->rangeredfrm)
for (k = 0; k < 6; k++)
for (j = 0; j < 64; j++)
v->block[v->cur_blk_idx][block_map[k]][j] *= 2;
vc1_put_blocks_clamped(v, 1);
} else {
if (v->rangeredfrm)
for (k = 0; k < 6; k++)
for (j = 0; j < 64; j++)
v->block[v->cur_blk_idx][block_map[k]][j] =
(v->block[v->cur_blk_idx][block_map[k]][j] - 64) * 2;
vc1_put_blocks_clamped(v, 0);
}
if (v->loop_filter)
ff_vc1_i_loop_filter(v);
if (get_bits_left(&v->gb) < 0) {
ff_er_add_slice(&s->er, 0, 0, s->mb_x, s->mb_y, ER_MB_ERROR);
warning("Bits overconsumption: %i > %i\n", get_bits_count(&v->gb), v->gb.size_in_bits);
return;
}
v->topleft_blk_idx = (v->topleft_blk_idx + 1) % (v->end_mb_x + 2);
v->top_blk_idx = (v->top_blk_idx + 1) % (v->end_mb_x + 2);
v->left_blk_idx = (v->left_blk_idx + 1) % (v->end_mb_x + 2);
v->cur_blk_idx = (v->cur_blk_idx + 1) % (v->end_mb_x + 2);
}
s->first_slice_line = 0;
}
/* This is intentionally mb_height and not end_mb_y - unlike in advanced
* profile, these only differ are when decoding MSS2 rectangles. */
ff_er_add_slice(&s->er, 0, 0, s->mb_width - 1, s->mb_height - 1, ER_MB_END);
}
/** Decode blocks of I-frame for advanced profile
*/
static int vc1_decode_i_blocks_adv(VC1Context *v) {
int k;
PictureState *s = &v->s;
Bits *const gb = &v->gb;
int cbp, val;
int mb_pos;
int mquant;
int mqdiff;
if (get_bits_left(gb) <= 1)
return (-1);
/* select coding mode used for VLC tables selection */
switch (v->y_ac_table_index) {
case 0:
v->codingset = (v->pqindex <= 8) ? CS_HIGH_RATE_INTRA : CS_LOW_MOT_INTRA;
break;
case 1:
v->codingset = CS_HIGH_MOT_INTRA;
break;
case 2:
v->codingset = CS_MID_RATE_INTRA;
break;
}
switch (v->c_ac_table_index) {
case 0:
v->codingset2 = (v->pqindex <= 8) ? CS_HIGH_RATE_INTER : CS_LOW_MOT_INTER;
break;
case 1:
v->codingset2 = CS_HIGH_MOT_INTER;
break;
case 2:
v->codingset2 = CS_MID_RATE_INTER;
break;
}
// do frame decode
s->mb_intra = 1;
s->first_slice_line = 1;
s->mb_x = 0;
s->mb_y = s->start_mb_y;
if (s->start_mb_y) {
memset(&s->coded_block[(2 * s->mb_y - 1) * s->b8_stride - 2], 0, (1 + s->b8_stride) * sizeof(*s->coded_block));
}
for (; s->mb_y < s->end_mb_y; s->mb_y++) {
s->mb_x = 0;
init_block_index(v);
for (; s->mb_x < s->mb_width; s->mb_x++) {
mquant = v->pq;
update_block_index(s);
s->bdsp.clear_blocks(v->block[v->cur_blk_idx][0]);
mb_pos = s->mb_x + s->mb_y * s->mb_stride;
s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA;
for (int i = 0; i < 4; i++) {
s->cur_pic.motion_val[1][s->block_index[i] + v->blocks_off][0] = 0;
s->cur_pic.motion_val[1][s->block_index[i] + v->blocks_off][1] = 0;
}
// do actual MB decoding and displaying
if (v->fieldtx_is_raw)
v->fieldtx_plane[mb_pos] = get_bits1(gb);
if (get_bits_left(gb) <= 1) {
ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR);
return 0;
}
cbp = get_vlc2(gb, ff_msmp4_mb_i_vlc);
if (v->acpred_is_raw)
v->s.ac_pred = get_bits1(gb);
else
v->s.ac_pred = v->acpred_plane[mb_pos];
if (v->condover == CONDOVER_SELECT && v->overflg_is_raw)
v->over_flags_plane[mb_pos] = get_bits1(gb);
GET_MQUANT();
s->cur_pic.qscale_table[mb_pos] = mquant;
/* Set DC scale - y and c use the same so we only set y */
s->y_dc_scale = ff_wmv3_dc_scale_table[ABS(mquant)];
for (k = 0; k < 6; k++) {
v->mb_type[s->block_index[k]] = 1;
val = ((cbp >> (5 - k)) & 1);
if (k < 4)
val = vc1_coded_block_pred(&v->s, k, val);
cbp |= val << (5 - k);
v->a_avail = !s->first_slice_line || (k == 2 || k == 3);
v->c_avail = !!s->mb_x || (k == 1 || k == 3);
vc1_decode_i_block_adv(v, v->block[v->cur_blk_idx][block_map[k]], k, val,
(k < 4) ? v->codingset : v->codingset2, mquant);
if (CONFIG_GRAY && k > 3 && (s->avctx->flags & AV_CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[k]]);
}
if (v->overlap && (v->pq >= 9 || v->condover != CONDOVER_NONE))
ff_vc1_i_overlap_filter(v);
vc1_put_blocks_clamped(v, 1);
if (v->loop_filter)
ff_vc1_i_loop_filter(v);
if (get_bits_left(gb) < 0) {
// TODO: may need modification to handle slice coding
ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR);
warning("Bits overconsumption: %i > %i\n", get_bits_count(gb), gb->size_in_bits);
return 0;
}
inc_blk_idx(v->topleft_blk_idx);
inc_blk_idx(v->top_blk_idx);
inc_blk_idx(v->left_blk_idx);
inc_blk_idx(v->cur_blk_idx);
}
s->first_slice_line = 0;
}
ff_er_add_slice(&s->er, 0, s->start_mb_y << v->field_mode, s->mb_width - 1, (s->end_mb_y << v->field_mode) - 1,
ER_MB_END);
return 0;
}
static void vc1_decode_p_blocks(VC1Context *v) {
PictureState *s = &v->s;
int apply_loop_filter;
int ret;
/* select coding mode used for VLC tables selection */
switch (v->c_ac_table_index) {
case 0:
v->codingset = (v->pqindex <= 8) ? CS_HIGH_RATE_INTRA : CS_LOW_MOT_INTRA;
break;
case 1:
v->codingset = CS_HIGH_MOT_INTRA;
break;
case 2:
v->codingset = CS_MID_RATE_INTRA;
break;
}
switch (v->c_ac_table_index) {
case 0:
v->codingset2 = (v->pqindex <= 8) ? CS_HIGH_RATE_INTER : CS_LOW_MOT_INTER;
break;
case 1:
v->codingset2 = CS_HIGH_MOT_INTER;
break;
case 2:
v->codingset2 = CS_MID_RATE_INTER;
break;
}
apply_loop_filter = v->loop_filter && !(s->avctx->skip_loop_filter >= AVDISCARD_NONKEY);
s->first_slice_line = 1;
memset(v->cbp_base, 0, sizeof(v->cbp_base[0]) * 3 * s->mb_stride);
for (s->mb_y = s->start_mb_y; s->mb_y < s->end_mb_y; s->mb_y++) {
s->mb_x = 0;
init_block_index(v);
for (; s->mb_x < s->mb_width; s->mb_x++) {
update_block_index(s);
if (v->fcm == ILACE_FIELD || (v->fcm == PROGRESSIVE && v->mv_type_is_raw) || v->skip_is_raw)
if (get_bits_left(&v->gb) <= 1) {
ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR);
return;
}
if (v->fcm == ILACE_FIELD) {
ret = vc1_decode_p_mb_intfi(v);
if (apply_loop_filter)
ff_vc1_p_loop_filter(v);
} else if (v->fcm == ILACE_FRAME) {
ret = vc1_decode_p_mb_intfr(v);
if (apply_loop_filter)
ff_vc1_p_intfr_loop_filter(v);
} else {
ret = vc1_decode_p_mb(v);
if (apply_loop_filter)
ff_vc1_p_loop_filter(v);
}
if (ret < 0 || get_bits_left(&v->gb) < 0 || get_bits_count(&v->gb) < 0) {
// TODO: may need modification to handle slice coding
ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR);
warning("Error or Bits overconsumption: %i > %i at %ix%i\n", get_bits_count(&v->gb), v->gb.size_in_bits,
s->mb_x, s->mb_y);
return;
}
inc_blk_idx(v->topleft_blk_idx);
inc_blk_idx(v->top_blk_idx);
inc_blk_idx(v->left_blk_idx);
inc_blk_idx(v->cur_blk_idx);
}
memmove(v->cbp_base, v->cbp - s->mb_stride, sizeof(v->cbp_base[0]) * 2 * s->mb_stride);
memmove(v->ttblk_base, v->ttblk - s->mb_stride, sizeof(v->ttblk_base[0]) * 2 * s->mb_stride);
memmove(v->is_intra_base, v->is_intra - s->mb_stride, sizeof(v->is_intra_base[0]) * 2 * s->mb_stride);
memmove(v->luma_mv_base, v->luma_mv - s->mb_stride, sizeof(v->luma_mv_base[0]) * 2 * s->mb_stride);
s->first_slice_line = 0;
}
ff_er_add_slice(&s->er, 0, s->start_mb_y << v->field_mode, s->mb_width - 1, (s->end_mb_y << v->field_mode) - 1,
ER_MB_END);
}
static void vc1_decode_b_blocks(VC1Context *v) {
PictureState *s = &v->s;
/* select coding mode used for VLC tables selection */
switch (v->c_ac_table_index) {
case 0:
v->codingset = (v->pqindex <= 8) ? CS_HIGH_RATE_INTRA : CS_LOW_MOT_INTRA;
break;
case 1:
v->codingset = CS_HIGH_MOT_INTRA;
break;
case 2:
v->codingset = CS_MID_RATE_INTRA;
break;
}
switch (v->c_ac_table_index) {
case 0:
v->codingset2 = (v->pqindex <= 8) ? CS_HIGH_RATE_INTER : CS_LOW_MOT_INTER;
break;
case 1:
v->codingset2 = CS_HIGH_MOT_INTER;
break;
case 2:
v->codingset2 = CS_MID_RATE_INTER;
break;
}
s->first_slice_line = 1;
for (s->mb_y = s->start_mb_y; s->mb_y < s->end_mb_y; s->mb_y++) {
s->mb_x = 0;
init_block_index(v);
for (; s->mb_x < s->mb_width; s->mb_x++) {
update_block_index(s);
if (v->fcm == ILACE_FIELD || v->skip_is_raw || v->dmb_is_raw)
if (get_bits_left(&v->gb) <= 1) {
ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR);
return;
}
if (v->fcm == ILACE_FIELD) {
vc1_decode_b_mb_intfi(v);
if (v->loop_filter)
ff_vc1_b_intfi_loop_filter(v);
} else if (v->fcm == ILACE_FRAME) {
vc1_decode_b_mb_intfr(v);
if (v->loop_filter)
ff_vc1_p_intfr_loop_filter(v);
} else {
vc1_decode_b_mb(v);
if (v->loop_filter)
ff_vc1_i_loop_filter(v);
}
if (get_bits_left(&v->gb) < 0 || get_bits_count(&v->gb) < 0) {
// TODO: may need modification to handle slice coding
ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR);
warning("Bits overconsumption: %i > %i at %ix%i\n", get_bits_count(&v->gb), v->gb.size_in_bits, s->mb_x,
s->mb_y);
return;
}
}
memmove(v->cbp_base, v->cbp - s->mb_stride, sizeof(v->cbp_base[0]) * 2 * s->mb_stride);
memmove(v->ttblk_base, v->ttblk - s->mb_stride, sizeof(v->ttblk_base[0]) * 2 * s->mb_stride);
memmove(v->is_intra_base, v->is_intra - s->mb_stride, sizeof(v->is_intra_base[0]) * 2 * s->mb_stride);
s->first_slice_line = 0;
}
ff_er_add_slice(&s->er, 0, s->start_mb_y << v->field_mode, s->mb_width - 1, (s->end_mb_y << v->field_mode) - 1,
ER_MB_END);
}
static void vc1_decode_skip_blocks(VC1Context *v) {
PictureState *s = &v->s;
if (!v->s.last_pic.data[0])
return;
ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_width - 1, s->end_mb_y - 1, ER_MB_END);
s->first_slice_line = 1;
for (s->mb_y = s->start_mb_y; s->mb_y < s->end_mb_y; s->mb_y++) {
s->mb_x = 0;
init_block_index(v);
update_block_index(s);
memcpy(s->dest[0], s->last_pic.data[0] + s->mb_y * 16 * s->linesize, s->linesize * 16);
memcpy(s->dest[1], s->last_pic.data[1] + s->mb_y * 8 * s->uvlinesize, s->uvlinesize * 8);
memcpy(s->dest[2], s->last_pic.data[2] + s->mb_y * 8 * s->uvlinesize, s->uvlinesize * 8);
s->first_slice_line = 0;
}
}
void ff_vc1_decode_blocks(VC1Context *v) {
v->esc3_level_length = 0;
if (v->x8_type) {
ff_intrax8_decode_picture(v->x8, v->s.cur_pic.ptr, &v->gb, &v->s.mb_x, &v->s.mb_y, 2 * v->pq + v->halfpq,
v->pq * !v->pquantizer, v->loop_filter, v->s.low_delay);
ff_er_add_slice(&v->s.er, 0, 0, (v->s.mb_x >> 1) - 1, (v->s.mb_y >> 1) - 1, ER_MB_END);
} else {
v->cur_blk_idx = 0;
v->left_blk_idx = -1;
v->topleft_blk_idx = 1;
v->top_blk_idx = 2;
switch (v->s.pict_type) {
case AV_PICTURE_TYPE_I:
if (v->profile == PROFILE_ADVANCED)
vc1_decode_i_blocks_adv(v);
else
vc1_decode_i_blocks(v);
break;
case AV_PICTURE_TYPE_P:
if (v->p_frame_skipped)
vc1_decode_skip_blocks(v);
else
vc1_decode_p_blocks(v);
break;
case AV_PICTURE_TYPE_B:
if (v->bi_type) {
if (v->profile == PROFILE_ADVANCED)
vc1_decode_i_blocks_adv(v);
else
vc1_decode_i_blocks(v);
} else
vc1_decode_b_blocks(v);
break;
}
}
}
#undef GET_MQUANT
#undef GET_MVDATA
#undef inc_blk_idx
enum {
VP_START = 1,
ER_AC_ERROR = 2,
ER_DC_ERROR = 4,
ER_MV_ERROR = 8,
ER_AC_END = 16,
ER_DC_END = 32,
ER_MV_END = 64,
FF_EC_GUESS_MVS = 1,
FF_EC_DEBLOCK = 2,
FF_EC_FAVOR_INTER = 256,
FF_THREAD_SLICE = 2,
FF_DEBUG_ER = 1024,
AV_EF_EXPLODE = 8,
FF_DECODE_ERROR_CONCEALMENT_ACTIVE = 4,
MB_TYPE_INTRA4x4 = 1,
MB_TYPE_L0 = 12288,
MB_TYPE_FORWARD_MV = 4096,
MV_DIR_FORWARD = 1,
MV_DIR_BACKWARD = 2,
MV_TYPE_16X16 = 0,
MV_TYPE_8X8 = 1
};
#define IS_INTRA(a) ((a) & 7)
#define IS_INTER(a) ((a) & 120)
#define IS_8X8(a) ((a) & 64)
/**
* @param stride the number of MVs to get to the next row
* @param mv_step the number of MVs per row or column in a macroblock
*/
static void set_mv_strides(ERContext *s, ptrdiff_t *mv_step, ptrdiff_t *stride) {
if (false) {
assert(s->quarter_sample);
*mv_step = 4;
*stride = s->mb_width * 4;
} else {
*mv_step = 2;
*stride = s->b8_stride;
}
}
/**
* Replace the current MB with a flat dc-only version.
*/
static void put_dc(ERContext *s, uint8 *dest_y, uint8 *dest_cb, uint8 *dest_cr, int mb_x, int mb_y) {
int *linesize = s->cur_pic.f->linesize;
int dc, dcu, dcv, y, i;
for (i = 0; i < 4; i++) {
dc = s->dc_val[0][mb_x * 2 + (i & 1) + (mb_y * 2 + (i >> 1)) * s->b8_stride];
if (dc < 0)
dc = 0;
else if (dc > 2040)
dc = 2040;
for (y = 0; y < 8; y++) {
int x;
for (x = 0; x < 8; x++)
dest_y[x + (i & 1) * 8 + (y + (i >> 1) * 8) * linesize[0]] = dc / 8;
}
}
dcu = s->dc_val[1][mb_x + mb_y * s->mb_stride];
dcv = s->dc_val[2][mb_x + mb_y * s->mb_stride];
if (dcu < 0)
dcu = 0;
else if (dcu > 2040)
dcu = 2040;
if (dcv < 0)
dcv = 0;
else if (dcv > 2040)
dcv = 2040;
if (dest_cr)
for (y = 0; y < 8; y++) {
int x;
for (x = 0; x < 8; x++) {
dest_cb[x + y * linesize[1]] = dcu / 8;
dest_cr[x + y * linesize[2]] = dcv / 8;
}
}
}
static void filter181(int16 *data, int width, int height, ptrdiff_t stride) {
int x, y;
/* horizontal filter */
for (y = 1; y < height - 1; y++) {
int prev_dc = data[0 + y * stride];
for (x = 1; x < width - 1; x++) {
int dc;
dc = -prev_dc + data[x + y * stride] * 8 - data[x + 1 + y * stride];
dc = (av_clip(dc, INT_MIN / 10923, INT_MAX / 10923 - 32768) * 10923 + 32768) >> 16;
prev_dc = data[x + y * stride];
data[x + y * stride] = dc;
}
}
/* vertical filter */
for (x = 1; x < width - 1; x++) {
int prev_dc = data[x];
for (y = 1; y < height - 1; y++) {
int dc;
dc = -prev_dc + data[x + y * stride] * 8 - data[x + (y + 1) * stride];
dc = (av_clip(dc, INT_MIN / 10923, INT_MAX / 10923 - 32768) * 10923 + 32768) >> 16;
prev_dc = data[x + y * stride];
data[x + y * stride] = dc;
}
}
}
/**
* guess the dc of blocks which do not have an undamaged dc
* @param w width in 8 pixel blocks
* @param h height in 8 pixel blocks
*/
static void guess_dc(ERContext *s, int16 *dc, int w, int h, ptrdiff_t stride, int is_luma) {
int b_x, b_y;
int16(*col)[4] = new int16[stride * h][4];
uint32(*dist)[4] = new uint32[stride * h][4];
if (!col || !dist) {
warning("guess_dc() is out of memory\n");
goto fail;
}
for (b_y = 0; b_y < h; b_y++) {
int color = 1024;
int distance = -1;
for (b_x = 0; b_x < w; b_x++) {
int mb_index_j = (b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride;
int error_j = s->error_status_table[mb_index_j];
int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
if (intra_j == 0 || !(error_j & ER_DC_ERROR)) {
color = dc[b_x + b_y * stride];
distance = b_x;
}
col[b_x + b_y * stride][1] = color;
dist[b_x + b_y * stride][1] = distance >= 0 ? b_x - distance : 9999;
}
color = 1024;
distance = -1;
for (b_x = w - 1; b_x >= 0; b_x--) {
int mb_index_j = (b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride;
int error_j = s->error_status_table[mb_index_j];
int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
if (intra_j == 0 || !(error_j & ER_DC_ERROR)) {
color = dc[b_x + b_y * stride];
distance = b_x;
}
col[b_x + b_y * stride][0] = color;
dist[b_x + b_y * stride][0] = distance >= 0 ? distance - b_x : 9999;
}
}
for (b_x = 0; b_x < w; b_x++) {
int color = 1024;
int distance = -1;
for (b_y = 0; b_y < h; b_y++) {
int mb_index_j = (b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride;
int error_j = s->error_status_table[mb_index_j];
int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
if (intra_j == 0 || !(error_j & ER_DC_ERROR)) {
color = dc[b_x + b_y * stride];
distance = b_y;
}
col[b_x + b_y * stride][3] = color;
dist[b_x + b_y * stride][3] = distance >= 0 ? b_y - distance : 9999;
}
color = 1024;
distance = -1;
for (b_y = h - 1; b_y >= 0; b_y--) {
int mb_index_j = (b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride;
int error_j = s->error_status_table[mb_index_j];
int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
if (intra_j == 0 || !(error_j & ER_DC_ERROR)) {
color = dc[b_x + b_y * stride];
distance = b_y;
}
col[b_x + b_y * stride][2] = color;
dist[b_x + b_y * stride][2] = distance >= 0 ? distance - b_y : 9999;
}
}
for (b_y = 0; b_y < h; b_y++) {
for (b_x = 0; b_x < w; b_x++) {
int mb_index, error, j;
int64 guess, weight_sum;
mb_index = (b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride;
error = s->error_status_table[mb_index];
if (IS_INTER(s->cur_pic.mb_type[mb_index]))
continue; // inter
if (!(error & ER_DC_ERROR))
continue; // dc-ok
weight_sum = 0;
guess = 0;
for (j = 0; j < 4; j++) {
int64 weight = 256 * 256 * 256 * 16 / MAX(dist[b_x + b_y * stride][j], 1U);
guess += weight * (int64)col[b_x + b_y * stride][j];
weight_sum += weight;
}
guess = (guess + weight_sum / 2) / weight_sum;
dc[b_x + b_y * stride] = guess;
}
}
fail:
delete[] col;
delete[] dist;
}
/**
* simple horizontal deblocking filter used for error resilience
* @param w width in 8 pixel blocks
* @param h height in 8 pixel blocks
*/
static void h_block_filter(ERContext *s, uint8 *dst, int w, int h, ptrdiff_t stride, int is_luma) {
int b_x, b_y;
ptrdiff_t mvx_stride, mvy_stride;
const Crop cm;
set_mv_strides(s, &mvx_stride, &mvy_stride);
mvx_stride >>= is_luma;
mvy_stride *= mvx_stride;
for (b_y = 0; b_y < h; b_y++) {
for (b_x = 0; b_x < w - 1; b_x++) {
int y;
int left_status = s->error_status_table[(b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride];
int right_status = s->error_status_table[((b_x + 1) >> is_luma) + (b_y >> is_luma) * s->mb_stride];
int left_intra = IS_INTRA(s->cur_pic.mb_type[(b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride]);
int right_intra = IS_INTRA(s->cur_pic.mb_type[((b_x + 1) >> is_luma) + (b_y >> is_luma) * s->mb_stride]);
int left_damage = left_status & ER_MB_ERROR;
int right_damage = right_status & ER_MB_ERROR;
int offset = b_x * 8 + b_y * stride * 8;
int16 *left_mv = s->cur_pic.motion_val[0][mvy_stride * b_y + mvx_stride * b_x];
int16 *right_mv = s->cur_pic.motion_val[0][mvy_stride * b_y + mvx_stride * (b_x + 1)];
if (!(left_damage || right_damage))
continue; // both undamaged
if ((!left_intra) && (!right_intra) && ABS(left_mv[0] - right_mv[0]) + ABS(left_mv[1] + right_mv[1]) < 2)
continue;
for (y = 0; y < 8; y++) {
int a, b, c, d;
a = dst[offset + 7 + y * stride] - dst[offset + 6 + y * stride];
b = dst[offset + 8 + y * stride] - dst[offset + 7 + y * stride];
c = dst[offset + 9 + y * stride] - dst[offset + 8 + y * stride];
d = ABS(b) - ((ABS(a) + ABS(c) + 1) >> 1);
d = MAX(d, 0);
if (b < 0)
d = -d;
if (d == 0)
continue;
if (!(left_damage && right_damage))
d = d * 16 / 9;
if (left_damage) {
dst[offset + 7 + y * stride] = cm[dst[offset + 7 + y * stride] + ((d * 7) >> 4)];
dst[offset + 6 + y * stride] = cm[dst[offset + 6 + y * stride] + ((d * 5) >> 4)];
dst[offset + 5 + y * stride] = cm[dst[offset + 5 + y * stride] + ((d * 3) >> 4)];
dst[offset + 4 + y * stride] = cm[dst[offset + 4 + y * stride] + ((d * 1) >> 4)];
}
if (right_damage) {
dst[offset + 8 + y * stride] = cm[dst[offset + 8 + y * stride] - ((d * 7) >> 4)];
dst[offset + 9 + y * stride] = cm[dst[offset + 9 + y * stride] - ((d * 5) >> 4)];
dst[offset + 10 + y * stride] = cm[dst[offset + 10 + y * stride] - ((d * 3) >> 4)];
dst[offset + 11 + y * stride] = cm[dst[offset + 11 + y * stride] - ((d * 1) >> 4)];
}
}
}
}
}
/**
* simple vertical deblocking filter used for error resilience
* @param w width in 8 pixel blocks
* @param h height in 8 pixel blocks
*/
static void v_block_filter(ERContext *s, uint8 *dst, int w, int h, ptrdiff_t stride, int is_luma) {
int b_x, b_y;
ptrdiff_t mvx_stride, mvy_stride;
const Crop cm;
set_mv_strides(s, &mvx_stride, &mvy_stride);
mvx_stride >>= is_luma;
mvy_stride *= mvx_stride;
for (b_y = 0; b_y < h - 1; b_y++) {
for (b_x = 0; b_x < w; b_x++) {
int x;
int top_status = s->error_status_table[(b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride];
int bottom_status = s->error_status_table[(b_x >> is_luma) + ((b_y + 1) >> is_luma) * s->mb_stride];
int top_intra = IS_INTRA(s->cur_pic.mb_type[(b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride]);
int bottom_intra = IS_INTRA(s->cur_pic.mb_type[(b_x >> is_luma) + ((b_y + 1) >> is_luma) * s->mb_stride]);
int top_damage = top_status & ER_MB_ERROR;
int bottom_damage = bottom_status & ER_MB_ERROR;
int offset = b_x * 8 + b_y * stride * 8;
int16 *top_mv = s->cur_pic.motion_val[0][mvy_stride * b_y + mvx_stride * b_x];
int16 *bottom_mv = s->cur_pic.motion_val[0][mvy_stride * (b_y + 1) + mvx_stride * b_x];
if (!(top_damage || bottom_damage))
continue; // both undamaged
if ((!top_intra) && (!bottom_intra) && ABS(top_mv[0] - bottom_mv[0]) + ABS(top_mv[1] + bottom_mv[1]) < 2)
continue;
for (x = 0; x < 8; x++) {
int a, b, c, d;
a = dst[offset + x + 7 * stride] - dst[offset + x + 6 * stride];
b = dst[offset + x + 8 * stride] - dst[offset + x + 7 * stride];
c = dst[offset + x + 9 * stride] - dst[offset + x + 8 * stride];
d = ABS(b) - ((ABS(a) + ABS(c) + 1) >> 1);
d = MAX(d, 0);
if (b < 0)
d = -d;
if (d == 0)
continue;
if (!(top_damage && bottom_damage))
d = d * 16 / 9;
if (top_damage) {
dst[offset + x + 7 * stride] = cm[dst[offset + x + 7 * stride] + ((d * 7) >> 4)];
dst[offset + x + 6 * stride] = cm[dst[offset + x + 6 * stride] + ((d * 5) >> 4)];
dst[offset + x + 5 * stride] = cm[dst[offset + x + 5 * stride] + ((d * 3) >> 4)];
dst[offset + x + 4 * stride] = cm[dst[offset + x + 4 * stride] + ((d * 1) >> 4)];
}
if (bottom_damage) {
dst[offset + x + 8 * stride] = cm[dst[offset + x + 8 * stride] - ((d * 7) >> 4)];
dst[offset + x + 9 * stride] = cm[dst[offset + x + 9 * stride] - ((d * 5) >> 4)];
dst[offset + x + 10 * stride] = cm[dst[offset + x + 10 * stride] - ((d * 3) >> 4)];
dst[offset + x + 11 * stride] = cm[dst[offset + x + 11 * stride] - ((d * 1) >> 4)];
}
}
}
}
}
#define MV_FROZEN 8
#define MV_CHANGED 4
#define MV_UNCHANGED 2
#define MV_LISTED 1
static inline void add_blocklist(int (*blocklist)[2], int *blocklist_length, uint8 *fixed, int mb_x, int mb_y,
int mb_xy) {
if (fixed[mb_xy])
return;
fixed[mb_xy] = MV_LISTED;
blocklist[*blocklist_length][0] = mb_x;
blocklist[(*blocklist_length)++][1] = mb_y;
}
static void guess_mv(ERContext *s) {
int (*blocklist)[2], (*next_blocklist)[2];
uint8 *fixed;
const ptrdiff_t mb_stride = s->mb_stride;
const int mb_width = s->mb_width;
int mb_height = s->mb_height;
int i, num_avail;
int mb_x, mb_y;
ptrdiff_t mot_step, mot_stride;
int blocklist_length, next_blocklist_length;
if (s->last_pic.f && s->last_pic.f->data[0])
mb_height = MIN(mb_height, (s->last_pic.f->height + 15) >> 4);
if (s->next_pic.f && s->next_pic.f->data[0])
mb_height = MIN(mb_height, (s->next_pic.f->height + 15) >> 4);
blocklist = (int (*)[2])s->er_temp_buffer;
next_blocklist = blocklist + s->mb_stride * s->mb_height;
fixed = (uint8 *)(next_blocklist + s->mb_stride * s->mb_height);
set_mv_strides(s, &mot_step, &mot_stride);
num_avail = 0;
if (s->last_pic.motion_val[0]) {
if (false)
(void)0;
else
(void)0;
}
for (i = 0; i < mb_width * mb_height; i++) {
const int mb_xy = s->mb_index2xy[i];
int f = 0;
int error = s->error_status_table[mb_xy];
if (IS_INTRA(s->cur_pic.mb_type[mb_xy]))
f = MV_FROZEN; // intra // FIXME check
if (!(error & ER_MV_ERROR))
f = MV_FROZEN; // inter with undamaged MV
fixed[mb_xy] = f;
if (f == MV_FROZEN)
num_avail++;
else if (s->last_pic.f->data[0] && s->last_pic.motion_val[0]) {
const int mb_y = mb_xy / s->mb_stride;
const int mb_x = mb_xy % s->mb_stride;
const int mot_index = (mb_x + mb_y * mot_stride) * mot_step;
s->cur_pic.motion_val[0][mot_index][0] = s->last_pic.motion_val[0][mot_index][0];
s->cur_pic.motion_val[0][mot_index][1] = s->last_pic.motion_val[0][mot_index][1];
s->cur_pic.ref_index[0][4 * mb_xy] = s->last_pic.ref_index[0][4 * mb_xy];
}
}
if ((!(s->avctx->error_concealment & FF_EC_GUESS_MVS)) || num_avail <= MAX(mb_width, mb_height) / 2) {
for (mb_y = 0; mb_y < mb_height; mb_y++) {
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
const int mb_xy = mb_x + mb_y * s->mb_stride;
int mv_dir = (s->last_pic.f && s->last_pic.f->data[0]) ? MV_DIR_FORWARD : MV_DIR_BACKWARD;
if (IS_INTRA(s->cur_pic.mb_type[mb_xy]))
continue;
if (!(s->error_status_table[mb_xy] & ER_MV_ERROR))
continue;
s->mv[0][0][0] = 0;
s->mv[0][0][1] = 0;
s->decode_mb(s->opaque, 0, mv_dir, MV_TYPE_16X16, &s->mv, mb_x, mb_y, 0, 0);
}
}
return;
}
blocklist_length = 0;
for (mb_y = 0; mb_y < mb_height; mb_y++) {
for (mb_x = 0; mb_x < mb_width; mb_x++) {
const int mb_xy = mb_x + mb_y * mb_stride;
if (fixed[mb_xy] == MV_FROZEN) {
if (mb_x)
add_blocklist(blocklist, &blocklist_length, fixed, mb_x - 1, mb_y, mb_xy - 1);
if (mb_y)
add_blocklist(blocklist, &blocklist_length, fixed, mb_x, mb_y - 1, mb_xy - mb_stride);
if (mb_x + 1 < mb_width)
add_blocklist(blocklist, &blocklist_length, fixed, mb_x + 1, mb_y, mb_xy + 1);
if (mb_y + 1 < mb_height)
add_blocklist(blocklist, &blocklist_length, fixed, mb_x, mb_y + 1, mb_xy + mb_stride);
}
}
}
for (;;) {
int changed, pass, none_left;
int blocklist_index;
none_left = 1;
changed = 1;
for (pass = 0; (changed || pass < 2) && pass < 10; pass++) {
changed = 0;
for (blocklist_index = 0; blocklist_index < blocklist_length; blocklist_index++) {
const int mb_x = blocklist[blocklist_index][0];
const int mb_y = blocklist[blocklist_index][1];
const int mb_xy = mb_x + mb_y * mb_stride;
int mv_predictor[8][2];
int ref[8];
int pred_count;
int j;
int best_score;
int best_pred;
int mot_index;
int prev_x, prev_y, prev_ref;
if ((mb_x ^ mb_y ^ pass) & 1)
continue;
assert(fixed[mb_xy] != MV_FROZEN);
assert(!IS_INTRA(s->cur_pic.mb_type[mb_xy]));
assert(s->last_pic.f && s->last_pic.f->data[0]);
j = 0;
if (mb_x > 0)
j |= fixed[mb_xy - 1];
if (mb_x + 1 < mb_width)
j |= fixed[mb_xy + 1];
if (mb_y > 0)
j |= fixed[mb_xy - mb_stride];
if (mb_y + 1 < mb_height)
j |= fixed[mb_xy + mb_stride];
assert(j & MV_FROZEN);
if (!(j & MV_CHANGED) && pass > 1)
continue;
none_left = 0;
pred_count = 0;
mot_index = (mb_x + mb_y * mot_stride) * mot_step;
if (mb_x > 0 && fixed[mb_xy - 1] > 1) {
mv_predictor[pred_count][0] = s->cur_pic.motion_val[0][mot_index - mot_step][0];
mv_predictor[pred_count][1] = s->cur_pic.motion_val[0][mot_index - mot_step][1];
ref[pred_count] = s->cur_pic.ref_index[0][4 * (mb_xy - 1)];
pred_count++;
}
if (mb_x + 1 < mb_width && fixed[mb_xy + 1] > 1) {
mv_predictor[pred_count][0] = s->cur_pic.motion_val[0][mot_index + mot_step][0];
mv_predictor[pred_count][1] = s->cur_pic.motion_val[0][mot_index + mot_step][1];
ref[pred_count] = s->cur_pic.ref_index[0][4 * (mb_xy + 1)];
pred_count++;
}
if (mb_y > 0 && fixed[mb_xy - mb_stride] > 1) {
mv_predictor[pred_count][0] = s->cur_pic.motion_val[0][mot_index - mot_stride * mot_step][0];
mv_predictor[pred_count][1] = s->cur_pic.motion_val[0][mot_index - mot_stride * mot_step][1];
ref[pred_count] = s->cur_pic.ref_index[0][4 * (mb_xy - s->mb_stride)];
pred_count++;
}
if (mb_y + 1 < mb_height && fixed[mb_xy + mb_stride] > 1) {
mv_predictor[pred_count][0] = s->cur_pic.motion_val[0][mot_index + mot_stride * mot_step][0];
mv_predictor[pred_count][1] = s->cur_pic.motion_val[0][mot_index + mot_stride * mot_step][1];
ref[pred_count] = s->cur_pic.ref_index[0][4 * (mb_xy + s->mb_stride)];
pred_count++;
}
if (pred_count == 0)
continue;
if (pred_count > 1) {
int sum_x = 0, sum_y = 0, sum_r = 0;
int max_x, max_y, min_x, min_y, max_r, min_r;
for (j = 0; j < pred_count; j++) {
sum_x += mv_predictor[j][0];
sum_y += mv_predictor[j][1];
sum_r += ref[j];
if (j && ref[j] != ref[j - 1])
goto skip_mean_and_median;
}
/* mean */
mv_predictor[pred_count][0] = sum_x / j;
mv_predictor[pred_count][1] = sum_y / j;
ref[pred_count] = sum_r / j;
/* median */
if (pred_count >= 3) {
min_y = min_x = min_r = 99999;
max_y = max_x = max_r = -99999;
} else {
min_x = min_y = max_x = max_y = min_r = max_r = 0;
}
for (j = 0; j < pred_count; j++) {
max_x = MAX(max_x, mv_predictor[j][0]);
max_y = MAX(max_y, mv_predictor[j][1]);
max_r = MAX(max_r, ref[j]);
min_x = MIN(min_x, mv_predictor[j][0]);
min_y = MIN(min_y, mv_predictor[j][1]);
min_r = MIN(min_r, ref[j]);
}
mv_predictor[pred_count + 1][0] = sum_x - max_x - min_x;
mv_predictor[pred_count + 1][1] = sum_y - max_y - min_y;
ref[pred_count + 1] = sum_r - max_r - min_r;
if (pred_count == 4) {
mv_predictor[pred_count + 1][0] /= 2;
mv_predictor[pred_count + 1][1] /= 2;
ref[pred_count + 1] /= 2;
}
pred_count += 2;
}
skip_mean_and_median:
/* zero MV */
mv_predictor[pred_count][0] = mv_predictor[pred_count][1] = ref[pred_count] = 0;
pred_count++;
prev_x = s->cur_pic.motion_val[0][mot_index][0];
prev_y = s->cur_pic.motion_val[0][mot_index][1];
prev_ref = s->cur_pic.ref_index[0][4 * mb_xy];
/* last MV */
mv_predictor[pred_count][0] = prev_x;
mv_predictor[pred_count][1] = prev_y;
ref[pred_count] = prev_ref;
pred_count++;
best_pred = 0;
best_score = 256 * 256 * 256 * 64;
for (j = 0; j < pred_count; j++) {
int *linesize = s->cur_pic.f->linesize;
int score = 0;
uint8 *src = s->cur_pic.f->data[0] + mb_x * 16 + mb_y * 16 * linesize[0];
s->cur_pic.motion_val[0][mot_index][0] = s->mv[0][0][0] = mv_predictor[j][0];
s->cur_pic.motion_val[0][mot_index][1] = s->mv[0][0][1] = mv_predictor[j][1];
// predictor intra or otherwise not available
if (ref[j] < 0)
continue;
s->decode_mb(s->opaque, ref[j], MV_DIR_FORWARD, MV_TYPE_16X16, &s->mv, mb_x, mb_y, 0, 0);
if (mb_x > 0 && fixed[mb_xy - 1] > 1) {
int k;
for (k = 0; k < 16; k++)
score += ABS(src[k * linesize[0] - 1] - src[k * linesize[0]]);
}
if (mb_x + 1 < mb_width && fixed[mb_xy + 1] > 1) {
int k;
for (k = 0; k < 16; k++)
score += ABS(src[k * linesize[0] + 15] - src[k * linesize[0] + 16]);
}
if (mb_y > 0 && fixed[mb_xy - mb_stride] > 1) {
int k;
for (k = 0; k < 16; k++)
score += ABS(src[k - linesize[0]] - src[k]);
}
if (mb_y + 1 < mb_height && fixed[mb_xy + mb_stride] > 1) {
int k;
for (k = 0; k < 16; k++)
score += ABS(src[k + linesize[0] * 15] - src[k + linesize[0] * 16]);
}
if (score <= best_score) { // <= will favor the last MV
best_score = score;
best_pred = j;
}
}
s->mv[0][0][0] = mv_predictor[best_pred][0];
s->mv[0][0][1] = mv_predictor[best_pred][1];
for (i = 0; i < mot_step; i++)
for (j = 0; j < mot_step; j++) {
s->cur_pic.motion_val[0][mot_index + i + j * mot_stride][0] = s->mv[0][0][0];
s->cur_pic.motion_val[0][mot_index + i + j * mot_stride][1] = s->mv[0][0][1];
}
s->decode_mb(s->opaque, ref[best_pred], MV_DIR_FORWARD, MV_TYPE_16X16, &s->mv, mb_x, mb_y, 0, 0);
if (s->mv[0][0][0] != prev_x || s->mv[0][0][1] != prev_y) {
fixed[mb_xy] = MV_CHANGED;
changed++;
} else
fixed[mb_xy] = MV_UNCHANGED;
}
}
if (none_left)
return;
next_blocklist_length = 0;
for (blocklist_index = 0; blocklist_index < blocklist_length; blocklist_index++) {
const int mb_x = blocklist[blocklist_index][0];
const int mb_y = blocklist[blocklist_index][1];
const int mb_xy = mb_x + mb_y * mb_stride;
if (fixed[mb_xy] & (MV_CHANGED | MV_UNCHANGED | MV_FROZEN)) {
fixed[mb_xy] = MV_FROZEN;
if (mb_x > 0)
add_blocklist(next_blocklist, &next_blocklist_length, fixed, mb_x - 1, mb_y, mb_xy - 1);
if (mb_y > 0)
add_blocklist(next_blocklist, &next_blocklist_length, fixed, mb_x, mb_y - 1, mb_xy - mb_stride);
if (mb_x + 1 < mb_width)
add_blocklist(next_blocklist, &next_blocklist_length, fixed, mb_x + 1, mb_y, mb_xy + 1);
if (mb_y + 1 < mb_height)
add_blocklist(next_blocklist, &next_blocklist_length, fixed, mb_x, mb_y + 1, mb_xy + mb_stride);
}
}
assert(next_blocklist_length <= mb_height * mb_width);
SWAP(blocklist_length, next_blocklist_length);
SWAP(blocklist, next_blocklist);
}
}
static int is_intra_more_likely(ERContext *s) {
int is_intra_likely, i, j, undamaged_count, skip_amount, mb_x, mb_y;
if (!s->last_pic.f || !s->last_pic.f->data[0])
return 1; // no previous frame available -> use spatial prediction
if (s->avctx->error_concealment & FF_EC_FAVOR_INTER)
return 0;
undamaged_count = 0;
for (i = 0; i < s->mb_num; i++) {
const int mb_xy = s->mb_index2xy[i];
const int error = s->error_status_table[mb_xy];
if (!((error & ER_DC_ERROR) && (error & ER_MV_ERROR)))
undamaged_count++;
}
if (undamaged_count < 5)
return 0; // almost all MBs damaged -> use temporal prediction
skip_amount = MAX(undamaged_count / 50, 1); // check only up to 50 MBs
is_intra_likely = 0;
j = 0;
for (mb_y = 0; mb_y < s->mb_height - 1; mb_y++) {
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
int error;
const int mb_xy = mb_x + mb_y * s->mb_stride;
error = s->error_status_table[mb_xy];
if ((error & ER_DC_ERROR) && (error & ER_MV_ERROR))
continue; // skip damaged
j++;
// skip a few to speed things up
if ((j % skip_amount) != 0)
continue;
if (s->cur_pic.f->pict_type == AV_PICTURE_TYPE_I) {
int *linesize = s->cur_pic.f->linesize;
uint8 *mb_ptr = s->cur_pic.f->data[0] + mb_x * 16 + mb_y * 16 * linesize[0];
uint8 *last_mb_ptr = s->last_pic.f->data[0] + mb_x * 16 + mb_y * 16 * linesize[0];
if (false) {
// FIXME
} else {
(void)0;
}
is_intra_likely += s->sad(NULL, last_mb_ptr, mb_ptr, linesize[0], 16);
// FIXME need await_progress() here
is_intra_likely -= s->sad(NULL, last_mb_ptr, last_mb_ptr + linesize[0] * 16, linesize[0], 16);
} else {
if (IS_INTRA(s->cur_pic.mb_type[mb_xy]))
is_intra_likely++;
else
is_intra_likely--;
}
}
}
// warning( "is_intra_likely: %d type:%d\n", is_intra_likely, s->pict_type);
return is_intra_likely > 0;
}
void ff_er_frame_start(ERContext *s) {
if (!s->avctx->error_concealment)
return;
memset(s->error_status_table, ER_MB_ERROR | VP_START | ER_MB_END, s->mb_stride * s->mb_height * sizeof(uint8));
s->error_count = 3 * s->mb_num;
s->error_occurred = 0;
}
static int er_supported(ERContext *s) {
if (false || !s->cur_pic.f || s->cur_pic.field_picture)
return 0;
return 1;
}
/**
* Add a slice.
* @param endx x component of the last macroblock, can be -1
* for the last of the previous line
* @param status the status at the end (ER_MV_END, ER_AC_ERROR, ...), it is
* assumed that no earlier end or error of the same type occurred
*/
void ff_er_add_slice(ERContext *s, int startx, int starty, int endx, int endy, int status) {
const int start_i = av_clip(startx + starty * s->mb_width, 0, s->mb_num - 1);
const int end_i = av_clip(endx + endy * s->mb_width, 0, s->mb_num);
const int start_xy = s->mb_index2xy[start_i];
const int end_xy = s->mb_index2xy[end_i];
int mask = -1;
if (false)
return;
if (start_i > end_i || start_xy > end_xy) {
warning("internal error, slice end before start\n");
return;
}
if (!s->avctx->error_concealment)
return;
mask &= ~VP_START;
if (status & (ER_AC_ERROR | ER_AC_END)) {
mask &= ~(ER_AC_ERROR | ER_AC_END);
s->error_count += start_i - end_i - 1;
}
if (status & (ER_DC_ERROR | ER_DC_END)) {
mask &= ~(ER_DC_ERROR | ER_DC_END);
s->error_count += start_i - end_i - 1;
}
if (status & (ER_MV_ERROR | ER_MV_END)) {
mask &= ~(ER_MV_ERROR | ER_MV_END);
s->error_count += start_i - end_i - 1;
}
if (status & ER_MB_ERROR) {
s->error_occurred = 1;
s->error_count = INT_MAX;
}
if (mask == ~0x7F) {
memset(&s->error_status_table[start_xy], 0, (end_xy - start_xy) * sizeof(uint8));
} else {
int i;
for (i = start_xy; i < end_xy; i++)
s->error_status_table[i] &= mask;
}
if (end_i == s->mb_num)
s->error_count = INT_MAX;
else {
s->error_status_table[end_xy] &= mask;
s->error_status_table[end_xy] |= status;
}
s->error_status_table[start_xy] |= VP_START;
if (start_xy > 0 && !(0 & FF_THREAD_SLICE) && er_supported(s) && 0 * s->mb_width < start_i) {
int prev_status = s->error_status_table[s->mb_index2xy[start_i - 1]];
prev_status &= ~VP_START;
if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END)) {
s->error_occurred = 1;
s->error_count = INT_MAX;
}
}
}
void ff_er_frame_end(ERContext *s, int *decode_error_flags) {
int *linesize = NULL;
int i, mb_x, mb_y, error, error_type, dc_error, mv_error, ac_error;
int distance;
int threshold_part[4] = {100, 100, 100};
int threshold = 50;
int is_intra_likely;
int guessed_mb_type;
/* We do not support ER of field pictures yet,
* though it should not crash if enabled. */
if (!s->avctx->error_concealment || !s->error_count || !er_supported(s)) {
return;
}
linesize = s->cur_pic.f->linesize;
if (s->last_pic.f) {
if (s->last_pic.f->width != s->cur_pic.f->width || s->last_pic.f->height != s->cur_pic.f->height ||
s->last_pic.f->format != s->cur_pic.f->format) {
warning("Cannot use previous picture in error concealment\n");
memset(&s->last_pic, 0, sizeof(s->last_pic));
}
}
if (s->next_pic.f) {
if (s->next_pic.f->width != s->cur_pic.f->width || s->next_pic.f->height != s->cur_pic.f->height ||
s->next_pic.f->format != s->cur_pic.f->format) {
warning("Cannot use next picture in error concealment\n");
memset(&s->next_pic, 0, sizeof(s->next_pic));
}
}
/* handle overlapping slices */
for (error_type = 1; error_type <= 3; error_type++) {
int end_ok = 0;
for (i = s->mb_num - 1; i >= 0; i--) {
const int mb_xy = s->mb_index2xy[i];
int error = s->error_status_table[mb_xy];
if (error & (1 << error_type))
end_ok = 1;
if (error & (8 << error_type))
end_ok = 1;
if (!end_ok)
s->error_status_table[mb_xy] |= 1 << error_type;
if (error & VP_START)
end_ok = 0;
}
}
/* handle slices with partitions of different length */
if (s->partitioned_frame) {
int end_ok = 0;
for (i = s->mb_num - 1; i >= 0; i--) {
const int mb_xy = s->mb_index2xy[i];
int error = s->error_status_table[mb_xy];
if (error & ER_AC_END)
end_ok = 0;
if ((error & ER_MV_END) || (error & ER_DC_END) || (error & ER_AC_ERROR))
end_ok = 1;
if (!end_ok)
s->error_status_table[mb_xy] |= ER_AC_ERROR;
if (error & VP_START)
end_ok = 0;
}
}
/* handle missing slices */
if (1 & AV_EF_EXPLODE) {
int end_ok = 1;
// FIXME + 100 hack
for (i = s->mb_num - 2; i >= s->mb_width + 100; i--) {
const int mb_xy = s->mb_index2xy[i];
int error1 = s->error_status_table[mb_xy];
int error2 = s->error_status_table[s->mb_index2xy[i + 1]];
if (error1 & VP_START)
end_ok = 1;
if (error2 == (VP_START | ER_MB_ERROR | ER_MB_END) && error1 != (VP_START | ER_MB_ERROR | ER_MB_END) &&
((error1 & ER_AC_END) || (error1 & ER_DC_END) || (error1 & ER_MV_END))) {
// end & uninit
end_ok = 0;
}
if (!end_ok)
s->error_status_table[mb_xy] |= ER_MB_ERROR;
}
}
/* backward mark errors */
distance = 9999999;
for (error_type = 1; error_type <= 3; error_type++) {
for (i = s->mb_num - 1; i >= 0; i--) {
const int mb_xy = s->mb_index2xy[i];
int error = s->error_status_table[mb_xy];
if (!s->mbskip_table || !s->mbskip_table[mb_xy]) // FIXME partition specific
distance++;
if (error & (1 << error_type))
distance = 0;
if (s->partitioned_frame) {
if (distance < threshold_part[error_type - 1])
s->error_status_table[mb_xy] |= 1 << error_type;
} else {
if (distance < threshold)
s->error_status_table[mb_xy] |= 1 << error_type;
}
if (error & VP_START)
distance = 9999999;
}
}
/* forward mark errors */
error = 0;
for (i = 0; i < s->mb_num; i++) {
const int mb_xy = s->mb_index2xy[i];
int old_error = s->error_status_table[mb_xy];
if (old_error & VP_START) {
error = old_error & ER_MB_ERROR;
} else {
error |= old_error & ER_MB_ERROR;
s->error_status_table[mb_xy] |= error;
}
}
/* handle not partitioned case */
if (!s->partitioned_frame) {
for (i = 0; i < s->mb_num; i++) {
const int mb_xy = s->mb_index2xy[i];
int error = s->error_status_table[mb_xy];
if (error & ER_MB_ERROR)
error |= ER_MB_ERROR;
s->error_status_table[mb_xy] = error;
}
}
dc_error = ac_error = mv_error = 0;
for (i = 0; i < s->mb_num; i++) {
const int mb_xy = s->mb_index2xy[i];
int error = s->error_status_table[mb_xy];
if (error & ER_DC_ERROR)
dc_error++;
if (error & ER_AC_ERROR)
ac_error++;
if (error & ER_MV_ERROR)
mv_error++;
}
warning("concealing %d DC, %d AC, %d MV errors in %c frame\n", dc_error, ac_error, mv_error,
"?IPB???i"[s->cur_pic.f->pict_type]);
if (decode_error_flags)
*decode_error_flags |= FF_DECODE_ERROR_CONCEALMENT_ACTIVE;
else
s->cur_pic.f->decode_error_flags |= FF_DECODE_ERROR_CONCEALMENT_ACTIVE;
is_intra_likely = is_intra_more_likely(s);
/* set unknown mb-type to most likely */
guessed_mb_type = is_intra_likely ? MB_TYPE_INTRA4x4 : (MB_TYPE_16x16 | (false ? MB_TYPE_L0 : MB_TYPE_FORWARD_MV));
for (i = 0; i < s->mb_num; i++) {
const int mb_xy = s->mb_index2xy[i];
int error = s->error_status_table[mb_xy];
if (!((error & ER_DC_ERROR) && (error & ER_MV_ERROR)))
continue;
s->cur_pic.mb_type[mb_xy] = guessed_mb_type;
}
// change inter to intra blocks if no reference frames are available
if (!(s->last_pic.f && s->last_pic.f->data[0]) && !(s->next_pic.f && s->next_pic.f->data[0]))
for (i = 0; i < s->mb_num; i++) {
const int mb_xy = s->mb_index2xy[i];
if (!IS_INTRA(s->cur_pic.mb_type[mb_xy]))
s->cur_pic.mb_type[mb_xy] = MB_TYPE_INTRA4x4;
}
/* handle inter blocks with damaged AC */
for (mb_y = 0; mb_y < s->mb_height; mb_y++) {
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
const int mb_xy = mb_x + mb_y * s->mb_stride;
const int mb_type = s->cur_pic.mb_type[mb_xy];
const int dir = !(s->last_pic.f && s->last_pic.f->data[0]);
const int mv_dir = dir ? MV_DIR_BACKWARD : MV_DIR_FORWARD;
int mv_type;
int error = s->error_status_table[mb_xy];
if (IS_INTRA(mb_type))
continue; // intra
if (error & ER_MV_ERROR)
continue; // inter with damaged MV
if (!(error & ER_AC_ERROR))
continue; // undamaged inter
if (IS_8X8(mb_type)) {
int mb_index = mb_x * 2 + mb_y * 2 * s->b8_stride;
int j;
mv_type = MV_TYPE_8X8;
for (j = 0; j < 4; j++) {
s->mv[0][j][0] = s->cur_pic.motion_val[dir][mb_index + (j & 1) + (j >> 1) * s->b8_stride][0];
s->mv[0][j][1] = s->cur_pic.motion_val[dir][mb_index + (j & 1) + (j >> 1) * s->b8_stride][1];
}
} else {
mv_type = MV_TYPE_16X16;
s->mv[0][0][0] = s->cur_pic.motion_val[dir][mb_x * 2 + mb_y * 2 * s->b8_stride][0];
s->mv[0][0][1] = s->cur_pic.motion_val[dir][mb_x * 2 + mb_y * 2 * s->b8_stride][1];
}
s->decode_mb(s->opaque, 0 /* FIXME H.264 partitioned slices need this set */, mv_dir, mv_type, &s->mv, mb_x,
mb_y, 0, 0);
}
}
/* guess MVs */
if (s->cur_pic.f->pict_type == AV_PICTURE_TYPE_B) {
for (mb_y = 0; mb_y < s->mb_height; mb_y++) {
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
int xy = mb_x * 2 + mb_y * 2 * s->b8_stride;
const int mb_xy = mb_x + mb_y * s->mb_stride;
const int mb_type = s->cur_pic.mb_type[mb_xy];
int mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD;
int error = s->error_status_table[mb_xy];
if (IS_INTRA(mb_type))
continue;
if (!(error & ER_MV_ERROR))
continue; // inter with undamaged MV
if (!(error & ER_AC_ERROR))
continue; // undamaged inter
if (!(s->last_pic.f && s->last_pic.f->data[0]))
mv_dir &= ~MV_DIR_FORWARD;
if (!(s->next_pic.f && s->next_pic.f->data[0]))
mv_dir &= ~MV_DIR_BACKWARD;
if (s->pp_time) {
int time_pp = s->pp_time;
int time_pb = s->pb_time;
assert(true);
(void)0;
s->mv[0][0][0] = s->next_pic.motion_val[0][xy][0] * time_pb / time_pp;
s->mv[0][0][1] = s->next_pic.motion_val[0][xy][1] * time_pb / time_pp;
s->mv[1][0][0] = s->next_pic.motion_val[0][xy][0] * (time_pb - time_pp) / time_pp;
s->mv[1][0][1] = s->next_pic.motion_val[0][xy][1] * (time_pb - time_pp) / time_pp;
} else {
s->mv[0][0][0] = 0;
s->mv[0][0][1] = 0;
s->mv[1][0][0] = 0;
s->mv[1][0][1] = 0;
}
s->decode_mb(s->opaque, 0, mv_dir, MV_TYPE_16X16, &s->mv, mb_x, mb_y, 0, 0);
}
}
} else
guess_mv(s);
/* fill DC for inter blocks */
for (mb_y = 0; mb_y < s->mb_height; mb_y++) {
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
int dc, dcu, dcv, y, n;
int16 *dc_ptr;
uint8 *dest_y, *dest_cb, *dest_cr;
const int mb_xy = mb_x + mb_y * s->mb_stride;
const int mb_type = s->cur_pic.mb_type[mb_xy];
// error = s->error_status_table[mb_xy];
if (IS_INTRA(mb_type) && s->partitioned_frame)
continue;
// if (error & ER_MV_ERROR)
// continue; // inter data damaged FIXME is this good?
dest_y = s->cur_pic.f->data[0] + mb_x * 16 + mb_y * 16 * linesize[0];
dest_cb = s->cur_pic.f->data[1] + mb_x * 8 + mb_y * 8 * linesize[1];
dest_cr = s->cur_pic.f->data[2] + mb_x * 8 + mb_y * 8 * linesize[2];
dc_ptr = &s->dc_val[0][mb_x * 2 + mb_y * 2 * s->b8_stride];
for (n = 0; n < 4; n++) {
dc = 0;
for (y = 0; y < 8; y++) {
int x;
for (x = 0; x < 8; x++)
dc += dest_y[x + (n & 1) * 8 + (y + (n >> 1) * 8) * linesize[0]];
}
dc_ptr[(n & 1) + (n >> 1) * s->b8_stride] = (dc + 4) >> 3;
}
if (!s->cur_pic.f->data[2])
continue;
dcu = dcv = 0;
for (y = 0; y < 8; y++) {
int x;
for (x = 0; x < 8; x++) {
dcu += dest_cb[x + y * linesize[1]];
dcv += dest_cr[x + y * linesize[2]];
}
}
s->dc_val[1][mb_x + mb_y * s->mb_stride] = (dcu + 4) >> 3;
s->dc_val[2][mb_x + mb_y * s->mb_stride] = (dcv + 4) >> 3;
}
}
/* guess DC for damaged blocks */
guess_dc(s, s->dc_val[0], s->mb_width * 2, s->mb_height * 2, s->b8_stride, 1);
guess_dc(s, s->dc_val[1], s->mb_width, s->mb_height, s->mb_stride, 0);
guess_dc(s, s->dc_val[2], s->mb_width, s->mb_height, s->mb_stride, 0);
/* filter luma DC */
filter181(s->dc_val[0], s->mb_width * 2, s->mb_height * 2, s->b8_stride);
/* render DC only intra */
for (mb_y = 0; mb_y < s->mb_height; mb_y++) {
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
uint8 *dest_y, *dest_cb, *dest_cr;
const int mb_xy = mb_x + mb_y * s->mb_stride;
const int mb_type = s->cur_pic.mb_type[mb_xy];
int error = s->error_status_table[mb_xy];
if (IS_INTER(mb_type))
continue;
if (!(error & ER_AC_ERROR))
continue; // undamaged
dest_y = s->cur_pic.f->data[0] + mb_x * 16 + mb_y * 16 * linesize[0];
dest_cb = s->cur_pic.f->data[1] + mb_x * 8 + mb_y * 8 * linesize[1];
dest_cr = s->cur_pic.f->data[2] + mb_x * 8 + mb_y * 8 * linesize[2];
if (!s->cur_pic.f->data[2])
dest_cb = dest_cr = NULL;
put_dc(s, dest_y, dest_cb, dest_cr, mb_x, mb_y);
}
}
if (s->avctx->error_concealment & FF_EC_DEBLOCK) {
/* filter horizontal block boundaries */
h_block_filter(s, s->cur_pic.f->data[0], s->mb_width * 2, s->mb_height * 2, linesize[0], 1);
/* filter vertical block boundaries */
v_block_filter(s, s->cur_pic.f->data[0], s->mb_width * 2, s->mb_height * 2, linesize[0], 1);
if (s->cur_pic.f->data[2]) {
h_block_filter(s, s->cur_pic.f->data[1], s->mb_width, s->mb_height, linesize[1], 0);
h_block_filter(s, s->cur_pic.f->data[2], s->mb_width, s->mb_height, linesize[2], 0);
v_block_filter(s, s->cur_pic.f->data[1], s->mb_width, s->mb_height, linesize[1], 0);
v_block_filter(s, s->cur_pic.f->data[2], s->mb_width, s->mb_height, linesize[2], 0);
}
}
/* clean a few tables */
for (i = 0; i < s->mb_num; i++) {
const int mb_xy = s->mb_index2xy[i];
int error = s->error_status_table[mb_xy];
if (s->mbskip_table && s->cur_pic.f->pict_type != AV_PICTURE_TYPE_B &&
(error & (ER_DC_ERROR | ER_MV_ERROR | ER_AC_ERROR))) {
s->mbskip_table[mb_xy] = 0;
}
if (s->mbintra_table)
s->mbintra_table[mb_xy] = 1;
}
memset(&s->cur_pic, 0, sizeof(Picture));
memset(&s->last_pic, 0, sizeof(Picture));
memset(&s->next_pic, 0, sizeof(Picture));
}
#undef IS_8X8
#undef IS_INTER
#undef IS_INTRA
#undef MV_CHANGED
#undef MV_FROZEN
#undef MV_LISTED
#undef MV_UNCHANGED
enum { FMT_H263 = 2, FMT_H261 = 1, FMT_MPEG1 = 0, CONFIG_SMALL = 0 };
static inline int ff_h263_round_chroma(int x) {
// FIXME static or not?
static const uint8 h263_chroma_roundtab[16] = {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
};
return h263_chroma_roundtab[x & 0xf] + (x >> 3);
}
static inline int hpel_motion(PictureState *s, uint8 *dest, uint8 *src, int src_x, int src_y, const PixelOp *pix_op,
int motion_x, int motion_y) {
int dxy = 0;
int emu = 0;
src_x += motion_x >> 1;
src_y += motion_y >> 1;
/* WARNING: do no forget half pels */
src_x = av_clip(src_x, -16, s->width); // FIXME unneeded for emu?
if (src_x != s->width)
dxy |= motion_x & 1;
src_y = av_clip(src_y, -16, s->height);
if (src_y != s->height)
dxy |= (motion_y & 1) << 1;
src += src_y * s->linesize + src_x;
if ((unsigned)src_x >= MAX(s->h_edge_pos - (motion_x & 1) - 7, 0) ||
(unsigned)src_y >= MAX(s->v_edge_pos - (motion_y & 1) - 7, 0)) {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, src, s->linesize, s->linesize, 9, 9, src_x, src_y,
s->h_edge_pos, s->v_edge_pos);
src = s->sc.edge_emu_buffer;
emu = 1;
}
pix_op[dxy](dest, src, s->linesize, 8);
return emu;
}
static inline void mpeg_motion_internal(PictureState *s, uint8 *dest_y, uint8 *dest_cb, uint8 *dest_cr, int field_based,
int bottom_field, int field_select, uint8 *const *ref_picture,
const PixelOp (*pix_op)[4], int motion_x, int motion_y, int h, int is_mpeg12,
int is_16x8, int mb_y) {
const uint8 *ptr_y, *ptr_cb, *ptr_cr;
int dxy, uvdxy, mx, my, src_x, src_y, uvsrc_x, uvsrc_y, v_edge_pos, block_y_half;
ptrdiff_t uvlinesize, linesize;
v_edge_pos = s->v_edge_pos >> field_based;
linesize = s->cur_pic.linesize[0] << field_based;
uvlinesize = s->cur_pic.linesize[1] << field_based;
block_y_half = (field_based | is_16x8);
dxy = ((motion_y & 1) << 1) | (motion_x & 1);
src_x = s->mb_x * 16 + (motion_x >> 1);
src_y = (mb_y << (4 - block_y_half)) + (motion_y >> 1);
if (!is_mpeg12 && FMT_H263 == FMT_H263) {
if ((0) && field_based) {
mx = (motion_x >> 1) | (motion_x & 1);
my = motion_y >> 1;
uvdxy = ((my & 1) << 1) | (mx & 1);
uvsrc_x = s->mb_x * 8 + (mx >> 1);
uvsrc_y = (mb_y << (3 - block_y_half)) + (my >> 1);
} else {
uvdxy = dxy | (motion_y & 2) | ((motion_x & 2) >> 1);
uvsrc_x = src_x >> 1;
uvsrc_y = src_y >> 1;
}
// Even chroma mv's are full pel in H261
} else if (!CONFIG_SMALL && !is_mpeg12 || CONFIG_SMALL && FMT_H263 == FMT_H261) {
assert(FMT_H263 == FMT_H261);
mx = motion_x / 4;
my = motion_y / 4;
uvdxy = 0;
uvsrc_x = s->mb_x * 8 + mx;
uvsrc_y = mb_y * 8 + my;
} else {
assert(FMT_H263 == FMT_MPEG1);
if (1) {
mx = motion_x / 2;
my = motion_y / 2;
uvdxy = ((my & 1) << 1) | (mx & 1);
uvsrc_x = s->mb_x * 8 + (mx >> 1);
uvsrc_y = (mb_y << (3 - block_y_half)) + (my >> 1);
} else {
if (s->chroma_x_shift) {
// Chroma422
mx = motion_x / 2;
uvdxy = ((motion_y & 1) << 1) | (mx & 1);
uvsrc_x = s->mb_x * 8 + (mx >> 1);
uvsrc_y = src_y;
} else {
// Chroma444
uvdxy = dxy;
uvsrc_x = src_x;
uvsrc_y = src_y;
}
}
}
ptr_y = ref_picture[0] + src_y * linesize + src_x;
ptr_cb = ref_picture[1] + uvsrc_y * uvlinesize + uvsrc_x;
ptr_cr = ref_picture[2] + uvsrc_y * uvlinesize + uvsrc_x;
if ((unsigned)src_x >= MAX(s->h_edge_pos - (motion_x & 1) - 15, 0) ||
(unsigned)src_y >= MAX(v_edge_pos - (motion_y & 1) - h + 1, 0)) {
if (is_mpeg12 || (CONFIG_SMALL && (false || false))) {
return;
}
src_y = (unsigned)src_y << field_based;
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr_y, s->linesize, s->linesize, 17, 17 + field_based, src_x,
src_y, s->h_edge_pos, s->v_edge_pos);
ptr_y = s->sc.edge_emu_buffer;
if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) {
uint8 *ubuf = s->sc.edge_emu_buffer + 18 * s->linesize;
uint8 *vbuf = ubuf + 10 * s->uvlinesize;
if (0)
vbuf -= s->uvlinesize;
uvsrc_y = (unsigned)uvsrc_y << field_based;
s->vdsp.emulated_edge_mc(ubuf, ptr_cb, s->uvlinesize, s->uvlinesize, 9, 9 + field_based, uvsrc_x, uvsrc_y,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
s->vdsp.emulated_edge_mc(vbuf, ptr_cr, s->uvlinesize, s->uvlinesize, 9, 9 + field_based, uvsrc_x, uvsrc_y,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
ptr_cb = ubuf;
ptr_cr = vbuf;
}
}
/* FIXME use this for field pix too instead of the obnoxious hack which
* changes picture.data */
if (bottom_field) {
dest_y += s->linesize;
dest_cb += s->uvlinesize;
dest_cr += s->uvlinesize;
}
if (field_select) {
ptr_y += s->linesize;
ptr_cb += s->uvlinesize;
ptr_cr += s->uvlinesize;
}
pix_op[0][dxy](dest_y, ptr_y, linesize, h);
if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) {
pix_op[s->chroma_x_shift][uvdxy](dest_cb, ptr_cb, uvlinesize, h >> 1);
pix_op[s->chroma_x_shift][uvdxy](dest_cr, ptr_cr, uvlinesize, h >> 1);
}
}
static inline void qpel_motion(PictureState *s, uint8 *dest_y, uint8 *dest_cb, uint8 *dest_cr, int field_based,
int bottom_field, int field_select, uint8 *const *ref_picture,
const PixelOp (*pix_op)[4], const QpelOp (*qpix_op)[16], int motion_x, int motion_y,
int h) {
const uint8 *ptr_y, *ptr_cb, *ptr_cr;
int dxy, uvdxy, mx, my, src_x, src_y, uvsrc_x, uvsrc_y, v_edge_pos;
ptrdiff_t linesize, uvlinesize;
dxy = ((motion_y & 3) << 2) | (motion_x & 3);
src_x = s->mb_x * 16 + (motion_x >> 2);
src_y = s->mb_y * (16 >> field_based) + (motion_y >> 2);
v_edge_pos = s->v_edge_pos >> field_based;
linesize = s->linesize << field_based;
uvlinesize = s->uvlinesize << field_based;
if (field_based) {
mx = motion_x / 2;
my = motion_y >> 1;
} else if (0) {
static const int rtab[8] = {0, 0, 1, 1, 0, 0, 0, 1};
mx = (motion_x >> 1) + rtab[motion_x & 7];
my = (motion_y >> 1) + rtab[motion_y & 7];
} else if (0) {
mx = (motion_x >> 1) | (motion_x & 1);
my = (motion_y >> 1) | (motion_y & 1);
} else {
mx = motion_x / 2;
my = motion_y / 2;
}
mx = (mx >> 1) | (mx & 1);
my = (my >> 1) | (my & 1);
uvdxy = (mx & 1) | ((my & 1) << 1);
mx >>= 1;
my >>= 1;
uvsrc_x = s->mb_x * 8 + mx;
uvsrc_y = s->mb_y * (8 >> field_based) + my;
ptr_y = ref_picture[0] + src_y * linesize + src_x;
ptr_cb = ref_picture[1] + uvsrc_y * uvlinesize + uvsrc_x;
ptr_cr = ref_picture[2] + uvsrc_y * uvlinesize + uvsrc_x;
if ((unsigned)src_x >= MAX(s->h_edge_pos - (motion_x & 3) - 15, 0) ||
(unsigned)src_y >= MAX(v_edge_pos - (motion_y & 3) - h + 1, 0)) {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr_y, s->linesize, s->linesize, 17, 17 + field_based, src_x,
src_y * (1 << field_based), s->h_edge_pos, s->v_edge_pos);
ptr_y = s->sc.edge_emu_buffer;
if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) {
uint8 *ubuf = s->sc.edge_emu_buffer + 18 * s->linesize;
uint8 *vbuf = ubuf + 10 * s->uvlinesize;
if (0)
vbuf -= s->uvlinesize;
s->vdsp.emulated_edge_mc(ubuf, ptr_cb, s->uvlinesize, s->uvlinesize, 9, 9 + field_based, uvsrc_x,
uvsrc_y * (1 << field_based), s->h_edge_pos >> 1, s->v_edge_pos >> 1);
s->vdsp.emulated_edge_mc(vbuf, ptr_cr, s->uvlinesize, s->uvlinesize, 9, 9 + field_based, uvsrc_x,
uvsrc_y * (1 << field_based), s->h_edge_pos >> 1, s->v_edge_pos >> 1);
ptr_cb = ubuf;
ptr_cr = vbuf;
}
}
if (!field_based)
qpix_op[0][dxy](dest_y, ptr_y, linesize);
else {
if (bottom_field) {
dest_y += s->linesize;
dest_cb += s->uvlinesize;
dest_cr += s->uvlinesize;
}
if (field_select) {
ptr_y += s->linesize;
ptr_cb += s->uvlinesize;
ptr_cr += s->uvlinesize;
}
// damn interlaced mode
// FIXME boundary mirroring is not exactly correct here
qpix_op[1][dxy](dest_y, ptr_y, linesize);
qpix_op[1][dxy](dest_y + 8, ptr_y + 8, linesize);
}
if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) {
pix_op[1][uvdxy](dest_cr, ptr_cr, uvlinesize, h >> 1);
pix_op[1][uvdxy](dest_cb, ptr_cb, uvlinesize, h >> 1);
}
}
/**
* H.263 chroma 4mv motion compensation.
*/
static void chroma_4mv_motion(PictureState *s, uint8 *dest_cb, uint8 *dest_cr, uint8 *const *ref_picture,
const PixelOp *pix_op, int mx, int my) {
const uint8 *ptr;
int src_x, src_y, dxy, emu = 0;
ptrdiff_t offset;
/* In case of 8X8, we construct a single chroma motion vector
* with a special rounding */
mx = ff_h263_round_chroma(mx);
my = ff_h263_round_chroma(my);
dxy = ((my & 1) << 1) | (mx & 1);
mx >>= 1;
my >>= 1;
src_x = s->mb_x * 8 + mx;
src_y = s->mb_y * 8 + my;
src_x = av_clip(src_x, -8, (s->width >> 1));
if (src_x == (s->width >> 1))
dxy &= ~1;
src_y = av_clip(src_y, -8, (s->height >> 1));
if (src_y == (s->height >> 1))
dxy &= ~2;
offset = src_y * s->uvlinesize + src_x;
ptr = ref_picture[1] + offset;
if ((unsigned)src_x >= MAX((s->h_edge_pos >> 1) - (dxy & 1) - 7, 0) ||
(unsigned)src_y >= MAX((s->v_edge_pos >> 1) - (dxy >> 1) - 7, 0)) {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr, s->uvlinesize, s->uvlinesize, 9, 9, src_x, src_y,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
ptr = s->sc.edge_emu_buffer;
emu = 1;
}
pix_op[dxy](dest_cb, ptr, s->uvlinesize, 8);
ptr = ref_picture[2] + offset;
if (emu) {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr, s->uvlinesize, s->uvlinesize, 9, 9, src_x, src_y,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
ptr = s->sc.edge_emu_buffer;
}
pix_op[dxy](dest_cr, ptr, s->uvlinesize, 8);
}
static inline void apply_8x8(PictureState *s, uint8 *dest_y, uint8 *dest_cb, uint8 *dest_cr, int dir,
uint8 *const *ref_picture, const QpelOp (*qpix_op)[16], const PixelOp (*pix_op)[4]) {
int dxy, mx, my, src_x, src_y;
int i;
int mb_x = s->mb_x;
int mb_y = s->mb_y;
uint8 *dest;
const uint8 *ptr;
mx = 0;
my = 0;
if (s->quarter_sample) {
for (i = 0; i < 4; i++) {
int motion_x = s->mv[dir][i][0];
int motion_y = s->mv[dir][i][1];
dxy = ((motion_y & 3) << 2) | (motion_x & 3);
src_x = mb_x * 16 + (motion_x >> 2) + (i & 1) * 8;
src_y = mb_y * 16 + (motion_y >> 2) + (i >> 1) * 8;
/* WARNING: do no forget half pels */
src_x = av_clip(src_x, -16, s->width);
if (src_x == s->width)
dxy &= ~3;
src_y = av_clip(src_y, -16, s->height);
if (src_y == s->height)
dxy &= ~12;
ptr = ref_picture[0] + (src_y * s->linesize) + (src_x);
if ((unsigned)src_x >= MAX(s->h_edge_pos - (motion_x & 3) - 7, 0) ||
(unsigned)src_y >= MAX(s->v_edge_pos - (motion_y & 3) - 7, 0)) {
s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr, s->linesize, s->linesize, 9, 9, src_x, src_y,
s->h_edge_pos, s->v_edge_pos);
ptr = s->sc.edge_emu_buffer;
}
dest = dest_y + ((i & 1) * 8) + (i >> 1) * 8 * s->linesize;
qpix_op[1][dxy](dest, ptr, s->linesize);
mx += s->mv[dir][i][0] / 2;
my += s->mv[dir][i][1] / 2;
}
} else {
for (i = 0; i < 4; i++) {
hpel_motion(s, dest_y + ((i & 1) * 8) + (i >> 1) * 8 * s->linesize, ref_picture[0], mb_x * 16 + (i & 1) * 8,
mb_y * 16 + (i >> 1) * 8, pix_op[1], s->mv[dir][i][0], s->mv[dir][i][1]);
mx += s->mv[dir][i][0];
my += s->mv[dir][i][1];
}
}
if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY))
chroma_4mv_motion(s, dest_cb, dest_cr, ref_picture, pix_op[1], mx, my);
}
static void concealMB(void *opaque, int ref, int dir, int type, int (*mv)[2][4][2], int x, int y, int intra,
int skipped) {
PictureState *s = static_cast<PictureState *>(opaque);
assert(!intra);
s->mb_x = x;
s->mb_y = y;
s->mb_intra = intra;
memcpy(s->mv, mv, sizeof(*mv));
uint8 *dest[3] = {s->cur_pic.data[0] + y * 16 * s->linesize + x * 16,
s->cur_pic.data[1] + y * 8 * s->uvlinesize + x * 8,
s->cur_pic.data[2] + y * 8 * s->uvlinesize + x * 8};
const PixelOp(*pixels)[4] = s->hdsp.put_pixels_tab;
const QpelOp(*qpel)[16] = s->qdsp.put_qpel_pixels_tab;
for (int d = 0; d < 2; ++d) {
if (!(dir & (1 << d)))
continue;
Picture &p = d ? s->next_pic : s->last_pic;
if (type == 1)
apply_8x8(s, dest[0], dest[1], dest[2], d, p.data, qpel, pixels);
else if (s->quarter_sample)
qpel_motion(s, dest[0], dest[1], dest[2], 0, 0, 0, p.data, pixels, qpel, s->mv[d][0][0], s->mv[d][0][1],
16);
else
mpeg_motion_internal(s, dest[0], dest[1], dest[2], 0, 0, 0, p.data, pixels, s->mv[d][0][0], s->mv[d][0][1],
16, 0, 0, y);
pixels = s->hdsp.avg_pixels_tab;
qpel = s->qdsp.avg_qpel_pixels_tab;
}
}
static int sad16(void *, const uint8 *a, const uint8 *b, ptrdiff_t stride, int h) {
int sum = 0;
for (int y = 0; y < h; ++y) {
for (int x = 0; x < 16; ++x)
sum += ABS(int(a[x]) - int(b[x]));
a += stride;
b += stride;
}
return sum;
}
void initializeER(PictureState *s) {
s->er.avctx = s->avctx;
s->er.sad = sad16;
s->er.decode_mb = concealMB;
s->er.opaque = s;
s->er.mb_num = s->mb_width * s->mb_height;
s->er.mb_width = s->mb_width;
s->er.mb_height = s->mb_height;
s->er.mb_stride = s->mb_stride;
s->er.b8_stride = s->b8_stride;
s->er.dc_val[0] = s->dc_val;
s->er.dc_val[1] = s->dc_val + s->b8_stride * 2 * FFALIGN(s->mb_height, 2) + s->mb_stride;
s->er.dc_val[2] = s->er.dc_val[1] + s->mb_stride * (FFALIGN(s->mb_height, 2) + 1);
s->er.mbskip_table = s->mbskip_table;
initQpel(&s->qdsp);
}
// Packet and slice storage
// Owns padded, unescaped data and its readers for one packet segment.
class Slice {
public:
Common::Array<uint8> data;
Common::ScopedPtr<Common::MemoryReadStream> input;
Common::ScopedPtr<Common::BitStream8MSB> stream;
Bits bits;
int row;
Slice(const uint8 *src, uint32 size, bool unescape) : input(nullptr), stream(nullptr), row(0) {
for (uint32 i = 0; i < size; ++i) {
if (unescape && i >= 2 && i + 1 < size && src[i] == 3 && src[i - 1] == 0 && src[i - 2] == 0 &&
src[i + 1] < 4)
continue;
data.push_back(src[i]);
}
int bytes = data.size();
data.resize(bytes + 64);
memset(data.data() + bytes, 0, 64);
input.reset(new Common::MemoryReadStream(data.data(), data.size()));
stream.reset(new Common::BitStream8MSB(input.get()));
bits.stream = stream.get();
bits.size_in_bits = bytes * 8;
}
private:
Slice(const Slice &) = delete;
Slice &operator=(const Slice &) = delete;
};
static uint32 nextMarker(const uint8 *p, uint32 size, uint32 from) {
for (uint32 i = from; i + 3 < size; ++i)
if (p[i] == 0 && p[i + 1] == 0 && p[i + 2] == 1)
return i;
return size;
}
Decoder::Decoder(int w, int h, bool advanced)
: _v(new VC1Context()), _settings{}, _pictures{}, _planes{}, _advanced(advanced), _ready(false), _failed(false),
_pending(false) {
_v->width = w;
_v->height = h;
_v->s.avctx = &_settings;
static const bool initialized = (initTables(), true);
(void)initialized;
_v->pq = 255;
initWMV3DSP(&_v->vc1dsp);
initSupport(&_v->s, &_v->h264chroma);
}
Decoder::~Decoder() {
clearPictures();
delete _v;
}
void Decoder::clearPictures() {
if (_v->x8) {
endX8(_v->x8);
delete _v->x8;
_v->x8 = nullptr;
}
for (uint i = 0; i < _allocations.size(); ++i)
delete[] _allocations[i];
_allocations.clear();
memset(_pictures, 0, sizeof(_pictures));
memset(_planes, 0, sizeof(_planes));
_v->s.cur_pic = {};
_v->s.last_pic = {};
_v->s.next_pic = {};
_pending = false;
}
bool Decoder::readHeader(const uint8 *data, uint32 size, bool entry) {
Common::MemoryReadStream input(data, size);
Common::BitStream8MSB bits(input);
return (entry ? readVC1Entry(_v, &bits) : readVC1Sequence(_v, &bits)) == 0;
}
bool Decoder::initialize(const uint8 *data, uint32 size) {
if (_ready || !size || size > 1024 * 1024)
return false;
if (!_advanced) {
if (!readHeader(data, size, false))
return false;
} else {
bool sequence = false, entry = false;
uint32 start = nextMarker(data, size, 0);
while (start < size) {
uint32 end = nextMarker(data, size, start + 4);
Slice chunk(data + start + 4, end - start - 4, true);
if (data[start + 3] == 15) {
if (!readHeader(chunk.data.data(), chunk.bits.size_in_bits / 8, false))
return false;
sequence = true;
}
if (data[start + 3] == 14) {
if (!readHeader(chunk.data.data(), chunk.bits.size_in_bits / 8, true))
return false;
entry = true;
}
start = end;
}
if (!sequence || !entry)
return false;
}
if (_v->width <= 0 || _v->height <= 0 || _v->width > 8192 || _v->height > 8192)
return false;
allocatePictures();
_ready = true;
return true;
}
// Picture allocation and initialization
// Keep allocation order explicit: predictors, reference pictures, concealment, transforms.
void Decoder::allocatePictures() {
initializePictureLayout();
allocatePredictors();
allocateReferencePictures();
initializeConcealment();
initializeTransforms();
}
void Decoder::initializePictureLayout() {
VC1Context *v = _v;
PictureState *s = &v->s;
s->height = v->height;
s->width = v->width;
_settings.coded_width = v->width;
_settings.coded_height = v->height;
s->mb_width = (v->width + 15) >> 4;
s->mb_height = (v->height + 15) >> 4;
s->mb_stride = s->mb_width + 1;
s->b8_stride = s->mb_width * 2 + 1;
s->chroma_x_shift = 1;
s->low_delay = !v->max_b_frames || v->res_sprite;
s->h_edge_pos = v->profile == PROFILE_ADVANCED ? v->width : s->mb_width * 16;
s->v_edge_pos = v->profile == PROFILE_ADVANCED ? v->height : s->mb_height * 16;
s->linesize = FFALIGN(s->mb_width * 16 + 64, 32);
s->uvlinesize = s->linesize / 2;
for (int i = 0; i < 6; ++i)
s->block_wrap[i] = i < 4 ? s->b8_stride : s->mb_stride;
}
void Decoder::allocatePredictors() {
VC1Context *v = _v;
PictureState *s = &v->s;
const int alignedMacroblockHeight = FFALIGN(s->mb_height, 2);
const int lumaPredictorCount = s->b8_stride * (2 * alignedMacroblockHeight + 1);
const int chromaPredictorCount = s->mb_stride * (alignedMacroblockHeight + 1);
const int predictorCount = lumaPredictorCount + 2 * chromaPredictorCount;
s->coded_block = allocate<uint8>(lumaPredictorCount) + s->b8_stride + 1;
s->dc_val = allocate<int16>(predictorCount) + s->b8_stride + 1;
for (int i = 0; i < predictorCount; ++i)
(s->dc_val - s->b8_stride - 1)[i] = 1024;
s->ac_val = allocate<int16[16]>(predictorCount) + s->b8_stride + 1;
s->mbskip_table = allocate<uint8>(s->mb_stride * alignedMacroblockHeight + 2);
s->sc.edge_emu_buffer = allocate<uint8>(s->linesize * 128);
v->mv_type_mb_plane = allocate<uint8>(s->mb_stride * alignedMacroblockHeight);
v->direct_mb_plane = allocate<uint8>(s->mb_stride * alignedMacroblockHeight);
v->forward_mb_plane = allocate<uint8>(s->mb_stride * alignedMacroblockHeight);
v->fieldtx_plane = allocate<uint8>(s->mb_stride * alignedMacroblockHeight);
v->acpred_plane = allocate<uint8>(s->mb_stride * alignedMacroblockHeight);
v->over_flags_plane = allocate<uint8>(s->mb_stride * alignedMacroblockHeight);
v->n_allocated_blks = s->mb_width + 2;
v->block = allocate<int16[6][64]>(v->n_allocated_blks);
v->cbp_base = allocate<uint32>(3 * s->mb_stride);
v->cbp = v->cbp_base + 2 * s->mb_stride;
v->ttblk_base = allocate<int>(3 * s->mb_stride);
v->ttblk = v->ttblk_base + 2 * s->mb_stride;
v->is_intra_base = allocate<uint8>(3 * s->mb_stride);
v->is_intra = v->is_intra_base + 2 * s->mb_stride;
v->luma_mv_base = allocate<int16[2]>(3 * s->mb_stride);
v->luma_mv = v->luma_mv_base + 2 * s->mb_stride;
v->mb_type_base = allocate<uint8>(predictorCount);
v->mb_type = v->mb_type_base + s->b8_stride + 1;
v->blk_mv_type_base = allocate<uint8>(lumaPredictorCount);
v->blk_mv_type = v->blk_mv_type_base + s->b8_stride + 1;
v->mv_f_base = allocate<uint8>(2 * predictorCount);
v->mv_f[0] = v->mv_f_base + s->b8_stride + 1;
v->mv_f[1] = v->mv_f[0] + predictorCount;
v->mv_f_next_base = allocate<uint8>(2 * predictorCount);
v->mv_f_next[0] = v->mv_f_next_base + s->b8_stride + 1;
v->mv_f_next[1] = v->mv_f_next[0] + predictorCount;
}
void Decoder::allocateReferencePictures() {
VC1Context *v = _v;
PictureState *s = &v->s;
const int alignedMacroblockHeight = FFALIGN(s->mb_height, 2);
const int lumaPredictorCount = s->b8_stride * (2 * alignedMacroblockHeight + 1);
const int chromaPredictorCount = s->mb_stride * (alignedMacroblockHeight + 1);
for (int n = 0; n < 3; ++n) {
Picture &p = _pictures[n];
p.f = &_planes[n];
p.f->width = v->width;
p.f->height = v->height;
p.ptr = &p;
for (int i = 0; i < 3; ++i) {
int stride = i ? s->uvlinesize : s->linesize;
int height = alignedMacroblockHeight * (i ? 8 : 16);
p.data[i] = allocate<uint8>(stride * (height + 64)) + stride * 32 + 32;
p.linesize[i] = stride;
p.f->data[i] = p.data[i];
p.f->linesize[i] = stride;
}
p.qscale_table = allocate<int8>(chromaPredictorCount);
p.mb_type = allocate<uint32>(chromaPredictorCount);
for (int i = 0; i < 2; ++i)
p.ref_index[i] = allocate<int8>(4 * chromaPredictorCount);
for (int i = 0; i < 2; ++i)
p.motion_val[i] = allocate<int16[2]>(lumaPredictorCount + 2 * s->b8_stride) + s->b8_stride + 1;
}
}
void Decoder::initializeConcealment() {
VC1Context *v = _v;
PictureState *s = &v->s;
const int alignedMacroblockHeight = FFALIGN(s->mb_height, 2);
initializeER(s);
s->er.error_status_table = allocate<uint8>(s->mb_stride * alignedMacroblockHeight);
s->er.er_temp_buffer = allocate<uint8>(s->mb_stride * alignedMacroblockHeight * (4 * sizeof(int) + 1));
s->er.mbintra_table = allocate<uint8>(s->mb_stride * alignedMacroblockHeight);
memset(s->er.mbintra_table, 1, s->mb_stride * alignedMacroblockHeight);
s->er.mb_index2xy = allocate<int>(s->mb_width * alignedMacroblockHeight + 1);
for (int y = 0; y < alignedMacroblockHeight; ++y)
for (int x = 0; x < s->mb_width; ++x)
s->er.mb_index2xy[x + y * s->mb_width] = x + y * s->mb_stride;
s->er.mb_index2xy[s->er.mb_num] = (s->mb_height - 1) * s->mb_stride + s->mb_width;
}
void Decoder::initializeTransforms() {
VC1Context *v = _v;
PictureState *s = &v->s;
v->x8 = new IntraX8Context();
initX8(v->x8, v->blocks[0], s->mb_width, s->mb_height);
for (int i = 0; i < 64; ++i) {
for (int j = 0; j < 4; ++j) {
int x = ff_wmv1_scantable[j][i];
v->zz_8x8[j][i] = v->profile == PROFILE_ADVANCED || v->res_fasttx ? ((x >> 3) | ((x & 7) << 3)) : x;
}
int x = ff_vc1_adv_interlaced_8x8_zz[i];
v->zzi_8x8[i] = (x >> 3) | ((x & 7) << 3);
}
v->left_blk_sh = 0;
v->top_blk_sh = 3;
if (v->profile != PROFILE_ADVANCED && !v->res_fasttx) {
v->left_blk_sh = 3;
v->top_blk_sh = 0;
v->vc1dsp.vc1_inv_trans_8x8 = ff_simple_idct_int16_8bit;
v->vc1dsp.vc1_inv_trans_8x8_dc = ff_simple_idct_add_int16_8bit;
v->vc1dsp.vc1_inv_trans_8x4 = v->vc1dsp.vc1_inv_trans_8x4_dc = ff_simple_idct84_add;
v->vc1dsp.vc1_inv_trans_4x8 = v->vc1dsp.vc1_inv_trans_4x8_dc = ff_simple_idct48_add;
v->vc1dsp.vc1_inv_trans_4x4 = v->vc1dsp.vc1_inv_trans_4x4_dc = ff_simple_idct44_add;
}
}
const Picture *Decoder::decode(const uint8 *data, uint32 size) {
_failed = false;
if (!_ready || size > 64 * 1024 * 1024) {
_failed = true;
return nullptr;
}
if (!size)
return drain();
const Picture *output = nullptr;
if (!decodePacket(data, size, output)) {
_failed = true;
return nullptr;
}
return output;
}
const Picture *Decoder::drain() {
if (!_pending)
return nullptr;
_pending = false;
return _v->s.next_pic.ptr;
}
// Packet decoding and reference-frame ordering
bool Decoder::decodePacket(const uint8 *data, uint32 size, const Picture *&output) {
VC1Context *v = _v;
PictureState *s = &v->s;
Common::Array<Slice *> chunks;
struct Cleanup {
Common::Array<Slice *> &a;
~Cleanup() {
for (uint i = 0; i < a.size(); ++i)
delete a[i];
}
} cleanup{chunks};
int firstFieldLast = -1;
if (_advanced) {
uint32 start = nextMarker(data, size, 0);
if (start > 0) {
chunks.push_back(new Slice(data, start, true));
}
while (start < size) {
uint32 end = nextMarker(data, size, start + 4);
uint8 type = data[start + 3];
if (type == 14) {
Slice chunk(data + start + 4, end - start - 4, true);
if (!readHeader(chunk.data.data(), chunk.bits.size_in_bits / 8, true))
return false;
} else if (type == 13 || type == 12 || type == 11) {
Slice *chunk = new Slice(data + start + 4, end - start - 4, true);
if (type == 12) {
chunk->row = (v->height + 31) >> 5;
firstFieldLast = int(chunks.size()) - 2;
} else if (type == 11)
chunk->row = get_bits(&chunk->bits, 9);
chunks.push_back(chunk);
}
start = end;
}
} else
chunks.push_back(new Slice(data, size, false));
if (chunks.empty())
return false;
if (_settings.coded_width != v->width || _settings.coded_height != v->height) {
clearPictures();
allocatePictures();
}
v->gb = chunks[0]->bits;
v->second_field = 0;
if (v->res_sprite) {
v->new_sprite = !get_bits1(&v->gb);
v->two_sprites = get_bits1(&v->gb);
}
v->pic_header_flag = 0;
v->first_pic_header_flag = 1;
int result =
v->profile < PROFILE_ADVANCED ? ff_vc1_parse_frame_header(v, &v->gb) : ff_vc1_parse_frame_header_adv(v, &v->gb);
v->first_pic_header_flag = 0;
if (result < 0 || get_bits_left(&v->gb) < 0)
return false;
if (s->pict_type == AV_PICTURE_TYPE_B && !s->last_pic.ptr)
return true;
Picture *current = nullptr;
for (int i = 0; i < 3; ++i)
if (&_pictures[i] != s->last_pic.ptr && &_pictures[i] != s->next_pic.ptr) {
current = &_pictures[i];
break;
}
if (!current)
return false;
s->cur_pic = *current;
if (s->pict_type != AV_PICTURE_TYPE_B) {
s->last_pic = s->next_pic;
s->next_pic = s->cur_pic;
}
if (s->pict_type != AV_PICTURE_TYPE_I && !s->last_pic.ptr)
return false;
current->field_picture = v->field_mode;
current->f->pict_type = s->pict_type;
current->interlaced = v->fcm != PROGRESSIVE;
v->last_interlaced = s->last_pic.ptr ? s->last_pic.ptr->interlaced : 0;
v->next_interlaced = s->next_pic.ptr ? s->next_pic.ptr->interlaced : 0;
s->er.cur_pic = s->cur_pic;
s->er.last_pic = s->last_pic;
s->er.next_pic = s->next_pic;
s->er.quarter_sample = s->quarter_sample;
ff_er_frame_start(&s->er);
v->end_mb_x = s->mb_width;
if (v->field_mode) {
for (int i = 0; i < 3; ++i)
s->cur_pic.linesize[i] *= 2;
s->linesize *= 2;
s->uvlinesize *= 2;
}
int mh = s->mb_height >> v->field_mode;
bool ok = mh > 0;
for (uint i = 0; ok && i < chunks.size(); ++i) {
v->second_field = i > 0 && chunks[i]->row >= mh;
if (v->second_field && !v->field_mode) {
ok = false;
break;
}
v->blocks_off = v->second_field ? s->b8_stride * (s->mb_height & ~1) : 0;
v->mb_off = v->second_field ? (s->mb_stride * s->mb_height) >> 1 : 0;
if (i) {
v->gb = chunks[i]->bits;
v->pic_header_flag = 0;
if ((v->field_mode && int(i) == firstFieldLast + 2) || (v->pic_header_flag = get_bits1(&v->gb))) {
if (ff_vc1_parse_frame_header_adv(v, &v->gb) < 0) {
ok = false;
break;
}
}
}
s->start_mb_y = i ? MAX(0, chunks[i]->row % mh) : 0;
if (!v->field_mode || v->second_field)
s->end_mb_y = i + 1 == chunks.size() ? mh : MIN(mh, chunks[i + 1]->row % mh);
else {
if (i + 1 >= chunks.size()) {
ok = false;
break;
}
s->end_mb_y = int(i) == firstFieldLast + 1 ? mh : MIN(mh, chunks[i + 1]->row % mh);
}
if (s->end_mb_y <= s->start_mb_y) {
ok = false;
break;
}
if (((s->pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) ||
(s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type)) &&
!v->cbpcy_vlc) {
ok = false;
break;
}
ff_vc1_decode_blocks(v);
}
if (v->field_mode) {
v->second_field = 0;
for (int i = 0; i < 3; ++i)
s->cur_pic.linesize[i] /= 2;
s->linesize /= 2;
s->uvlinesize /= 2;
if (s->pict_type != AV_PICTURE_TYPE_B) {
SWAP(v->mv_f_next[0], v->mv_f[0]);
SWAP(v->mv_f_next[1], v->mv_f[1]);
}
}
if (!ok)
return false;
if (s->er.error_occurred && s->pict_type == AV_PICTURE_TYPE_B)
return false;
if (!v->field_mode)
ff_er_frame_end(&s->er, nullptr);
if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay)
output = current;
else {
output = s->last_pic.ptr;
_pending = true;
}
return true;
}
} // namespace VC1
// ScummVM codec interface
WMV3Decoder::WMV3Decoder(int width, int height, bool advanced)
: _decoder(new VC1::Decoder(width, height, advanced)), _format(Codec::getDefaultYUVFormat()) {
}
WMV3Decoder::~WMV3Decoder() {
_surface.free();
delete _decoder;
}
bool WMV3Decoder::setExtraData(Common::SeekableReadStream &stream) {
int64 size = stream.size() - stream.pos();
if (size <= 0 || size > 1024 * 1024)
return false;
Common::Array<uint8> data;
data.resize(size);
if (stream.read(data.data(), size) != size)
return false;
return _decoder->initialize(data.data(), size);
}
const Graphics::Surface *WMV3Decoder::decodeFrame(Common::SeekableReadStream &stream) {
int64 size = stream.size() - stream.pos();
if (size < 0 || size > 64 * 1024 * 1024)
return nullptr;
Common::Array<uint8> data;
data.resize(size);
if (size && stream.read(data.data(), size) != size)
return nullptr;
return convert(_decoder->decode(data.data(), size));
}
const Graphics::Surface *WMV3Decoder::drainFrame() {
return convert(_decoder->drain());
}
bool WMV3Decoder::hasError() const {
return _decoder->failed();
}
bool WMV3Decoder::setOutputPixelFormat(const Graphics::PixelFormat &format) {
if (format.bytesPerPixel != 2 && format.bytesPerPixel != 4)
return false;
if (format != _format) {
_surface.free();
_format = format;
}
return true;
}
const Graphics::Surface *WMV3Decoder::convert(const VC1::Picture *picture) {
if (!picture)
return nullptr;
int w = _decoder->width(), h = _decoder->height();
if (!_surface.getPixels() || _surface.w != w || _surface.h != h) {
_surface.free();
_surface.create((w + 1) & ~1, (h + 1) & ~1, _format);
}
YUVToRGBMan.convert420(&_surface, Graphics::YUVToRGBManager::kScaleITU, picture->data[0], picture->data[1],
picture->data[2], (w + 1) & ~1, (h + 1) & ~1, picture->linesize[0], picture->linesize[1]);
_surface.w = w;
_surface.h = h;
return &_surface;
}
} // namespace Image