mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-18 16:03:05 +00:00
VIDEO: Add remaining SVQ1 code derived from FFMPEG.
This still requires some work to make it usuable, mainly changing the Variable Length Code reader to work with Common::BitStream input.
This commit is contained in:
parent
9330a7c54d
commit
b99565d701
@ -29,6 +29,7 @@
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "common/bitstream.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/system.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/textconsole.h"
|
||||
@ -37,14 +38,771 @@
|
||||
|
||||
namespace Video {
|
||||
|
||||
#define SVQ1_BLOCK_SKIP 0
|
||||
#define SVQ1_BLOCK_INTER 1
|
||||
#define SVQ1_BLOCK_INTER_4V 2
|
||||
#define SVQ1_BLOCK_INTRA 3
|
||||
|
||||
struct VLC {
|
||||
int32 bits;
|
||||
int16 (*table)[2]; // code, bits
|
||||
int32 table_size;
|
||||
int32 table_allocated;
|
||||
};
|
||||
|
||||
/**
|
||||
* parses a vlc code, faster then get_vlc()
|
||||
* @param bits is the number of bits which will be read at once, must be
|
||||
* identical to nb_bits in init_vlc()
|
||||
* @param max_depth is the number of times bits bits must be read to completely
|
||||
* read the longest vlc code
|
||||
* = (max_vlc_length + bits - 1) / bits
|
||||
*/
|
||||
static int getVlc2(Common::BitStream *s, int16 (*table)[2], int bits, int maxDepth) {
|
||||
//FIXME - Change this code to working with BitStream...
|
||||
//GetBitContext *s
|
||||
//int reIndex;
|
||||
//int reCache;
|
||||
//int index;
|
||||
int code = 0;
|
||||
//int n;
|
||||
|
||||
/* FIXME
|
||||
reIndex = s->index;
|
||||
reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
|
||||
index = reCache & (0xffffffff >> (32 - bits));
|
||||
code = table[index][0];
|
||||
n = table[index][1];
|
||||
|
||||
if (maxDepth > 1 && n < 0){
|
||||
reIndex += bits;
|
||||
reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
|
||||
|
||||
int nbBits = -n;
|
||||
|
||||
index = (reCache & (0xffffffff >> (32 - nbBits))) + code;
|
||||
code = table[index][0];
|
||||
n = table[index][1];
|
||||
|
||||
if(maxDepth > 2 && n < 0) {
|
||||
reIndex += nbBits;
|
||||
reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
|
||||
|
||||
nbBits = -n;
|
||||
|
||||
index = (reCache & (0xffffffff >> (32 - nbBits))) + code;
|
||||
code = table[index][0];
|
||||
n = table[index][1];
|
||||
}
|
||||
}
|
||||
|
||||
reCache >>= n;
|
||||
s->index = reIndex + n;
|
||||
*/
|
||||
return code;
|
||||
}
|
||||
|
||||
static int allocTable(VLC *vlc, int size, int use_static) {
|
||||
int index;
|
||||
int16 (*temp)[2] = NULL;
|
||||
index = vlc->table_size;
|
||||
vlc->table_size += size;
|
||||
if (vlc->table_size > vlc->table_allocated) {
|
||||
if(use_static)
|
||||
error("SVQ1 cant do anything, init_vlc() is used with too little memory");
|
||||
vlc->table_allocated += (1 << vlc->bits);
|
||||
temp = (int16 (*)[2])realloc(vlc->table, sizeof(int16 *) * 2 * vlc->table_allocated);
|
||||
if (!temp) {
|
||||
free(vlc->table);
|
||||
vlc->table = NULL;
|
||||
return -1;
|
||||
}
|
||||
vlc->table = temp;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
static VLC svq1_block_type;
|
||||
static VLC svq1_motion_component;
|
||||
static VLC svq1_intra_multistage[6];
|
||||
static VLC svq1_inter_multistage[6];
|
||||
static VLC svq1_intra_mean;
|
||||
static VLC svq1_inter_mean;
|
||||
|
||||
static int svq1DecodeBlockIntra(Common::BitStream *s, uint8 *pixels, int pitch) {
|
||||
uint8 *list[63];
|
||||
uint32 *dst;
|
||||
int entries[6];
|
||||
int i, j, m, n;
|
||||
int mean, stages;
|
||||
unsigned int x, y, width, height, level;
|
||||
uint32 n1, n2, n3, n4;
|
||||
|
||||
// initialize list for breadth first processing of vectors
|
||||
list[0] = pixels;
|
||||
|
||||
// recursively process vector
|
||||
for (i=0, m=1, n=1, level=5; i < n; i++) {
|
||||
// SVQ1_PROCESS_VECTOR()
|
||||
for (; level > 0; i++) {
|
||||
// process next depth
|
||||
if (i == m) {
|
||||
m = n;
|
||||
if (--level == 0)
|
||||
break;
|
||||
}
|
||||
// divide block if next bit set
|
||||
if (s->getBit() == 0)
|
||||
break;
|
||||
// add child nodes
|
||||
list[n++] = list[i];
|
||||
list[n++] = list[i] + (((level & 1) ? pitch : 1) << ((level / 2) + 1));
|
||||
}
|
||||
|
||||
// destination address and vector size
|
||||
dst = (uint32 *) list[i];
|
||||
width = 1 << ((4 + level) /2);
|
||||
height = 1 << ((3 + level) /2);
|
||||
|
||||
// get number of stages (-1 skips vector, 0 for mean only)
|
||||
stages = getVlc2(s, svq1_intra_multistage[level].table, 3, 3) - 1;
|
||||
|
||||
if (stages == -1) {
|
||||
for (y=0; y < height; y++) {
|
||||
memset (&dst[y*(pitch / 4)], 0, width);
|
||||
}
|
||||
continue; // skip vector
|
||||
}
|
||||
|
||||
if ((stages > 0) && (level >= 4)) {
|
||||
warning("Error (svq1_decode_block_intra): invalid vector: stages=%i level=%i", stages, level);
|
||||
return -1; // invalid vector
|
||||
}
|
||||
|
||||
mean = getVlc2(s, svq1_intra_mean.table, 8, 3);
|
||||
|
||||
if (stages == 0) {
|
||||
for (y=0; y < height; y++) {
|
||||
memset (&dst[y*(pitch / 4)], mean, width);
|
||||
}
|
||||
} else {
|
||||
// SVQ1_CALC_CODEBOOK_ENTRIES(svq1_intra_codebooks);
|
||||
const uint32 *codebook = (const uint32 *) svq1_intra_codebooks[level];
|
||||
uint32 bit_cache = s->getBits(4*stages);
|
||||
// calculate codebook entries for this vector
|
||||
for (j=0; j < stages; j++) {
|
||||
entries[j] = (((bit_cache >> (4*(stages - j - 1))) & 0xF) + 16*j) << (level + 1);
|
||||
}
|
||||
mean -= (stages * 128);
|
||||
n4 = ((mean + (mean >> 31)) << 16) | (mean & 0xFFFF);
|
||||
|
||||
// SVQ1_DO_CODEBOOK_INTRA()
|
||||
for (y=0; y < height; y++) {
|
||||
for (x=0; x < (width / 4); x++, codebook++) {
|
||||
n1 = n4;
|
||||
n2 = n4;
|
||||
// SVQ1_ADD_CODEBOOK()
|
||||
// add codebook entries to vector
|
||||
for (j=0; j < stages; j++) {
|
||||
n3 = codebook[entries[j]] ^ 0x80808080;
|
||||
n1 += ((n3 & 0xFF00FF00) >> 8);
|
||||
n2 += (n3 & 0x00FF00FF);
|
||||
}
|
||||
|
||||
// clip to [0..255]
|
||||
if (n1 & 0xFF00FF00) {
|
||||
n3 = ((( n1 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;
|
||||
n1 += 0x7F007F00;
|
||||
n1 |= (((~n1 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;
|
||||
n1 &= (n3 & 0x00FF00FF);
|
||||
}
|
||||
|
||||
if (n2 & 0xFF00FF00) {
|
||||
n3 = ((( n2 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;
|
||||
n2 += 0x7F007F00;
|
||||
n2 |= (((~n2 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;
|
||||
n2 &= (n3 & 0x00FF00FF);
|
||||
}
|
||||
|
||||
// store result
|
||||
dst[x] = (n1 << 8) | n2;
|
||||
}
|
||||
dst += (pitch / 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int svq1DecodeBlockNonIntra(Common::BitStream *s, uint8 *pixels, int pitch) {
|
||||
uint8 *list[63];
|
||||
uint32 *dst;
|
||||
int entries[6];
|
||||
int i, j, m, n;
|
||||
int mean, stages;
|
||||
int x, y, width, height, level;
|
||||
uint32 n1, n2, n3, n4;
|
||||
|
||||
// initialize list for breadth first processing of vectors
|
||||
list[0] = pixels;
|
||||
|
||||
// recursively process vector
|
||||
for (i=0, m=1, n=1, level=5; i < n; i++) {
|
||||
// SVQ1_PROCESS_VECTOR()
|
||||
for (; level > 0; i++) {
|
||||
// process next depth
|
||||
if (i == m) {
|
||||
m = n;
|
||||
if (--level == 0)
|
||||
break;
|
||||
}
|
||||
// divide block if next bit set
|
||||
if (s->getBit() == 0)
|
||||
break;
|
||||
// add child nodes
|
||||
list[n++] = list[i];
|
||||
list[n++] = list[i] + (((level & 1) ? pitch : 1) << ((level / 2) + 1));
|
||||
}
|
||||
|
||||
// destination address and vector size
|
||||
dst = (uint32 *) list[i];
|
||||
width = 1 << ((4 + level) /2);
|
||||
height = 1 << ((3 + level) /2);
|
||||
|
||||
// get number of stages (-1 skips vector, 0 for mean only)
|
||||
stages = getVlc2(s, svq1_inter_multistage[level].table, 3, 2) - 1;
|
||||
|
||||
if (stages == -1) continue; // skip vector
|
||||
|
||||
if ((stages > 0) && (level >= 4)) {
|
||||
warning("Error (svq1_decode_block_non_intra): invalid vector: stages=%i level=%i", stages, level);
|
||||
return -1; // invalid vector
|
||||
}
|
||||
|
||||
mean = getVlc2(s, svq1_inter_mean.table, 9, 3) - 256;
|
||||
|
||||
// SVQ1_CALC_CODEBOOK_ENTRIES(svq1_inter_codebooks);
|
||||
const uint32 *codebook = (const uint32 *) svq1_inter_codebooks[level];
|
||||
uint32 bit_cache = s->getBits(4*stages);
|
||||
// calculate codebook entries for this vector
|
||||
for (j=0; j < stages; j++) {
|
||||
entries[j] = (((bit_cache >> (4*(stages - j - 1))) & 0xF) + 16*j) << (level + 1);
|
||||
}
|
||||
mean -= (stages * 128);
|
||||
n4 = ((mean + (mean >> 31)) << 16) | (mean & 0xFFFF);
|
||||
|
||||
// SVQ1_DO_CODEBOOK_NONINTRA()
|
||||
for (y=0; y < height; y++) {
|
||||
for (x=0; x < (width / 4); x++, codebook++) {
|
||||
n3 = dst[x];
|
||||
// add mean value to vector
|
||||
n1 = ((n3 & 0xFF00FF00) >> 8) + n4;
|
||||
n2 = (n3 & 0x00FF00FF) + n4;
|
||||
//SVQ1_ADD_CODEBOOK()
|
||||
// add codebook entries to vector
|
||||
for (j=0; j < stages; j++) {
|
||||
n3 = codebook[entries[j]] ^ 0x80808080;
|
||||
n1 += ((n3 & 0xFF00FF00) >> 8);
|
||||
n2 += (n3 & 0x00FF00FF);
|
||||
}
|
||||
|
||||
// clip to [0..255]
|
||||
if (n1 & 0xFF00FF00) {
|
||||
n3 = ((( n1 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;
|
||||
n1 += 0x7F007F00;
|
||||
n1 |= (((~n1 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;
|
||||
n1 &= (n3 & 0x00FF00FF);
|
||||
}
|
||||
|
||||
if (n2 & 0xFF00FF00) {
|
||||
n3 = ((( n2 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;
|
||||
n2 += 0x7F007F00;
|
||||
n2 |= (((~n2 >> 15) & 0x00010001) | 0x01000100) - 0x00010001;
|
||||
n2 &= (n3 & 0x00FF00FF);
|
||||
}
|
||||
|
||||
// store result
|
||||
dst[x] = (n1 << 8) | n2;
|
||||
}
|
||||
dst += (pitch / 4);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// median of 3
|
||||
static inline int mid_pred(int a, int b, int c) {
|
||||
if (a > b) {
|
||||
if (c > b) {
|
||||
if (c > a) b = a;
|
||||
else b = c;
|
||||
}
|
||||
} else {
|
||||
if (b > c) {
|
||||
if (c > a) b = c;
|
||||
else b = a;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
static int svq1DecodeMotionVector(Common::BitStream *s, Common::Point *mv, Common::Point **pmv) {
|
||||
for (int i=0; i < 2; i++) {
|
||||
// get motion code
|
||||
int diff = getVlc2(s, svq1_motion_component.table, 7, 2);
|
||||
if (diff < 0)
|
||||
return -1;
|
||||
else if (diff) {
|
||||
if (s->getBit()) diff= -diff;
|
||||
}
|
||||
|
||||
// add median of motion vector predictors and clip result
|
||||
if (i == 1)
|
||||
mv->y = ((diff + mid_pred(pmv[0]->y, pmv[1]->y, pmv[2]->y)) << 26) >> 26;
|
||||
else
|
||||
mv->x = ((diff + mid_pred(pmv[0]->x, pmv[1]->x, pmv[2]->x)) << 26) >> 26;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void svq1SkipBlock(uint8 *current, uint8 *previous, int pitch, int x, int y) {
|
||||
uint8 *src;
|
||||
uint8 *dst;
|
||||
|
||||
src = &previous[x + y*pitch];
|
||||
dst = current;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
memcpy(dst, src, 16);
|
||||
src += pitch;
|
||||
dst += pitch;
|
||||
}
|
||||
}
|
||||
|
||||
static int svq1MotionInterBlock(Common::BitStream *ss,
|
||||
uint8 *current, uint8 *previous, int pitch,
|
||||
Common::Point *motion, int x, int y) {
|
||||
uint8 *src;
|
||||
uint8 *dst;
|
||||
Common::Point mv;
|
||||
Common::Point *pmv[3];
|
||||
int result;
|
||||
|
||||
// predict and decode motion vector
|
||||
pmv[0] = &motion[0];
|
||||
if (y == 0) {
|
||||
pmv[1] = pmv[2] = pmv[0];
|
||||
} else {
|
||||
pmv[1] = &motion[(x / 8) + 2];
|
||||
pmv[2] = &motion[(x / 8) + 4];
|
||||
}
|
||||
|
||||
result = svq1DecodeMotionVector(ss, &mv, pmv);
|
||||
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
motion[0].x =
|
||||
motion[(x / 8) + 2].x =
|
||||
motion[(x / 8) + 3].x = mv.x;
|
||||
motion[0].y =
|
||||
motion[(x / 8) + 2].y =
|
||||
motion[(x / 8) + 3].y = mv.y;
|
||||
|
||||
if(y + (mv.y >> 1)<0)
|
||||
mv.y= 0;
|
||||
if(x + (mv.x >> 1)<0)
|
||||
mv.x= 0;
|
||||
|
||||
#if 0
|
||||
int w = (s->width+15)&~15;
|
||||
int h = (s->height+15)&~15;
|
||||
if(x + (mv.x >> 1)<0 || y + (mv.y >> 1)<0 || x + (mv.x >> 1) + 16 > w || y + (mv.y >> 1) + 16> h)
|
||||
debug(1, "%d %d %d %d", x, y, x + (mv.x >> 1), y + (mv.y >> 1));
|
||||
#endif
|
||||
|
||||
src = &previous[(x + (mv.x >> 1)) + (y + (mv.y >> 1))*pitch];
|
||||
dst = current;
|
||||
|
||||
// FIXME
|
||||
//MpegEncContext *s
|
||||
//s->dsp.put_pixels_tab[0][((mv.y & 1) << 1) | (mv.x & 1)](dst,src,pitch,16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int svq1MotionInter4vBlock(Common::BitStream *ss,
|
||||
uint8 *current, uint8 *previous, int pitch,
|
||||
Common::Point *motion, int x, int y) {
|
||||
uint8 *src;
|
||||
uint8 *dst;
|
||||
Common::Point mv;
|
||||
Common::Point *pmv[4];
|
||||
int i, result;
|
||||
|
||||
// predict and decode motion vector (0)
|
||||
pmv[0] = &motion[0];
|
||||
if (y == 0) {
|
||||
pmv[1] = pmv[2] = pmv[0];
|
||||
} else {
|
||||
pmv[1] = &motion[(x / 8) + 2];
|
||||
pmv[2] = &motion[(x / 8) + 4];
|
||||
}
|
||||
|
||||
result = svq1DecodeMotionVector(ss, &mv, pmv);
|
||||
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
// predict and decode motion vector (1)
|
||||
pmv[0] = &mv;
|
||||
if (y == 0) {
|
||||
pmv[1] = pmv[2] = pmv[0];
|
||||
} else {
|
||||
pmv[1] = &motion[(x / 8) + 3];
|
||||
}
|
||||
result = svq1DecodeMotionVector(ss, &motion[0], pmv);
|
||||
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
// predict and decode motion vector (2)
|
||||
pmv[1] = &motion[0];
|
||||
pmv[2] = &motion[(x / 8) + 1];
|
||||
|
||||
result = svq1DecodeMotionVector(ss, &motion[(x / 8) + 2], pmv);
|
||||
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
// predict and decode motion vector (3)
|
||||
pmv[2] = &motion[(x / 8) + 2];
|
||||
pmv[3] = &motion[(x / 8) + 3];
|
||||
|
||||
result = svq1DecodeMotionVector(ss, pmv[3], pmv);
|
||||
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
// form predictions
|
||||
for (i=0; i < 4; i++) {
|
||||
int mvx = pmv[i]->x + (i&1)*16;
|
||||
int mvy = pmv[i]->y + (i>>1)*16;
|
||||
|
||||
///XXX /FIXME clipping or padding?
|
||||
if(y + (mvy >> 1)<0)
|
||||
mvy = 0;
|
||||
if(x + (mvx >> 1)<0)
|
||||
mvx = 0;
|
||||
|
||||
#if 0
|
||||
int w = (s->width+15)&~15;
|
||||
int h = (s->height+15)&~15;
|
||||
if(x + (mvx >> 1)<0 || y + (mvy >> 1)<0 || x + (mvx >> 1) + 8 > w || y + (mvy >> 1) + 8> h)
|
||||
debug(1, "%d %d %d %d", x, y, x + (mvx >> 1), y + (mvy >> 1));
|
||||
#endif
|
||||
src = &previous[(x + (mvx >> 1)) + (y + (mvy >> 1))*pitch];
|
||||
dst = current;
|
||||
|
||||
// FIXME
|
||||
//MpegEncContext *s
|
||||
//s->dsp.put_pixels_tab[1][((mvy & 1) << 1) | (mvx & 1)](dst,src,pitch,8);
|
||||
|
||||
// select next block
|
||||
if (i & 1) {
|
||||
current += 8*(pitch - 1);
|
||||
} else {
|
||||
current += 8;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int svq1DecodeDeltaBlock(Common::BitStream *ss,
|
||||
uint8 *current, uint8 *previous, int pitch,
|
||||
Common::Point *motion, int x, int y) {
|
||||
uint32 block_type;
|
||||
int result = 0;
|
||||
|
||||
// get block type
|
||||
block_type = getVlc2(ss, svq1_block_type.table, 2, 2);
|
||||
|
||||
// reset motion vectors
|
||||
if (block_type == SVQ1_BLOCK_SKIP || block_type == SVQ1_BLOCK_INTRA) {
|
||||
motion[0].x =
|
||||
motion[0].y =
|
||||
motion[(x / 8) + 2].x =
|
||||
motion[(x / 8) + 2].y =
|
||||
motion[(x / 8) + 3].x =
|
||||
motion[(x / 8) + 3].y = 0;
|
||||
}
|
||||
|
||||
switch (block_type) {
|
||||
case SVQ1_BLOCK_SKIP:
|
||||
svq1SkipBlock(current, previous, pitch, x, y);
|
||||
break;
|
||||
|
||||
case SVQ1_BLOCK_INTER:
|
||||
result = svq1MotionInterBlock(ss, current, previous, pitch, motion, x, y);
|
||||
if (result != 0) {
|
||||
warning("Error in svq1MotionInterBlock %i", result);
|
||||
break;
|
||||
}
|
||||
result = svq1DecodeBlockNonIntra(ss, current, pitch);
|
||||
break;
|
||||
|
||||
case SVQ1_BLOCK_INTER_4V:
|
||||
result = svq1MotionInter4vBlock(ss, current, previous, pitch, motion, x, y);
|
||||
if (result != 0) {
|
||||
warning("Error in svq1MotionInter4vBlock %i", result);
|
||||
break;
|
||||
}
|
||||
result = svq1DecodeBlockNonIntra(ss, current, pitch);
|
||||
break;
|
||||
|
||||
case SVQ1_BLOCK_INTRA:
|
||||
result = svq1DecodeBlockIntra(ss, current, pitch);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define GET_DATA(v, table, i, wrap, size)\
|
||||
{\
|
||||
const uint8 *ptr = (const uint8 *)table + i * wrap;\
|
||||
switch(size) {\
|
||||
case 1:\
|
||||
v = *(const uint8 *)ptr;\
|
||||
break;\
|
||||
case 2:\
|
||||
v = *(const uint16 *)ptr;\
|
||||
break;\
|
||||
default:\
|
||||
v = *(const uint32 *)ptr;\
|
||||
break;\
|
||||
}\
|
||||
}
|
||||
|
||||
static int build_table(VLC *vlc, int table_nb_bits,
|
||||
int nb_codes,
|
||||
const void *bits, int bits_wrap, int bits_size,
|
||||
const void *codes, int codes_wrap, int codes_size,
|
||||
const void *symbols, int symbols_wrap, int symbols_size,
|
||||
int code_prefix, int n_prefix, int flags)
|
||||
{
|
||||
int i, j, k, n, table_size, table_index, nb, n1, index, code_prefix2, symbol;
|
||||
uint32 code;
|
||||
int16 (*table)[2];
|
||||
|
||||
table_size = 1 << table_nb_bits;
|
||||
table_index = allocTable(vlc, table_size, flags & 4);
|
||||
if (table_index < 0)
|
||||
return -1;
|
||||
table = &vlc->table[table_index];
|
||||
|
||||
for(i = 0; i < table_size; i++) {
|
||||
table[i][1] = 0; //bits
|
||||
table[i][0] = -1; //codes
|
||||
}
|
||||
|
||||
// first pass: map codes and compute auxillary table sizes
|
||||
for(i = 0; i < nb_codes; i++) {
|
||||
GET_DATA(n, bits, i, bits_wrap, bits_size);
|
||||
GET_DATA(code, codes, i, codes_wrap, codes_size);
|
||||
// we accept tables with holes
|
||||
if (n <= 0)
|
||||
continue;
|
||||
if (!symbols)
|
||||
symbol = i;
|
||||
else
|
||||
GET_DATA(symbol, symbols, i, symbols_wrap, symbols_size);
|
||||
// if code matches the prefix, it is in the table
|
||||
n -= n_prefix;
|
||||
if(flags & 2)
|
||||
code_prefix2= code & (n_prefix>=32 ? 0xffffffff : (1 << n_prefix)-1);
|
||||
else
|
||||
code_prefix2= code >> n;
|
||||
if (n > 0 && code_prefix2 == code_prefix) {
|
||||
if (n <= table_nb_bits) {
|
||||
// no need to add another table
|
||||
j = (code << (table_nb_bits - n)) & (table_size - 1);
|
||||
nb = 1 << (table_nb_bits - n);
|
||||
for(k = 0; k < nb; k++) {
|
||||
if(flags & 2)
|
||||
j = (code >> n_prefix) + (k<<n);
|
||||
if (table[j][1] /*bits*/ != 0) {
|
||||
error("SVQ1 incorrect codes");
|
||||
return -1;
|
||||
}
|
||||
table[j][1] = n; //bits
|
||||
table[j][0] = symbol;
|
||||
j++;
|
||||
}
|
||||
} else {
|
||||
n -= table_nb_bits;
|
||||
j = (code >> ((flags & 2) ? n_prefix : n)) & ((1 << table_nb_bits) - 1);
|
||||
// compute table size
|
||||
n1 = -table[j][1]; //bits
|
||||
if (n > n1)
|
||||
n1 = n;
|
||||
table[j][1] = -n1; //bits
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// second pass : fill auxillary tables recursively
|
||||
for(i = 0;i < table_size; i++) {
|
||||
n = table[i][1]; //bits
|
||||
if (n < 0) {
|
||||
n = -n;
|
||||
if (n > table_nb_bits) {
|
||||
n = table_nb_bits;
|
||||
table[i][1] = -n; //bits
|
||||
}
|
||||
index = build_table(vlc, n, nb_codes,
|
||||
bits, bits_wrap, bits_size,
|
||||
codes, codes_wrap, codes_size,
|
||||
symbols, symbols_wrap, symbols_size,
|
||||
(flags & 2) ? (code_prefix | (i << n_prefix)) : ((code_prefix << table_nb_bits) | i),
|
||||
n_prefix + table_nb_bits, flags);
|
||||
if (index < 0)
|
||||
return -1;
|
||||
// note: realloc has been done, so reload tables
|
||||
table = &vlc->table[table_index];
|
||||
table[i][0] = index; //code
|
||||
}
|
||||
}
|
||||
return table_index;
|
||||
}
|
||||
|
||||
/* Build VLC decoding tables suitable for use with get_vlc().
|
||||
|
||||
'nb_bits' set thee decoding table size (2^nb_bits) entries. The
|
||||
bigger it is, the faster is the decoding. But it should not be too
|
||||
big to save memory and L1 cache. '9' is a good compromise.
|
||||
|
||||
'nb_codes' : number of vlcs codes
|
||||
|
||||
'bits' : table which gives the size (in bits) of each vlc code.
|
||||
|
||||
'codes' : table which gives the bit pattern of of each vlc code.
|
||||
|
||||
'symbols' : table which gives the values to be returned from get_vlc().
|
||||
|
||||
'xxx_wrap' : give the number of bytes between each entry of the
|
||||
'bits' or 'codes' tables.
|
||||
|
||||
'xxx_size' : gives the number of bytes of each entry of the 'bits'
|
||||
or 'codes' tables.
|
||||
|
||||
'wrap' and 'size' allows to use any memory configuration and types
|
||||
(byte/word/long) to store the 'bits', 'codes', and 'symbols' tables.
|
||||
|
||||
'use_static' should be set to 1 for tables, which should be freed
|
||||
with av_free_static(), 0 if free_vlc() will be used.
|
||||
*/
|
||||
void initVlcSparse(VLC *vlc, int nb_bits, int nb_codes,
|
||||
const void *bits, int bits_wrap, int bits_size,
|
||||
const void *codes, int codes_wrap, int codes_size,
|
||||
const void *symbols, int symbols_wrap, int symbols_size) {
|
||||
vlc->bits = nb_bits;
|
||||
|
||||
if(vlc->table_size && vlc->table_size == vlc->table_allocated) {
|
||||
return;
|
||||
} else if(vlc->table_size) {
|
||||
error("called on a partially initialized table");
|
||||
}
|
||||
|
||||
if (build_table(vlc, nb_bits, nb_codes,
|
||||
bits, bits_wrap, bits_size,
|
||||
codes, codes_wrap, codes_size,
|
||||
symbols, symbols_wrap, symbols_size,
|
||||
0, 0, 4 | 2) < 0) {
|
||||
free(&vlc->table);
|
||||
return; // Error
|
||||
}
|
||||
|
||||
if(vlc->table_size != vlc->table_allocated)
|
||||
error("SVQ1 needed %d had %d", vlc->table_size, vlc->table_allocated);
|
||||
}
|
||||
|
||||
SVQ1Decoder::SVQ1Decoder(uint16 width, uint16 height) {
|
||||
_surface = new Graphics::Surface();
|
||||
_surface->create(width, height, g_system->getScreenFormat());
|
||||
|
||||
_current[0] = new byte[width*height];
|
||||
_current[1] = new byte[(width/4)*(height/4)];
|
||||
_current[2] = new byte[(width/4)*(height/4)];
|
||||
|
||||
_last[0] = 0;
|
||||
_last[1] = 0;
|
||||
_last[2] = 0;
|
||||
|
||||
// Setup Variable Length Code Tables
|
||||
static int16 tableA[6][2];
|
||||
svq1_block_type.table = tableA;
|
||||
svq1_block_type.table_allocated = 6;
|
||||
initVlcSparse(&svq1_block_type, 2, 4,
|
||||
&svq1_block_type_vlc[0][1], 2, 1,
|
||||
&svq1_block_type_vlc[0][0], 2, 1, NULL, 0, 0);
|
||||
|
||||
static int16 tableB[176][2];
|
||||
svq1_motion_component.table = tableB;
|
||||
svq1_motion_component.table_allocated = 176;
|
||||
initVlcSparse(&svq1_motion_component, 7, 33,
|
||||
&mvtab[0][1], 2, 1,
|
||||
&mvtab[0][0], 2, 1, NULL, 0, 0);
|
||||
|
||||
uint16 offset = 0;
|
||||
for (uint8 i = 0; i < 6; i++) {
|
||||
static const uint8 sizes[2][6] = {{14, 10, 14, 18, 16, 18}, {10, 10, 14, 14, 14, 16}};
|
||||
static int16 tableC[168][2];
|
||||
|
||||
svq1_intra_multistage[i].table = &tableC[offset];
|
||||
svq1_intra_multistage[i].table_allocated = sizes[0][i];
|
||||
offset += sizes[0][i];
|
||||
initVlcSparse(&svq1_intra_multistage[i], 3, 8,
|
||||
&svq1_intra_multistage_vlc[i][0][1], 2, 1,
|
||||
&svq1_intra_multistage_vlc[i][0][0], 2, 1, NULL, 0, 0);
|
||||
|
||||
svq1_inter_multistage[i].table = &tableC[offset];
|
||||
svq1_inter_multistage[i].table_allocated = sizes[1][i];
|
||||
offset += sizes[1][i];
|
||||
initVlcSparse(&svq1_inter_multistage[i], 3, 8,
|
||||
&svq1_inter_multistage_vlc[i][0][1], 2, 1,
|
||||
&svq1_inter_multistage_vlc[i][0][0], 2, 1, NULL, 0, 0);
|
||||
}
|
||||
|
||||
static int16 tableD[632][2];
|
||||
svq1_intra_mean.table = tableD;
|
||||
svq1_intra_mean.table_allocated = 632;
|
||||
initVlcSparse(&svq1_intra_mean, 8, 256,
|
||||
&svq1_intra_mean_vlc[0][1], 4, 2,
|
||||
&svq1_intra_mean_vlc[0][0], 4, 2, NULL, 0, 0);
|
||||
|
||||
static int16 tableE[1434][2];
|
||||
svq1_inter_mean.table = tableE;
|
||||
svq1_inter_mean.table_allocated = 1434;
|
||||
initVlcSparse(&svq1_inter_mean, 9, 512,
|
||||
&svq1_inter_mean_vlc[0][1], 4, 2,
|
||||
&svq1_inter_mean_vlc[0][0], 4, 2, NULL, 0, 0);
|
||||
}
|
||||
|
||||
SVQ1Decoder::~SVQ1Decoder() {
|
||||
_surface->free();
|
||||
delete _surface;
|
||||
|
||||
delete[] _current[0];
|
||||
delete[] _current[1];
|
||||
delete[] _current[2];
|
||||
|
||||
delete[] _last[0];
|
||||
delete[] _last[1];
|
||||
delete[] _last[2];
|
||||
}
|
||||
|
||||
const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *stream) {
|
||||
@ -108,23 +866,25 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
|
||||
|
||||
byte temporalReference = frameData.getBits(8);
|
||||
debug(1, " temporalReference: %d", temporalReference);
|
||||
const char* types[4] = { "I Frame", "P Frame", "B Frame", "Invalid" };
|
||||
byte pictureType = frameData.getBits(2);
|
||||
debug(1, " pictureType: %d (%s)", pictureType, types[pictureType]);
|
||||
if (pictureType == 3) { // Invalid
|
||||
warning("Invalid pictureType");
|
||||
return _surface;
|
||||
}
|
||||
else if (pictureType == 0) { // I Frame
|
||||
const char* types[4] = { "I (Key)", "P (Delta from Previous)", "B (Delta from Next)", "Invalid" };
|
||||
byte frameType = frameData.getBits(2);
|
||||
debug(1, " frameType: %d = %s Frame", frameType, types[frameType]);
|
||||
if (frameType == 0) { // I Frame
|
||||
// TODO: Validate checksum if present
|
||||
if (frameCode == 0x50 || frameCode == 0x60) {
|
||||
uint32 checksum = frameData.getBits(16);
|
||||
debug(1, " checksum:0x%02x", checksum);
|
||||
// TODO: Validate checksum
|
||||
//uint16 calculate_packet_checksum (const uint8 *data, const int length) {
|
||||
// int value;
|
||||
//for (int i = 0; i < length; i++)
|
||||
// value = checksum_table[data[i] ^ (value >> 8)] ^ ((value & 0xFF) << 8);
|
||||
//for (int i = 0; i < length; i++)
|
||||
// value = checksum_table[data[i] ^ (value >> 8)] ^ ((value & 0xFF) << 8);
|
||||
}
|
||||
} else if (frameType == 2) { // B Frame
|
||||
warning("B Frames not supported by SVQ1 decoder");
|
||||
return _surface;
|
||||
} else if (frameType == 3) { // Invalid
|
||||
warning("Invalid Frame Type");
|
||||
return _surface;
|
||||
}
|
||||
|
||||
static const uint8 stringXORTable[256] = {
|
||||
@ -188,7 +948,7 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
|
||||
{ 128, 96 }, // 1
|
||||
{ 176, 144 }, // 2
|
||||
{ 352, 288 }, // 3
|
||||
{ 704, 576 }, // 4
|
||||
{ 704, 576 }, // 4
|
||||
{ 240, 180 }, // 5
|
||||
{ 320, 240 } // 6
|
||||
};
|
||||
@ -205,9 +965,10 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
|
||||
}
|
||||
debug(1, " frameWidth: %d", frameWidth);
|
||||
debug(1, " frameHeight: %d", frameHeight);
|
||||
if (frameWidth == 0 || frameHeight == 0) // Invalid
|
||||
if (frameWidth == 0 || frameHeight == 0) { // Invalid
|
||||
warning("Invalid Frame Size");
|
||||
return _surface;
|
||||
|
||||
}
|
||||
bool checksumPresent = frameData.getBit();
|
||||
debug(1, " checksumPresent: %d", checksumPresent);
|
||||
if (checksumPresent) {
|
||||
@ -238,24 +999,89 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
|
||||
}
|
||||
}
|
||||
|
||||
if (frameWidth <= _surface->w && frameHeight <= _surface->h) {
|
||||
byte *yPlane = new byte[frameWidth*frameHeight];
|
||||
byte *uPlane = new byte[(frameWidth/2)*(frameHeight/2)];
|
||||
byte *vPlane = new byte[(frameWidth/2)*(frameHeight/2)];
|
||||
if (frameWidth == _surface->w && frameHeight == _surface->h) {
|
||||
// Decode Y, U and V component planes
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int linesize, width, height;
|
||||
if (i == 0) {
|
||||
// Y Size is width * height
|
||||
width = frameWidth;
|
||||
if (width % 16) {
|
||||
width /= 16;
|
||||
width++;
|
||||
width *= 16;
|
||||
}
|
||||
assert(width % 16 == 0);
|
||||
height = frameHeight;
|
||||
if (height % 16) {
|
||||
height /= 16;
|
||||
height++;
|
||||
height *= 16;
|
||||
}
|
||||
assert(height % 16 == 0);
|
||||
linesize = width;
|
||||
} else {
|
||||
// U and V size is width/4 * height/4
|
||||
width = frameWidth/4;
|
||||
if (width % 16) {
|
||||
width /= 16;
|
||||
width++;
|
||||
width *= 16;
|
||||
}
|
||||
assert(width % 16 == 0);
|
||||
height = frameHeight/4;
|
||||
if (height % 16) {
|
||||
height /= 16;
|
||||
height++;
|
||||
height *= 16;
|
||||
}
|
||||
assert(height % 16 == 0);
|
||||
linesize = width;
|
||||
}
|
||||
|
||||
// TODO: Read Plane Data
|
||||
for (uint32 i = 0; i < frameWidth*frameHeight; i++)
|
||||
yPlane[i] = 0;
|
||||
for (uint32 i = 0; i < (frameWidth/2)*(frameHeight/2); i++) {
|
||||
uPlane[i] = 0;
|
||||
vPlane[i] = 0;
|
||||
if (frameType == 0) { // I Frame
|
||||
// Keyframe (I)
|
||||
byte *current = _current[i];
|
||||
for (uint16 y = 0; y < height; y += 16) {
|
||||
for (uint16 x = 0; x < width; x += 16) {
|
||||
if (int result = svq1DecodeBlockIntra(&frameData, ¤t[x], linesize) != 0) {
|
||||
warning("Error in svq1DecodeBlock %i (keyframe)", result);
|
||||
return _surface;
|
||||
}
|
||||
}
|
||||
current += 16 * linesize;
|
||||
}
|
||||
} else {
|
||||
// Delta frame (P or B)
|
||||
|
||||
// Prediction Motion Vector
|
||||
Common::Point *pmv = new Common::Point[(width/8) + 3];
|
||||
|
||||
byte *previous;
|
||||
if(frameType == 2) { // B Frame
|
||||
warning("B Frame not supported currently");
|
||||
//previous = _next[i];
|
||||
} else
|
||||
previous = _last[i];
|
||||
|
||||
byte *current = _current[i];
|
||||
for (uint16 y = 0; y < height; y += 16) {
|
||||
for (uint16 x = 0; x < width; x += 16) {
|
||||
if (int result = svq1DecodeDeltaBlock(&frameData, ¤t[x], previous, linesize, pmv, x, y) != 0) {
|
||||
warning("Error in svq1DecodeDeltaBlock %i", result);
|
||||
return _surface;
|
||||
}
|
||||
}
|
||||
|
||||
pmv[0].x = pmv[0].y = 0;
|
||||
|
||||
current += 16*linesize;
|
||||
}
|
||||
delete[] pmv;
|
||||
}
|
||||
}
|
||||
|
||||
convertYUV410ToRGB(_surface, yPlane, uPlane, vPlane, frameWidth, frameHeight, frameWidth, frameWidth/2);
|
||||
|
||||
delete[] yPlane;
|
||||
delete[] uPlane;
|
||||
delete[] vPlane;
|
||||
convertYUV410ToRGB(_surface, _current[0], _current[1], _current[2], frameWidth, frameHeight, frameWidth, frameWidth/2);
|
||||
} else
|
||||
warning("FrameWidth/Height Sanity Check Failed!");
|
||||
|
||||
|
@ -37,6 +37,9 @@ public:
|
||||
|
||||
private:
|
||||
Graphics::Surface *_surface;
|
||||
|
||||
byte *_current[3];
|
||||
byte *_last[3];
|
||||
};
|
||||
|
||||
} // End of namespace Video
|
||||
|
@ -760,7 +760,7 @@ static const int8 svq1_inter_codebook_8x8[6144] = {
|
||||
};
|
||||
|
||||
// list of codebooks for inter-coded vectors
|
||||
const int8_t* const ff_svq1_inter_codebooks[6] = {
|
||||
const int8_t* const svq1_inter_codebooks[6] = {
|
||||
svq1_inter_codebook_4x2, svq1_inter_codebook_4x4,
|
||||
svq1_inter_codebook_8x4, svq1_inter_codebook_8x8,
|
||||
NULL, NULL,
|
||||
@ -1503,7 +1503,7 @@ static const int8 svq1_intra_codebook_8x8[6144] = {
|
||||
};
|
||||
|
||||
// list of codebooks for intra-coded vectors/
|
||||
const int8* const ff_svq1_intra_codebooks[6] = {
|
||||
const int8* const svq1_intra_codebooks[6] = {
|
||||
svq1_intra_codebook_4x2, svq1_intra_codebook_4x4,
|
||||
svq1_intra_codebook_8x4, svq1_intra_codebook_8x8,
|
||||
NULL, NULL,
|
||||
|
@ -24,14 +24,14 @@
|
||||
#define VIDEO_CODECS_SVQ1_VLC_H
|
||||
|
||||
// values in this table range from 0..3; adjust retrieved value by +0
|
||||
const uint8 ff_svq1_block_type_vlc[4][2] = {
|
||||
const uint8 svq1_block_type_vlc[4][2] = {
|
||||
// { code, length }
|
||||
{ 0x1, 1 }, { 0x1, 2 }, { 0x1, 3 }, { 0x0, 3 }
|
||||
|
||||
};
|
||||
|
||||
// values in this table range from -1..6; adjust retrieved value by -1
|
||||
const uint8 ff_svq1_intra_multistage_vlc[6][8][2] = {
|
||||
const uint8 svq1_intra_multistage_vlc[6][8][2] = {
|
||||
// { code, length }
|
||||
{
|
||||
{ 0x1, 5 }, { 0x1, 1 }, { 0x3, 3 }, { 0x2, 3 },
|
||||
@ -55,7 +55,7 @@ const uint8 ff_svq1_intra_multistage_vlc[6][8][2] = {
|
||||
};
|
||||
|
||||
// values in this table range from -1..6; adjust retrieved value by -1
|
||||
const uint8 ff_svq1_inter_multistage_vlc[6][8][2] = {
|
||||
const uint8 svq1_inter_multistage_vlc[6][8][2] = {
|
||||
// { code, length }
|
||||
{
|
||||
{ 0x3, 2 }, { 0x5, 3 }, { 0x4, 3 }, { 0x3, 3 },
|
||||
@ -79,7 +79,7 @@ const uint8 ff_svq1_inter_multistage_vlc[6][8][2] = {
|
||||
};
|
||||
|
||||
// values in this table range from 0..255; adjust retrieved value by +0
|
||||
const uint16 ff_svq1_intra_mean_vlc[256][2] = {
|
||||
const uint16 svq1_intra_mean_vlc[256][2] = {
|
||||
// { code, length }
|
||||
{ 0x37, 6 }, { 0x56, 7 }, { 0x1, 17 }, { 0x1, 20 },
|
||||
{ 0x2, 20 }, { 0x3, 20 }, { 0x0, 20 }, { 0x4, 20 },
|
||||
@ -148,7 +148,7 @@ const uint16 ff_svq1_intra_mean_vlc[256][2] = {
|
||||
};
|
||||
|
||||
// values in this table range from -256..255; adjust retrieved value by -256
|
||||
const uint16 ff_svq1_inter_mean_vlc[512][2] = {
|
||||
const uint16 svq1_inter_mean_vlc[512][2] = {
|
||||
// { code, length }
|
||||
{ 0x5A, 22 }, { 0xD4, 22 }, { 0xD5, 22 }, { 0xD6, 22 },
|
||||
{ 0xD7, 22 }, { 0xD8, 22 }, { 0xD9, 22 }, { 0xDA, 22 },
|
||||
@ -280,4 +280,15 @@ const uint16 ff_svq1_inter_mean_vlc[512][2] = {
|
||||
{ 0x3, 22 }, { 0x2, 22 }, { 0x1, 22 }, { 0x0, 22 }
|
||||
};
|
||||
|
||||
// From H263 Data Tables
|
||||
const uint8 mvtab[33][2] =
|
||||
{
|
||||
{1,1}, {1,2}, {1,3}, {1,4}, {3,6}, {5,7}, {4,7}, {3,7},
|
||||
{11,9}, {10,9}, {9,9}, {17,10}, {16,10}, {15,10}, {14,10}, {13,10},
|
||||
{12,10}, {11,10}, {10,10}, {9,10}, {8,10}, {7,10}, {6,10}, {5,10},
|
||||
{4,10}, {7,11}, {6,11}, {5,11}, {4,11}, {3,11}, {2,11}, {3,12},
|
||||
{2,12}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user