1309 lines
29 KiB
C
Executable File
1309 lines
29 KiB
C
Executable File
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#define true 1
|
|
#define false 0
|
|
|
|
#define RST0 0xd0 /* Restart 0 */
|
|
#define SOI 0xd8 /* Start of Image */
|
|
#define APP0 0xe0 /* application segments */
|
|
#define DQT 0xdb /* quantization table */
|
|
#define SOF0 0xc0 /* Start of Frame */
|
|
#define DHT 0xc4 /* Huffman table */
|
|
#define SOS 0xda /* Start of Scan */
|
|
#define EOI 0xd9 /* End of Image */
|
|
|
|
#define EOB 0 /* End of Block */
|
|
#define ZRL 240 /* Zero Run Length */
|
|
|
|
#define SECTION_MARKER 0xff
|
|
#define NO_OF_HUF_TBLS 4
|
|
#define MAX_NODES 256
|
|
#define MAX_COMPONENTS 3
|
|
#define WORD_LEN 8
|
|
|
|
#define ic1 251
|
|
#define is1 50
|
|
#define ic3 213
|
|
#define is3 142
|
|
#define ir2c6 277
|
|
#define ir2s6 669
|
|
#define ir2 181
|
|
|
|
typedef struct
|
|
{
|
|
short app0_len;
|
|
char identifier[5];
|
|
short version;
|
|
unsigned char units;
|
|
short x_density;
|
|
short y_density;
|
|
short x_thumbnail;
|
|
short y_thumbnail;
|
|
} JPGHEADER;
|
|
|
|
typedef struct
|
|
{
|
|
unsigned char id;
|
|
unsigned char samp_factor;
|
|
unsigned char v_samp_factor;
|
|
unsigned char h_samp_factor;
|
|
unsigned char quant_tbl_no;
|
|
} COMPONENT;
|
|
|
|
typedef struct
|
|
{
|
|
unsigned char precision;
|
|
short height;
|
|
short width;
|
|
unsigned char components;
|
|
COMPONENT component[3];
|
|
} SOFINFO;
|
|
|
|
typedef struct
|
|
{
|
|
unsigned char id;
|
|
unsigned char tbl_no;
|
|
unsigned char ac_tbl_no;
|
|
unsigned char dc_tbl_no;
|
|
} SCANCOMPONENT;
|
|
|
|
typedef struct
|
|
{
|
|
unsigned char components;
|
|
SCANCOMPONENT component[3];
|
|
} SOSINFO;
|
|
|
|
typedef struct
|
|
{
|
|
unsigned char bits[16];
|
|
unsigned char val[256];
|
|
} HUFTBL;
|
|
|
|
typedef struct
|
|
{
|
|
unsigned short code;
|
|
short size;
|
|
short value;
|
|
unsigned long tree_index;
|
|
} huf_node;
|
|
|
|
//unsigned short videobuf[38016]; //QCIF: 176*144*3=76032 bytes
|
|
//static unsigned short videobuf[4]; //QCIF: 176*144*3=76032 bytes
|
|
static unsigned char* videobuf;
|
|
|
|
static short reset_mcu;
|
|
static short image_started=false;
|
|
static JPGHEADER jpg_header;
|
|
static SOFINFO sof_info;
|
|
static short image_height;
|
|
static short image_width;
|
|
static SOSINFO sos_info;
|
|
static HUFTBL ac_huf_tbl[NO_OF_HUF_TBLS];
|
|
static HUFTBL dc_huf_tbl[NO_OF_HUF_TBLS];
|
|
static short quant_tbl[2][64];
|
|
static char identifier_mark[5];
|
|
static short thumbnail_size;
|
|
static short jfif_found;
|
|
|
|
static huf_node ac_node[MAX_COMPONENTS][MAX_NODES];
|
|
static huf_node dc_node[MAX_COMPONENTS][MAX_NODES];
|
|
|
|
static short h_div[MAX_COMPONENTS];
|
|
static short v_div[MAX_COMPONENTS];
|
|
|
|
static short total_nodes;
|
|
static short dc_total_nodes[MAX_COMPONENTS];
|
|
static short ac_total_nodes[MAX_COMPONENTS];
|
|
static short size,amplitude,symbol,run;
|
|
|
|
static short prev_dc_amplitude[MAX_COMPONENTS];
|
|
|
|
static short component[4][4][MAX_COMPONENTS][8][8];
|
|
static short transform[8][8];
|
|
static short block[64];
|
|
static short coefficient[64];
|
|
static short zigzag_array[64];
|
|
|
|
static unsigned char max_v_samp_factor;
|
|
static unsigned char max_h_samp_factor;
|
|
|
|
static short mcu_ctr;
|
|
static short mcu_x;
|
|
static short mcu_y;
|
|
|
|
static short mcu_width;
|
|
static short mcu_height;
|
|
|
|
static unsigned char current_word;
|
|
static short current_bit;
|
|
|
|
static unsigned short word_var;
|
|
static unsigned char byte_var;
|
|
static unsigned char three_byte_var[3];
|
|
|
|
static short done;
|
|
static int iter = 0;
|
|
static unsigned char* in_stream;
|
|
|
|
static long x0, x1, x2, x3, x4, x5, x6, x7, x8;
|
|
|
|
static unsigned int bg_width;
|
|
static unsigned int bg_height;
|
|
static unsigned int offset_x;
|
|
static unsigned int offset_y;
|
|
static unsigned int out_format =0;
|
|
|
|
|
|
void jpeg_dec(unsigned char* inbuf, unsigned char* outbuf);
|
|
|
|
static unsigned char stream_getc()
|
|
{
|
|
unsigned char r = in_stream[iter];
|
|
iter++;
|
|
return r;
|
|
}
|
|
|
|
static void stream_read(unsigned char* buf, short len)
|
|
{
|
|
short i;
|
|
for(i=0; i<len; i++){
|
|
buf[i] = stream_getc();
|
|
}
|
|
}
|
|
|
|
|
|
static short get_word()
|
|
{
|
|
unsigned char byte1,byte2;
|
|
short word;
|
|
|
|
stream_read(&byte1,1);
|
|
stream_read(&byte2,1);
|
|
|
|
word=(byte1<<8)+byte2;
|
|
return word;
|
|
}
|
|
|
|
static void new_idct(short k,short l,short m)
|
|
{
|
|
short i;
|
|
|
|
for (i = 0; i < 8; i ++)
|
|
{
|
|
x0 = (long) transform[i][0] << 9;
|
|
x1 = (long) transform[i][1] << 7;
|
|
x2 = (long) transform[i][2];
|
|
x3 = (long) transform[i][3] * ir2;
|
|
x4 = (long) transform[i][4] << 9;
|
|
x5 = (long) transform[i][5] * ir2;
|
|
x6 = (long) transform[i][6];
|
|
x7 = (long) transform[i][7] << 7;
|
|
x8 = x7 + x1;
|
|
x1 -= x7;
|
|
|
|
x7 = x0 + x4;
|
|
x0 -= x4;
|
|
x4 = x1 + x5;
|
|
x1 -= x5;
|
|
x5 = x3 + x8;
|
|
x8 -= x3;
|
|
x3 = ir2c6 * (x2 + x6);
|
|
x6 = x3 + (- ir2c6 - ir2s6) * x6;
|
|
x2 = x3 + (- ir2c6 + ir2s6) * x2;
|
|
|
|
x3 = x7 + x2;
|
|
x7 -= x2;
|
|
x2 = x0 + x6;
|
|
x0 -= x6;
|
|
x6 = ic3 * (x4 + x5);
|
|
x5 = (x6 + (- ic3 - is3) * x5) >> 6;
|
|
x4 = (x6 + (- ic3 + is3) * x4) >> 6;
|
|
x6 = ic1 * (x1 + x8);
|
|
x1 = (x6 + (- ic1 - is1) * x1) >> 6;
|
|
x8 = (x6 + (- ic1 + is1) * x8) >> 6;
|
|
|
|
x7 += 512;
|
|
x2 += 512;
|
|
x0 += 512;
|
|
x3 += 512;
|
|
component[l][m][k][i][0] = (short) ((x3 + x4) >> 10);
|
|
component[l][m][k][i][1] = (short) ((x2 + x8) >> 10);
|
|
component[l][m][k][i][2] = (short) ((x0 + x1) >> 10);
|
|
component[l][m][k][i][3] = (short) ((x7 + x5) >> 10);
|
|
component[l][m][k][i][4] = (short) ((x7 - x5) >> 10);
|
|
component[l][m][k][i][5] = (short) ((x0 - x1) >> 10);
|
|
component[l][m][k][i][6] = (short) ((x2 - x8) >> 10);
|
|
component[l][m][k][i][7] = (short) ((x3 - x4) >> 10);
|
|
}
|
|
|
|
|
|
for (i = 0; i < 8; i ++)
|
|
{
|
|
x0 = (long) component[l][m][k][0][i]<< 9;
|
|
x1 = (long) component[l][m][k][1][i] << 7;
|
|
x2 = (long) component[l][m][k][2][i];
|
|
x3 = (long) component[l][m][k][3][i] * ir2;
|
|
x4 = (long) component[l][m][k][4][i] << 9;
|
|
x5 = (long) component[l][m][k][5][i] * ir2;
|
|
x6 = (long) component[l][m][k][6][i];
|
|
x7 = (long) component[l][m][k][7][i] << 7;
|
|
x8 = x7 + x1;
|
|
x1 -= x7;
|
|
|
|
x7 = x0 + x4;
|
|
x0 -= x4;
|
|
x4 = x1 + x5;
|
|
x1 -= x5;
|
|
x5 = x3 + x8;
|
|
x8 -= x3;
|
|
x3 = ir2c6 * (x2 + x6);
|
|
x6 = x3 + (- ir2c6 - ir2s6) * x6;
|
|
x2 = x3 + (- ir2c6 + ir2s6) * x2;
|
|
|
|
x3 = x7 + x2;
|
|
x7 -= x2;
|
|
x2 = x0 + x6;
|
|
x0 -= x6;
|
|
x4 >>= 6;
|
|
x5 >>= 6;
|
|
x1 >>= 6;
|
|
x8 >>= 6;
|
|
x6 = ic3 * (x4 + x5);
|
|
x5 = (x6 + (- ic3 - is3) * x5);
|
|
x4 = (x6 + (- ic3 + is3) * x4);
|
|
x6 = ic1 * (x1 + x8);
|
|
x1 = (x6 + (- ic1 - is1) * x1);
|
|
x8 = (x6 + (- ic1 + is1) * x8);
|
|
|
|
x7 += 1024;
|
|
x2 += 1024;
|
|
x0 += 1024;
|
|
x3 += 1024;
|
|
component[l][m][k][0][i] = (short) ((x3 + x4) >> 11);
|
|
component[l][m][k][1][i] = (short) ((x2 + x8) >> 11);
|
|
component[l][m][k][2][i] = (short) ((x0 + x1) >> 11);
|
|
component[l][m][k][3][i] = (short) ((x7 + x5) >> 11);
|
|
component[l][m][k][4][i] = (short) ((x7 - x5) >> 11);
|
|
component[l][m][k][5][i] = (short) ((x0 - x1) >> 11);
|
|
component[l][m][k][6][i] = (short) ((x2 - x8) >> 11);
|
|
component[l][m][k][7][i] = (short) ((x3 - x4) >> 11);
|
|
}
|
|
}
|
|
|
|
static void set_pixel_yuv422(unsigned x, unsigned y, unsigned char y1, unsigned char u, unsigned char v)
|
|
{
|
|
long idx;
|
|
unsigned char* videobuf2= videobuf+ sof_info.width*sof_info.height;
|
|
idx = (long)y;
|
|
idx *= sof_info.width;
|
|
idx += x;
|
|
//YUV422 pack
|
|
if(x & 1){
|
|
videobuf[idx] = y1;
|
|
videobuf2[idx] = v;
|
|
}
|
|
else{
|
|
videobuf[idx] = y1;
|
|
videobuf2[idx] = u;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
static void set_pixel_vyuy(unsigned x, unsigned y, unsigned char y1, unsigned char u, unsigned char v)
|
|
{
|
|
long idx;
|
|
|
|
#if 0
|
|
idx = (long)y;
|
|
idx *= sof_info.width;
|
|
idx += x;
|
|
idx *= 2;
|
|
#else
|
|
idx = (long)(y+offset_y);
|
|
idx *= bg_width;
|
|
idx += x+offset_x;
|
|
idx *= 2;
|
|
#endif
|
|
|
|
if(x & 1){
|
|
videobuf[idx] = v;
|
|
videobuf[idx+1] = y1;
|
|
}
|
|
else{
|
|
videobuf[idx] = u;
|
|
videobuf[idx+1] = y1;
|
|
}
|
|
}
|
|
static void set_pixel(unsigned x,unsigned y, unsigned char red,unsigned char green,unsigned char blue)
|
|
{
|
|
long idx;
|
|
|
|
//idx = (y * sof_info.width + x) * 3;
|
|
|
|
idx = (long)y;
|
|
idx *= sof_info.width;
|
|
idx += x;
|
|
idx *= 3;
|
|
#if 0
|
|
if(idx % 2)
|
|
{
|
|
idx /= 2;
|
|
videobuf[idx] += red;
|
|
videobuf[idx+1] = (green<<8) + blue;
|
|
}
|
|
else
|
|
{
|
|
idx /= 2;
|
|
videobuf[idx] = (red<<8) + green;
|
|
videobuf[idx+1] = (blue<<8);
|
|
}
|
|
#else
|
|
videobuf[idx] = red;
|
|
videobuf[idx+1] = green;
|
|
videobuf[idx+2] = blue;
|
|
#endif
|
|
}
|
|
|
|
|
|
static void check_for_reset_marker(unsigned char buf)
|
|
{
|
|
short i;
|
|
|
|
for (i=0;i<8;i++)
|
|
{
|
|
if (buf==(RST0+i))
|
|
{
|
|
reset_mcu=true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (reset_mcu)
|
|
{
|
|
/* zero out the previous dc values */
|
|
for (i=0;i<MAX_COMPONENTS;i++)
|
|
prev_dc_amplitude[i]=0;
|
|
}
|
|
}
|
|
|
|
static unsigned char getbit()
|
|
{
|
|
unsigned char mask;
|
|
unsigned char buf;
|
|
|
|
if (current_bit==0)
|
|
{
|
|
current_word=stream_getc();
|
|
if (current_word==SECTION_MARKER)
|
|
{
|
|
/* Process section markers found in image data stream */
|
|
buf=stream_getc();
|
|
if (buf==EOI){
|
|
done=true;
|
|
}
|
|
else if (buf!=0 && buf!=SECTION_MARKER)
|
|
{
|
|
check_for_reset_marker(buf);
|
|
if (reset_mcu)
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
mask=1<<(WORD_LEN-current_bit-1);
|
|
current_bit++;
|
|
if (current_bit==WORD_LEN) current_bit=0;
|
|
if ((current_word & mask)==mask)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void setup_zigzag_array()
|
|
{
|
|
short i,j,x,y,k=0;
|
|
|
|
for (j=0;j<8;j++)
|
|
{
|
|
for (i=0;i<=j;i++)
|
|
{
|
|
if (j%2==0)
|
|
{
|
|
x=i;
|
|
y=j-i;
|
|
}
|
|
else
|
|
{
|
|
x=j-i;
|
|
y=i;
|
|
}
|
|
zigzag_array[k]=(y<<3)+x;
|
|
k++;
|
|
}
|
|
}
|
|
|
|
for (j=1;j<8;j++)
|
|
{
|
|
for (i=0;i<=8-1-j;i++)
|
|
{
|
|
if (j%2==0)
|
|
{
|
|
x=8-1-i;
|
|
y=j+i;
|
|
}
|
|
else
|
|
{
|
|
x=j+i;
|
|
y=8-1-i;
|
|
}
|
|
zigzag_array[k]=(y<<3)+x;
|
|
k++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void dec_unknown_marker()
|
|
{
|
|
short length;
|
|
short i;
|
|
|
|
if (!image_started)
|
|
done=true;
|
|
else
|
|
{
|
|
length=get_word();
|
|
length-=2; /* Subtract length of length word */
|
|
|
|
/* Skip over the rest of the unknown marker */
|
|
for (i=0;i<length;i++)
|
|
stream_read(&byte_var,1);
|
|
}
|
|
}
|
|
|
|
|
|
static void dec_application_segment()
|
|
{
|
|
short i;
|
|
|
|
if (!image_started)
|
|
done=true;
|
|
else
|
|
{
|
|
jpg_header.app0_len=get_word();
|
|
|
|
stream_read((unsigned char*)identifier_mark, 5);
|
|
if (strcmp(identifier_mark,"JFIF")==0)
|
|
{
|
|
jfif_found=true;
|
|
}
|
|
else
|
|
{
|
|
if (jfif_found)
|
|
{
|
|
/* application extension found */
|
|
for (i=0;i<jpg_header.app0_len-2;i++)
|
|
stream_read(&byte_var, 1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
strcpy(jpg_header.identifier,identifier_mark);
|
|
|
|
stream_read((unsigned char*)&word_var,2);
|
|
jpg_header.version=word_var;
|
|
|
|
stream_read(&byte_var,1);
|
|
jpg_header.units=byte_var;
|
|
|
|
stream_read((unsigned char*)&word_var,2);
|
|
jpg_header.x_density=word_var;
|
|
|
|
stream_read((unsigned char*)&word_var,2);
|
|
jpg_header.y_density=word_var;
|
|
|
|
stream_read(&byte_var,1);
|
|
jpg_header.x_thumbnail=byte_var;
|
|
|
|
stream_read(&byte_var,1);
|
|
jpg_header.y_thumbnail=byte_var;
|
|
|
|
thumbnail_size=jpg_header.x_thumbnail*jpg_header.y_thumbnail;
|
|
|
|
/* Skip over thumbnail */
|
|
for (i=0;i<thumbnail_size;i++)
|
|
stream_read((unsigned char*)three_byte_var,3);
|
|
|
|
/* Skip over the rest of the app0 marker */
|
|
for (i=0;i<jpg_header.app0_len-16-3*thumbnail_size;i++)
|
|
stream_read(&byte_var,1);
|
|
}
|
|
}
|
|
|
|
static void dec_quantization_table()
|
|
{
|
|
short length,number,no_of_tables;
|
|
short i,j;
|
|
|
|
if (!image_started)
|
|
done=true;
|
|
else
|
|
{
|
|
length=get_word();
|
|
no_of_tables=(length-2)/65;
|
|
for (i=0;i<no_of_tables;i++)
|
|
{
|
|
stream_read(&byte_var,1);
|
|
number=byte_var;
|
|
for (j=0;j<64;j++)
|
|
{
|
|
stream_read(&byte_var,1);
|
|
quant_tbl[number][j]=byte_var;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void dec_start_of_frame()
|
|
{
|
|
short length;
|
|
short i;
|
|
|
|
if (!image_started)
|
|
done=true;
|
|
else
|
|
{
|
|
length=get_word();
|
|
|
|
stream_read(&byte_var,1);
|
|
sof_info.precision=byte_var;
|
|
if (sof_info.precision!=8)
|
|
{
|
|
done=true;
|
|
return;
|
|
}
|
|
|
|
sof_info.height=get_word();
|
|
image_height = sof_info.height;
|
|
sof_info.width=get_word();
|
|
image_width = sof_info.width;
|
|
|
|
if((bg_width == 0) && (bg_height == 0)){
|
|
offset_x = 0;
|
|
offset_y = 0;
|
|
bg_width = image_width;
|
|
bg_height = image_height;
|
|
}
|
|
else{
|
|
if((bg_width < image_width) || (bg_height < image_height)){
|
|
// printf("image width/height > bg_width/bg_height!!\n");
|
|
offset_x = 0;
|
|
offset_y = 0;
|
|
bg_width = image_width;
|
|
bg_height = image_height;
|
|
}
|
|
else{
|
|
offset_x = (bg_width - image_width)/2;
|
|
offset_y = (bg_height - image_height)/2;
|
|
}
|
|
}
|
|
|
|
stream_read(&byte_var,1);
|
|
sof_info.components=byte_var;
|
|
if (sof_info.components!=3)
|
|
{
|
|
done=true;
|
|
return;
|
|
}
|
|
|
|
max_v_samp_factor=0;
|
|
max_h_samp_factor=0;
|
|
for (i=0;i<sof_info.components;i++)
|
|
{
|
|
stream_read(&byte_var,1);
|
|
sof_info.component[i].id=byte_var;
|
|
|
|
stream_read(&byte_var,1);
|
|
sof_info.component[i].samp_factor=byte_var;
|
|
sof_info.component[i].v_samp_factor= /* Lo Nibble */
|
|
sof_info.component[i].samp_factor & 0x0f;
|
|
sof_info.component[i].h_samp_factor= /* Hi Nibble */
|
|
sof_info.component[i].samp_factor>>4;
|
|
|
|
if (sof_info.component[i].v_samp_factor>max_v_samp_factor)
|
|
max_v_samp_factor=sof_info.component[i].v_samp_factor;
|
|
|
|
if (sof_info.component[i].h_samp_factor>max_h_samp_factor)
|
|
max_h_samp_factor=sof_info.component[i].h_samp_factor;
|
|
|
|
stream_read(&byte_var,1);
|
|
sof_info.component[i].quant_tbl_no=byte_var;
|
|
}
|
|
|
|
/* Get divisors used for upsampling the chrominance components */
|
|
for (i=0;i<sof_info.components;i++)
|
|
{
|
|
h_div[i]=max_h_samp_factor/sof_info.component[i].h_samp_factor;
|
|
v_div[i]=max_v_samp_factor/sof_info.component[i].v_samp_factor;
|
|
}
|
|
|
|
/* Get number of MCUs across and down in the image */
|
|
mcu_width=(sof_info.width-1)/(max_h_samp_factor*8)+1;
|
|
mcu_height=(sof_info.height-1)/(max_v_samp_factor*8)+1;
|
|
|
|
/* Skip over the rest of the start of frame */
|
|
for (i=0;i<length-8-3*sof_info.components;i++)
|
|
stream_read(&byte_var,1);
|
|
}
|
|
}
|
|
|
|
static void dec_huffman_table()
|
|
{
|
|
short length;
|
|
short i,count,len;
|
|
unsigned char type,ndx;
|
|
HUFTBL *huf_tbl_ptr;
|
|
|
|
if (!image_started)
|
|
done=true;
|
|
else
|
|
{
|
|
length=get_word();
|
|
len=length-2; /* Subtract length of length word */
|
|
|
|
while (len>0)
|
|
{
|
|
stream_read(&byte_var,1);
|
|
|
|
type=byte_var>>4; /* Hi Nibble */
|
|
ndx=byte_var&0x0f; /* Lo Nibble */
|
|
|
|
/* Choose Huffman Table for AC or DC components */
|
|
if (type==1)
|
|
huf_tbl_ptr=&ac_huf_tbl[ndx];
|
|
else
|
|
huf_tbl_ptr=&dc_huf_tbl[ndx];
|
|
|
|
count=0;
|
|
for (i=0;i<16;i++)
|
|
{
|
|
stream_read(&byte_var,1);
|
|
huf_tbl_ptr->bits[i]=byte_var;
|
|
count+=byte_var;
|
|
}
|
|
|
|
if (count>256)
|
|
{
|
|
done=true;
|
|
return;
|
|
}
|
|
|
|
for (i=0;i<count;i++)
|
|
{
|
|
stream_read(&byte_var,1);
|
|
huf_tbl_ptr->val[i]=byte_var;
|
|
}
|
|
len-=(1+16+count); /* subtract for type, index, bits & values */
|
|
}
|
|
}
|
|
}
|
|
|
|
static void dec_mcu(void);
|
|
static void build_huf_nodes();
|
|
static void dec_image_data()
|
|
{
|
|
short i;
|
|
|
|
if (!image_started)
|
|
done=true;
|
|
else
|
|
{
|
|
build_huf_nodes();
|
|
|
|
/* Initialize previous DC amplitudes to zero for each component */
|
|
for (i=0;i<MAX_COMPONENTS;i++)
|
|
prev_dc_amplitude[i]=0;
|
|
mcu_ctr=0;
|
|
current_bit=0;
|
|
while (!done)
|
|
dec_mcu();
|
|
}
|
|
}
|
|
|
|
static void dec_start_of_scan()
|
|
{
|
|
short length,len;
|
|
short i;
|
|
|
|
if (!image_started)
|
|
done=true;
|
|
else
|
|
{
|
|
length=get_word();
|
|
|
|
len=length;
|
|
|
|
stream_read(&byte_var,1);
|
|
sos_info.components=byte_var;
|
|
|
|
len-=3; /* Subtract for length & components */
|
|
|
|
for (i=0;i<sos_info.components;i++)
|
|
{
|
|
stream_read(&byte_var,1);
|
|
sos_info.component[i].id=byte_var;
|
|
|
|
stream_read(&byte_var,1);
|
|
sos_info.component[i].id=byte_var;
|
|
sos_info.component[i].tbl_no=byte_var;
|
|
sos_info.component[i].ac_tbl_no= /* Lo Nibble */
|
|
sos_info.component[i].tbl_no & 0x0f;
|
|
sos_info.component[i].dc_tbl_no= /* Hi Nibble */
|
|
sos_info.component[i].tbl_no>>4;
|
|
len-=2;
|
|
}
|
|
|
|
/* Skip over the rest of the start of scan */
|
|
for (i=0;i<len;i++)
|
|
stream_read(&byte_var,1);
|
|
}
|
|
|
|
dec_image_data();
|
|
}
|
|
|
|
void jpeg_decode_central(unsigned int bg_w, unsigned int bg_h, unsigned char* inbuf, unsigned char* outbuf)
|
|
{
|
|
int i;
|
|
unsigned int* tmpbuf = (unsigned int*)outbuf;
|
|
bg_width = bg_w;
|
|
bg_height = bg_h;
|
|
|
|
for(i=0; i<(bg_width*bg_height)*2/4; i++){
|
|
tmpbuf[i] = 0x00800080L;
|
|
}
|
|
|
|
jpeg_dec(inbuf, outbuf);
|
|
}
|
|
void jpeg_setfmt(unsigned int fmt)
|
|
{
|
|
out_format = fmt;
|
|
}
|
|
void jpeg_decode(unsigned char* inbuf, unsigned char* outbuf)
|
|
{
|
|
bg_width = 0;
|
|
bg_height = 0;
|
|
jpeg_dec(inbuf, outbuf);
|
|
}
|
|
|
|
void jpeg_getdim(unsigned int* width, unsigned int* height)
|
|
{
|
|
*width = image_width;
|
|
*height = image_height;
|
|
}
|
|
|
|
void jpeg_dec(unsigned char* inbuf, unsigned char* outbuf)
|
|
{
|
|
short c;
|
|
|
|
in_stream = inbuf;
|
|
videobuf = outbuf;
|
|
|
|
iter = 0;
|
|
|
|
setup_zigzag_array();
|
|
|
|
done=false;
|
|
jfif_found=false;
|
|
while (!done)
|
|
{
|
|
c=stream_getc();
|
|
{
|
|
if (c!=SECTION_MARKER)
|
|
done=true;
|
|
else
|
|
{
|
|
c=stream_getc();
|
|
{
|
|
if(c== SOI){
|
|
image_started=true;
|
|
}
|
|
else if(c== APP0)
|
|
dec_application_segment();
|
|
else if(c== DQT)
|
|
dec_quantization_table();
|
|
else if(c== SOF0)
|
|
dec_start_of_frame();
|
|
else if(c== DHT)
|
|
dec_huffman_table();
|
|
else if(c== SOS)
|
|
dec_start_of_scan();
|
|
else if(c== EOI){
|
|
done=true;
|
|
}
|
|
else
|
|
dec_unknown_marker();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void create_index(huf_node *node,short total_nodes)
|
|
{
|
|
short i;
|
|
|
|
for (i=0;i<total_nodes;i++)
|
|
node[i].tree_index=(1L<<node[i].size)-1+node[i].code;
|
|
}
|
|
|
|
|
|
static void sort(huf_node *node,short total_nodes)
|
|
{
|
|
short i,j;
|
|
huf_node t;
|
|
|
|
for (i=0;i<total_nodes;i++)
|
|
for (j=i;j<total_nodes-1;j++)
|
|
if (node[j+1].tree_index<node[i].tree_index)
|
|
{
|
|
t=node[i];
|
|
node[i]=node[j+1];
|
|
node[j+1]=t;
|
|
}
|
|
}
|
|
|
|
|
|
static void generate_codes(unsigned char *hufval,huf_node *node)
|
|
{
|
|
short k,
|
|
code,si;
|
|
|
|
k=0;
|
|
code=0;
|
|
si=node[k].size;
|
|
while (node[k].size>0)
|
|
{
|
|
while (node[k].size==si)
|
|
{
|
|
node[k].code=code;
|
|
node[k].value=hufval[k];
|
|
code++;
|
|
k++;
|
|
}
|
|
|
|
if (node[k].size>0)
|
|
{
|
|
while (node[k].size!=si)
|
|
{
|
|
code<<=1;
|
|
si++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void generate_code_size(unsigned char *bits,huf_node *node)
|
|
{
|
|
short i,j,k;
|
|
|
|
i=0;j=1;k=0;
|
|
while (i<16)
|
|
{
|
|
while (j<=bits[i])
|
|
{
|
|
node[k].size=i+1;
|
|
k++;
|
|
j++;
|
|
}
|
|
i++;
|
|
j=1;
|
|
}
|
|
node[k].size=0;
|
|
total_nodes=k;
|
|
}
|
|
|
|
static void build_huf_nodes()
|
|
{
|
|
short k;
|
|
|
|
for (k=0;k<sof_info.components;k++)
|
|
{
|
|
generate_code_size(dc_huf_tbl[sos_info.component[k].dc_tbl_no].bits,
|
|
dc_node[k]);
|
|
dc_total_nodes[k]=total_nodes;
|
|
generate_codes(dc_huf_tbl[sos_info.component[k].dc_tbl_no].val,
|
|
dc_node[k]);
|
|
create_index(dc_node[k],dc_total_nodes[k]);
|
|
sort(dc_node[k],dc_total_nodes[k]);
|
|
|
|
generate_code_size(ac_huf_tbl[sos_info.component[k].ac_tbl_no].bits,
|
|
ac_node[k]);
|
|
ac_total_nodes[k]=total_nodes;
|
|
generate_codes(ac_huf_tbl[sos_info.component[k].ac_tbl_no].val,
|
|
ac_node[k]);
|
|
create_index(ac_node[k],ac_total_nodes[k]);
|
|
sort(ac_node[k],ac_total_nodes[k]);
|
|
}
|
|
}
|
|
|
|
|
|
static void build_transform()
|
|
{
|
|
short x,y,k=0;
|
|
|
|
for (y=0;y<8;y++)
|
|
for (x=0;x<8;x++)
|
|
{
|
|
transform[x][y]=block[k];
|
|
k++;
|
|
}
|
|
}
|
|
|
|
static void de_zigzag(short k)
|
|
{
|
|
short i;
|
|
for (i=0;i<64;i++)
|
|
block[zigzag_array[i]]=coefficient[i]*
|
|
quant_tbl[sof_info.component[k].quant_tbl_no][i];
|
|
}
|
|
|
|
static void dequantize_block(short k)
|
|
{
|
|
short i;
|
|
|
|
for (i=0;i<64;i++)
|
|
block[i]*=quant_tbl[sof_info.component[k].quant_tbl_no][i];
|
|
}
|
|
|
|
|
|
static void shift_block(short k,short l,short m)
|
|
{
|
|
short x,y;
|
|
|
|
for (x=0;x<8;x++)
|
|
for (y=0;y<8;y++)
|
|
component[l][m][k][x][y]+=128;
|
|
}
|
|
|
|
static short find_node_index(unsigned long index,short *value,huf_node *node,short total_nodes)
|
|
{
|
|
short found=false;
|
|
short first=0;
|
|
short last=total_nodes-1;
|
|
short middle;
|
|
|
|
while (last>=first && !found)
|
|
{
|
|
middle=(first+last)>>1;
|
|
if (index<node[middle].tree_index)
|
|
last=middle-1;
|
|
else if (index>node[middle].tree_index)
|
|
first=middle+1;
|
|
else
|
|
{
|
|
found=true;
|
|
*value=node[middle].value;
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
static short get_huf_code(huf_node *node,short total_nodes)
|
|
{
|
|
char bit;
|
|
short found=false;
|
|
unsigned long index=0;
|
|
short value,ctr=0;
|
|
|
|
while (!found && ctr<16)
|
|
{
|
|
bit=getbit();
|
|
if (reset_mcu) return 0;
|
|
if (bit==0)
|
|
index=(index<<1)+1; /* take left branch */
|
|
else
|
|
index=(index<<1)+2; /* take right branch */
|
|
found=find_node_index(index,&value,node,total_nodes);
|
|
if (found) return value;
|
|
ctr++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static unsigned short get_binary_number(short length)
|
|
{
|
|
short i;
|
|
char bit;
|
|
unsigned short mask,number;
|
|
|
|
number=0;
|
|
mask=1<<(length-1);
|
|
for (i=0;i<length;i++)
|
|
{
|
|
bit=getbit();
|
|
if (reset_mcu) return 0;
|
|
if (bit==1)
|
|
{
|
|
number|=mask;
|
|
}
|
|
mask>>=1;
|
|
}
|
|
if (number<1<<(length-1))
|
|
/* negative */
|
|
return number+((-1)<<length)+1;
|
|
else
|
|
/* positive */
|
|
return number;
|
|
}
|
|
|
|
|
|
static void get_component_block(short k,short l,short m)
|
|
{
|
|
short done_with_dat_unit=false;
|
|
short i,index=0;
|
|
|
|
size=get_huf_code(dc_node[k],dc_total_nodes[k]);
|
|
if (reset_mcu) return;
|
|
amplitude=get_binary_number(size);
|
|
|
|
coefficient[index]=amplitude+prev_dc_amplitude[k];
|
|
prev_dc_amplitude[k]=coefficient[index];
|
|
index++;
|
|
|
|
while (!done_with_dat_unit)
|
|
{
|
|
symbol=get_huf_code(ac_node[k],ac_total_nodes[k]);
|
|
if (reset_mcu) return;
|
|
if (symbol==EOB)
|
|
{
|
|
for (i=index;i<64;i++)
|
|
coefficient[i]=0;
|
|
done_with_dat_unit=true;
|
|
}
|
|
else
|
|
{
|
|
run=symbol>>4; /* Hi Nibble */
|
|
size=symbol & 0x0f; /* Lo Nibble */
|
|
if (symbol==ZRL) run++;
|
|
for (i=0;i<run;i++)
|
|
{
|
|
coefficient[index]=0;
|
|
index++;
|
|
}
|
|
if (size>0)
|
|
{
|
|
amplitude=get_binary_number(size);
|
|
coefficient[index]=amplitude;
|
|
index++;
|
|
}
|
|
if (index==64) done_with_dat_unit=true;
|
|
}
|
|
}
|
|
|
|
de_zigzag(k);
|
|
build_transform();
|
|
new_idct(k,l,m);
|
|
shift_block(k,l,m);
|
|
}
|
|
|
|
|
|
static void dec_dat_unit(short k)
|
|
{
|
|
short i,j;
|
|
|
|
for (j=0;j<sof_info.component[k].v_samp_factor;j++)
|
|
for (i=0;i<sof_info.component[k].h_samp_factor;i++)
|
|
{
|
|
get_component_block(k,i,j);
|
|
if (reset_mcu) return;
|
|
}
|
|
}
|
|
|
|
|
|
static void convert_yuv_to_rgb(short y,short u,short v,
|
|
unsigned char *r,unsigned char *g,unsigned char *b)
|
|
{
|
|
float red,green,blue;
|
|
|
|
red=y+1.402*(v-128);
|
|
if (red<0) red=0;
|
|
if (red>255) red=255;
|
|
|
|
green=y-0.34414*(u-128)-0.71414*(v-128);
|
|
if (green<0) green=0;
|
|
if (green>255) green=255;
|
|
|
|
blue=y+1.772*(u-128);
|
|
if (blue<0) blue=0;
|
|
if (blue>255) blue=255;
|
|
|
|
*r=(unsigned char)red;
|
|
*g=(unsigned char)green;
|
|
*b=(unsigned char)blue;
|
|
}
|
|
|
|
|
|
static void display_data_block(short i,short j)
|
|
{
|
|
short x,y;
|
|
short y_comp,u_comp,v_comp;
|
|
unsigned char r,g,b;
|
|
unsigned x_pos,y_pos;
|
|
short v_data_index,h_data_index;
|
|
|
|
for (y=0;y<8;y++)
|
|
for (x=0;x<8;x++)
|
|
{
|
|
y_comp=component[i][j][0][x][y];
|
|
|
|
/* Up Sample the blue chrominance */
|
|
if (i>=sof_info.component[1].h_samp_factor)
|
|
h_data_index=sof_info.component[1].h_samp_factor-1;
|
|
else
|
|
h_data_index=i;
|
|
|
|
if (j>=sof_info.component[1].v_samp_factor)
|
|
v_data_index=sof_info.component[1].v_samp_factor-1;
|
|
else
|
|
v_data_index=j;
|
|
|
|
u_comp=component[h_data_index][v_data_index][1][(x+i*8)/h_div[1]][(y+j*8)/v_div[1]];
|
|
|
|
/* Up Sample the red chrominance */
|
|
if (i>=sof_info.component[2].h_samp_factor)
|
|
h_data_index=sof_info.component[2].h_samp_factor-1;
|
|
else
|
|
h_data_index=i;
|
|
if (j>=sof_info.component[2].v_samp_factor)
|
|
v_data_index=sof_info.component[2].v_samp_factor-1;
|
|
else
|
|
v_data_index=j;
|
|
|
|
v_comp=component[h_data_index][v_data_index][2][(x+i*8)/h_div[1]][(y+j*8)/v_div[1]];
|
|
/* //???, it should be
|
|
//v_comp=component[h_data_index][v_data_index][2][(x+i*8)/h_div[2]][(y+j*8)/v_div[2]];
|
|
*/
|
|
|
|
#if 1 //YUV422
|
|
#else //RGB888
|
|
convert_yuv_to_rgb(y_comp,u_comp,v_comp,&r,&g,&b);
|
|
#endif
|
|
mcu_x=mcu_ctr % mcu_width;
|
|
mcu_y=mcu_ctr/mcu_width;
|
|
|
|
x_pos=mcu_x*max_h_samp_factor*8+i*8+x;
|
|
y_pos=mcu_y*max_v_samp_factor*8+j*8+y;
|
|
|
|
if (x_pos<sof_info.width && y_pos<sof_info.height)
|
|
#if 1 //YUV422
|
|
{
|
|
//printf("(%02d, %02d)=%04X, %04X, %04X\n", x_pos, y_pos, y_comp, u_comp, v_comp);
|
|
if(y_comp < 0) y_comp = 0;
|
|
if(u_comp < 0) u_comp = 0;
|
|
if(v_comp < 0) v_comp = 0;
|
|
if(y_comp > 0xFF) y_comp = 0xFF;
|
|
if(u_comp > 0xFF) u_comp = 0xFF;
|
|
if(v_comp > 0xFF) v_comp = 0xFF;
|
|
if(out_format==1) {
|
|
set_pixel_yuv422(x_pos, y_pos, (unsigned char)y_comp, (unsigned char)u_comp, (unsigned char)v_comp);
|
|
} else {
|
|
set_pixel_vyuy(x_pos, y_pos, (unsigned char)y_comp, (unsigned char)u_comp, (unsigned char)v_comp);
|
|
}
|
|
}
|
|
#else //RGB888
|
|
set_pixel(x_pos, y_pos, r, g, b);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
static void dec_mcu(void)
|
|
{
|
|
short i,j,k;
|
|
|
|
reset_mcu=false;
|
|
for (k=0;k<sof_info.components;k++)
|
|
{
|
|
dec_dat_unit(k);
|
|
if (reset_mcu) break;
|
|
}
|
|
if (!reset_mcu)
|
|
{
|
|
for (j=0;j<max_v_samp_factor;j++)
|
|
for (i=0;i<max_h_samp_factor;i++)
|
|
display_data_block(i,j);
|
|
mcu_ctr++;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
int main(int argc, char* argv[])
|
|
{
|
|
FILE *inp, *outp;
|
|
int filelen;
|
|
unsigned char* inbuf;
|
|
unsigned char* outbuf;
|
|
|
|
|
|
if(argc != 3){
|
|
printf("\nusage: jdec input.jpg output.rgb\n\n");
|
|
return -1;
|
|
}
|
|
|
|
inp = fopen (argv[1], "rb");
|
|
if (inp == NULL) {
|
|
printf("open file %s error!\n", argv[1]);
|
|
return -1;
|
|
}
|
|
|
|
fseek (inp , 0 , SEEK_END);
|
|
filelen = ftell (inp);
|
|
fseek (inp , 0 , SEEK_SET);
|
|
|
|
inbuf = (unsigned char*) malloc (sizeof(char)*filelen);
|
|
if (inbuf == NULL) {
|
|
printf("memory alloc error!\n");
|
|
return -1;
|
|
}
|
|
|
|
if(fread (inbuf, 1, filelen, inp) != filelen){
|
|
printf("fread error!\n");
|
|
return -1;
|
|
}
|
|
|
|
fclose(inp);
|
|
|
|
outp = fopen (argv[2], "wb");
|
|
if (outp == NULL) {
|
|
printf("open file %s error!\n", argv[2]);
|
|
return -1;
|
|
}
|
|
|
|
outbuf = (unsigned char*) malloc (1920*1080*2);
|
|
if (outbuf == NULL) {
|
|
printf("memory alloc 2 error!\n");
|
|
return -1;
|
|
}
|
|
|
|
iter = 0;
|
|
|
|
jpeg_decode(inbuf, outbuf);
|
|
|
|
fwrite (outbuf, 1, image_height*image_width*2, outp) ;
|
|
|
|
fclose(outp);
|
|
|
|
free(inbuf);
|
|
free(outbuf);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|