You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/kopete/libkopete/avdevice/sonix_compress.cpp

181 lines
3.3 KiB

#include "sonix_compress.h"
#define CLAMP(x) ((x)<0?0:((x)>255)?255:(x))
typedef struct {
int is_abs;
int len;
int val;
int unk;
} code_table_t;
/* local storage */
static code_table_t table[256];
static int init_done = 0;
/* global variable */
int sonix_unknown = 0;
/*
sonix_decompress_init
=====================
pre-calculates a locally stored table for efficient huffman-decoding.
Each entry at index x in the table represents the codeword
present at the MSB of byte x.
*/
void sonix_decompress_init(void)
{
int i;
int is_abs, val, len, unk;
for (i = 0; i < 256; i++) {
is_abs = 0;
val = 0;
len = 0;
unk = 0;
if ((i & 0x80) == 0) {
/* code 0 */
val = 0;
len = 1;
}
else if ((i & 0xE0) == 0x80) {
/* code 100 */
val = +4;
len = 3;
}
else if ((i & 0xE0) == 0xA0) {
/* code 101 */
val = -4;
len = 3;
}
else if ((i & 0xF0) == 0xD0) {
/* code 1101 */
val = +11;
len = 4;
}
else if ((i & 0xF0) == 0xF0) {
/* code 1111 */
val = -11;
len = 4;
}
else if ((i & 0xF8) == 0xC8) {
/* code 11001 */
val = +20;
len = 5;
}
else if ((i & 0xFC) == 0xC0) {
/* code 110000 */
val = -20;
len = 6;
}
else if ((i & 0xFC) == 0xC4) {
/* code 110001xx: unknown */
val = 0;
len = 8;
unk = 1;
}
else if ((i & 0xF0) == 0xE0) {
/* code 1110xxxx */
is_abs = 1;
val = (i & 0x0F) << 4;
len = 8;
}
table[i].is_abs = is_abs;
table[i].val = val;
table[i].len = len;
table[i].unk = unk;
}
sonix_unknown = 0;
init_done = 1;
}
/*
sonix_decompress
================
decompresses an image encoded by a SN9C101 camera controller chip.
IN width
height
inp pointer to compressed frame (with header already stripped)
OUT outp pointer to decompressed frame
Returns 0 if the operation was successful.
Returns <0 if operation failed.
*/
int sonix_decompress(int width, int height, unsigned char *inp, unsigned char *outp)
{
int row, col;
int val;
int bitpos;
unsigned char code;
unsigned char *addr;
if (!init_done) {
/* do sonix_decompress_init first! */
return -1;
}
bitpos = 0;
for (row = 0; row < height; row++) {
col = 0;
/* first two pixels in first two rows are stored as raw 8-bit */
if (row < 2) {
addr = inp + (bitpos >> 3);
code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
bitpos += 8;
*outp++ = code;
addr = inp + (bitpos >> 3);
code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
bitpos += 8;
*outp++ = code;
col += 2;
}
while (col < width) {
/* get bitcode from bitstream */
addr = inp + (bitpos >> 3);
code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
/* update bit position */
bitpos += table[code].len;
/* update code statistics */
sonix_unknown += table[code].unk;
/* calculate pixel value */
val = table[code].val;
if (!table[code].is_abs) {
/* value is relative to top and left pixel */
if (col < 2) {
/* left column: relative to top pixel */
val += outp[-2*width];
}
else if (row < 2) {
/* top row: relative to left pixel */
val += outp[-2];
}
else {
/* main area: average of left pixel and top pixel */
val += (outp[-2] + outp[-2*width]) / 2;
}
}
/* store pixel */
*outp++ = CLAMP(val);
col++;
}
}
return 0;
}