📄 mbcoding.c
字号:
/*****************************************************************************
*
* XVID MPEG-4 VIDEO CODEC
* - MB coding -
*
* Copyright (C) 2002 Michael Militzer <isibaar@xvid.org>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: mbcoding.c,v 1.56 2007/06/28 14:55:11 Skal Exp $
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../portab.h"
#include "../global.h"
#include "bitstream.h"
#include "zigzag.h"
#include "vlc_codes.h"
#include "mbcoding.h"
#include "../utils/mbfunctions.h"
#ifdef _DEBUG
# include "../motion/estimation.h"
# include "../motion/motion_inlines.h"
# include <assert.h>
#endif
#define LEVELOFFSET 32
/* Initialized once during xvid_global call
* RO access is thread safe */
static REVERSE_EVENT DCT3D[2][4096];
static VLC coeff_VLC[2][2][64][64];
/* not really MB related, but VLCs are only available here */
void bs_put_spritetrajectory(Bitstream * bs, const int val)
{
const int code = sprite_trajectory_code[val+16384].code;
const int len = sprite_trajectory_code[val+16384].len;
const int code2 = sprite_trajectory_len[len].code;
const int len2 = sprite_trajectory_len[len].len;
#if 0
printf("GMC=%d Code/Len = %d / %d ",val, code,len);
printf("Code2 / Len2 = %d / %d \n",code2,len2);
#endif
BitstreamPutBits(bs, code2, len2);
if (len) BitstreamPutBits(bs, code, len);
}
int bs_get_spritetrajectory(Bitstream * bs)
{
int i;
for (i = 0; i < 12; i++)
{
if (BitstreamShowBits(bs, sprite_trajectory_len[i].len) == sprite_trajectory_len[i].code)
{
BitstreamSkip(bs, sprite_trajectory_len[i].len);
return i;
}
}
return -1;
}
void
init_vlc_tables(void)
{
uint32_t i, j, k, intra, last, run, run_esc, level, level_esc, escape, escape_len, offset;
int32_t l;
for (intra = 0; intra < 2; intra++)
for (i = 0; i < 4096; i++)
DCT3D[intra][i].event.level = 0;
for (intra = 0; intra < 2; intra++) {
for (last = 0; last < 2; last++) {
for (run = 0; run < 63 + last; run++) {
for (level = 0; level < (uint32_t)(32 << intra); level++) {
offset = !intra * LEVELOFFSET;
coeff_VLC[intra][last][level + offset][run].len = 128;
}
}
}
}
for (intra = 0; intra < 2; intra++) {
for (i = 0; i < 102; i++) {
offset = !intra * LEVELOFFSET;
for (j = 0; j < (uint32_t)(1 << (12 - coeff_tab[intra][i].vlc.len)); j++) {
DCT3D[intra][(coeff_tab[intra][i].vlc.code << (12 - coeff_tab[intra][i].vlc.len)) | j].len = coeff_tab[intra][i].vlc.len;
DCT3D[intra][(coeff_tab[intra][i].vlc.code << (12 - coeff_tab[intra][i].vlc.len)) | j].event = coeff_tab[intra][i].event;
}
coeff_VLC[intra][coeff_tab[intra][i].event.last][coeff_tab[intra][i].event.level + offset][coeff_tab[intra][i].event.run].code
= coeff_tab[intra][i].vlc.code << 1;
coeff_VLC[intra][coeff_tab[intra][i].event.last][coeff_tab[intra][i].event.level + offset][coeff_tab[intra][i].event.run].len
= coeff_tab[intra][i].vlc.len + 1;
if (!intra) {
coeff_VLC[intra][coeff_tab[intra][i].event.last][offset - coeff_tab[intra][i].event.level][coeff_tab[intra][i].event.run].code
= (coeff_tab[intra][i].vlc.code << 1) | 1;
coeff_VLC[intra][coeff_tab[intra][i].event.last][offset - coeff_tab[intra][i].event.level][coeff_tab[intra][i].event.run].len
= coeff_tab[intra][i].vlc.len + 1;
}
}
}
for (intra = 0; intra < 2; intra++) {
for (last = 0; last < 2; last++) {
for (run = 0; run < 63 + last; run++) {
for (level = 1; level < (uint32_t)(32 << intra); level++) {
if (level <= max_level[intra][last][run] && run <= max_run[intra][last][level])
continue;
offset = !intra * LEVELOFFSET;
level_esc = level - max_level[intra][last][run];
run_esc = run - 1 - max_run[intra][last][level];
if (level_esc <= max_level[intra][last][run] && run <= max_run[intra][last][level_esc]) {
escape = ESCAPE1;
escape_len = 7 + 1;
run_esc = run;
} else {
if (run_esc <= max_run[intra][last][level] && level <= max_level[intra][last][run_esc]) {
escape = ESCAPE2;
escape_len = 7 + 2;
level_esc = level;
} else {
if (!intra) {
coeff_VLC[intra][last][level + offset][run].code
= (ESCAPE3 << 21) | (last << 20) | (run << 14) | (1 << 13) | ((level & 0xfff) << 1) | 1;
coeff_VLC[intra][last][level + offset][run].len = 30;
coeff_VLC[intra][last][offset - level][run].code
= (ESCAPE3 << 21) | (last << 20) | (run << 14) | (1 << 13) | ((-(int32_t)level & 0xfff) << 1) | 1;
coeff_VLC[intra][last][offset - level][run].len = 30;
}
continue;
}
}
coeff_VLC[intra][last][level + offset][run].code
= (escape << coeff_VLC[intra][last][level_esc + offset][run_esc].len)
| coeff_VLC[intra][last][level_esc + offset][run_esc].code;
coeff_VLC[intra][last][level + offset][run].len
= coeff_VLC[intra][last][level_esc + offset][run_esc].len + escape_len;
if (!intra) {
coeff_VLC[intra][last][offset - level][run].code
= (escape << coeff_VLC[intra][last][level_esc + offset][run_esc].len)
| coeff_VLC[intra][last][level_esc + offset][run_esc].code | 1;
coeff_VLC[intra][last][offset - level][run].len
= coeff_VLC[intra][last][level_esc + offset][run_esc].len + escape_len;
}
}
if (!intra) {
coeff_VLC[intra][last][0][run].code
= (ESCAPE3 << 21) | (last << 20) | (run << 14) | (1 << 13) | ((-32 & 0xfff) << 1) | 1;
coeff_VLC[intra][last][0][run].len = 30;
}
}
}
}
/* init sprite_trajectory tables
* even if GMC is not specified (it might be used later...) */
sprite_trajectory_code[0+16384].code = 0;
sprite_trajectory_code[0+16384].len = 0;
for (k=0;k<14;k++) {
int limit = (1<<k);
for (l=-(2*limit-1); l <= -limit; l++) {
sprite_trajectory_code[l+16384].code = (2*limit-1)+l;
sprite_trajectory_code[l+16384].len = k+1;
}
for (l=limit; l<= 2*limit-1; l++) {
sprite_trajectory_code[l+16384].code = l;
sprite_trajectory_code[l+16384].len = k+1;
}
}
}
static __inline void
CodeVector(Bitstream * bs,
int32_t value,
int32_t f_code)
{
const int scale_factor = 1 << (f_code - 1);
const int cmp = scale_factor << 5;
if (value < (-1 * cmp))
value += 64 * scale_factor;
if (value > (cmp - 1))
value -= 64 * scale_factor;
if (value == 0) {
BitstreamPutBits(bs, mb_motion_table[32].code,
mb_motion_table[32].len);
} else {
uint16_t length, code, mv_res, sign;
length = 16 << f_code;
f_code--;
sign = (value < 0);
if (value >= length)
value -= 2 * length;
else if (value < -length)
value += 2 * length;
if (sign)
value = -value;
value--;
mv_res = value & ((1 << f_code) - 1);
code = ((value - mv_res) >> f_code) + 1;
if (sign)
code = -code;
code += 32;
BitstreamPutBits(bs, mb_motion_table[code].code,
mb_motion_table[code].len);
if (f_code)
BitstreamPutBits(bs, mv_res, f_code);
}
}
static __inline void
CodeCoeffInter(Bitstream * bs,
const int16_t qcoeff[64],
const uint16_t * zigzag)
{
uint32_t i, run, prev_run, code, len;
int32_t level, prev_level, level_shifted;
i = 0;
run = 0;
while (!(level = qcoeff[zigzag[i++]]))
run++;
prev_level = level;
prev_run = run;
run = 0;
while (i < 64)
{
if ((level = qcoeff[zigzag[i++]]) != 0)
{
level_shifted = prev_level + 32;
if (!(level_shifted & -64))
{
code = coeff_VLC[0][0][level_shifted][prev_run].code;
len = coeff_VLC[0][0][level_shifted][prev_run].len;
}
else
{
code = (ESCAPE3 << 21) | (prev_run << 14) | (1 << 13) | ((prev_level & 0xfff) << 1) | 1;
len = 30;
}
BitstreamPutBits(bs, code, len);
prev_level = level;
prev_run = run;
run = 0;
}
else
run++;
}
level_shifted = prev_level + 32;
if (!(level_shifted & -64))
{
code = coeff_VLC[0][1][level_shifted][prev_run].code;
len = coeff_VLC[0][1][level_shifted][prev_run].len;
}
else
{
code = (ESCAPE3 << 21) | (1 << 20) | (prev_run << 14) | (1 << 13) | ((prev_level & 0xfff) << 1) | 1;
len = 30;
}
BitstreamPutBits(bs, code, len);
}
static __inline void
CodeCoeffIntra(Bitstream * bs,
const int16_t qcoeff[64],
const uint16_t * zigzag)
{
uint32_t i, abs_level, run, prev_run, code, len;
int32_t level, prev_level;
i = 1;
run = 0;
while (i<64 && !(level = qcoeff[zigzag[i++]]))
run++;
prev_level = level;
prev_run = run;
run = 0;
while (i < 64)
{
if ((level = qcoeff[zigzag[i++]]) != 0)
{
abs_level = abs(prev_level);
abs_level = abs_level < 64 ? abs_level : 0;
code = coeff_VLC[1][0][abs_level][prev_run].code;
len = coeff_VLC[1][0][abs_level][prev_run].len;
if (len != 128)
code |= (prev_level < 0);
else
{
code = (ESCAPE3 << 21) | (prev_run << 14) | (1 << 13) | ((prev_level & 0xfff) << 1) | 1;
len = 30;
}
BitstreamPutBits(bs, code, len);
prev_level = level;
prev_run = run;
run = 0;
}
else
run++;
}
abs_level = abs(prev_level);
abs_level = abs_level < 64 ? abs_level : 0;
code = coeff_VLC[1][1][abs_level][prev_run].code;
len = coeff_VLC[1][1][abs_level][prev_run].len;
if (len != 128)
code |= (prev_level < 0);
else
{
code = (ESCAPE3 << 21) | (1 << 20) | (prev_run << 14) | (1 << 13) | ((prev_level & 0xfff) << 1) | 1;
len = 30;
}
BitstreamPutBits(bs, code, len);
}
/* returns the number of bits required to encode qcoeff */
int
CodeCoeffIntra_CalcBits(const int16_t qcoeff[64], const uint16_t * zigzag)
{
int bits = 0;
uint32_t i, abs_level, run, prev_run, len;
int32_t level, prev_level;
i = 1;
run = 0;
while (i<64 && !(level = qcoeff[zigzag[i++]]))
run++;
if (i >= 64) return 0; /* empty block */
prev_level = level;
prev_run = run;
run = 0;
while (i < 64)
{
if ((level = qcoeff[zigzag[i++]]) != 0)
{
abs_level = abs(prev_level);
abs_level = abs_level < 64 ? abs_level : 0;
len = coeff_VLC[1][0][abs_level][prev_run].len;
bits += len!=128 ? len : 30;
prev_level = level;
prev_run = run;
run = 0;
}
else
run++;
}
abs_level = abs(prev_level);
abs_level = abs_level < 64 ? abs_level : 0;
len = coeff_VLC[1][1][abs_level][prev_run].len;
bits += len!=128 ? len : 30;
return bits;
}
int
CodeCoeffInter_CalcBits(const int16_t qcoeff[64], const uint16_t * zigzag)
{
uint32_t i, run, prev_run, len;
int32_t level, prev_level, level_shifted;
int bits = 0;
i = 0;
run = 0;
while (!(level = qcoeff[zigzag[i++]]))
run++;
prev_level = level;
prev_run = run;
run = 0;
while (i < 64) {
if ((level = qcoeff[zigzag[i++]]) != 0) {
level_shifted = prev_level + 32;
if (!(level_shifted & -64))
len = coeff_VLC[0][0][level_shifted][prev_run].len;
else
len = 30;
bits += len;
prev_level = level;
prev_run = run;
run = 0;
}
else
run++;
}
level_shifted = prev_level + 32;
if (!(level_shifted & -64))
len = coeff_VLC[0][1][level_shifted][prev_run].len;
else
len = 30;
bits += len;
return bits;
}
static const int iDQtab[5] = {
1, 0, -1 /* no change */, 2, 3
};
#define DQ_VALUE2INDEX(value) iDQtab[(value)+2]
static __inline void
CodeBlockIntra(const FRAMEINFO * const frame,
const MACROBLOCK * pMB,
int16_t qcoeff[6 * 64],
Bitstream * bs,
Statistics * pStat)
{
uint32_t i, mcbpc, cbpy, bits;
cbpy = pMB->cbp >> 2;
/* write mcbpc */
if (frame->coding_type == I_VOP) {
mcbpc = ((pMB->mode >> 1) & 3) | ((pMB->cbp & 3) << 2);
BitstreamPutBits(bs, mcbpc_intra_tab[mcbpc].code,
mcbpc_intra_tab[mcbpc].len);
} else {
mcbpc = (pMB->mode & 7) | ((pMB->cbp & 3) << 3);
BitstreamPutBits(bs, mcbpc_inter_tab[mcbpc].code,
mcbpc_inter_tab[mcbpc].len);
}
/* ac prediction flag */
if (pMB->acpred_directions[0])
BitstreamPutBits(bs, 1, 1);
else
BitstreamPutBits(bs, 0, 1);
/* write cbpy */
BitstreamPutBits(bs, xvid_cbpy_tab[cbpy].code, xvid_cbpy_tab[cbpy].len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -