/*-----------------------------------------*/
|
/*-----------------------------------------*/
|
/* File : parse.c, utilities for jfif view */
|
/* File : parse.c, utilities for jfif view */
|
/* Author : Pierre Guerrier, march 1998 */
|
/* Author : Pierre Guerrier, march 1998 */
|
/*-----------------------------------------*/
|
/*-----------------------------------------*/
|
|
|
#include
|
#include
|
#include
|
#include
|
#include
|
#include
|
|
|
|
|
|
|
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
|
|
|
|
/* utility and counter to return the number of bits from file */
|
/* utility and counter to return the number of bits from file */
|
/* right aligned, masked, first bit towards MSB's */
|
/* right aligned, masked, first bit towards MSB's */
|
|
|
static unsigned char bit_count; /* available bits in the window */
|
static unsigned char bit_count; /* available bits in the window */
|
static unsigned char window;
|
static unsigned char window;
|
|
|
unsigned long
|
unsigned long
|
get_bits(FILE *fi, int number)
|
get_bits(FILE *fi, int number)
|
{
|
{
|
int i, newbit;
|
int i, newbit;
|
unsigned long result = 0;
|
unsigned long result = 0;
|
unsigned char aux, wwindow;
|
unsigned char aux, wwindow;
|
|
|
if (!number)
|
if (!number)
|
return 0;
|
return 0;
|
|
|
for (i = 0; i < number; i++) {
|
for (i = 0; i < number; i++) {
|
if (bit_count == 0) {
|
if (bit_count == 0) {
|
wwindow = fgetc(fi);
|
wwindow = fgetc(fi);
|
|
|
if (wwindow == 0xFF)
|
if (wwindow == 0xFF)
|
switch (aux = fgetc(fi)) { /* skip stuffer 0 byte */
|
switch (aux = fgetc(fi)) { /* skip stuffer 0 byte */
|
case EOF:
|
case EOF:
|
case 0xFF:
|
case 0xFF:
|
fprintf(stderr, "%ld:\tERROR:\tRan out of bit stream\n", ftell(fi));
|
fprintf(stderr, "%ld:\tERROR:\tRan out of bit stream\n", ftell(fi));
|
aborted_stream(fi);
|
aborted_stream(fi);
|
break;
|
break;
|
|
|
case 0x00:
|
case 0x00:
|
stuffers++;
|
stuffers++;
|
break;
|
break;
|
|
|
default:
|
default:
|
if (RST_MK(0xFF00 | aux))
|
if (RST_MK(0xFF00 | aux))
|
fprintf(stderr, "%ld:\tERROR:\tSpontaneously found restart!\n",
|
fprintf(stderr, "%ld:\tERROR:\tSpontaneously found restart!\n",
|
ftell(fi));
|
ftell(fi));
|
fprintf(stderr, "%ld:\tERROR:\tLost sync in bit stream\n",
|
fprintf(stderr, "%ld:\tERROR:\tLost sync in bit stream\n",
|
ftell(fi));
|
ftell(fi));
|
aborted_stream(fi);
|
aborted_stream(fi);
|
break;
|
break;
|
}
|
}
|
|
|
bit_count = 8;
|
bit_count = 8;
|
}
|
}
|
else wwindow = window;
|
else wwindow = window;
|
newbit = (wwindow>>7) & 1;
|
newbit = (wwindow>>7) & 1;
|
window = wwindow << 1;
|
window = wwindow << 1;
|
bit_count--;
|
bit_count--;
|
result = (result << 1) | newbit;
|
result = (result << 1) | newbit;
|
}
|
}
|
return result;
|
return result;
|
}
|
}
|
|
|
|
|
void
|
void
|
clear_bits(void)
|
clear_bits(void)
|
{
|
{
|
bit_count = 0;
|
bit_count = 0;
|
}
|
}
|
|
|
|
|
unsigned char
|
unsigned char
|
get_one_bit(FILE *fi)
|
get_one_bit(FILE *fi)
|
{
|
{
|
int newbit;
|
int newbit;
|
unsigned char aux, wwindow;
|
unsigned char aux, wwindow;
|
|
|
if (bit_count == 0) {
|
if (bit_count == 0) {
|
wwindow = fgetc(fi);
|
wwindow = fgetc(fi);
|
|
|
if (wwindow == 0xFF)
|
if (wwindow == 0xFF)
|
switch (aux = fgetc(fi)) { /* skip stuffer 0 byte */
|
switch (aux = fgetc(fi)) { /* skip stuffer 0 byte */
|
case EOF:
|
case EOF:
|
case 0xFF:
|
case 0xFF:
|
fprintf(stderr, "%ld:\tERROR:\tRan out of bit stream\n", ftell(fi));
|
fprintf(stderr, "%ld:\tERROR:\tRan out of bit stream\n", ftell(fi));
|
aborted_stream(fi);
|
aborted_stream(fi);
|
break;
|
break;
|
|
|
case 0x00:
|
case 0x00:
|
stuffers++;
|
stuffers++;
|
break;
|
break;
|
|
|
default:
|
default:
|
if (RST_MK(0xFF00 | aux))
|
if (RST_MK(0xFF00 | aux))
|
fprintf(stderr, "%ld:\tERROR:\tSpontaneously found restart!\n",
|
fprintf(stderr, "%ld:\tERROR:\tSpontaneously found restart!\n",
|
ftell(fi));
|
ftell(fi));
|
fprintf(stderr, "%ld:\tERROR:\tLost sync in bit stream\n",
|
fprintf(stderr, "%ld:\tERROR:\tLost sync in bit stream\n",
|
ftell(fi));
|
ftell(fi));
|
aborted_stream(fi);
|
aborted_stream(fi);
|
break;
|
break;
|
}
|
}
|
|
|
bit_count = 8;
|
bit_count = 8;
|
}
|
}
|
else
|
else
|
wwindow = window;
|
wwindow = window;
|
|
|
newbit = (wwindow >> 7) & 1;
|
newbit = (wwindow >> 7) & 1;
|
window = wwindow << 1;
|
window = wwindow << 1;
|
bit_count--;
|
bit_count--;
|
return newbit;
|
return newbit;
|
}
|
}
|
|
|
/*----------------------------------------------------------*/
|
/*----------------------------------------------------------*/
|
|
|
|
|
unsigned int
|
unsigned int
|
get_size(FILE *fi)
|
get_size(FILE *fi)
|
{
|
{
|
unsigned char aux;
|
unsigned char aux;
|
|
|
aux = fgetc(fi);
|
aux = fgetc(fi);
|
return (aux << 8) | fgetc(fi); /* big endian */
|
return (aux << 8) | fgetc(fi); /* big endian */
|
}
|
}
|
|
|
|
|
/*----------------------------------------------------------*/
|
/*----------------------------------------------------------*/
|
|
|
|
|
void
|
void
|
skip_segment(FILE *fi) /* skip a segment we don't want */
|
skip_segment(FILE *fi) /* skip a segment we don't want */
|
{
|
{
|
unsigned int size;
|
unsigned int size;
|
char tag[5];
|
char tag[5];
|
int i;
|
int i;
|
|
|
size = get_size(fi);
|
size = get_size(fi);
|
if (size > 5) {
|
if (size > 5) {
|
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
tag[i] = fgetc(fi);
|
tag[i] = fgetc(fi);
|
tag[4] = '\0';
|
tag[4] = '\0';
|
if (verbose)
|
if (verbose)
|
fprintf(stderr, "\tINFO:\tTag is %s\n", tag);
|
fprintf(stderr, "\tINFO:\tTag is %s\n", tag);
|
size -= 4;
|
size -= 4;
|
}
|
}
|
fseek(fi, size-2, SEEK_CUR);
|
fseek(fi, size-2, SEEK_CUR);
|
}
|
}
|
|
|
|
|
/*----------------------------------------------------------------*/
|
/*----------------------------------------------------------------*/
|
/* find next marker of any type, returns it, positions just after */
|
/* find next marker of any type, returns it, positions just after */
|
/* EOF instead of marker if end of file met while searching ... */
|
/* EOF instead of marker if end of file met while searching ... */
|
/*----------------------------------------------------------------*/
|
/*----------------------------------------------------------------*/
|
|
|
unsigned int
|
unsigned int
|
get_next_MK(FILE *fi)
|
get_next_MK(FILE *fi)
|
{
|
{
|
unsigned int c;
|
unsigned int c;
|
int ffmet = 0;
|
int ffmet = 0;
|
int locpassed = -1;
|
int locpassed = -1;
|
|
|
passed--; /* as we fetch one anyway */
|
passed--; /* as we fetch one anyway */
|
|
|
while ((c = fgetc(fi)) != (unsigned int) EOF) {
|
while ((c = fgetc(fi)) != (unsigned int) EOF) {
|
switch (c) {
|
switch (c) {
|
case 0xFF:
|
case 0xFF:
|
ffmet = 1;
|
ffmet = 1;
|
break;
|
break;
|
case 0x00:
|
case 0x00:
|
ffmet = 0;
|
ffmet = 0;
|
break;
|
break;
|
default:
|
default:
|
if (locpassed > 1)
|
if (locpassed > 1)
|
fprintf(stderr, "NOTE: passed %d bytes\n", locpassed);
|
fprintf(stderr, "NOTE: passed %d bytes\n", locpassed);
|
if (ffmet)
|
if (ffmet)
|
return (0xFF00 | c);
|
return (0xFF00 | c);
|
ffmet = 0;
|
ffmet = 0;
|
break;
|
break;
|
}
|
}
|
locpassed++;
|
locpassed++;
|
passed++;
|
passed++;
|
}
|
}
|
|
|
return (unsigned int) EOF;
|
return (unsigned int) EOF;
|
}
|
}
|
|
|
|
|
/*----------------------------------------------------------*/
|
/*----------------------------------------------------------*/
|
/* loading and allocating of quantization table */
|
/* loading and allocating of quantization table */
|
/* table elements are in ZZ order (same as unpack output) */
|
/* table elements are in ZZ order (same as unpack output) */
|
/*----------------------------------------------------------*/
|
/*----------------------------------------------------------*/
|
|
|
int
|
int
|
load_quant_tables(FILE *fi)
|
load_quant_tables(FILE *fi)
|
{
|
{
|
char aux;
|
char aux;
|
unsigned int size, n, i, id, x;
|
unsigned int size, n, i, id, x;
|
|
|
size = get_size(fi); /* this is the tables' size */
|
size = get_size(fi); /* this is the tables' size */
|
n = (size - 2) / 65;
|
n = (size - 2) / 65;
|
|
|
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
aux = fgetc(fi);
|
aux = fgetc(fi);
|
if (first_quad(aux) > 0) {
|
if (first_quad(aux) > 0) {
|
fprintf(stderr, "\tERROR:\tBad QTable precision!\n");
|
fprintf(stderr, "\tERROR:\tBad QTable precision!\n");
|
return -1;
|
return -1;
|
}
|
}
|
id = second_quad(aux);
|
id = second_quad(aux);
|
if (verbose)
|
if (verbose)
|
fprintf(stderr, "\tINFO:\tLoading table %d\n", id);
|
fprintf(stderr, "\tINFO:\tLoading table %d\n", id);
|
QTable[id] = (PBlock *) malloc(sizeof(PBlock));
|
QTable[id] = (PBlock *) malloc(sizeof(PBlock));
|
if (QTable[id] == NULL) {
|
if (QTable[id] == NULL) {
|
fprintf(stderr, "\tERROR:\tCould not allocate table storage!\n");
|
fprintf(stderr, "\tERROR:\tCould not allocate table storage!\n");
|
exit(1);
|
exit(1);
|
}
|
}
|
QTvalid[id] = 1;
|
QTvalid[id] = 1;
|
for (x = 0; x < 64; x++)
|
for (x = 0; x < 64; x++)
|
QTable[id]->linear[x] = fgetc(fi);
|
QTable[id]->linear[x] = fgetc(fi);
|
/*
|
/*
|
-- This is useful to print out the table content --
|
-- This is useful to print out the table content --
|
for (x = 0; x < 64; x++)
|
for (x = 0; x < 64; x++)
|
fprintf(stderr, "%d\n", QTable[id]->linear[x]);
|
fprintf(stderr, "%d\n", QTable[id]->linear[x]);
|
*/
|
*/
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
|
/*----------------------------------------------------------*/
|
/*----------------------------------------------------------*/
|
/* initialise MCU block descriptors */
|
/* initialise MCU block descriptors */
|
/*----------------------------------------------------------*/
|
/*----------------------------------------------------------*/
|
|
|
int
|
int
|
init_MCU(void)
|
init_MCU(void)
|
{
|
{
|
int i, j, k, n, hmax = 0, vmax = 0;
|
int i, j, k, n, hmax = 0, vmax = 0;
|
|
|
for (i = 0; i < 10; i++)
|
for (i = 0; i < 10; i++)
|
MCU_valid[i] = -1;
|
MCU_valid[i] = -1;
|
|
|
k = 0;
|
k = 0;
|
|
|
for (i = 0; i < n_comp; i++) {
|
for (i = 0; i < n_comp; i++) {
|
if (comp[i].HS > hmax)
|
if (comp[i].HS > hmax)
|
hmax = comp[i].HS;
|
hmax = comp[i].HS;
|
if (comp[i].VS > vmax)
|
if (comp[i].VS > vmax)
|
vmax = comp[i].VS;
|
vmax = comp[i].VS;
|
n = comp[i].HS * comp[i].VS;
|
n = comp[i].HS * comp[i].VS;
|
|
|
comp[i].IDX = k;
|
comp[i].IDX = k;
|
for (j = 0; j < n; j++) {
|
for (j = 0; j < n; j++) {
|
MCU_valid[k] = i;
|
MCU_valid[k] = i;
|
MCU_buff[k] = (PBlock *) malloc(sizeof(PBlock));
|
MCU_buff[k] = (PBlock *) malloc(sizeof(PBlock));
|
if (MCU_buff[k] == NULL) {
|
if (MCU_buff[k] == NULL) {
|
fprintf(stderr, "\tERROR:\tCould not allocate MCU buffers!\n");
|
fprintf(stderr, "\tERROR:\tCould not allocate MCU buffers!\n");
|
exit(1);
|
exit(1);
|
}
|
}
|
k++;
|
k++;
|
if (k == 10) {
|
if (k == 10) {
|
fprintf(stderr, "\tERROR:\tMax subsampling exceeded!\n");
|
fprintf(stderr, "\tERROR:\tMax subsampling exceeded!\n");
|
return -1;
|
return -1;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
MCU_sx = 8 * hmax;
|
MCU_sx = 8 * hmax;
|
MCU_sy = 8 * vmax;
|
MCU_sy = 8 * vmax;
|
for (i = 0; i < n_comp; i++) {
|
for (i = 0; i < n_comp; i++) {
|
comp[i].HDIV = (hmax / comp[i].HS > 1); /* if 1 shift by 0 */
|
comp[i].HDIV = (hmax / comp[i].HS > 1); /* if 1 shift by 0 */
|
comp[i].VDIV = (vmax / comp[i].VS > 1); /* if 2 shift by one */
|
comp[i].VDIV = (vmax / comp[i].VS > 1); /* if 2 shift by one */
|
}
|
}
|
|
|
mx_size = ceil_div(x_size,MCU_sx);
|
mx_size = ceil_div(x_size,MCU_sx);
|
my_size = ceil_div(y_size,MCU_sy);
|
my_size = ceil_div(y_size,MCU_sy);
|
rx_size = MCU_sx * floor_div(x_size,MCU_sx);
|
rx_size = MCU_sx * floor_div(x_size,MCU_sx);
|
ry_size = MCU_sy * floor_div(y_size,MCU_sy);
|
ry_size = MCU_sy * floor_div(y_size,MCU_sy);
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
|
/*----------------------------------------------------------*/
|
/*----------------------------------------------------------*/
|
/* this takes care for processing all the blocks in one MCU */
|
/* this takes care for processing all the blocks in one MCU */
|
/*----------------------------------------------------------*/
|
/*----------------------------------------------------------*/
|
|
|
int
|
int
|
process_MCU(FILE *fi)
|
process_MCU(FILE *fi)
|
{
|
{
|
int i;
|
int i;
|
long offset;
|
long offset;
|
int goodrows, goodcolumns;
|
int goodrows, goodcolumns;
|
|
|
if (MCU_column == mx_size) {
|
if (MCU_column == mx_size) {
|
MCU_column = 0;
|
MCU_column = 0;
|
MCU_row++;
|
MCU_row++;
|
if (MCU_row == my_size) {
|
if (MCU_row == my_size) {
|
in_frame = 0;
|
in_frame = 0;
|
return 0;
|
return 0;
|
}
|
}
|
if (verbose)
|
if (verbose)
|
fprintf(stderr, "%ld:\tINFO:\tProcessing stripe %d/%d\n", ftell(fi),
|
fprintf(stderr, "%ld:\tINFO:\tProcessing stripe %d/%d\n", ftell(fi),
|
MCU_row+1, my_size);
|
MCU_row+1, my_size);
|
}
|
}
|
|
|
for (curcomp = 0; MCU_valid[curcomp] != -1; curcomp++) {
|
for (curcomp = 0; MCU_valid[curcomp] != -1; curcomp++) {
|
unpack_block(fi, FBuff, MCU_valid[curcomp]); /* pass index to HT,QT,pred */
|
unpack_block(fi, FBuff, MCU_valid[curcomp]); /* pass index to HT,QT,pred */
|
IDCT(FBuff, MCU_buff[curcomp]);
|
IDCT(FBuff, MCU_buff[curcomp]);
|
}
|
}
|
|
|
/* YCrCb to RGB color space transform here */
|
/* YCrCb to RGB color space transform here */
|
if (n_comp > 1)
|
if (n_comp > 1)
|
color_conversion();
|
color_conversion();
|
else
|
else
|
memmove(ColorBuffer, MCU_buff[0], 64);
|
memmove(ColorBuffer, MCU_buff[0], 64);
|
|
|
/* cut last row/column as needed */
|
/* cut last row/column as needed */
|
if ((y_size != ry_size) && (MCU_row == (my_size - 1)))
|
if ((y_size != ry_size) && (MCU_row == (my_size - 1)))
|
goodrows = y_size - ry_size;
|
goodrows = y_size - ry_size;
|
else
|
else
|
goodrows = MCU_sy;
|
goodrows = MCU_sy;
|
|
|
if ((x_size != rx_size) && (MCU_column == (mx_size - 1)))
|
if ((x_size != rx_size) && (MCU_column == (mx_size - 1)))
|
goodcolumns = x_size - rx_size;
|
goodcolumns = x_size - rx_size;
|
else
|
else
|
goodcolumns = MCU_sx;
|
goodcolumns = MCU_sx;
|
|
|
offset = n_comp * (MCU_row * MCU_sy * x_size + MCU_column * MCU_sx);
|
offset = n_comp * (MCU_row * MCU_sy * x_size + MCU_column * MCU_sx);
|
|
|
for (i = 0; i < goodrows; i++)
|
for (i = 0; i < goodrows; i++)
|
memmove(FrameBuffer + offset + n_comp * i * x_size,
|
memmove(FrameBuffer + offset + n_comp * i * x_size,
|
ColorBuffer + n_comp * i * MCU_sx,
|
ColorBuffer + n_comp * i * MCU_sx,
|
n_comp * goodcolumns);
|
n_comp * goodcolumns);
|
|
|
MCU_column++;
|
MCU_column++;
|
return 1;
|
return 1;
|
}
|
}
|
|
|