forked from len0rd/rockbox
These are all from upstream code, so just force-ignore the warnings Change-Id: I9936e1cb79636b0bfee5dd4db0c98a06792d2f69
1001 lines
No EOL
27 KiB
C
1001 lines
No EOL
27 KiB
C
/************************************************************************
|
|
jpeg81.c
|
|
|
|
An ITU T.81 JPEG coefficient-decoder - without de-quantization and IDCT.
|
|
Used for conformance testing of ITU T.83 data (a little verbose output).
|
|
Allocates full image coefficient buffer.
|
|
|
|
Supports:
|
|
- JPEG Interchange Format (JIF)
|
|
- DCT- and Lossless operation
|
|
- Huffman- and arithmetic coding
|
|
- Sequential- and progressive mode
|
|
- max. 4 components
|
|
- all sub-sampling
|
|
- 8/12 - bit samples for DCT
|
|
- 2-16 - bit for Lossless
|
|
|
|
It does not support the Hierarchial mode.
|
|
TODO: more error checking.
|
|
|
|
|
|
* Copyright (c) 2017 A. Tarpai
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#include "GETC.h"
|
|
#include "rb_glue.h"
|
|
#include "jpeg81.h"
|
|
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
|
#if (__GNUC__ >= 6)
|
|
#pragma GCC diagnostic ignored "-Wshift-negative-value"
|
|
#endif
|
|
|
|
///////////////////////////////////////// LOSSLESS /////////////////////////////////////////
|
|
|
|
static int P1(struct COMP *C, TSAMP *samp) // Px = Ra
|
|
{
|
|
return samp[-1];
|
|
}
|
|
|
|
static int P2(struct COMP *C, TSAMP *samp) // Px = Rb
|
|
{
|
|
return samp[-C->du_width];
|
|
}
|
|
|
|
static int P3(struct COMP *C, TSAMP *samp) // Px = Rc
|
|
{
|
|
return samp[-C->du_width-1];
|
|
}
|
|
|
|
static int P4(struct COMP *C, TSAMP *samp) // Px = Ra + Rb - Rc
|
|
{
|
|
return samp[-1] + samp[-C->du_width] - samp[-C->du_width-1];
|
|
}
|
|
|
|
static int P5(struct COMP *C, TSAMP *samp) // Px = Ra + ((Rb - Rc)/2)
|
|
{
|
|
return samp[-1] + ( (samp[-C->du_width] - samp[-C->du_width-1]) >> 1 );
|
|
}
|
|
|
|
static int P6(struct COMP *C, TSAMP *samp) // Px = Rb + ((Ra - Rc)/2)
|
|
{
|
|
return samp[-C->du_width] + ( (samp[-1] - samp[-C->du_width-1]) >> 1 );
|
|
}
|
|
|
|
static int P7(struct COMP *C, TSAMP *samp) // Px = (Ra + Rb)/2
|
|
{
|
|
return (samp[-1] + samp[-C->du_width]) >> 1;
|
|
}
|
|
|
|
static int (*PN[])(struct COMP *C, TSAMP *samp) = {
|
|
0, P1, P2, P3, P4, P5, P6, P7
|
|
};
|
|
|
|
static int Predx(struct JPEGD *j, struct COMP *C, int x, int y, TSAMP *samp)
|
|
{
|
|
int Px;
|
|
if (!x) {
|
|
if (y) Px= samp[-C->du_width]; // Px = Rb (P2)
|
|
else Px= 1<<(j->P-1); // 'P0'
|
|
}
|
|
else {
|
|
if (y) Px= PN[j->Ss](C, samp); // (PN)
|
|
else Px= samp[-1]; // Px = Ra (P1)
|
|
}
|
|
return Px;
|
|
}
|
|
|
|
|
|
//////////////////////////////////// HUFFMAN ////////////////////////////////////////////////
|
|
|
|
static int Byte_in_huff(struct JPEGD *j)
|
|
{
|
|
j->ScanByte = GETC();
|
|
if ( 0xFF == j->ScanByte )
|
|
{
|
|
int marker = GETC();
|
|
if ( marker ) // DEBUG: ERR in Huffman:
|
|
{
|
|
printf("%08X: FF%02x\n", TELL()-2, marker);
|
|
printf("STREAM ERROR: marker found in Huffman ECS\n");
|
|
}
|
|
//else skip zero-stuffing
|
|
}
|
|
return j->ScanByte;
|
|
}
|
|
|
|
static int GetBit(struct JPEGD *j)
|
|
{
|
|
if ( j->ScanBit ) return (j->ScanByte >> --j->ScanBit) & 1;
|
|
j->ScanBit=7;
|
|
return j->Byte_in(j) >> 7; // arith/huff
|
|
}
|
|
|
|
static int Getnbit(struct JPEGD *j, int n) // n>0
|
|
{
|
|
int v= GetBit(j);
|
|
while (--n) v= 2*v + GetBit(j);
|
|
return v;
|
|
}
|
|
|
|
static int ReadDiff(struct JPEGD *j, int s) // JPEG magnitude stuff. One way to do this..
|
|
{
|
|
int x= Getnbit(j, s);
|
|
if ( 0 == (x >> (s-1)) ) x= (-1<<s) - ~x; // 0xxxxxx means neg //x= ~x & ((1<<s)-1);
|
|
return x << j->Al; // point transform included PRED??? seems ok.
|
|
}
|
|
|
|
static int ReadHuffmanCode(struct JPEGD *j, int *pb) // index into the sym-table
|
|
{
|
|
int v= GetBit(j);
|
|
while ( v >= *pb ) v= 2*v + GetBit(j) - *pb++;
|
|
return v;
|
|
}
|
|
|
|
static void dc_succ_huff(struct JPEGD *j, struct COMP *sc, TCOEF *coef)
|
|
{
|
|
*coef |= GetBit(j) << j->Al;
|
|
}
|
|
|
|
static void dc_decode_huff(struct JPEGD *j, struct COMP *sc, TCOEF *coef)
|
|
{
|
|
int s= sc->DCS[ReadHuffmanCode(j, sc->DCB)];
|
|
if (s) sc->DC+= ReadDiff(j, s);
|
|
*coef= sc->DC;
|
|
}
|
|
|
|
static void ac_decode_huff(struct JPEGD *j, struct COMP *sc, TCOEF *coef)
|
|
{
|
|
int k= j->Ss;
|
|
if (0==sc->EOBRUN) {
|
|
for (; ;k++) {
|
|
int s= sc->ACS[ReadHuffmanCode(j, sc->ACB)];
|
|
int r= s>>4;
|
|
if ( s&=15 ) s= ReadDiff(j, s);
|
|
else {
|
|
if (r < 15) { // EOBn?
|
|
if (r) sc->EOBRUN= Getnbit(j, r) + ~(-1<<r); // ((1<<r)-1); -1 included
|
|
return;
|
|
}//else ZRL
|
|
}
|
|
k+=r;
|
|
coef[k]= s;
|
|
if (k==j->Se) return;
|
|
}
|
|
}
|
|
else sc->EOBRUN--;
|
|
}
|
|
|
|
static int ac_refine(struct JPEGD *j, TCOEF *coef)
|
|
{
|
|
if (*coef) if (GetBit(j)) *coef+= (*coef > 0)? j->Al2 : -j->Al2;
|
|
return *coef;
|
|
}
|
|
|
|
static void ac_succ_huff(struct JPEGD *j, struct COMP *sc, TCOEF *coef)
|
|
{
|
|
int k= j->Ss;
|
|
if (0==sc->EOBRUN) {
|
|
for (; ;k++) {
|
|
int s= sc->ACS[ReadHuffmanCode(j, sc->ACB)];
|
|
int r= s>>4;
|
|
if ( s&=15 ) s= GetBit(j)? j->Al2 : -j->Al2;
|
|
else {
|
|
if (r < 15) { // EOBn?
|
|
if (r) sc->EOBRUN= Getnbit(j, r) + ~(-1<<r); //=((1<<r)-1), -1 included
|
|
break;
|
|
}//else ZRL
|
|
}
|
|
for (; ;k++) if (!ac_refine(j, coef+k)) if (!r--) break;
|
|
coef[k]= s;
|
|
if (k==j->Se) return;
|
|
}
|
|
}
|
|
else sc->EOBRUN--;
|
|
for (; k<=j->Se; k++) ac_refine(j, coef+k); // Refine EOBRUN
|
|
}
|
|
|
|
static void du_sequential_huff(struct JPEGD *j, struct COMP *sc, TCOEF *coef)
|
|
{
|
|
int s, k;
|
|
dc_decode_huff(j, sc, coef);
|
|
for (k=1; (s=sc->ACS[ReadHuffmanCode(j, sc->ACB)]); k++) { // EOB?
|
|
k+= s>>4;
|
|
if (s==0xf0) continue; // ZRL
|
|
coef[k]= ReadDiff(j, s&15);
|
|
if (k==63) return;
|
|
}
|
|
}
|
|
|
|
static void decode_lossless_huff(struct JPEGD *j, struct COMP *sc, int x, int y, TSAMP *samp) // TODO: Pt
|
|
{
|
|
int DIFF= sc->DCS[ReadHuffmanCode(j, sc->DCB)];
|
|
*samp= Predx(j, sc, x, y, samp);
|
|
if (DIFF) *samp+= (DIFF==16)? 32768 : ReadDiff(j, DIFF);
|
|
}
|
|
|
|
|
|
static void Reset_decoder_huff(struct JPEGD *j)
|
|
{
|
|
int c;
|
|
for (c=0; c < j->Ns; c++) j->ScanComponents[c]->DC=0; // DC/EOBRUN
|
|
j->ScanBit=0; // trigger next byte read (skipping stuffing '1'-s)
|
|
}
|
|
|
|
static void Reset_decoder_huff_lossless(struct JPEGD *j)
|
|
{
|
|
j->LineNo=0;
|
|
j->ScanBit=0; // trigger next byte read
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////// ARITHMETIC //////////////////////////////////////////////
|
|
|
|
static int Byte_in_arith(struct JPEGD *j)
|
|
{
|
|
j->ScanByte = GETC();
|
|
if ( 0xFF == j->ScanByte )
|
|
{
|
|
if ( GETC() ) { // Marker detection
|
|
SEEK(-2); // Arith: "zero byte fed to decoder"
|
|
j->ScanBit=~0; // Seems like 8 was not enough.. TODO
|
|
j->ScanByte=0;
|
|
}
|
|
//else skip zero-stuffing
|
|
}
|
|
return j->ScanByte;
|
|
}
|
|
|
|
static void ResetStat(struct CABACSTATE *st, int n) // Initialize statistics areas
|
|
{
|
|
while (--n >= 0) st[n].valMPS= st[n].StateIdx=0;
|
|
}
|
|
|
|
static void InitDecoder(struct JPEGD *j)
|
|
{
|
|
j->ScanBit=0; // trigger next byte read
|
|
j->A=0;
|
|
j->C= Byte_in_arith(j) << 8;
|
|
j->C|= Byte_in_arith(j);
|
|
}
|
|
|
|
static void Reset_decoder_arith(struct JPEGD *j)
|
|
{
|
|
int c;
|
|
for (c=0; c < j->Ns; c++)
|
|
{
|
|
struct COMP *sc= j->ScanComponents[c];
|
|
if (j->Se) ResetStat(sc->ACST+1, 245); // AC in Scan (+1 adjusted)
|
|
if (!j->Ss) // DC in Scan
|
|
{
|
|
ResetStat(sc->DCST, 49);
|
|
sc->DC= 0;
|
|
sc->DIFF= 0; // extra in Arith
|
|
}
|
|
}
|
|
InitDecoder(j);
|
|
}
|
|
|
|
static void Reset_decoder_arith_lossless(struct JPEGD *j)
|
|
{
|
|
int c;
|
|
for (c=0; c < j->Ns; c++) ResetStat(j->ScanComponents[c]->LLST, 158);
|
|
j->LineNo=0; // Special in lossless
|
|
InitDecoder(j);
|
|
}
|
|
|
|
|
|
static struct _STATE {
|
|
int Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS;
|
|
} STATE[] = {{0x5A1D,1,1,1},{0x2586,14,2,0},{0x1114,16,3,0},{0x080B,18,4,0},{0x03D8,20,5,0},{0x01DA,23,6,0},{0x00E5,25,7,0},{0x006F,28,8,0},{0x0036,30,9,0},{0x001A,33,10,0},{0x000D,35,11,0},{0x0006,9,12,0},{0x0003,10,13,0},{0x0001,12,13,0},{0x5A7F,15,15,1},{0x3F25,36,16,0},{0x2CF2,38,17,0},{0x207C,39,18,0},{0x17B9,40,19,0},{0x1182,42,20,0},{0x0CEF,43,21,0},{0x09A1,45,22,0},{0x072F,46,23,0},{0x055C,48,24,0},{0x0406,49,25,0},{0x0303,51,26,0},{0x0240,52,27,0},{0x01B1,54,28,0},{0x0144,56,29,0},{0x00F5,57,30,0},{0x00B7,59,31,0},{0x008A,60,32,0},{0x0068,62,33,0},{0x004E,63,34,0},{0x003B,32,35,0},{0x002C,33,9,0},{0x5AE1,37,37,1},{0x484C,64,38,0},{0x3A0D,65,39,0},{0x2EF1,67,40,0},{0x261F,68,41,0},{0x1F33,69,42,0},{0x19A8,70,43,0},{0x1518,72,44,0},{0x1177,73,45,0},{0x0E74,74,46,0},{0x0BFB,75,47,0},{0x09F8,77,48,0},{0x0861,78,49,0},{0x0706,79,50,0},{0x05CD,48,51,0},{0x04DE,50,52,0},{0x040F,50,53,0},{0x0363,51,54,0},{0x02D4,52,55,0},{0x025C,53,56,0},{0x01F8,54,57,0},{0x01A4,55,58,0},{0x0160,56,59,0},{0x0125,57,60,0},{0x00F6,58,61,0},{0x00CB,59,62,0},{0x00AB,61,63,0},{0x008F,61,32,0},{0x5B12,65,65,1},{0x4D04,80,66,0},{0x412C,81,67,0},{0x37D8,82,68,0},{0x2FE8,83,69,0},{0x293C,84,70,0},{0x2379,86,71,0},{0x1EDF,87,72,0},{0x1AA9,87,73,0},{0x174E,72,74,0},{0x1424,72,75,0},{0x119C,74,76,0},{0x0F6B,74,77,0},{0x0D51,75,78,0},{0x0BB6,77,79,0},{0x0A40,77,48,0},{0x5832,80,81,1},{0x4D1C,88,82,0},{0x438E,89,83,0},{0x3BDD,90,84,0},{0x34EE,91,85,0},{0x2EAE,92,86,0},{0x299A,93,87,0},{0x2516,86,71,0},{0x5570,88,89,1},{0x4CA9,95,90,0},{0x44D9,96,91,0},{0x3E22,97,92,0},{0x3824,99,93,0},{0x32B4,99,94,0},{0x2E17,93,86,0},{0x56A8,95,96,1},{0x4F46,101,97,0},{0x47E5,102,98,0},{0x41CF,103,99,0},{0x3C3D,104,100,0},{0x375E,99,93,0},{0x5231,105,102,0},{0x4C0F,106,103,0},{0x4639,107,104,0},{0x415E,103,99,0},{0x5627,105,106,1},{0x50E7,108,107,0},{0x4B85,109,103,0},{0x5597,110,109,0},{0x504F,111,107,0},{0x5A10,110,111,1},{0x5522,112,109,0},{0x59EB,112,111,1}};
|
|
|
|
static void Renorm(struct JPEGD *j)
|
|
{
|
|
do j->C= 2*j->C | GetBit(j);
|
|
while ( (short)(j->A*=2) >= 0);
|
|
}
|
|
|
|
static int tr_MPS(struct JPEGD *j, struct CABACSTATE *st)
|
|
{
|
|
Renorm(j);
|
|
st->StateIdx= STATE[ st->StateIdx ].Next_Index_MPS;
|
|
return st->valMPS;
|
|
}
|
|
|
|
static int tr_LPS(struct JPEGD *j, struct CABACSTATE *st)
|
|
{
|
|
int D= st->valMPS^1;
|
|
st->valMPS ^= STATE[ st->StateIdx ].Switch_MPS;
|
|
st->StateIdx= STATE[ st->StateIdx ].Next_Index_LPS;
|
|
Renorm(j);
|
|
return D;
|
|
}
|
|
|
|
static int DecodeBin(struct JPEGD *j, struct CABACSTATE *st)
|
|
{
|
|
unsigned short A= j->A - STATE[ st->StateIdx ].Qe_Value;
|
|
if ( j->C < A )
|
|
{
|
|
j->A = A;
|
|
if ((short)A<0) return st->valMPS;
|
|
return ( A < STATE[ st->StateIdx ].Qe_Value )? tr_LPS(j, st) : tr_MPS(j, st);
|
|
}
|
|
j->C -= A;
|
|
j->A= STATE[ st->StateIdx ].Qe_Value;
|
|
return ( A < j->A )? tr_MPS(j, st) : tr_LPS(j, st);
|
|
}
|
|
|
|
static int DecodeFIX(struct JPEGD *j)
|
|
{
|
|
unsigned short A= j->A - 0x5A1D;
|
|
if ( j->C < A ) {
|
|
if ((short)(j->A = A)<0) return 0;
|
|
Renorm(j);
|
|
return ( A < 0x5A1D ) ? 1 : 0;
|
|
}
|
|
else {
|
|
j->C = 2*( j->C - A ) | GetBit(j);
|
|
j->A= 0x5A1D*2;
|
|
return ( A < 0x5A1D ) ? 0 : 1;
|
|
}
|
|
}
|
|
|
|
static int DC_Context(struct COMP *sc, int D) // DC + LOSSLESS
|
|
{
|
|
if (D < 0) {
|
|
if ( D < -sc->U ) return 16; // large neg
|
|
if ( D < -sc->L ) return 8;
|
|
}
|
|
else {
|
|
if ( D > sc->U ) return 12; // large pos
|
|
if ( D > sc->L ) return 4;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int Decode_V(struct JPEGD *j, struct CABACSTATE *ST, int SNSP, int X1, int X2) // DC/AC
|
|
{
|
|
int Sz, M;
|
|
if ( !DecodeBin(j, ST+SNSP) ) return 1;
|
|
if ( !DecodeBin(j, ST+X1) ) return 2;
|
|
M=2, ST+=X2;
|
|
while ( DecodeBin(j, ST) ) M <<= 1, ST++;
|
|
Sz= M;
|
|
ST += 14;
|
|
while (M>>=1) if (DecodeBin(j, ST)) Sz |= M;
|
|
return Sz+1;
|
|
}
|
|
|
|
static int Decode_DIFF(struct JPEGD *j, struct CABACSTATE *ST, int S0, int X1) // DC + LOSSLESS
|
|
{
|
|
if ( DecodeBin(j, ST+S0) ) // (S0)
|
|
{
|
|
int sign= DecodeBin(j, ST + S0 + 1); // (SS)
|
|
int DIFF= Decode_V(j, ST, S0 + 2 + sign, X1, X1+1);
|
|
return (sign)? -DIFF : DIFF;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void dc_decode_arith(struct JPEGD *j, struct COMP *sc, TCOEF *coef)
|
|
{
|
|
int S0= DC_Context(sc, sc->DIFF);
|
|
sc->DIFF= Decode_DIFF(j, sc->DCST, S0, 20);
|
|
sc->DC+= sc->DIFF << j->Al;
|
|
*coef= sc->DC;
|
|
}
|
|
|
|
static void ac_band(struct JPEGD *j, struct COMP *sc, TCOEF *coef, int k) // NB: we re-arrange contexts a little (so indexing simply by k)
|
|
{
|
|
while ( !DecodeBin(j, sc->ACST+k) ) // EOB?
|
|
{
|
|
int V, sign;
|
|
while ( !DecodeBin(j, sc->ACST+k+63) ) k++; // S0
|
|
sign= DecodeFIX(j);
|
|
V= Decode_V(j, sc->ACST, k+126, k+126, (k>sc->Kx)? (217+1) : (189+1) );
|
|
if (sign) V = -V;
|
|
coef[k]= V << j->Al;
|
|
if (k==j->Se) return;
|
|
k++;
|
|
}
|
|
}
|
|
|
|
static void du_sequential_arith(struct JPEGD *j, struct COMP *sc, TCOEF *coef)
|
|
{
|
|
dc_decode_arith(j, sc, coef);
|
|
ac_band(j, sc, coef, 1);
|
|
}
|
|
|
|
static void ac_decode_arith(struct JPEGD *j, struct COMP *sc, TCOEF *coef)
|
|
{
|
|
ac_band(j, sc, coef, j->Ss);
|
|
}
|
|
|
|
static void dc_succ_arith(struct JPEGD *j, struct COMP *sc, TCOEF *coef)
|
|
{
|
|
*coef |= DecodeFIX(j) << j->Al;
|
|
}
|
|
|
|
static void ac_succ_arith(struct JPEGD *j, struct COMP *sc, TCOEF *coef)
|
|
{
|
|
int k= j->Ss;
|
|
int EOBx= j->Se; // actually index of last non-zero coeff already decoded in band
|
|
|
|
while ( !coef[EOBx] && EOBx >= k ) EOBx--;
|
|
|
|
for (; k <= EOBx; k++)
|
|
{
|
|
if ( coef[k])
|
|
{
|
|
if (DecodeBin(j, sc->ACST+k+126)) coef[k] += (coef[k] > 0)? j->Al2 : -j->Al2; // SC: correction bit?
|
|
}
|
|
else
|
|
{
|
|
if (DecodeBin(j, sc->ACST+k+63)) coef[k]= DecodeFIX(j)? -j->Al2 : j->Al2; // New coeff?
|
|
}
|
|
}
|
|
|
|
for (; k <= j->Se && !DecodeBin(j, sc->ACST+k); k++) // SE: EOB?
|
|
{
|
|
while (!DecodeBin(j, sc->ACST+k+63)) k++;
|
|
coef[k]= DecodeFIX(j)? -j->Al2 : j->Al2;
|
|
}
|
|
}
|
|
|
|
static void decode_lossless_arith(struct JPEGD *j, struct COMP *sc, int x, int y, TSAMP *samp) // TODO: Pt
|
|
{
|
|
int Da= x? 5 * DC_Context(sc, sc->diffLeft[y]) : 0;
|
|
int Db= y? DC_Context(sc, sc->diffAbove[x]) : 0;
|
|
int DIFF= Decode_DIFF(j, sc->LLST, Da + Db, (Db>8)? 129 : 100);
|
|
sc->diffAbove[x]= DIFF;
|
|
sc->diffLeft[y]= DIFF;
|
|
*samp= Predx(j, sc, x, y, samp) + DIFF;
|
|
}
|
|
|
|
|
|
/////////////////////////// SCAN DECODING ///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//static int LocateMarker(struct JPEGD *j)
|
|
|
|
static int NextMarker(struct JPEGD *j) // at expected location - this is not LocateMarker()
|
|
{
|
|
int Marker;
|
|
printf("%08X: ", TELL());
|
|
while ( 0xFF == (Marker=GETC()) ) printf("FF"); // marker stuffing FF
|
|
printf("%02X ", Marker);
|
|
return Marker;
|
|
}
|
|
|
|
static void Ri(struct JPEGD *j, int n)
|
|
{
|
|
if (j->Ri) // Restart enabled?
|
|
{
|
|
if ( 0 == n % j->Ri )
|
|
{
|
|
int Marker= NextMarker(j);
|
|
if ( (Marker & 0xf8) == 0xD0 ) // RSTn expected
|
|
{
|
|
printf("RST%d\n", Marker&7);
|
|
printf("%08X: ECS\n", TELL());
|
|
}
|
|
else { printf("STREAM ERROR: expected RSTn missing from ECS\n"); }
|
|
j->Reset_decoder(j);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void DecodeInterleaved_DCT(struct JPEGD *j)
|
|
{
|
|
int n=0, c, x, y;
|
|
|
|
for(;;)
|
|
{
|
|
int mcuy = n / j->mcu_width;
|
|
int mcux = n % j->mcu_width;
|
|
|
|
for (c=0; c < j->Ns; c++)
|
|
{
|
|
struct COMP *C= j->ScanComponents[c];
|
|
DU *du= C->du + mcuy * C->du_width * C->Vi + mcux * C->Hi;
|
|
for (y=0; y<C->Vi; y++) for (x=0; x<C->Hi; x++) j->DecodeDataUnit(j, C, du[ C->du_width * y + x ]); // Huff/arith
|
|
}
|
|
|
|
if (++n==j->mcu_total) return; // We count MCU-s. No RST after the last
|
|
Ri(j, n);
|
|
}
|
|
}
|
|
|
|
static void DecodeSingle_DCT(struct JPEGD *j)
|
|
{
|
|
int n=0;
|
|
struct COMP *C= j->ScanComponents[0];
|
|
|
|
for (;;)
|
|
{
|
|
j->DecodeDataUnit(j, C, C->du[ (n / C->du_w) * C->du_width + n % C->du_w ]); // Huff/arith
|
|
if ( ++n == C->du_size ) return; // We count DU-s. No RST after the last
|
|
Ri(j, n);
|
|
}
|
|
}
|
|
|
|
|
|
static void DecodeSingle_LL(struct JPEGD *j)
|
|
{
|
|
int n=0, x;
|
|
struct COMP *C= j->ScanComponents[0];
|
|
TSAMP *samp= C->samp;
|
|
j->LineNo=0;
|
|
for (;;)
|
|
{
|
|
for (x=0; x < C->du_w; x++) j->decode_lossless(j, C, x, j->LineNo, samp+x); // Huff/arith
|
|
if ( (n+=C->du_w) == C->du_size ) return; // we count by lines
|
|
j->LineNo=1;
|
|
Ri(j, n); // Lossless restart interval is one mcu-line
|
|
samp+=C->du_width;
|
|
}
|
|
}
|
|
|
|
|
|
static void DecodeInterleaved_LL(struct JPEGD *j)
|
|
{
|
|
int n=0, c;
|
|
int x, mcux;
|
|
int y, mcuy;
|
|
j->LineNo=0;
|
|
for (mcuy=0; ; mcuy++)
|
|
{
|
|
for (mcux=0; mcux < j->mcu_width; mcux++)
|
|
{
|
|
for (c=0; c < j->Ns; c++)
|
|
{
|
|
struct COMP *C= j->ScanComponents[c];
|
|
int xs= mcux * C->Hi;
|
|
TSAMP *samp= C->samp + C->du_width * (mcuy * C->Vi) + xs;
|
|
|
|
for (y=0; y < C->Vi; y++, samp+=C->du_width)
|
|
{
|
|
for (x=0; x < C->Hi; x++) j->decode_lossless(j, C, xs+x, j->LineNo+y, samp + x); // Huff/arith
|
|
}
|
|
}
|
|
}
|
|
if ( (n+=j->mcu_width) == j->mcu_total ) return; // we count by lines
|
|
j->LineNo=1;
|
|
Ri(j, n); // Lossless restart interval is one mcu-line
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////// PARSING //////////////////////////////////////////////////////////////////////////////
|
|
|
|
static char *SOFSTRING[] = { // debug
|
|
// non-differential, Huffman coding
|
|
"Baseline DCT",
|
|
"Huffman Extended sequential DCT",
|
|
"Huffman Progressive DCT",
|
|
"Huffman Lossless sequential",
|
|
// differential, Huffman coding (Hierarchial)
|
|
"", // DHT
|
|
"-Differential sequential DCT",
|
|
"-Differential progressive DCT",
|
|
"-Differential lossless (sequential)",
|
|
// non-differential, arithmetic coding
|
|
"", // JPG
|
|
"Arithmetic Extended sequential DCT",
|
|
"Arithmetic Progressive DCT",
|
|
"Arithmetic Lossless sequential",
|
|
// differential, arithmetic coding (Hierarchial)
|
|
"", // DAC
|
|
"-Arithmetic Differential sequential DCT",
|
|
"-Arithmetic Differential progressive DCT",
|
|
"-Arithmetic Differential lossless sequential",
|
|
|
|
};
|
|
|
|
static int div_up(int a, int b) // ~ciel([a/b])
|
|
{
|
|
return (a + b - 1) / b;
|
|
}
|
|
|
|
static int set_dim(struct JPEGD *j, int d) // d= 1 (LL) or 8 (DCT)
|
|
{
|
|
int i, TotalDU=0;
|
|
|
|
j->Hmax= j->Vmax= 0;
|
|
|
|
for (i=0; i<j->Nf; i++) // read component data, set Hmax/Vmax
|
|
{
|
|
struct COMP *C= j->Components + i;
|
|
|
|
C->Ci= GETC(); //Cid
|
|
C->Vi= GETC(); //HV
|
|
C->Hi= C->Vi>>4;
|
|
C->Vi&= 15;
|
|
C->Qi= GETC();
|
|
|
|
if ( C->Hi > j->Hmax ) j->Hmax = C->Hi;
|
|
if ( C->Vi > j->Vmax ) j->Vmax = C->Vi;
|
|
|
|
printf(" Ci=%3d HV=%dx%d Qi=%d\n", C->Ci, C->Hi, C->Vi, C->Qi);
|
|
}
|
|
printf("\n");
|
|
|
|
// Full Image MCU cover:
|
|
j->mcu_width= div_up(j->X, j->Hmax*d);
|
|
j->mcu_height= div_up(j->Y, j->Vmax*d);
|
|
j->mcu_total= j->mcu_width * j->mcu_height;
|
|
|
|
// now set parameters based on Hmax/Vmax
|
|
for (i=0; i<j->Nf; i++)
|
|
{
|
|
struct COMP *C= j->Components + i;
|
|
|
|
int xi= div_up(j->X*C->Hi, j->Hmax); // as Standard: sample rectangle (from image X,Y and Sampling factors)
|
|
int yi= div_up(j->Y*C->Vi, j->Vmax); // used to compute single scan 'coverage'
|
|
|
|
// Single scan DU-cover (LL: d=1)
|
|
C->du_w= div_up(xi, d);
|
|
C->du_h= div_up(yi, d);
|
|
C->du_size= C->du_w * C->du_h;
|
|
|
|
// Interleaved scan DU-cover
|
|
C->du_width= j->mcu_width*C->Hi;
|
|
C->du_total= C->du_width * j->mcu_height*C->Vi;
|
|
|
|
TotalDU+= C->du_total;
|
|
|
|
//printf(" %d\n", i);
|
|
//printf(" Sample: x=%d+%d (1:%d) y=%d+%d (1:%d)\n", C->xi, C->dux*8-C->xi, j->Hmax/C->Hi, C->yi, C->duy*8-C->yi, j->Vmax/C->Vi);
|
|
//printf(" 8x8 Data Unit: %d (X=%d Y=%d)\n", C->duN, C->dux, C->duy);
|
|
//printf(" MCU Data Unit: %d (X=%d Y=%d)\n", C->du_total, C->du_width, C->duyI);
|
|
// LL
|
|
//printf(" Sample: x=%d (1:%d) y=%d (1:%d)\n", C->du_xi, j->Hmax/C->Hi, C->du_yi, j->Vmax/C->Vi);
|
|
}
|
|
|
|
return TotalDU;
|
|
}
|
|
|
|
|
|
extern enum JPEGENUM JPEGDecode(struct JPEGD *j)
|
|
{
|
|
int marker, i;
|
|
|
|
j->jpeg_mem= 0;
|
|
marker = NextMarker(j);
|
|
if ( marker != 0xD8 ) return JPEGENUMERR_MISSING_SOI;
|
|
printf("SOI\n");
|
|
|
|
// The 'Decoder_setup' procedure
|
|
j->Ri=0;
|
|
// Arithmetic capable Decoder this is:
|
|
// default DC bounds: L = 0 and U = 1, Kx=5
|
|
j->U[0]= j->U[1]= j->U[2]= j->U[3]= 2; // 1<<U
|
|
j->L[0]= j->L[1]= j->L[2]= j->L[3]= 0;
|
|
j->Kx[0]= j->Kx[1]= j->Kx[2]= j->Kx[3]= 5;
|
|
|
|
// Set first to zero for scaled quantization
|
|
// Also for QT entry redefinition (not implemented, see remarks)
|
|
j->QT[0][0]=j->QT[1][0]=j->QT[2][0]=j->QT[3][0]=0;
|
|
|
|
for (;;)
|
|
{
|
|
marker = NextMarker(j);
|
|
|
|
if ( marker == 0xCC ) // DAC
|
|
{
|
|
int La= GETWbi();
|
|
printf("DAC\n");
|
|
printf(" Arithmetic Conditioning\n parameters:\n");
|
|
for (La-=2; La; La-=2)
|
|
{
|
|
int CB= GETC();
|
|
int Tc= CB>>4;
|
|
int Tb= CB&15;
|
|
int Cs= GETC();
|
|
if (Tc) // AC
|
|
{
|
|
printf(" AC%d Kx=%d\n", Tb, Cs);
|
|
j->Kx[Tb]= Cs;
|
|
}
|
|
else
|
|
{
|
|
int L= Cs&15;
|
|
int U= Cs>>4;
|
|
printf(" DC%d L=%d U=%d\n", Tb, Cs&15, Cs>>4);
|
|
j->U[Tb]= 1<<U;
|
|
j->L[Tb]= L? 1 << (L-1) : 0;
|
|
}
|
|
}
|
|
}
|
|
else if ( marker == 0xC8 ) // T.851??
|
|
{
|
|
return JPEGENUMERR_MARKERC8;
|
|
}
|
|
else if ( marker == 0xC4 ) // DHT
|
|
{
|
|
int N;
|
|
int Lh= GETWbi();
|
|
printf("DHT\n");
|
|
for (Lh-=2; Lh; Lh -= 17 + N)
|
|
{
|
|
int CH= GETC();
|
|
int Tc= CH>>4;
|
|
int Th= CH&15;
|
|
int *B= j->HTB[Tc][Th];
|
|
unsigned char *S= j->HTS[Tc][Th];
|
|
printf(" %s%d\n", Tc?"AC":"DC", Th);
|
|
printf(" N: ");
|
|
for (i=N=0; i<16; i++) {
|
|
int n= GETC();
|
|
N+= n;
|
|
printf("%d ", n);
|
|
B[i]= N; // running total
|
|
}
|
|
printf("\n");
|
|
printf(" S: %d symbol bytes\n", N);
|
|
for (i=0; i<N; i++) S[i]= GETC();
|
|
}
|
|
}
|
|
else if ( (marker & 0xf0) == 0xC0 ) // START OF FRAME SOFn C0..CF (C4, CC, C8 checked before)
|
|
{
|
|
GETWbi();//Lf
|
|
j->P= GETC();//P
|
|
j->Y= GETWbi();//Y: Number of lines
|
|
j->X= GETWbi();//X: Number of samples per line
|
|
j->Nf= GETC();//Nf
|
|
|
|
printf("SOF%d (%s)\n", marker&15, SOFSTRING[marker&15]);
|
|
printf(" P=%d Y=%d X=%d\n", j->P, j->Y, j->X);
|
|
printf(" Nf=%d\n", j->Nf);
|
|
|
|
if (*SOFSTRING[marker&15] == '-') return JPEGENUMERR_UNKNOWN_SOF;
|
|
if (j->Nf>4) return JPEGENUMERR_COMP4;
|
|
if (!j->Y) return JPEGENUMERR_ZEROY; // I have no idea about this DNL stuff
|
|
j->SOF= marker;
|
|
|
|
if ( (j->SOF&3)==3 ) // LOSSLESS-mode
|
|
{
|
|
int TotalDU= set_dim(j, 1); // for malloc: in samples as coeff;
|
|
|
|
if (j->SOF > 0xC8) { // arithmetic:
|
|
|
|
j->Reset_decoder= Reset_decoder_arith_lossless;
|
|
j->decode_lossless= decode_lossless_arith;
|
|
j->Byte_in= Byte_in_arith;
|
|
|
|
// Arithmetic: need a line to store DIFF, where???
|
|
for (i=0; i<j->Nf; i++)
|
|
{
|
|
struct COMP *C= j->Components + i;
|
|
C->du_total += C->du_width;
|
|
TotalDU+= C->du_width;
|
|
}
|
|
}
|
|
else { // Huffman
|
|
j->Reset_decoder= Reset_decoder_huff_lossless;
|
|
j->decode_lossless= decode_lossless_huff;
|
|
j->Byte_in= Byte_in_huff;
|
|
}
|
|
|
|
// malloc sample storage
|
|
{
|
|
TSAMP *samp;
|
|
int mallocTotalCoef= sizeof(TSAMP) * TotalDU;
|
|
j->jpeg_mem= calloc(mallocTotalCoef, 1);
|
|
if ( 0 == j->jpeg_mem ) return JPEGENUMERR_MALLOC;
|
|
samp= j->jpeg_mem;
|
|
for (i=0; i<j->Nf; i++)
|
|
{
|
|
struct COMP *C= j->Components + i;
|
|
C->samp= samp;
|
|
samp+= C->du_total;
|
|
C->diffAbove= samp - C->du_width; // 1 line DIFF-BUFFER for Arith
|
|
}
|
|
}
|
|
}
|
|
else // DCT-mode
|
|
{
|
|
int TotalDU= set_dim(j, 8); // for malloc in DU;
|
|
|
|
printf(" %d MCU (%d x %d)\n", j->mcu_total, j->mcu_width, j->mcu_height);
|
|
|
|
// malloc DU-s
|
|
{
|
|
DU *du;
|
|
int mallocTotalCoef= sizeof(DU) * TotalDU;
|
|
j->jpeg_mem= calloc(mallocTotalCoef, 1);
|
|
if ( 0 == j->jpeg_mem ) return JPEGENUMERR_MALLOC;
|
|
du= j->jpeg_mem;
|
|
for (i=0; i<j->Nf; i++)
|
|
{
|
|
struct COMP *C= j->Components + i;
|
|
C->du= du;
|
|
du+= C->du_total;
|
|
}
|
|
}
|
|
|
|
printf(" Malloc for %d Data Units (%lu bytes)\n\n", TotalDU, sizeof(DU)*TotalDU);
|
|
|
|
if (j->SOF > 0xC8) { // DCT Arithmetic
|
|
j->Reset_decoder= Reset_decoder_arith;
|
|
j->Byte_in= Byte_in_arith;
|
|
}
|
|
else { // DCT Huffman
|
|
j->Reset_decoder= Reset_decoder_huff;
|
|
j->Byte_in= Byte_in_huff;
|
|
}
|
|
}
|
|
}
|
|
/*else if ( (marker & 0xf8) == 0xD0 ) // RSTn D0..D7
|
|
{
|
|
printf("RST%d\n", marker&7);
|
|
printf("%08X: ....\n", TELL());
|
|
}*/
|
|
else if ( marker == 0xD9 ) // EOI
|
|
{
|
|
printf("EOI\n");
|
|
return JPEGENUM_OK;
|
|
}
|
|
else if ( marker == 0xDA ) // SOS
|
|
{
|
|
int ci;
|
|
GETWbi(); //Ls
|
|
printf("SOS\n");
|
|
j->Ns= GETC();//Ns
|
|
printf(" Ns: %d (%s scan)\n", j->Ns, (j->Ns>1)?"Interleaved":"Single");
|
|
|
|
for (ci=0; ci<j->Ns; ci++)
|
|
{
|
|
struct COMP *sc;
|
|
int Cs= GETC(); // Cs -> Cid (Scan component selector)
|
|
int T= GETC();
|
|
int Td= T>>4;
|
|
int Ta= T&15;
|
|
printf(" Cs=%d Td=%d Ta=%d\n", Cs, Td, Ta);
|
|
|
|
{// safe search
|
|
for ( i=0; i<4 && j->Components[i].Ci != Cs; i++ ) ;
|
|
if ( 4 == i ) return JPEGENUMERR_COMPNOTFOUND;
|
|
j->ScanComponents[ci]= sc= j->Components+i;
|
|
}
|
|
|
|
if (j->SOF > 0xC8) // arithmetic
|
|
{
|
|
sc->U= j->U[Td];
|
|
sc->L= j->L[Td];
|
|
sc->Kx= j->Kx[Ta];
|
|
|
|
if ((j->SOF&3)==3) sc->LLST= j->ACST[Td]; // LOSSLESS: ACST re-used to save storage (lossles stat. area little less than AC, but more than DC)
|
|
else {
|
|
sc->ACST= j->ACST[Ta]-1; // DCT. Modified for speed: use 'k' to index the 63 increments for S0, SN,SP...
|
|
sc->DCST= j->DCST[Td];
|
|
}
|
|
}
|
|
else { // Huffman
|
|
sc->ACB= j->HTB[1][Ta];
|
|
sc->ACS= j->HTS[1][Ta];
|
|
sc->DCB= j->HTB[0][Td];
|
|
sc->DCS= j->HTS[0][Td];
|
|
}
|
|
}
|
|
|
|
j->Ss= GETC();//Ss (DCT) or Px (LL)
|
|
j->Se= GETC();//Se
|
|
j->Al= GETC();//AhAl
|
|
j->Ah= j->Al>>4;
|
|
j->Al&= 15;
|
|
j->Al2= 1<<j->Al;//pre-computed
|
|
|
|
printf(" %s: %d\n", ((j->SOF&3)==3)?"Px":"Ss", j->Ss);
|
|
printf(" Se: %d\n", j->Se);
|
|
printf(" Ah: %d\n", j->Ah);
|
|
printf(" %s: %d\n", ((j->SOF&3)==3)?"Pt":"Al", j->Al);
|
|
|
|
printf("%08X: ECS\n", TELL()); // Entropy-Coded Segment
|
|
|
|
j->Reset_decoder(j); // arithmetic/huffman/lossless
|
|
|
|
if ((j->SOF&3)==3) // LOSSLESS
|
|
{
|
|
if (j->Ns>1)
|
|
{
|
|
DecodeInterleaved_LL(j);
|
|
}
|
|
else
|
|
{
|
|
DecodeSingle_LL(j);
|
|
}
|
|
}
|
|
else { // DCT-type
|
|
|
|
if (j->SOF > 0xC8) // arithmetic:
|
|
{
|
|
j->DecodeDataUnit= j->Ss? (j->Ah? ac_succ_arith : ac_decode_arith) : (j->Se? du_sequential_arith : (j->Ah? dc_succ_arith : dc_decode_arith));
|
|
}
|
|
else {
|
|
j->DecodeDataUnit= j->Ss? (j->Ah? ac_succ_huff : ac_decode_huff) : (j->Se? du_sequential_huff : (j->Ah? dc_succ_huff : dc_decode_huff));
|
|
}
|
|
|
|
if (j->Ns>1)
|
|
{
|
|
DecodeInterleaved_DCT(j);
|
|
}
|
|
else
|
|
{
|
|
DecodeSingle_DCT(j);
|
|
}
|
|
}
|
|
}
|
|
else if ( marker == 0xDB ) // DQT
|
|
{
|
|
// Just read in (this is a coeff-decoder)
|
|
int Pq;
|
|
int Lq= GETWbi();
|
|
printf("DQT\n");
|
|
|
|
for (Lq-=2; Lq; Lq -= 65 + 64*Pq)
|
|
{
|
|
int (*get)(void);
|
|
int T= GETC();
|
|
int Tq= T&3;
|
|
int *qt= j->QT[Tq];
|
|
Pq= T>>4;
|
|
printf(" Tq=%d Pq=%d (%d-bit)\n", Tq, Pq, Pq?16:8);
|
|
get= Pq? GETWbi : GETC;
|
|
if (*qt) return JPEGENUMERR_QTREDEF; // re-defined quant table? Can be, not implemented.
|
|
for (i=0; i<64; i++) qt[i]= get();
|
|
}
|
|
}
|
|
else if ( marker == 0xDC ) // DNL
|
|
{
|
|
printf("DNL\n");
|
|
return JPEGENUMERR_MARKERDNL;
|
|
}
|
|
else if ( marker == 0xDD ) // DRI
|
|
{
|
|
GETWbi();//Lr
|
|
j->Ri= GETWbi();
|
|
printf("DRI\n");
|
|
printf(" Ri: %d\n", j->Ri);
|
|
}
|
|
else if ( (marker & 0xf0) == 0xE0 ) // APPn E0..EF
|
|
{
|
|
int La= GETWbi();
|
|
SEEK(La-2);
|
|
printf("APP%d\n", marker&15);
|
|
}
|
|
else if ( marker == 0xFE ) // COM
|
|
{
|
|
SEEK(GETWbi()-2);
|
|
printf("COM\n");
|
|
}
|
|
else
|
|
{
|
|
printf("???\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma GCC diagnostic pop |