jpeg: use the quantization table each component selects

Both JPEG decoders ignored the Tq selector in the frame header and
always dequantized luma with table 0 and chroma with table 1. Files
with a single shared table multiplied chroma by an empty table, and
files with separate Cb and Cr tables used the wrong one for Cr.

imageviewer/jpeg: build one dequantization table per component (3
instead of 2, +256 bytes) from the table it selects. tab_membership is
no longer used and is removed.

Core loader: the raw tables are pre-scaled in place for the IDCT, and
luma and chroma can use different IDCT scales. fix_quant_tables() now
maps each component to a table slot, copying a table that luma and
chroma share at different scales to a slot no component uses (there are
4 slots and at most 3 components, so one is always free), and rewrites
quanttable_select to that slot. No extra memory.

Selectors above 3 are rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: If04c61fb0fef95da11d98d9918ea7225d8a440b0
This commit is contained in:
Michael Giacomelli 2026-09-28 23:22:38 -04:00 • committed by Solomon Peachy
parent b897766a7a
commit 0e50ed3c43
3 changed files with 65 additions and 41 deletions

View file

@ -533,6 +533,8 @@ int process_markers(unsigned char* p_src, long size, struct jpeg* p_jpeg)
p_jpeg->frameheader[i].horizontal_sampling = *p_src >> 4;
p_jpeg->frameheader[i].vertical_sampling = *p_src++ & 0x0F;
p_jpeg->frameheader[i].quanttable_select = *p_src++;
if (p_jpeg->frameheader[i].quanttable_select > 3)
return -8; /* Unsupported quantization table */
if (p_jpeg->frameheader[i].horizontal_sampling > 2
|| p_jpeg->frameheader[i].vertical_sampling > 2)
return -3; /* Unsupported SOF0 subsampling */
@ -890,7 +892,7 @@ static const int zag[] =
void build_lut(struct jpeg* p_jpeg)
{
int i;
int i, c;
fix_huff_tbl(p_jpeg->hufftable[0].huffmancodes_dc,
&p_jpeg->dc_derived_tbls[0]);
fix_huff_tbl(p_jpeg->hufftable[0].huffmancodes_ac,
@ -900,11 +902,14 @@ void build_lut(struct jpeg* p_jpeg)
fix_huff_tbl(p_jpeg->hufftable[1].huffmancodes_ac,
&p_jpeg->ac_derived_tbls[1]);
/* build the dequantization tables for the IDCT (De-ZiZagged) */
for (i=0; i<64; i++)
/* build each component's dequantization table for the IDCT
(De-ZiZagged); p_jpeg->blocks is still the component count here */
for (c=0; c<p_jpeg->blocks; c++)
{
p_jpeg->qt_idct[0][zag[i]] = p_jpeg->quanttable[0][i];
p_jpeg->qt_idct[1][zag[i]] = p_jpeg->quanttable[1][i];
const int* qt = p_jpeg->quanttable[
p_jpeg->frameheader[c].quanttable_select];
for (i=0; i<64; i++)
p_jpeg->qt_idct[c][zag[i]] = qt[i];
}
for (i=0; i<4; i++)
@ -923,10 +928,6 @@ void build_lut(struct jpeg* p_jpeg)
p_jpeg->mcu_membership[1] = 0;
p_jpeg->mcu_membership[2] = 1;
p_jpeg->mcu_membership[3] = 2;
p_jpeg->tab_membership[0] = 0; /* DC, DC, AC, AC */
p_jpeg->tab_membership[1] = 0;
p_jpeg->tab_membership[2] = 1;
p_jpeg->tab_membership[3] = 1;
p_jpeg->subsample_x[0] = 1;
p_jpeg->subsample_x[1] = 2;
p_jpeg->subsample_x[2] = 2;
@ -948,10 +949,6 @@ void build_lut(struct jpeg* p_jpeg)
p_jpeg->mcu_membership[1] = 0;
p_jpeg->mcu_membership[2] = 1;
p_jpeg->mcu_membership[3] = 2;
p_jpeg->tab_membership[0] = 0; /* DC, DC, AC, AC */
p_jpeg->tab_membership[1] = 0;
p_jpeg->tab_membership[2] = 1;
p_jpeg->tab_membership[3] = 1;
p_jpeg->subsample_x[0] = 1;
p_jpeg->subsample_x[1] = 1;
p_jpeg->subsample_x[2] = 1;
@ -973,12 +970,6 @@ void build_lut(struct jpeg* p_jpeg)
p_jpeg->mcu_membership[3] = 0;
p_jpeg->mcu_membership[4] = 1;
p_jpeg->mcu_membership[5] = 2;
p_jpeg->tab_membership[0] = 0;
p_jpeg->tab_membership[1] = 0;
p_jpeg->tab_membership[2] = 0;
p_jpeg->tab_membership[3] = 0;
p_jpeg->tab_membership[4] = 1;
p_jpeg->tab_membership[5] = 1;
p_jpeg->subsample_x[0] = 1;
p_jpeg->subsample_x[1] = 2;
p_jpeg->subsample_x[2] = 2;
@ -997,9 +988,6 @@ void build_lut(struct jpeg* p_jpeg)
p_jpeg->mcu_membership[0] = 0;
p_jpeg->mcu_membership[1] = 1;
p_jpeg->mcu_membership[2] = 2;
p_jpeg->tab_membership[0] = 0;
p_jpeg->tab_membership[1] = 1;
p_jpeg->tab_membership[2] = 1;
p_jpeg->subsample_x[0] = 1;
p_jpeg->subsample_x[1] = 1;
p_jpeg->subsample_x[2] = 1;
@ -1286,7 +1274,6 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel[3],
int k = 1; /* coefficient index */
int s, r; /* huffman values */
int ci = p_jpeg->mcu_membership[blkn]; /* component index */
int ti = p_jpeg->tab_membership[blkn]; /* table index */
struct derived_tbl* dctbl =
&p_jpeg->dc_derived_tbls[p_jpeg->scanheader[ci].DC_select];
struct derived_tbl* actbl =
@ -1349,11 +1336,11 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel[3],
if (ci == 0)
{ /* Y component needs to bother about block store */
pf_idct(p_byte[0]+store_offs[blkn], block,
p_jpeg->qt_idct[ti], skip_line[0]);
p_jpeg->qt_idct[ci], skip_line[0]);
}
else
{ /* chroma */
pf_idct(p_byte[ci], block, p_jpeg->qt_idct[ti],
pf_idct(p_byte[ci], block, p_jpeg->qt_idct[ci],
skip_line[ci]);
}
} /* for blkn */
@ -1459,7 +1446,6 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel[1], int downscale,
int k = 1; /* coefficient index */
int s, r; /* huffman values */
int ci = p_jpeg->mcu_membership[blkn]; /* component index */
int ti = p_jpeg->tab_membership[blkn]; /* table index */
struct derived_tbl* dctbl =
&p_jpeg->dc_derived_tbls[p_jpeg->scanheader[ci].DC_select];
struct derived_tbl* actbl =
@ -1524,7 +1510,7 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel[1], int downscale,
if (ci == 0)
{ /* only for Y component */
pf_idct(p_byte+store_offs[blkn], block, p_jpeg->qt_idct[ti],
pf_idct(p_byte+store_offs[blkn], block, p_jpeg->qt_idct[ci],
skip_line);
}
} /* for blkn */

View file

@ -42,7 +42,7 @@ struct jpeg
unsigned char* p_entropy_end;
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[3][QUANT_TABLE_LENGTH]; /* per component, for IDCT */
struct huffman_table hufftable[2]; /* Huffman tables */
struct derived_tbl dc_derived_tbls[2]; /* Huffman-LUTs */
@ -52,7 +52,6 @@ struct jpeg
struct scan_component scanheader[3]; /* Huffman tables per component */
int mcu_membership[6]; /* info per block */
int tab_membership[6];
int subsample_x[3]; /* info per component */
int subsample_y[3];
};

View file

@ -1043,6 +1043,8 @@ static int process_markers(struct jpeg* p_jpeg)
p_jpeg->frameheader[i].vertical_sampling = c & 0x0F;
p_jpeg->frameheader[i].quanttable_select =
e_getc(p_jpeg, -1);
if (p_jpeg->frameheader[i].quanttable_select > 3)
return -8; /* Unsupported quantization table */
if (p_jpeg->frameheader[i].horizontal_sampling > 2
|| p_jpeg->frameheader[i].vertical_sampling > 2)
return -3; /* Unsupported SOF0 subsampling */
@ -1567,23 +1569,60 @@ INLINE void fix_huff_tables(struct jpeg *p_jpeg)
* quantization table when one of these IDCT routines is used, rather than
* have the IDCT shift each value it processes.
*/
/* Pre-scale the quantization tables for the IDCT. Luma and chroma can use
* different IDCT scales, so a table that both select is copied to a slot no
* component selects before scaling; each component's quanttable_select is
* rewritten to the slot it should use. There are 4 slots and at most 3
* components, so when a table is shared a free slot always exists. */
INLINE void fix_quant_tables(struct jpeg *p_jpeg)
{
int shift, i, j;
int want[4] = { -1, -1, -1, -1 }; /* scale shift wanted for each slot */
int orig[4] = { 0, 1, 2, 3 }; /* table each slot holds */
int c, c2, f, j;
#ifdef HAVE_LCD_COLOR
const int k = 2;
const int nc = p_jpeg->blocks > 1 ? 3 : 1;
#else
const int k = 1;
const int nc = 1; /* chroma is not decoded */
#endif
for (i = 0; i < k; i++)
for (c = 0; c < nc; c++)
{
shift = idct_tbl[p_jpeg->v_scale[i]].scale;
if (shift)
int t = p_jpeg->frameheader[c].quanttable_select;
int shift = idct_tbl[p_jpeg->v_scale[!!c]].scale;
for (f = 0; f < 4; f++) /* a slot already holding t at this scale? */
if (orig[f] == t && want[f] == shift)
break;
if (f == 4 && want[t] < 0)
f = t; /* first use of t */
if (f == 4)
{ /* t is in use at another scale: copy it to a free slot that no
later component still needs */
for (f = 0; f < 4; f++)
{
if (want[f] >= 0)
continue;
for (c2 = c + 1; c2 < nc; c2++)
if (p_jpeg->frameheader[c2].quanttable_select == f)
break;
if (c2 == nc)
break;
}
MEMCPY(p_jpeg->quanttable[f], p_jpeg->quanttable[t],
sizeof(p_jpeg->quanttable[f]));
orig[f] = t;
}
want[f] = shift;
p_jpeg->frameheader[c].quanttable_select = f;
}
for (f = 0; f < 4; f++)
{
if (want[f] > 0)
{
for (j = 0; j < 64; j++)
p_jpeg->quanttable[i][j] <<= shift;
p_jpeg->quanttable[f][j] <<= want[f];
}
}
}
@ -1841,6 +1880,8 @@ static struct img_part *store_row_jpeg(void *jpeg_args)
&p_jpeg->dc_derived_tbls[p_jpeg->scanheader[ci].DC_select];
struct derived_tbl* actbl =
&p_jpeg->ac_derived_tbls[p_jpeg->scanheader[ci].AC_select];
const int16_t *qt = p_jpeg->quanttable[
p_jpeg->frameheader[ci].quanttable_select];
/* Section F.2.2.1: decode the DC coefficient difference */
huff_decode_dc(p_jpeg, dctbl, s, r);
@ -1853,13 +1894,11 @@ static struct img_part *store_row_jpeg(void *jpeg_args)
#ifdef HAVE_LCD_COLOR
p_jpeg->last_dc_val[ci] += s;
/* output it (assumes zag[0] = 0) */
block[0] = MULTIPLY16(p_jpeg->last_dc_val[ci],
p_jpeg->quanttable[!!ci][0]);
block[0] = MULTIPLY16(p_jpeg->last_dc_val[ci], qt[0]);
#else
p_jpeg->last_dc_val += s;
/* output it (assumes zag[0] = 0) */
block[0] = MULTIPLY16(p_jpeg->last_dc_val,
p_jpeg->quanttable[0][0]);
block[0] = MULTIPLY16(p_jpeg->last_dc_val, qt[0]);
#endif
/* coefficient buffer must be cleared */
MEMSET(block+1, 0, p_jpeg->zero_need[!!ci] * sizeof(int));
@ -1877,7 +1916,7 @@ static struct img_part *store_row_jpeg(void *jpeg_args)
goto skip_rest;
r = get_bits(p_jpeg, s);
r = HUFF_EXTEND(r, s);
r = MULTIPLY16(r, p_jpeg->quanttable[!!ci][k]);
r = MULTIPLY16(r, qt[k]);
#ifdef JPEG_IDCT_TRANSPOSE
block[zag[transpose ? k : k + 64]] = r ;
#else