This source file includes following definitions.
- Resize
- decoder_create
- packed_mode
- Init
- get_dc_scaler
- XVID_ClearMatrix
- MBIntra
- mb_decode
- DecodeInterMacroBlock
- gmc_sanitize
- mbgmc
- I_Frame
- GetMotionVector
- P_Frame
- get_b_motion_vector
- BFrameInterpolateMBInter
- get_dbquant
- get_mbtype
- B_Frame
- Decode
#include "quant.h"
#include "quant_matrix.h"
#include "interpolate8x8.h"
#include "reduced.h"
#include "mbprediction.h"
#include "gmc.h"
#include "mem_align.h"
#ifdef __SYMBIAN32__
#include <e32base.h>
#endif
# define DECLARE_ALIGNED_MATRIX(name,sizex,sizey,type,alignment) \
type name##_storage[(sizex)*(sizey)+(alignment)-1]; \
type * name = (type *) (((int) name##_storage+(alignment - 1)) & ~((int)(alignment)-1))
static const dword roundtab_76[16] = { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 };
const dword roundtab_79[4] = { 0, 1, 0, 0 };
int S_decoder::Resize() {
image_destroy(&cur, edged_width, edged_height);
image_destroy(&refn[0], edged_width, edged_height);
image_destroy(&refn[1], edged_width, edged_height);
image_destroy(&tmp, edged_width, edged_height);
image_destroy(&qtmp, edged_width, edged_height);
image_destroy(&gmc, edged_width, edged_height);
if(last_mbs)
xvid_free(last_mbs);
if(mbs)
xvid_free(mbs);
mb_width = (width + 15) / 16;
mb_height = (height + 15) / 16;
edged_width = 16 * mb_width + 2 * EDGE_SIZE;
edged_height = 16 * mb_height + 2 * EDGE_SIZE;
if(image_create(&cur, edged_width, edged_height)) {
xvid_free(this);
return XVID_ERR_MEMORY;
}
if(image_create(&refn[0], edged_width, edged_height)) {
image_destroy(&cur, edged_width, edged_height);
xvid_free(this);
return XVID_ERR_MEMORY;
}
if(image_create(&refn[1], edged_width, edged_height)) {
image_destroy(&cur, edged_width, edged_height);
image_destroy(&refn[0], edged_width, edged_height);
xvid_free(this);
return XVID_ERR_MEMORY;
}
if(image_create(&tmp, edged_width, edged_height)) {
image_destroy(&cur, edged_width, edged_height);
image_destroy(&refn[0], edged_width, edged_height);
image_destroy(&refn[1], edged_width, edged_height);
xvid_free(this);
return XVID_ERR_MEMORY;
}
if(image_create(&qtmp, edged_width, edged_height)) {
image_destroy(&cur, edged_width, edged_height);
image_destroy(&refn[0], edged_width, edged_height);
image_destroy(&refn[1], edged_width, edged_height);
image_destroy(&tmp, edged_width, edged_height);
xvid_free(this);
return XVID_ERR_MEMORY;
}
if(image_create(&gmc, edged_width, edged_height)) {
image_destroy(&qtmp, edged_width, edged_height);
image_destroy(&cur, edged_width, edged_height);
image_destroy(&refn[0], edged_width, edged_height);
image_destroy(&refn[1], edged_width, edged_height);
image_destroy(&tmp, edged_width, edged_height);
xvid_free(this);
return XVID_ERR_MEMORY;
}
mbs = (MACROBLOCK*)xvid_malloc(sizeof(MACROBLOCK) * mb_width * mb_height, CACHE_LINE);
if(mbs == NULL) {
image_destroy(&cur, edged_width, edged_height);
image_destroy(&refn[0], edged_width, edged_height);
image_destroy(&refn[1], edged_width, edged_height);
image_destroy(&tmp, edged_width, edged_height);
image_destroy(&qtmp, edged_width, edged_height);
xvid_free(this);
return XVID_ERR_MEMORY;
}
MemSet(mbs, 0, sizeof(MACROBLOCK) * mb_width * mb_height);
last_mbs = (MACROBLOCK*)xvid_malloc(sizeof(MACROBLOCK) * mb_width * mb_height, CACHE_LINE);
if(!last_mbs) {
xvid_free(mbs);
image_destroy(&cur, edged_width, edged_height);
image_destroy(&refn[0], edged_width, edged_height);
image_destroy(&refn[1], edged_width, edged_height);
image_destroy(&tmp, edged_width, edged_height);
image_destroy(&qtmp, edged_width, edged_height);
xvid_free(this);
return XVID_ERR_MEMORY;
}
MemSet(last_mbs, 0, sizeof(MACROBLOCK) * mb_width * mb_height);
return 0;
}
int decoder_create(xvid_dec_create_t *create) {
if(XVID_VERSION_MAJOR(create->version) != 1)
return XVID_ERR_VERSION;
S_decoder *dec = (S_decoder*)xvid_malloc(sizeof(S_decoder), CACHE_LINE);
if(!dec)
return XVID_ERR_MEMORY;
return dec->Init(create);
}
S_decoder::S_decoder(xvid_dec_create_t *create):
#ifdef PROFILE
prof(*create->prof),
#endif
time_inc_resolution(0),
fixed_time_inc(0),
time_inc_bits(0),
shape(0),
quant_bits(0),
quant_type(0),
mpeg_quant_matrices(0),
quarterpel(0),
complexity_estimation_disable(0),
interlacing(false),
top_field_first(0),
alternate_vertical_scan(0),
aspect_ratio(0),
par_width(0),
par_height(0),
sprite_enable(0),
sprite_warping_points(0),
sprite_warping_accuracy(0),
sprite_brightness_change(0),
newpred_enable(0),
reduced_resolution_enable(false),
bs_version(0),
width(0),
height(0),
edged_width(0),
edged_height(0),
mb_width(0),
mb_height(0),
mbs(0),
last_mbs(0),
last_coding_type(0),
frames(0),
time(0),
time_base(0),
last_time_base(0),
last_non_b_time(0),
time_pp(0),
time_bp(0),
fixed_dimensions(false),
scalability(false),
low_delay(false),
low_delay_default(false),
last_reduced_resolution(false),
packed_mode(false)
{
MemSet(&p_fmv, 0, sizeof(p_fmv));
MemSet(&p_bmv, 0, sizeof(p_bmv));
}
S_decoder::~S_decoder() {
xvid_free(last_mbs);
xvid_free(mbs);
image_destroy(&gmc, edged_width, edged_height);
image_destroy(&refn[0], edged_width, edged_height);
image_destroy(&refn[1], edged_width, edged_height);
image_destroy(&tmp, edged_width, edged_height);
image_destroy(&qtmp, edged_width, edged_height);
image_destroy(&cur, edged_width, edged_height);
xvid_free(mpeg_quant_matrices);
}
int S_decoder::Init(xvid_dec_create_t *create) {
mpeg_quant_matrices = (dword*)xvid_malloc(sizeof(dword) * 64 * 8, CACHE_LINE);
if(!mpeg_quant_matrices) {
delete this;
return XVID_ERR_MEMORY;
}
create->handle = this;
width = create->width;
height = create->height;
cur.Null();
refn[0].Null();
refn[1].Null();
tmp.Null();
qtmp.Null();
gmc.Null();
mbs = NULL;
last_mbs = NULL;
init_mpeg_matrix(mpeg_quant_matrices);
frames = 0;
time = time_base = last_time_base = 0;
low_delay = false;
packed_mode = false;
fixed_dimensions = (width > 0 && height > 0);
init_vlc_tables();
idct_int32_init();
if(fixed_dimensions)
return Resize();
return 0;
}
static const int dquant_table[4] = {
-1, -2, 1, 2
};
static dword get_dc_scaler(dword quant, dword lum) {
if(quant < 5)
return 8;
if(quant < 25 && !lum)
return (quant + 13) / 2;
if(quant < 9)
return 2 * quant;
if(quant < 25)
return quant + 8;
if(lum)
return 2 * quant - 16;
return quant - 6;
}
#ifdef _ARM_
extern"C"
void XVID_ClearMatrix(void *dst);
#else
void XVID_ClearMatrix(void *dst);
#ifndef USE_ARM_ASM
inline void XVID_ClearMatrix(void *dst) {
MemSet(dst, 0, 64 * sizeof(int));
}
#endif
#endif
void S_decoder::MBIntra(MACROBLOCK *pMB, dword x_pos, dword y_pos, dword acpred_flag, dword cbp, Bitstream *bs,
dword quant, dword intra_dc_threshold, dword bound, bool reduced_resolution) {
DECLARE_ALIGNED_MATRIX(block, 6, 64, int, CACHE_LINE);
DECLARE_ALIGNED_MATRIX(data, 6, 64, int, CACHE_LINE);
int i;
dword stride = edged_width;
const dword stride2 = stride / 2;
byte *pY_Cur, *pU_Cur, *pV_Cur;
if(reduced_resolution) {
pY_Cur = cur.y + (y_pos << 5) * stride + (x_pos << 5);
pU_Cur = cur.u + (y_pos << 4) * stride2 + (x_pos << 4);
pV_Cur = cur.v + (y_pos << 4) * stride2 + (x_pos << 4);
} else {
pY_Cur = cur.y + (y_pos << 4) * stride + (x_pos << 4);
pU_Cur = cur.u + (y_pos << 3) * stride2 + (x_pos << 3);
pV_Cur = cur.v + (y_pos << 3) * stride2 + (x_pos << 3);
}
MemSet(block, 0, 6 * 64 * sizeof(int));
const dword iQuant = pMB->quant;
for(i = 0; i < 6; i++) {
dword iDcScaler = get_dc_scaler(iQuant, i < 4);
int predictors[8];
int start_coeff;
predict_acdc(mbs, x_pos, y_pos, mb_width, i, &block[i * 64], iQuant, iDcScaler, predictors, bound);
if(!acpred_flag)
pMB->acpred_directions[i] = 0;
if(quant < intra_dc_threshold) {
PROF_S(PROF_1);
int dc_size;
int dc_dif;
dc_size = i < 4 ? bs->get_dc_size_lum() : bs->get_dc_size_chrom();
dc_dif = dc_size ? bs->get_dc_dif(dc_size) : 0;
if (dc_size > 8) {
bs->Skip(1);
}
block[i * 64 + 0] = dc_dif;
start_coeff = 1;
DPRINTF(XVID_DEBUG_COEFF,"block[0] %i\n", dc_dif);
PROF_E(PROF_1);
} else {
start_coeff = 0;
}
if(cbp & (1 << (5 - i))) {
int direction = alternate_vertical_scan ? 2 : pMB->acpred_directions[i];
get_intra_block(bs, &block[i * 64], direction, start_coeff);
}
add_acdc(pMB, i, &block[i * 64], iDcScaler, predictors);
if(quant_type == 0) {
dequant_h263_intra(&data[i * 64], &block[i * 64], iQuant, iDcScaler, mpeg_quant_matrices);
} else {
dequant_mpeg_intra(&data[i * 64], &block[i * 64], iQuant, iDcScaler, mpeg_quant_matrices);
}
InverseDiscreteCosineTransform(&data[i * 64]);
}
dword next_block = stride * 8;
if(interlacing && pMB->field_dct) {
next_block = stride;
stride *= 2;
}
if(reduced_resolution) {
next_block*=2;
copy_upsampled_8x8_16to8(pY_Cur, &data[0 * 64], stride);
copy_upsampled_8x8_16to8(pY_Cur + 16, &data[1 * 64], stride);
copy_upsampled_8x8_16to8(pY_Cur + next_block, &data[2 * 64], stride);
copy_upsampled_8x8_16to8(pY_Cur + 16 + next_block, &data[3 * 64], stride);
copy_upsampled_8x8_16to8(pU_Cur, &data[4 * 64], stride2);
copy_upsampled_8x8_16to8(pV_Cur, &data[5 * 64], stride2);
} else {
transfer_16to8copy(pY_Cur, &data[0 * 64], stride);
transfer_16to8copy(pY_Cur + 8, &data[1 * 64], stride);
transfer_16to8copy(pY_Cur + next_block, &data[2 * 64], stride);
transfer_16to8copy(pY_Cur + 8 + next_block, &data[3 * 64], stride);
transfer_16to8copy(pU_Cur, &data[4 * 64], stride2);
transfer_16to8copy(pV_Cur, &data[5 * 64], stride2);
}
}
void S_decoder::mb_decode(const dword cbp, Bitstream * bs, byte * pY_Cur, byte * pU_Cur, byte * pV_Cur, bool reduced_resolution, const MACROBLOCK *pMB) {
DECLARE_ALIGNED_MATRIX(block, 1, 64, int, CACHE_LINE);
DECLARE_ALIGNED_MATRIX(data, 6, 64, int, CACHE_LINE);
int i;
int stride = edged_width;
const int stride2 = stride/2;
const dword iQuant = pMB->quant;
const int direction = alternate_vertical_scan ? 2 : 0;
const quant_interFuncPtr dequant = quant_type == 0 ? dequant_h263_inter : dequant_mpeg_inter;
for(i = 0; i < 6; i++) {
if(cbp & (1 << (5 - i))) {
XVID_ClearMatrix(block);
get_inter_block(bs, block, direction);
dequant(&data[i * 64], block, iQuant, mpeg_quant_matrices);
InverseDiscreteCosineTransform(&data[i * 64]);
}
}
int next_block = stride * (reduced_resolution ? 16 : 8);
if(interlacing && pMB->field_dct) {
next_block = stride;
stride *= 2;
}
if(reduced_resolution) {
if(cbp & 32)
add_upsampled_8x8_16to8(pY_Cur, &data[0 * 64], stride);
if(cbp & 16)
add_upsampled_8x8_16to8(pY_Cur + 16, &data[1 * 64], stride);
if(cbp & 8)
add_upsampled_8x8_16to8(pY_Cur + next_block, &data[2 * 64], stride);
if(cbp & 4)
add_upsampled_8x8_16to8(pY_Cur + 16 + next_block, &data[3 * 64], stride);
if(cbp & 2)
add_upsampled_8x8_16to8(pU_Cur, &data[4 * 64], stride2);
if(cbp & 1)
add_upsampled_8x8_16to8(pV_Cur, &data[5 * 64], stride2);
} else {
if(cbp & 32)
transfer_16to8add(pY_Cur, &data[0 * 64], stride);
if(cbp & 16)
transfer_16to8add(pY_Cur + 8, &data[1 * 64], stride);
if(cbp & 8)
transfer_16to8add(pY_Cur + next_block, &data[2 * 64], stride);
if(cbp & 4)
transfer_16to8add(pY_Cur + 8 + next_block, &data[3 * 64], stride);
if(cbp & 2)
transfer_16to8add(pU_Cur, &data[4 * 64], stride2);
if(cbp & 1)
transfer_16to8add(pV_Cur, &data[5 * 64], stride2);
}
}
void S_decoder::DecodeInterMacroBlock(const MACROBLOCK * pMB, dword x_pos, dword y_pos, dword cbp, Bitstream *bs,
bool rounding, bool reduced_resolution, int ref) {
dword stride = edged_width;
dword stride2 = stride / 2;
dword i;
byte *pY_Cur, *pU_Cur, *pV_Cur;
int uv_dx, uv_dy;
VECTOR mv[4];
if(reduced_resolution) {
pY_Cur = cur.y + (y_pos << 5) * stride + (x_pos << 5);
pU_Cur = cur.u + (y_pos << 4) * stride2 + (x_pos << 4);
pV_Cur = cur.v + (y_pos << 4) * stride2 + (x_pos << 4);
for (i = 0; i < 4; i++) {
mv[i].x = RRV_MV_SCALEUP(pMB->mvs[i].x);
mv[i].y = RRV_MV_SCALEUP(pMB->mvs[i].y);
}
} else {
pY_Cur = cur.y + (y_pos << 4) * stride + (x_pos << 4);
pU_Cur = cur.u + (y_pos << 3) * stride2 + (x_pos << 3);
pV_Cur = cur.v + (y_pos << 3) * stride2 + (x_pos << 3);
for(i = 0; i < 4; i++)
mv[i] = pMB->mvs[i];
}
if(pMB->mode != MODE_INTER4V) {
uv_dx = mv[0].x;
uv_dy = mv[0].y;
if (quarterpel) {
uv_dx /= 2;
uv_dy /= 2;
}
uv_dx = (uv_dx >> 1) + roundtab_79[uv_dx & 0x3];
uv_dy = (uv_dy >> 1) + roundtab_79[uv_dy & 0x3];
if(reduced_resolution)
interpolate32x32_switch(cur.y, refn[0].y, 32*x_pos, 32*y_pos, mv[0].x, mv[0].y, stride, rounding);
else if(quarterpel)
interpolate16x16_quarterpel(cur.y, refn[ref].y, qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos, 16*y_pos, mv[0].x, mv[0].y, stride, rounding);
else
interpolate16x16_switch(cur.y, refn[ref].y, 16*x_pos, 16*y_pos, mv[0].x, mv[0].y, stride, rounding);
} else {
if(quarterpel) {
uv_dx = (mv[0].x / 2) + (mv[1].x / 2) + (mv[2].x / 2) + (mv[3].x / 2);
uv_dy = (mv[0].y / 2) + (mv[1].y / 2) + (mv[2].y / 2) + (mv[3].y / 2);
} else {
uv_dx = mv[0].x + mv[1].x + mv[2].x + mv[3].x;
uv_dy = mv[0].y + mv[1].y + mv[2].y + mv[3].y;
}
uv_dx = (uv_dx >> 3) + roundtab_76[uv_dx & 0xf];
uv_dy = (uv_dy >> 3) + roundtab_76[uv_dy & 0xf];
if(reduced_resolution) {
interpolate16x16_switch(cur.y, refn[0].y, 32*x_pos, 32*y_pos, mv[0].x, mv[0].y, stride, rounding);
interpolate16x16_switch(cur.y, refn[0].y, 32*x_pos + 16, 32*y_pos, mv[1].x, mv[1].y, stride, rounding);
interpolate16x16_switch(cur.y, refn[0].y, 32*x_pos, 32*y_pos + 16, mv[2].x, mv[2].y, stride, rounding);
interpolate16x16_switch(cur.y, refn[0].y, 32*x_pos + 16, 32*y_pos + 16, mv[3].x, mv[3].y, stride, rounding);
interpolate16x16_switch(cur.u, refn[0].u, 16*x_pos, 16*y_pos, uv_dx, uv_dy, stride2, rounding);
interpolate16x16_switch(cur.v, refn[0].v, 16*x_pos, 16*y_pos, uv_dx, uv_dy, stride2, rounding);
} else if(quarterpel) {
interpolate8x8_quarterpel(cur.y, refn[0].y , qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos, 16*y_pos, mv[0].x, mv[0].y, stride, rounding);
interpolate8x8_quarterpel(cur.y, refn[0].y , qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos + 8, 16*y_pos, mv[1].x, mv[1].y, stride, rounding);
interpolate8x8_quarterpel(cur.y, refn[0].y , qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos, 16*y_pos + 8, mv[2].x, mv[2].y, stride, rounding);
interpolate8x8_quarterpel(cur.y, refn[0].y , qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos + 8, 16*y_pos + 8, mv[3].x, mv[3].y, stride, rounding);
} else {
interpolate8x8_switch(cur.y, refn[0].y , 16*x_pos, 16*y_pos, mv[0].x, mv[0].y, stride, rounding);
interpolate8x8_switch(cur.y, refn[0].y , 16*x_pos + 8, 16*y_pos, mv[1].x, mv[1].y, stride, rounding);
interpolate8x8_switch(cur.y, refn[0].y , 16*x_pos, 16*y_pos + 8, mv[2].x, mv[2].y, stride, rounding);
interpolate8x8_switch(cur.y, refn[0].y , 16*x_pos + 8, 16*y_pos + 8, mv[3].x, mv[3].y, stride, rounding);
}
}
if(reduced_resolution) {
interpolate16x16_switch(cur.u, refn[0].u, 16*x_pos, 16*y_pos, uv_dx, uv_dy, stride2, rounding);
interpolate16x16_switch(cur.v, refn[0].v, 16*x_pos, 16*y_pos, uv_dx, uv_dy, stride2, rounding);
} else {
interpolate8x8_switch(cur.u, refn[ref].u, 8*x_pos, 8*y_pos, uv_dx, uv_dy, stride2, rounding);
interpolate8x8_switch(cur.v, refn[ref].v, 8*x_pos, 8*y_pos, uv_dx, uv_dy, stride2, rounding);
}
if(cbp)
mb_decode(cbp, bs, pY_Cur, pU_Cur, pV_Cur, reduced_resolution, pMB);
}
inline int gmc_sanitize(int value, int quarterpel, int fcode) {
int length = 1 << (fcode+4);
#if 0
if (quarterpel) value *= 2;
#endif
if (value < -length)
return -length;
else if (value >= length)
return length-1;
else return value;
}
void S_decoder::mbgmc(MACROBLOCK *pMB, dword x_pos, dword y_pos, dword fcode, dword cbp, Bitstream * bs, bool rounding) {
const dword stride = edged_width;
const dword stride2 = stride / 2;
byte *const pY_Cur=cur.y + (y_pos << 4) * stride + (x_pos << 4);
byte *const pU_Cur=cur.u + (y_pos << 3) * stride2 + (x_pos << 3);
byte *const pV_Cur=cur.v + (y_pos << 3) * stride2 + (x_pos << 3);
NEW_GMC_DATA *gmc_data = &new_gmc_data;
pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->amv;
gmc_data->predict_16x16(gmc_data, cur.y + y_pos*16*stride + x_pos*16, refn[0].y, stride, stride, x_pos, y_pos, rounding);
gmc_data->predict_8x8(gmc_data, cur.u + y_pos*8*stride2 + x_pos*8, refn[0].u, cur.v + y_pos*8*stride2 + x_pos*8, refn[0].v, stride2, stride2, x_pos, y_pos, rounding);
gmc_data->get_average_mv(gmc_data, &pMB->amv, x_pos, y_pos, quarterpel);
pMB->amv.x = gmc_sanitize(pMB->amv.x, quarterpel, fcode);
pMB->amv.y = gmc_sanitize(pMB->amv.y, quarterpel, fcode);
pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->amv;
if(cbp)
mb_decode(cbp, bs, pY_Cur, pU_Cur, pV_Cur, 0, pMB);
}
void S_decoder::I_Frame(Bitstream * bs, bool reduced_resolution, int quant, int intra_dc_threshold) {
dword bound;
dword x, y;
if (reduced_resolution) {
mb_width = (width + 31) / 32;
mb_height = (height + 31) / 32;
}
bound = 0;
for (y = 0; y < mb_height; y++) {
for (x = 0; x < mb_width; x++) {
dword mcbpc;
dword cbpc;
dword acpred_flag;
dword cbpy;
dword cbp;
while(bs->ShowBits(9) == 1)
bs->Skip(9);
if(bs->check_resync_marker(0)) {
bound = read_video_packet_header(bs, 0, &quant, NULL, NULL, &intra_dc_threshold);
x = bound % mb_width;
y = bound / mb_width;
}
MACROBLOCK *mb = &mbs[y * mb_width + x];
mcbpc = bs->get_mcbpc_intra();
mb->mode = mcbpc & 7;
cbpc = (mcbpc >> 4);
acpred_flag = bs->GetBit();
cbpy = bs->GetCbpy(1);
cbp = (cbpy << 2) | cbpc;
if (mb->mode == MODE_INTRA_Q) {
quant += dquant_table[bs->GetBits(2)];
if (quant > 31) {
quant = 31;
} else if (quant < 1) {
quant = 1;
}
}
mb->quant = quant;
mb->mvs[0].x = mb->mvs[0].y =
mb->mvs[1].x = mb->mvs[1].y =
mb->mvs[2].x = mb->mvs[2].y =
mb->mvs[3].x = mb->mvs[3].y =0;
if(interlacing) {
mb->field_dct = bs->GetBit();
DPRINTF(XVID_DEBUG_MB,"deci: field_dct: %i\n", mb->field_dct);
}
MBIntra(mb, x, y, acpred_flag, cbp, bs, quant, intra_dc_threshold, bound, reduced_resolution);
}
}
}
void S_decoder::GetMotionVector(Bitstream * bs, int x, int y, int k, VECTOR *ret_mv, int fcode, int bound) {
const int scale_fac = 1 << (fcode - 1);
const int high = (32 * scale_fac) - 1;
const int low = ((-32) * scale_fac);
const int range = (64 * scale_fac);
const VECTOR pmv = get_pmv2(mbs, mb_width, bound, x, y, k);
VECTOR mv;
mv.x = bs->GetMoveVector(fcode);
mv.y = bs->GetMoveVector(fcode);
mv.x += pmv.x;
mv.y += pmv.y;
if(mv.x < low) {
mv.x += range;
} else if(mv.x > high) {
mv.x -= range;
}
if(mv.y < low) {
mv.y += range;
} else if(mv.y > high) {
mv.y -= range;
}
ret_mv->x = mv.x;
ret_mv->y = mv.y;
}
void S_decoder::P_Frame(Bitstream *bs, int rounding, bool reduced_resolution, int quant, int fcode,
int intra_dc_threshold, const WARPPOINTS *gmc_warp) {
if(reduced_resolution) {
mb_width = (width + 31) / 32;
mb_height = (height + 31) / 32;
}
SetEdges(refn[0]);
if(gmc_warp) {
generate_GMCparameters(sprite_warping_points, sprite_warping_accuracy, gmc_warp, width, height, &new_gmc_data);
}
PROF_S(PROF_FRM_P);
dword bound = 0;
for(dword y = 0; y < mb_height; y++) {
for(dword x = 0; x < mb_width; x++) {
while(bs->ShowBits(10) == 1)
bs->Skip(10);
if(bs->check_resync_marker(fcode - 1)) {
bound = read_video_packet_header(bs, fcode - 1, &quant, &fcode, NULL, &intra_dc_threshold);
x = bound % mb_width;
y = bound / mb_width;
}
MACROBLOCK *mb = &mbs[y * mb_width + x];
if(!(bs->GetBit())) {
int mcsel = 0;
dword mcbpc = bs->GetMcbpcInter();
mb->mode = mcbpc & 7;
dword cbpc = (mcbpc >> 4);
DPRINTF(XVID_DEBUG_MB, "mode %i\n", mb->mode);
DPRINTF(XVID_DEBUG_MB, "cbpc %i\n", cbpc);
dword intra = (mb->mode == MODE_INTRA || mb->mode == MODE_INTRA_Q);
dword acpred_flag = 0;
if(gmc_warp && (mb->mode == MODE_INTER || mb->mode == MODE_INTER_Q))
mcsel = bs->GetBit();
else if(intra)
acpred_flag = bs->GetBit();
dword cbpy = bs->GetCbpy(intra);
dword cbp = (cbpy << 2) | cbpc;
if(mb->mode == MODE_INTER_Q || mb->mode == MODE_INTRA_Q) {
int dquant = dquant_table[bs->GetBits(2)];
DPRINTF(XVID_DEBUG_MB, "dquant %i\n", dquant);
quant += dquant;
if (quant > 31) {
quant = 31;
} else if (quant < 1) {
quant = 1;
}
DPRINTF(XVID_DEBUG_MB, "quant %i\n", quant);
}
mb->quant = quant;
if(interlacing) {
if((cbp || intra) && !mcsel) {
mb->field_dct = bs->GetBit();
DPRINTF(XVID_DEBUG_MB,"decp: field_dct: %i\n", mb->field_dct);
}
if(mb->mode == MODE_INTER || mb->mode == MODE_INTER_Q) {
mb->field_pred = bs->GetBit();
DPRINTF(XVID_DEBUG_MB, "decp: field_pred: %i\n", mb->field_pred);
if(mb->field_pred) {
mb->field_for_top = bs->GetBit();
DPRINTF(XVID_DEBUG_MB,"decp: field_for_top: %i\n", mb->field_for_top);
mb->field_for_bot = bs->GetBit();
DPRINTF(XVID_DEBUG_MB,"decp: field_for_bot: %i\n", mb->field_for_bot);
}
}
}
if(mcsel) {
mbgmc(mb, x, y, fcode, cbp, bs, rounding);
PROF_E(PROF_0);
continue;
} else if(mb->mode == MODE_INTER || mb->mode == MODE_INTER_Q) {
if(interlacing && mb->field_pred) {
GetMotionVector(bs, x, y, 0, &mb->mvs[0], fcode, bound);
GetMotionVector(bs, x, y, 0, &mb->mvs[1], fcode, bound);
} else {
GetMotionVector(bs, x, y, 0, &mb->mvs[0], fcode, bound);
mb->mvs[1] = mb->mvs[2] = mb->mvs[3] = mb->mvs[0];
}
} else if(mb->mode == MODE_INTER4V) {
GetMotionVector(bs, x, y, 0, &mb->mvs[0], fcode, bound);
GetMotionVector(bs, x, y, 1, &mb->mvs[1], fcode, bound);
GetMotionVector(bs, x, y, 2, &mb->mvs[2], fcode, bound);
GetMotionVector(bs, x, y, 3, &mb->mvs[3], fcode, bound);
} else {
mb->mvs[0].x = mb->mvs[1].x = mb->mvs[2].x = mb->mvs[3].x = 0;
mb->mvs[0].y = mb->mvs[1].y = mb->mvs[2].y = mb->mvs[3].y = 0;
MBIntra(mb, x, y, acpred_flag, cbp, bs, quant, intra_dc_threshold, bound, reduced_resolution);
continue;
}
PROF_S(PROF_5);
DecodeInterMacroBlock(mb, x, y, cbp, bs, rounding, reduced_resolution, 0);
PROF_E(PROF_5);
} else if(gmc_warp) {
mb->mode = MODE_NOT_CODED_GMC;
mbgmc(mb, x, y, fcode, 0x00, bs, rounding);
} else {
mb->mode = MODE_NOT_CODED;
mb->mvs[0].x = mb->mvs[1].x = mb->mvs[2].x = mb->mvs[3].x = 0;
mb->mvs[0].y = mb->mvs[1].y = mb->mvs[2].y = mb->mvs[3].y = 0;
DecodeInterMacroBlock(mb, x, y, 0, bs, rounding, reduced_resolution, 0);
}
}
}
PROF_E(PROF_FRM_P);
}
static void get_b_motion_vector(Bitstream * bs, VECTOR * mv, int fcode, const VECTOR pmv) {
const int scale_fac = 1 << (fcode - 1);
const int high = (32 * scale_fac) - 1;
const int low = ((-32) * scale_fac);
const int range = (64 * scale_fac);
int mv_x = bs->GetMoveVector(fcode);
int mv_y = bs->GetMoveVector(fcode);
mv_x += pmv.x;
mv_y += pmv.y;
if (mv_x < low)
mv_x += range;
else if (mv_x > high)
mv_x -= range;
if (mv_y < low)
mv_y += range;
else if (mv_y > high)
mv_y -= range;
mv->x = mv_x;
mv->y = mv_y;
}
void S_decoder::BFrameInterpolateMBInter(const IMAGE &forward, const IMAGE &backward, const MACROBLOCK *pMB, dword x_pos, dword y_pos, Bitstream *bs, int direct) {
PROF_S(PROF_BINT_MBI);
dword stride = edged_width;
dword stride2 = stride / 2;
int uv_dx, uv_dy;
int b_uv_dx, b_uv_dy;
byte *pY_Cur, *pU_Cur, *pV_Cur;
const dword cbp = pMB->cbp;
pY_Cur = cur.y + (y_pos << 4) * stride + (x_pos << 4);
pU_Cur = cur.u + (y_pos << 3) * stride2 + (x_pos << 3);
pV_Cur = cur.v + (y_pos << 3) * stride2 + (x_pos << 3);
if(!direct) {
uv_dx = pMB->mvs[0].x;
uv_dy = pMB->mvs[0].y;
b_uv_dx = pMB->b_mvs[0].x;
b_uv_dy = pMB->b_mvs[0].y;
if(quarterpel) {
uv_dx /= 2;
uv_dy /= 2;
b_uv_dx /= 2;
b_uv_dy /= 2;
}
uv_dx = (uv_dx >> 1) + roundtab_79[uv_dx & 0x3];
uv_dy = (uv_dy >> 1) + roundtab_79[uv_dy & 0x3];
b_uv_dx = (b_uv_dx >> 1) + roundtab_79[b_uv_dx & 0x3];
b_uv_dy = (b_uv_dy >> 1) + roundtab_79[b_uv_dy & 0x3];
} else {
if(quarterpel) {
uv_dx = (pMB->mvs[0].x / 2) + (pMB->mvs[1].x / 2) + (pMB->mvs[2].x / 2) + (pMB->mvs[3].x / 2);
uv_dy = (pMB->mvs[0].y / 2) + (pMB->mvs[1].y / 2) + (pMB->mvs[2].y / 2) + (pMB->mvs[3].y / 2);
b_uv_dx = (pMB->b_mvs[0].x / 2) + (pMB->b_mvs[1].x / 2) + (pMB->b_mvs[2].x / 2) + (pMB->b_mvs[3].x / 2);
b_uv_dy = (pMB->b_mvs[0].y / 2) + (pMB->b_mvs[1].y / 2) + (pMB->b_mvs[2].y / 2) + (pMB->b_mvs[3].y / 2);
} else {
uv_dx = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
uv_dy = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
b_uv_dx = pMB->b_mvs[0].x + pMB->b_mvs[1].x + pMB->b_mvs[2].x + pMB->b_mvs[3].x;
b_uv_dy = pMB->b_mvs[0].y + pMB->b_mvs[1].y + pMB->b_mvs[2].y + pMB->b_mvs[3].y;
}
uv_dx = (uv_dx >> 3) + roundtab_76[uv_dx & 0xf];
uv_dy = (uv_dy >> 3) + roundtab_76[uv_dy & 0xf];
b_uv_dx = (b_uv_dx >> 3) + roundtab_76[b_uv_dx & 0xf];
b_uv_dy = (b_uv_dy >> 3) + roundtab_76[b_uv_dy & 0xf];
}
if(quarterpel) {
if(!direct) {
interpolate16x16_quarterpel(cur.y, forward.y, qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos, 16*y_pos, pMB->mvs[0].x, pMB->mvs[0].y, stride, 0);
} else {
interpolate8x8_quarterpel(cur.y, forward.y, qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos, 16*y_pos, pMB->mvs[0].x, pMB->mvs[0].y, stride, 0);
interpolate8x8_quarterpel(cur.y, forward.y, qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos + 8, 16*y_pos, pMB->mvs[1].x, pMB->mvs[1].y, stride, 0);
interpolate8x8_quarterpel(cur.y, forward.y, qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos, 16*y_pos + 8, pMB->mvs[2].x, pMB->mvs[2].y, stride, 0);
interpolate8x8_quarterpel(cur.y, forward.y, qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos + 8, 16*y_pos + 8, pMB->mvs[3].x, pMB->mvs[3].y, stride, 0);
}
} else {
interpolate8x8_switch(cur.y, forward.y, 16 * x_pos, 16 * y_pos, pMB->mvs[0].x, pMB->mvs[0].y, stride, 0);
interpolate8x8_switch(cur.y, forward.y, 16 * x_pos + 8, 16 * y_pos, pMB->mvs[1].x, pMB->mvs[1].y, stride, 0);
interpolate8x8_switch(cur.y, forward.y, 16 * x_pos, 16 * y_pos + 8, pMB->mvs[2].x, pMB->mvs[2].y, stride, 0);
interpolate8x8_switch(cur.y, forward.y, 16 * x_pos + 8, 16 * y_pos + 8, pMB->mvs[3].x, pMB->mvs[3].y, stride, 0);
}
interpolate8x8_switch(cur.u, forward.u, 8 * x_pos, 8 * y_pos, uv_dx, uv_dy, stride2, 0);
interpolate8x8_switch(cur.v, forward.v, 8 * x_pos, 8 * y_pos, uv_dx, uv_dy, stride2, 0);
if(quarterpel) {
if(!direct) {
interpolate16x16_quarterpel(tmp.y, backward.y, qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos, 16*y_pos, pMB->b_mvs[0].x, pMB->b_mvs[0].y, stride, 0);
} else {
interpolate8x8_quarterpel(tmp.y, backward.y, qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos, 16*y_pos, pMB->b_mvs[0].x, pMB->b_mvs[0].y, stride, 0);
interpolate8x8_quarterpel(tmp.y, backward.y, qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos + 8, 16*y_pos, pMB->b_mvs[1].x, pMB->b_mvs[1].y, stride, 0);
interpolate8x8_quarterpel(tmp.y, backward.y, qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos, 16*y_pos + 8, pMB->b_mvs[2].x, pMB->b_mvs[2].y, stride, 0);
interpolate8x8_quarterpel(tmp.y, backward.y, qtmp.y, qtmp.y + 64, qtmp.y + 128, 16*x_pos + 8, 16*y_pos + 8, pMB->b_mvs[3].x, pMB->b_mvs[3].y, stride, 0);
}
} else {
interpolate8x8_switch(tmp.y, backward.y, 16 * x_pos, 16 * y_pos, pMB->b_mvs[0].x, pMB->b_mvs[0].y, stride, 0);
interpolate8x8_switch(tmp.y, backward.y, 16 * x_pos + 8, 16 * y_pos, pMB->b_mvs[1].x, pMB->b_mvs[1].y, stride, 0);
interpolate8x8_switch(tmp.y, backward.y, 16 * x_pos, 16 * y_pos + 8, pMB->b_mvs[2].x, pMB->b_mvs[2].y, stride, 0);
interpolate8x8_switch(tmp.y, backward.y, 16 * x_pos + 8, 16 * y_pos + 8, pMB->b_mvs[3].x, pMB->b_mvs[3].y, stride, 0);
}
interpolate8x8_switch(tmp.u, backward.u, 8 * x_pos, 8 * y_pos, b_uv_dx, b_uv_dy, stride2, 0);
interpolate8x8_switch(tmp.v, backward.v, 8 * x_pos, 8 * y_pos, b_uv_dx, b_uv_dy, stride2, 0);
interpolate8x8_avg2(cur.y + (16 * y_pos * stride) + 16 * x_pos, cur.y + (16 * y_pos * stride) + 16 * x_pos,
tmp.y + (16 * y_pos * stride) + 16 * x_pos, stride, 1, 8);
interpolate8x8_avg2(cur.y + (16 * y_pos * stride) + 16 * x_pos + 8, cur.y + (16 * y_pos * stride) + 16 * x_pos + 8,
tmp.y + (16 * y_pos * stride) + 16 * x_pos + 8, stride, 1, 8);
interpolate8x8_avg2(cur.y + ((16 * y_pos + 8) * stride) + 16 * x_pos, cur.y + ((16 * y_pos + 8) * stride) + 16 * x_pos,
tmp.y + ((16 * y_pos + 8) * stride) + 16 * x_pos, stride, 1, 8);
interpolate8x8_avg2(cur.y + ((16 * y_pos + 8) * stride) + 16 * x_pos + 8, cur.y + ((16 * y_pos + 8) * stride) + 16 * x_pos + 8,
tmp.y + ((16 * y_pos + 8) * stride) + 16 * x_pos + 8, stride, 1, 8);
interpolate8x8_avg2(cur.u + (8 * y_pos * stride2) + 8 * x_pos, cur.u + (8 * y_pos * stride2) + 8 * x_pos,
tmp.u + (8 * y_pos * stride2) + 8 * x_pos, stride2, 1, 8);
interpolate8x8_avg2(cur.v + (8 * y_pos * stride2) + 8 * x_pos, cur.v + (8 * y_pos * stride2) + 8 * x_pos,
tmp.v + (8 * y_pos * stride2) + 8 * x_pos, stride2, 1, 8);
if(cbp)
mb_decode(cbp, bs, pY_Cur, pU_Cur, pV_Cur, 0, pMB);
PROF_E(PROF_BINT_MBI);
}
static int get_dbquant(Bitstream * bs) {
if (!bs->GetBit())
return (0);
else if (!bs->GetBit())
return (-2);
else
return (2);
}
static int get_mbtype(Bitstream * bs) {
int mb_type;
for (mb_type = 0; mb_type <= 3; mb_type++)
if (bs->GetBit())
return (mb_type);
return -1;
}
void S_decoder::B_Frame(Bitstream *bs, int quant, int fcode_forward, int fcode_backward) {
dword x, y;
VECTOR mv;
const VECTOR zeromv = {0,0};
const int64_t TRB = time_pp - time_bp, TRD = time_pp;
int i;
PROF_S(PROF_FRM_B);
SetEdges(refn[0]);
SetEdges(refn[1]);
for(y = 0; y < mb_height; y++) {
p_fmv = p_bmv = zeromv;
for(x = 0; x < mb_width; x++) {
MACROBLOCK *mb = &mbs[y * mb_width + x];
MACROBLOCK *last_mb = &last_mbs[y * mb_width + x];
const int fcode_max = (fcode_forward>fcode_backward) ? fcode_forward : fcode_backward;
if(bs->check_resync_marker(fcode_max - 1)) {
dword intra_dc_threshold;
int bound = read_video_packet_header(bs, fcode_max - 1, &quant, &fcode_forward, &fcode_backward, (int*)&intra_dc_threshold);
x = bound % mb_width;
y = bound / mb_width;
p_fmv = p_bmv = zeromv;
}
mv = mb->b_mvs[0] = mb->b_mvs[1] = mb->b_mvs[2] = mb->b_mvs[3] = mb->mvs[0] = mb->mvs[1] = mb->mvs[2] = mb->mvs[3] = zeromv;
mb->quant = quant;
if(last_mb->mode == MODE_NOT_CODED) {
mb->cbp = 0;
mb->mode = MODE_FORWARD;
DecodeInterMacroBlock(mb, x, y, mb->cbp, bs, 0, 0, 1);
continue;
}
if(!bs->GetBit()) {
const byte modb2 = bs->GetBit();
mb->mode = get_mbtype(bs);
if (!modb2)
mb->cbp = bs->GetBits(6);
else
mb->cbp = 0;
if (mb->mode && mb->cbp) {
quant += get_dbquant(bs);
if (quant > 31)
quant = 31;
else if (quant < 1)
quant = 1;
}
mb->quant = quant;
if(interlacing) {
if (mb->cbp) {
mb->field_dct = bs->GetBit();
DPRINTF(XVID_DEBUG_MB,"decp: field_dct: %i\n", mb->field_dct);
}
if (mb->mode) {
mb->field_pred = bs->GetBit();
DPRINTF(XVID_DEBUG_MB, "decp: field_pred: %i\n", mb->field_pred);
if (mb->field_pred) {
mb->field_for_top = bs->GetBit();
DPRINTF(XVID_DEBUG_MB,"decp: field_for_top: %i\n", mb->field_for_top);
mb->field_for_bot = bs->GetBit();
DPRINTF(XVID_DEBUG_MB,"decp: field_for_bot: %i\n", mb->field_for_bot);
}
}
}
} else {
mb->mode = MODE_DIRECT_NONE_MV;
mb->cbp = 0;
}
switch(mb->mode) {
case MODE_DIRECT:
get_b_motion_vector(bs, &mv, 1, zeromv);
case MODE_DIRECT_NONE_MV:
for(i=0; i<4; i++) {
mb->mvs[i].x = (int)((int(TRB) * last_mb->mvs[i].x) / (int)TRD + mv.x);
mb->b_mvs[i].x = (int) ((mv.x == 0) ?
(int(TRB - TRD) * last_mb->mvs[i].x) / (int)TRD :
mb->mvs[i].x - last_mb->mvs[i].x);
mb->mvs[i].y = (int) ((int(TRB) * last_mb->mvs[i].y) / (int)TRD + mv.y);
mb->b_mvs[i].y = (int) ((mv.y == 0) ?
(int(TRB - TRD) * last_mb->mvs[i].y) / int(TRD) :
int(mb->mvs[i].y - last_mb->mvs[i].y));
}
BFrameInterpolateMBInter(refn[1], refn[0], mb, x, y, bs, 1);
break;
case MODE_INTERPOLATE:
get_b_motion_vector(bs, &mb->mvs[0], fcode_forward, p_fmv);
p_fmv = mb->mvs[1] = mb->mvs[2] = mb->mvs[3] = mb->mvs[0];
get_b_motion_vector(bs, &mb->b_mvs[0], fcode_backward, p_bmv);
p_bmv = mb->b_mvs[1] = mb->b_mvs[2] = mb->b_mvs[3] = mb->b_mvs[0];
BFrameInterpolateMBInter(refn[1], refn[0], mb, x, y, bs, 0);
break;
case MODE_BACKWARD:
get_b_motion_vector(bs, &mb->mvs[0], fcode_backward, p_bmv);
p_bmv = mb->mvs[1] = mb->mvs[2] = mb->mvs[3] = mb->mvs[0];
DecodeInterMacroBlock(mb, x, y, mb->cbp, bs, 0, 0, 0);
break;
case MODE_FORWARD:
get_b_motion_vector(bs, &mb->mvs[0], fcode_forward, p_fmv);
p_fmv = mb->mvs[1] = mb->mvs[2] = mb->mvs[3] = mb->mvs[0];
DecodeInterMacroBlock(mb, x, y, mb->cbp, bs, 0, 0, 1);
break;
default:
DPRINTF(XVID_DEBUG_ERROR,"Not supported B-frame mb_type = %i\n", mb->mode);
}
}
}
PROF_E(PROF_FRM_B);
}
int S_decoder::Decode(xvid_dec_frame_t *frame, xvid_dec_stats_t *stats) {
PROF_S(PROF_DECODE);
Bitstream bs;
bool rounding;
bool reduced_resolution;
dword quant;
dword fcode_forward;
dword fcode_backward;
dword intra_dc_threshold;
WARPPOINTS gmc_warp;
int coding_type;
frame->img_out = NULL;
if(XVID_VERSION_MAJOR(frame->version) != 1 || (stats && XVID_VERSION_MAJOR(stats->version) != 1)) {
PROF_E(PROF_DECODE);
return XVID_ERR_VERSION;
}
low_delay_default = (frame->general & XVID_LOWDELAY);
if((frame->general & XVID_DISCONTINUITY))
frames = 0;
if(frame->length < 0) {
int ret;
if(!(low_delay_default && packed_mode) && !low_delay && frames>0) {
frame->img_out = &refn[0];
frames = 0;
ret = 0;
} else {
if (stats) stats->type = XVID_TYPE_NOTHING;
ret = XVID_ERR_END;
}
PROF_E(PROF_DECODE);
return ret;
}
bs.Init(frame->bitstream, frame->length);
if(low_delay_default && frame->length == 1 && bs.ShowBits(8) == 0x7f) {
if(stats)
stats->type = XVID_TYPE_NOTHING;
PROF_E(PROF_DECODE);
return 1;
}
bool success = false;
bool output = false;
bool seen_something = false;
repeat:
coding_type = BitstreamReadHeaders(&bs, rounding, &reduced_resolution, &quant, &fcode_forward, &fcode_backward, &intra_dc_threshold, &gmc_warp);
if(coding_type == -1) {
if(success)
goto done;
if(stats)
stats->type = XVID_TYPE_NOTHING;
PROF_E(PROF_DECODE);
return bs.Pos()/8;
}
if(coding_type == -2 || coding_type == -3) {
if(coding_type == -3)
Resize();
goto repeat;
}
p_bmv.x = p_bmv.y = p_fmv.y = p_fmv.y = 0;
if(packed_mode && coding_type == N_VOP) {
if(low_delay_default && frames > 0) {
frame->img_out = &refn[0];
output = true;
}
} else if(coding_type != B_VOP) {
switch(coding_type) {
case I_VOP:
PROF_S(PROF_FRM_I);
I_Frame(&bs, reduced_resolution, quant, intra_dc_threshold);
PROF_E(PROF_FRM_I);
break;
case P_VOP:
P_Frame(&bs, rounding, reduced_resolution, quant, fcode_forward, intra_dc_threshold, NULL);
break;
case S_VOP:
P_Frame(&bs, rounding, reduced_resolution, quant, fcode_forward, intra_dc_threshold, &gmc_warp);
break;
case N_VOP:
cur.Copy(&refn[0], edged_width, height);
break;
}
if(reduced_resolution)
cur.deblock_rrv(edged_width, mbs, (width + 31) / 32, (height + 31) / 32, mb_width, 16, 0);
if(!(low_delay_default && packed_mode)) {
if(low_delay) {
frame->img_out = &cur;
output = true;
} else if(frames > 0) {
frame->img_out = &refn[1];
output = true;
}
}
refn[0].Swap(&refn[1]);
cur.Swap(&refn[0]);
Swap(mbs, last_mbs);
last_reduced_resolution = reduced_resolution;
last_coding_type = coding_type;
frames++;
seen_something = true;
} else {
if(low_delay) {
DPRINTF(XVID_DEBUG_ERROR, "warning: bvop found in low_delay==1 stream\n");
low_delay = true;
}
if(frames < 2) {
cur.Print(edged_width, height, 16, 16, "broken b-frame, mising ref frames");
} else if(time_pp <= time_bp) {
cur.Print(edged_width, height, 16, 16, "broken b-frame");
} else {
B_Frame(&bs, quant, fcode_forward, fcode_backward);
}
frame->img_out = &cur;
output = true;
frames++;
}
bs.ByteAlign();
if(low_delay_default && packed_mode && !output && !success) {
success = true;
goto repeat;
}
done:
if(low_delay_default && !output) {
if(packed_mode && seen_something) {
frame->img_out = &refn[0];
} else {
cur.Clear(width, height, edged_width, 0, 128, 128);
cur.Print(edged_width, height, 16, 16, "warning: nothing to output");
cur.Print(edged_width, height, 16, 64, "bframe decoder lag");
frame->img_out = &cur;
if(stats)
stats->type = XVID_TYPE_NOTHING;
}
}
PROF_E(PROF_DECODE);
return bs.Pos() / 8;
}