forked from len0rd/rockbox
now supports images with restart markers
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4693 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
bdaf5884ca
commit
9592ebb879
1 changed files with 67 additions and 69 deletions
|
@ -594,8 +594,8 @@ struct bitstream
|
||||||
{
|
{
|
||||||
unsigned long get_buffer; /* current bit-extraction buffer */
|
unsigned long get_buffer; /* current bit-extraction buffer */
|
||||||
int bits_left; /* # of unused bits in it */
|
int bits_left; /* # of unused bits in it */
|
||||||
unsigned short* next_input_word;
|
unsigned char* next_input_byte;
|
||||||
long words_left; /* # of words remaining in source buffer */
|
unsigned char* input_end; /* upper limit +1 */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct jpeg
|
struct jpeg
|
||||||
|
@ -605,9 +605,10 @@ struct jpeg
|
||||||
int x_mbl; /* x dimension of MBL */
|
int x_mbl; /* x dimension of MBL */
|
||||||
int y_mbl; /* y dimension of MBL */
|
int y_mbl; /* y dimension of MBL */
|
||||||
int blocks; /* blocks per MBL */
|
int blocks; /* blocks per MBL */
|
||||||
|
int restart_interval; /* number of MCUs between RSTm markers */
|
||||||
|
|
||||||
unsigned short* p_entropy_data;
|
unsigned char* p_entropy_data;
|
||||||
long words_in_buffer; /* # of valid words in source buffer */
|
unsigned char* p_entropy_end;
|
||||||
|
|
||||||
int quanttable[4][QUANT_TABLE_LENGTH]; /* raw quantization tables 0-3 */
|
int quanttable[4][QUANT_TABLE_LENGTH]; /* raw quantization tables 0-3 */
|
||||||
int qt_idct[2][QUANT_TABLE_LENGTH]; /* quantization tables for IDCT */
|
int qt_idct[2][QUANT_TABLE_LENGTH]; /* quantization tables for IDCT */
|
||||||
|
@ -635,20 +636,21 @@ struct jpeg
|
||||||
#define DQT 0x0080 /* with definition of quantization table */
|
#define DQT 0x0080 /* with definition of quantization table */
|
||||||
|
|
||||||
/* Preprocess the JPEG JFIF file */
|
/* Preprocess the JPEG JFIF file */
|
||||||
int process_markers(unsigned char* p_bytes, long size, struct jpeg* p_jpeg)
|
int process_markers(unsigned char* p_src, long size, struct jpeg* p_jpeg)
|
||||||
{
|
{
|
||||||
unsigned char* p_src = p_bytes;
|
unsigned char* p_bytes = p_src;
|
||||||
/* write without markers nor stuffing in same buffer */
|
|
||||||
unsigned char* p_dest;
|
|
||||||
int marker_size; /* variable length of marker segment */
|
int marker_size; /* variable length of marker segment */
|
||||||
int i, j, n;
|
int i, j, n;
|
||||||
int ret = 0; /* returned flags */
|
int ret = 0; /* returned flags */
|
||||||
|
|
||||||
|
p_jpeg->p_entropy_end = p_src + size;
|
||||||
|
|
||||||
while (p_src < p_bytes + size)
|
while (p_src < p_bytes + size)
|
||||||
{
|
{
|
||||||
if (*p_src++ != 0xFF) /* no marker? */
|
if (*p_src++ != 0xFF) /* no marker? */
|
||||||
{
|
{
|
||||||
p_src--; /* it's image data, put it back */
|
p_src--; /* it's image data, put it back */
|
||||||
|
p_jpeg->p_entropy_data = p_src;
|
||||||
break; /* exit marker processing */
|
break; /* exit marker processing */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -818,14 +820,6 @@ int process_markers(unsigned char* p_bytes, long size, struct jpeg* p_jpeg)
|
||||||
case 0xCC: /* Define Arithmetic coding conditioning(s) */
|
case 0xCC: /* Define Arithmetic coding conditioning(s) */
|
||||||
return(-6); /* Arithmetic coding not supported */
|
return(-6); /* Arithmetic coding not supported */
|
||||||
|
|
||||||
case 0xD0: /* Restart with modulo 8 count 0 */
|
|
||||||
case 0xD1: /* Restart with modulo 8 count 1 */
|
|
||||||
case 0xD2: /* Restart with modulo 8 count 2 */
|
|
||||||
case 0xD3: /* Restart with modulo 8 count 3 */
|
|
||||||
case 0xD4: /* Restart with modulo 8 count 4 */
|
|
||||||
case 0xD5: /* Restart with modulo 8 count 5 */
|
|
||||||
case 0xD6: /* Restart with modulo 8 count 6 */
|
|
||||||
case 0xD7: /* Restart with modulo 8 count 7 */
|
|
||||||
case 0xD8: /* Start of Image */
|
case 0xD8: /* Start of Image */
|
||||||
case 0xD9: /* End of Image */
|
case 0xD9: /* End of Image */
|
||||||
case 0x01: /* for temp private use arith code */
|
case 0x01: /* for temp private use arith code */
|
||||||
|
@ -873,8 +867,17 @@ int process_markers(unsigned char* p_bytes, long size, struct jpeg* p_jpeg)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xDC: /* Define Number of Lines */
|
|
||||||
case 0xDD: /* Define Restart Interval */
|
case 0xDD: /* Define Restart Interval */
|
||||||
|
{
|
||||||
|
marker_size = *p_src++ << 8; /* Highbyte */
|
||||||
|
marker_size |= *p_src++; /* Lowbyte */
|
||||||
|
p_jpeg->restart_interval = *p_src++ << 8; /* Highbyte */
|
||||||
|
p_jpeg->restart_interval |= *p_src++; /* Lowbyte */
|
||||||
|
p_src += marker_size-4; /* skip segment */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xDC: /* Define Number of Lines */
|
||||||
case 0xDE: /* Define Hierarchical progression */
|
case 0xDE: /* Define Hierarchical progression */
|
||||||
case 0xDF: /* Expand Reference Component(s) */
|
case 0xDF: /* Expand Reference Component(s) */
|
||||||
case 0xE0: /* Application Field 0*/
|
case 0xE0: /* Application Field 0*/
|
||||||
|
@ -921,38 +924,6 @@ int process_markers(unsigned char* p_bytes, long size, struct jpeg* p_jpeg)
|
||||||
} /* switch */
|
} /* switch */
|
||||||
} /* while */
|
} /* while */
|
||||||
|
|
||||||
|
|
||||||
/* memory location for later decompress (16-bit aligned) */
|
|
||||||
p_dest = (unsigned char*)(((int)p_bytes + 1) & ~1);
|
|
||||||
p_jpeg->p_entropy_data = (unsigned short*)p_dest;
|
|
||||||
|
|
||||||
|
|
||||||
/* remove byte stuffing and restart markers, if present */
|
|
||||||
while (p_src < p_bytes + size)
|
|
||||||
{
|
|
||||||
if ((*p_dest++ = *p_src++) != 0xFF)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* 0xFF marker found, have a closer look at the next byte */
|
|
||||||
|
|
||||||
if (*p_src == 0x00)
|
|
||||||
{
|
|
||||||
p_src++; /* continue reading after marker */
|
|
||||||
continue; /* stuffing byte, a true 0xFF */
|
|
||||||
}
|
|
||||||
else if (*p_src >= 0xD0 && *p_src <= 0xD7) /* restart marker */
|
|
||||||
{
|
|
||||||
return (-12); /* can't decode such images for now */
|
|
||||||
/* below won't work, is not seamless to the huffman decoder */
|
|
||||||
p_src++; /* continue reading after marker */
|
|
||||||
p_dest--; /* roll back, don't copy it */
|
|
||||||
continue; /* ignore */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break; /* exit on any other marker */
|
|
||||||
}
|
|
||||||
MEMSET(p_dest, 0, size - (p_dest - p_bytes)); /* fill tail with zeros */
|
|
||||||
p_jpeg->words_in_buffer = (p_dest - p_bytes) / sizeof(unsigned short);
|
|
||||||
return (ret); /* return flags with seen markers */
|
return (ret); /* return flags with seen markers */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1154,10 +1125,23 @@ void build_lut(struct jpeg* p_jpeg)
|
||||||
INLINE void check_bit_buffer(struct bitstream* pb, int nbits)
|
INLINE void check_bit_buffer(struct bitstream* pb, int nbits)
|
||||||
{
|
{
|
||||||
if (pb->bits_left < nbits)
|
if (pb->bits_left < nbits)
|
||||||
{
|
{ /* nbits is <= 16, so I can always refill 2 bytes in this case */
|
||||||
pb->words_left--;
|
unsigned char byte;
|
||||||
pb->get_buffer = (pb->get_buffer << 16)
|
|
||||||
| ENDIAN_SWAP16(*pb->next_input_word++);
|
byte = *pb->next_input_byte++;
|
||||||
|
if (byte == 0xFF) /* legal marker can be byte stuffing or RSTm */
|
||||||
|
{ /* simplification: just skip the (one-byte) marker code */
|
||||||
|
pb->next_input_byte++;
|
||||||
|
}
|
||||||
|
pb->get_buffer = (pb->get_buffer << 8) | byte;
|
||||||
|
|
||||||
|
byte = *pb->next_input_byte++;
|
||||||
|
if (byte == 0xFF) /* legal marker can be byte stuffing or RSTm */
|
||||||
|
{ /* simplification: just skip the (one-byte) marker code */
|
||||||
|
pb->next_input_byte++;
|
||||||
|
}
|
||||||
|
pb->get_buffer = (pb->get_buffer << 8) | byte;
|
||||||
|
|
||||||
pb->bits_left += 16;
|
pb->bits_left += 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1177,6 +1161,19 @@ INLINE void drop_bits(struct bitstream* pb, int nbits)
|
||||||
pb->bits_left -= nbits;
|
pb->bits_left -= nbits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* re-synchronize to entropy data (skip restart marker) */
|
||||||
|
void search_restart(struct bitstream* pb)
|
||||||
|
{
|
||||||
|
pb->next_input_byte--; /* we may have overread it, taking 2 bytes */
|
||||||
|
/* search for a non-byte-padding marker, has to be RSTm or EOS */
|
||||||
|
while (pb->next_input_byte < pb->input_end &&
|
||||||
|
(pb->next_input_byte[-2] != 0xFF || pb->next_input_byte[-1] == 0x00))
|
||||||
|
{
|
||||||
|
pb->next_input_byte++;
|
||||||
|
}
|
||||||
|
pb->bits_left = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Figure F.12: extend sign bit. */
|
/* Figure F.12: extend sign bit. */
|
||||||
#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
|
#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
|
||||||
|
|
||||||
|
@ -1295,6 +1292,7 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale,
|
||||||
|
|
||||||
int last_dc_val = 0;
|
int last_dc_val = 0;
|
||||||
int store_offs[4]; /* memory offsets: order of Y11 Y12 Y21 Y22 U V */
|
int store_offs[4]; /* memory offsets: order of Y11 Y12 Y21 Y22 U V */
|
||||||
|
int restart = p_jpeg->restart_interval; /* MCUs until restart marker */
|
||||||
|
|
||||||
/* pick the IDCT we want, determine how to work with coefs */
|
/* pick the IDCT we want, determine how to work with coefs */
|
||||||
if (downscale == 1)
|
if (downscale == 1)
|
||||||
|
@ -1323,10 +1321,10 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale,
|
||||||
}
|
}
|
||||||
else return -1; /* not supported */
|
else return -1; /* not supported */
|
||||||
|
|
||||||
/* init bitstream */
|
/* init bitstream, fake a restart to make it start */
|
||||||
|
bs.next_input_byte = p_jpeg->p_entropy_data;
|
||||||
bs.bits_left = 0;
|
bs.bits_left = 0;
|
||||||
bs.next_input_word = p_jpeg->p_entropy_data;
|
bs.input_end = p_jpeg->p_entropy_end;
|
||||||
bs.words_left = p_jpeg->words_in_buffer;
|
|
||||||
|
|
||||||
width = p_jpeg->x_phys / downscale;
|
width = p_jpeg->x_phys / downscale;
|
||||||
height = p_jpeg->y_phys / downscale;
|
height = p_jpeg->y_phys / downscale;
|
||||||
|
@ -1340,7 +1338,7 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale,
|
||||||
store_offs[2] = width * 8 / downscale; /* below */
|
store_offs[2] = width * 8 / downscale; /* below */
|
||||||
store_offs[3] = store_offs[1] + store_offs[2]; /* right+below */
|
store_offs[3] = store_offs[1] + store_offs[2]; /* right+below */
|
||||||
|
|
||||||
for(y=0; y<p_jpeg->y_mbl; y++)
|
for(y=0; y<p_jpeg->y_mbl && bs.next_input_byte <= bs.input_end; y++)
|
||||||
{
|
{
|
||||||
p_byte = p_pixel;
|
p_byte = p_pixel;
|
||||||
p_pixel += skip_strip;
|
p_pixel += skip_strip;
|
||||||
|
@ -1349,8 +1347,7 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale,
|
||||||
int blkn;
|
int blkn;
|
||||||
|
|
||||||
/* Outer loop handles each block in the MCU */
|
/* Outer loop handles each block in the MCU */
|
||||||
|
for (blkn = 0; blkn < p_jpeg->blocks; blkn++)
|
||||||
for (blkn = 0; blkn < p_jpeg->blocks && bs.words_left>=0; blkn++)
|
|
||||||
{ /* Decode a single block's worth of coefficients */
|
{ /* Decode a single block's worth of coefficients */
|
||||||
int k = 1; /* coefficient index */
|
int k = 1; /* coefficient index */
|
||||||
int s, r; /* huffman values */
|
int s, r; /* huffman values */
|
||||||
|
@ -1368,7 +1365,7 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale,
|
||||||
block[0] = last_dc_val; /* output it (assumes zag[0] = 0) */
|
block[0] = last_dc_val; /* output it (assumes zag[0] = 0) */
|
||||||
|
|
||||||
/* coefficient buffer must be cleared */
|
/* coefficient buffer must be cleared */
|
||||||
MEMSET(block+1, 0, zero_need*sizeof(int));
|
MEMSET(block+1, 0, zero_need*sizeof(block[0]));
|
||||||
|
|
||||||
/* Section F.2.2.2: decode the AC coefficients */
|
/* Section F.2.2.2: decode the AC coefficients */
|
||||||
for (; k < k_need; k++)
|
for (; k < k_need; k++)
|
||||||
|
@ -1423,6 +1420,12 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale,
|
||||||
}
|
}
|
||||||
} /* for blkn */
|
} /* for blkn */
|
||||||
p_byte += skip_mcu;
|
p_byte += skip_mcu;
|
||||||
|
if (p_jpeg->restart_interval && --restart == 0)
|
||||||
|
{ /* if a restart marker is due: */
|
||||||
|
restart = p_jpeg->restart_interval; /* count again */
|
||||||
|
search_restart(&bs); /* align the bitstream */
|
||||||
|
last_dc_val = 0; /* reset decoder */
|
||||||
|
}
|
||||||
} /* for x */
|
} /* for x */
|
||||||
if (pf_progress != NULL)
|
if (pf_progress != NULL)
|
||||||
pf_progress(y, p_jpeg->y_mbl-1); /* notify about decoding progress */
|
pf_progress(y, p_jpeg->y_mbl-1); /* notify about decoding progress */
|
||||||
|
@ -1431,6 +1434,7 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale,
|
||||||
return 0; /* success */
|
return 0; /* success */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************** end JPEG code ********************/
|
/**************** end JPEG code ********************/
|
||||||
|
|
||||||
|
|
||||||
|
@ -1765,6 +1769,8 @@ int main(char* filename)
|
||||||
buf_jpeg = (unsigned char*)(((int)buf + 1) & ~1);
|
buf_jpeg = (unsigned char*)(((int)buf + 1) & ~1);
|
||||||
buf += filesize;
|
buf += filesize;
|
||||||
buf_size -= filesize;
|
buf_size -= filesize;
|
||||||
|
buf_root = buf; /* we can start the decompressed images behind it */
|
||||||
|
root_size = buf_size;
|
||||||
if (buf_size <= 0)
|
if (buf_size <= 0)
|
||||||
{
|
{
|
||||||
rb->splash(HZ*2, true, "out of memory");
|
rb->splash(HZ*2, true, "out of memory");
|
||||||
|
@ -1795,14 +1801,6 @@ int main(char* filename)
|
||||||
default_huff_tbl(&jpg); /* use default */
|
default_huff_tbl(&jpg); /* use default */
|
||||||
build_lut(&jpg); /* derive Huffman and other lookup-tables */
|
build_lut(&jpg); /* derive Huffman and other lookup-tables */
|
||||||
|
|
||||||
/* I can correct the buffer now, re-gain what the removed markers took */
|
|
||||||
buf -= filesize; /* back to before */
|
|
||||||
buf_size += filesize;
|
|
||||||
buf += jpg.words_in_buffer * sizeof(short); /* real space */
|
|
||||||
buf_size -= jpg.words_in_buffer * sizeof(short);
|
|
||||||
buf_root = buf; /* we can start the images here */
|
|
||||||
root_size = buf_size;
|
|
||||||
|
|
||||||
rb->snprintf(print, sizeof(print), "image %d*%d", jpg.x_size, jpg.y_size);
|
rb->snprintf(print, sizeof(print), "image %d*%d", jpg.x_size, jpg.y_size);
|
||||||
rb->lcd_puts(0, 2, print);
|
rb->lcd_puts(0, 2, print);
|
||||||
rb->lcd_update();
|
rb->lcd_update();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue