Martin Sturm
/
Lab3
picojpeg/picojpeg.c@0:c546b51ecf0b, 2011-10-11 (annotated)
- Committer:
- XkLi
- Date:
- Tue Oct 11 01:24:18 2011 +0000
- Revision:
- 0:c546b51ecf0b
v1.0
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
XkLi | 0:c546b51ecf0b | 1 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 2 | // picojpeg v1.0 - Public domain, Rich Geldreich <richgel99@gmail.com> |
XkLi | 0:c546b51ecf0b | 3 | // Last modified Nov. 27, 2010 |
XkLi | 0:c546b51ecf0b | 4 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 5 | #include "picojpeg.h" |
XkLi | 0:c546b51ecf0b | 6 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 7 | typedef unsigned char uint8; |
XkLi | 0:c546b51ecf0b | 8 | typedef unsigned short uint16; |
XkLi | 0:c546b51ecf0b | 9 | typedef signed char int8; |
XkLi | 0:c546b51ecf0b | 10 | typedef signed short int16; |
XkLi | 0:c546b51ecf0b | 11 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 12 | // Change as needed - the PJPG_MAX_WIDTH/PJPG_MAX_HEIGHT checks are only present |
XkLi | 0:c546b51ecf0b | 13 | // to quickly detect bogus files. |
XkLi | 0:c546b51ecf0b | 14 | #define PJPG_MAX_WIDTH 16384 |
XkLi | 0:c546b51ecf0b | 15 | #define PJPG_MAX_HEIGHT 16384 |
XkLi | 0:c546b51ecf0b | 16 | |
XkLi | 0:c546b51ecf0b | 17 | #define PJPG_MAXCOMPSINSCAN 3 |
XkLi | 0:c546b51ecf0b | 18 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 19 | typedef enum |
XkLi | 0:c546b51ecf0b | 20 | { |
XkLi | 0:c546b51ecf0b | 21 | M_SOF0 = 0xC0, |
XkLi | 0:c546b51ecf0b | 22 | M_SOF1 = 0xC1, |
XkLi | 0:c546b51ecf0b | 23 | M_SOF2 = 0xC2, |
XkLi | 0:c546b51ecf0b | 24 | M_SOF3 = 0xC3, |
XkLi | 0:c546b51ecf0b | 25 | |
XkLi | 0:c546b51ecf0b | 26 | M_SOF5 = 0xC5, |
XkLi | 0:c546b51ecf0b | 27 | M_SOF6 = 0xC6, |
XkLi | 0:c546b51ecf0b | 28 | M_SOF7 = 0xC7, |
XkLi | 0:c546b51ecf0b | 29 | |
XkLi | 0:c546b51ecf0b | 30 | M_JPG = 0xC8, |
XkLi | 0:c546b51ecf0b | 31 | M_SOF9 = 0xC9, |
XkLi | 0:c546b51ecf0b | 32 | M_SOF10 = 0xCA, |
XkLi | 0:c546b51ecf0b | 33 | M_SOF11 = 0xCB, |
XkLi | 0:c546b51ecf0b | 34 | |
XkLi | 0:c546b51ecf0b | 35 | M_SOF13 = 0xCD, |
XkLi | 0:c546b51ecf0b | 36 | M_SOF14 = 0xCE, |
XkLi | 0:c546b51ecf0b | 37 | M_SOF15 = 0xCF, |
XkLi | 0:c546b51ecf0b | 38 | |
XkLi | 0:c546b51ecf0b | 39 | M_DHT = 0xC4, |
XkLi | 0:c546b51ecf0b | 40 | |
XkLi | 0:c546b51ecf0b | 41 | M_DAC = 0xCC, |
XkLi | 0:c546b51ecf0b | 42 | |
XkLi | 0:c546b51ecf0b | 43 | M_RST0 = 0xD0, |
XkLi | 0:c546b51ecf0b | 44 | M_RST1 = 0xD1, |
XkLi | 0:c546b51ecf0b | 45 | M_RST2 = 0xD2, |
XkLi | 0:c546b51ecf0b | 46 | M_RST3 = 0xD3, |
XkLi | 0:c546b51ecf0b | 47 | M_RST4 = 0xD4, |
XkLi | 0:c546b51ecf0b | 48 | M_RST5 = 0xD5, |
XkLi | 0:c546b51ecf0b | 49 | M_RST6 = 0xD6, |
XkLi | 0:c546b51ecf0b | 50 | M_RST7 = 0xD7, |
XkLi | 0:c546b51ecf0b | 51 | |
XkLi | 0:c546b51ecf0b | 52 | M_SOI = 0xD8, |
XkLi | 0:c546b51ecf0b | 53 | M_EOI = 0xD9, |
XkLi | 0:c546b51ecf0b | 54 | M_SOS = 0xDA, |
XkLi | 0:c546b51ecf0b | 55 | M_DQT = 0xDB, |
XkLi | 0:c546b51ecf0b | 56 | M_DNL = 0xDC, |
XkLi | 0:c546b51ecf0b | 57 | M_DRI = 0xDD, |
XkLi | 0:c546b51ecf0b | 58 | M_DHP = 0xDE, |
XkLi | 0:c546b51ecf0b | 59 | M_EXP = 0xDF, |
XkLi | 0:c546b51ecf0b | 60 | |
XkLi | 0:c546b51ecf0b | 61 | M_APP0 = 0xE0, |
XkLi | 0:c546b51ecf0b | 62 | M_APP15 = 0xEF, |
XkLi | 0:c546b51ecf0b | 63 | |
XkLi | 0:c546b51ecf0b | 64 | M_JPG0 = 0xF0, |
XkLi | 0:c546b51ecf0b | 65 | M_JPG13 = 0xFD, |
XkLi | 0:c546b51ecf0b | 66 | M_COM = 0xFE, |
XkLi | 0:c546b51ecf0b | 67 | |
XkLi | 0:c546b51ecf0b | 68 | M_TEM = 0x01, |
XkLi | 0:c546b51ecf0b | 69 | |
XkLi | 0:c546b51ecf0b | 70 | M_ERROR = 0x100 |
XkLi | 0:c546b51ecf0b | 71 | } JPEG_MARKER; |
XkLi | 0:c546b51ecf0b | 72 | |
XkLi | 0:c546b51ecf0b | 73 | #define RST0 0xD0 |
XkLi | 0:c546b51ecf0b | 74 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 75 | const int8 ZAG[] = |
XkLi | 0:c546b51ecf0b | 76 | { |
XkLi | 0:c546b51ecf0b | 77 | 0, 1, 8, 16, 9, 2, 3, 10, |
XkLi | 0:c546b51ecf0b | 78 | 17, 24, 32, 25, 18, 11, 4, 5, |
XkLi | 0:c546b51ecf0b | 79 | 12, 19, 26, 33, 40, 48, 41, 34, |
XkLi | 0:c546b51ecf0b | 80 | 27, 20, 13, 6, 7, 14, 21, 28, |
XkLi | 0:c546b51ecf0b | 81 | 35, 42, 49, 56, 57, 50, 43, 36, |
XkLi | 0:c546b51ecf0b | 82 | 29, 22, 15, 23, 30, 37, 44, 51, |
XkLi | 0:c546b51ecf0b | 83 | 58, 59, 52, 45, 38, 31, 39, 46, |
XkLi | 0:c546b51ecf0b | 84 | 53, 60, 61, 54, 47, 55, 62, 63, |
XkLi | 0:c546b51ecf0b | 85 | }; |
XkLi | 0:c546b51ecf0b | 86 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 87 | // 128 bytes |
XkLi | 0:c546b51ecf0b | 88 | static int16 gCoeffBuf[8*8]; |
XkLi | 0:c546b51ecf0b | 89 | |
XkLi | 0:c546b51ecf0b | 90 | // 8*8*4 bytes * 3 = 768 |
XkLi | 0:c546b51ecf0b | 91 | static uint8 gMCUBufR[256]; |
XkLi | 0:c546b51ecf0b | 92 | static uint8 gMCUBufG[256]; |
XkLi | 0:c546b51ecf0b | 93 | static uint8 gMCUBufB[256]; |
XkLi | 0:c546b51ecf0b | 94 | |
XkLi | 0:c546b51ecf0b | 95 | // 256 bytes |
XkLi | 0:c546b51ecf0b | 96 | static int16 gQuant0[8*8]; |
XkLi | 0:c546b51ecf0b | 97 | static int16 gQuant1[8*8]; |
XkLi | 0:c546b51ecf0b | 98 | |
XkLi | 0:c546b51ecf0b | 99 | // 6 bytes |
XkLi | 0:c546b51ecf0b | 100 | static int16 gLastDC[3]; |
XkLi | 0:c546b51ecf0b | 101 | |
XkLi | 0:c546b51ecf0b | 102 | typedef struct HuffTableT |
XkLi | 0:c546b51ecf0b | 103 | { |
XkLi | 0:c546b51ecf0b | 104 | uint16 mMinCode[16]; |
XkLi | 0:c546b51ecf0b | 105 | uint16 mMaxCode[16]; |
XkLi | 0:c546b51ecf0b | 106 | uint8 mValPtr[16]; |
XkLi | 0:c546b51ecf0b | 107 | } HuffTable; |
XkLi | 0:c546b51ecf0b | 108 | |
XkLi | 0:c546b51ecf0b | 109 | // DC - 192 |
XkLi | 0:c546b51ecf0b | 110 | static HuffTable gHuffTab0; |
XkLi | 0:c546b51ecf0b | 111 | |
XkLi | 0:c546b51ecf0b | 112 | static uint8 gHuffVal0[16]; |
XkLi | 0:c546b51ecf0b | 113 | |
XkLi | 0:c546b51ecf0b | 114 | static HuffTable gHuffTab1; |
XkLi | 0:c546b51ecf0b | 115 | static uint8 gHuffVal1[16]; |
XkLi | 0:c546b51ecf0b | 116 | |
XkLi | 0:c546b51ecf0b | 117 | // AC - 672 |
XkLi | 0:c546b51ecf0b | 118 | static HuffTable gHuffTab2; |
XkLi | 0:c546b51ecf0b | 119 | static uint8 gHuffVal2[256]; |
XkLi | 0:c546b51ecf0b | 120 | |
XkLi | 0:c546b51ecf0b | 121 | static HuffTable gHuffTab3; |
XkLi | 0:c546b51ecf0b | 122 | static uint8 gHuffVal3[256]; |
XkLi | 0:c546b51ecf0b | 123 | |
XkLi | 0:c546b51ecf0b | 124 | static uint8 gValidHuffTables; |
XkLi | 0:c546b51ecf0b | 125 | static uint8 gValidQuantTables; |
XkLi | 0:c546b51ecf0b | 126 | |
XkLi | 0:c546b51ecf0b | 127 | static uint8 gTemFlag; |
XkLi | 0:c546b51ecf0b | 128 | #define MAX_IN_BUF_SIZE 256 |
XkLi | 0:c546b51ecf0b | 129 | static uint8 gInBuf[MAX_IN_BUF_SIZE]; |
XkLi | 0:c546b51ecf0b | 130 | static uint8 gInBufOfs; |
XkLi | 0:c546b51ecf0b | 131 | static uint8 gInBufLeft; |
XkLi | 0:c546b51ecf0b | 132 | |
XkLi | 0:c546b51ecf0b | 133 | static uint16 gBitBuf; |
XkLi | 0:c546b51ecf0b | 134 | static uint8 gBitsLeft; |
XkLi | 0:c546b51ecf0b | 135 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 136 | static uint16 gImageXSize; |
XkLi | 0:c546b51ecf0b | 137 | static uint16 gImageYSize; |
XkLi | 0:c546b51ecf0b | 138 | static uint8 gCompsInFrame; |
XkLi | 0:c546b51ecf0b | 139 | static uint8 gCompIdent[3]; |
XkLi | 0:c546b51ecf0b | 140 | static uint8 gCompHSamp[3]; |
XkLi | 0:c546b51ecf0b | 141 | static uint8 gCompVSamp[3]; |
XkLi | 0:c546b51ecf0b | 142 | static uint8 gCompQuant[3]; |
XkLi | 0:c546b51ecf0b | 143 | |
XkLi | 0:c546b51ecf0b | 144 | static uint16 gRestartInterval; |
XkLi | 0:c546b51ecf0b | 145 | static uint16 gNextRestartNum; |
XkLi | 0:c546b51ecf0b | 146 | static uint16 gRestartsLeft; |
XkLi | 0:c546b51ecf0b | 147 | |
XkLi | 0:c546b51ecf0b | 148 | static uint8 gCompsInScan; |
XkLi | 0:c546b51ecf0b | 149 | static uint8 gCompList[3]; |
XkLi | 0:c546b51ecf0b | 150 | static uint8 gCompDCTab[3]; // 0,1 |
XkLi | 0:c546b51ecf0b | 151 | static uint8 gCompACTab[3]; // 0,1 |
XkLi | 0:c546b51ecf0b | 152 | |
XkLi | 0:c546b51ecf0b | 153 | static pjpeg_scan_type_t gScanType; |
XkLi | 0:c546b51ecf0b | 154 | |
XkLi | 0:c546b51ecf0b | 155 | static uint8 gMaxBlocksPerMCU; |
XkLi | 0:c546b51ecf0b | 156 | static uint8 gMaxMCUXSize; |
XkLi | 0:c546b51ecf0b | 157 | static uint8 gMaxMCUYSize; |
XkLi | 0:c546b51ecf0b | 158 | static uint16 gMaxMCUSPerRow; |
XkLi | 0:c546b51ecf0b | 159 | static uint16 gMaxMCUSPerCol; |
XkLi | 0:c546b51ecf0b | 160 | static uint16 gNumMCUSRemaining; |
XkLi | 0:c546b51ecf0b | 161 | static uint8 gMCUOrg[6]; |
XkLi | 0:c546b51ecf0b | 162 | |
XkLi | 0:c546b51ecf0b | 163 | static pjpeg_need_bytes_callback_t g_pNeedBytesCallback; |
XkLi | 0:c546b51ecf0b | 164 | static void *g_pCallback_data; |
XkLi | 0:c546b51ecf0b | 165 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 166 | static uint8 fillInBuf(void) |
XkLi | 0:c546b51ecf0b | 167 | { |
XkLi | 0:c546b51ecf0b | 168 | unsigned char status; |
XkLi | 0:c546b51ecf0b | 169 | |
XkLi | 0:c546b51ecf0b | 170 | // Reserve a few bytes at the beginning of the buffer for putting back ("stuffing") chars. |
XkLi | 0:c546b51ecf0b | 171 | gInBufOfs = 4; |
XkLi | 0:c546b51ecf0b | 172 | gInBufLeft = 0; |
XkLi | 0:c546b51ecf0b | 173 | |
XkLi | 0:c546b51ecf0b | 174 | status = (*g_pNeedBytesCallback)(gInBuf + gInBufOfs, MAX_IN_BUF_SIZE - gInBufOfs, &gInBufLeft, g_pCallback_data); |
XkLi | 0:c546b51ecf0b | 175 | if (status) |
XkLi | 0:c546b51ecf0b | 176 | return status; |
XkLi | 0:c546b51ecf0b | 177 | |
XkLi | 0:c546b51ecf0b | 178 | return 0; |
XkLi | 0:c546b51ecf0b | 179 | } |
XkLi | 0:c546b51ecf0b | 180 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 181 | static uint8 getChar(void) |
XkLi | 0:c546b51ecf0b | 182 | { |
XkLi | 0:c546b51ecf0b | 183 | if (!gInBufLeft) |
XkLi | 0:c546b51ecf0b | 184 | { |
XkLi | 0:c546b51ecf0b | 185 | fillInBuf(); |
XkLi | 0:c546b51ecf0b | 186 | if (!gInBufLeft) |
XkLi | 0:c546b51ecf0b | 187 | { |
XkLi | 0:c546b51ecf0b | 188 | gTemFlag = ~gTemFlag; |
XkLi | 0:c546b51ecf0b | 189 | return gTemFlag ? 0xFF : 0xD9; |
XkLi | 0:c546b51ecf0b | 190 | } |
XkLi | 0:c546b51ecf0b | 191 | } |
XkLi | 0:c546b51ecf0b | 192 | |
XkLi | 0:c546b51ecf0b | 193 | gInBufLeft--; |
XkLi | 0:c546b51ecf0b | 194 | return gInBuf[gInBufOfs++]; |
XkLi | 0:c546b51ecf0b | 195 | } |
XkLi | 0:c546b51ecf0b | 196 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 197 | static void stuffChar(uint8 i) |
XkLi | 0:c546b51ecf0b | 198 | { |
XkLi | 0:c546b51ecf0b | 199 | gInBufOfs--; |
XkLi | 0:c546b51ecf0b | 200 | gInBuf[gInBufOfs] = i; |
XkLi | 0:c546b51ecf0b | 201 | gInBufLeft++; |
XkLi | 0:c546b51ecf0b | 202 | } |
XkLi | 0:c546b51ecf0b | 203 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 204 | static uint8 getOctet(uint8 FFCheck) |
XkLi | 0:c546b51ecf0b | 205 | { |
XkLi | 0:c546b51ecf0b | 206 | uint8 c = getChar(); |
XkLi | 0:c546b51ecf0b | 207 | |
XkLi | 0:c546b51ecf0b | 208 | if ((FFCheck) && (c == 0xFF)) |
XkLi | 0:c546b51ecf0b | 209 | { |
XkLi | 0:c546b51ecf0b | 210 | uint8 n = getChar(); |
XkLi | 0:c546b51ecf0b | 211 | |
XkLi | 0:c546b51ecf0b | 212 | if (n) |
XkLi | 0:c546b51ecf0b | 213 | { |
XkLi | 0:c546b51ecf0b | 214 | stuffChar(n); |
XkLi | 0:c546b51ecf0b | 215 | stuffChar(0xFF); |
XkLi | 0:c546b51ecf0b | 216 | } |
XkLi | 0:c546b51ecf0b | 217 | } |
XkLi | 0:c546b51ecf0b | 218 | |
XkLi | 0:c546b51ecf0b | 219 | return c; |
XkLi | 0:c546b51ecf0b | 220 | } |
XkLi | 0:c546b51ecf0b | 221 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 222 | static uint16 getBits(uint8 numBits, uint8 FFCheck) |
XkLi | 0:c546b51ecf0b | 223 | { |
XkLi | 0:c546b51ecf0b | 224 | uint8 origBits = numBits; |
XkLi | 0:c546b51ecf0b | 225 | uint16 ret = gBitBuf; |
XkLi | 0:c546b51ecf0b | 226 | |
XkLi | 0:c546b51ecf0b | 227 | if (numBits > 8) |
XkLi | 0:c546b51ecf0b | 228 | { |
XkLi | 0:c546b51ecf0b | 229 | numBits -= 8; |
XkLi | 0:c546b51ecf0b | 230 | |
XkLi | 0:c546b51ecf0b | 231 | gBitBuf <<= gBitsLeft; |
XkLi | 0:c546b51ecf0b | 232 | |
XkLi | 0:c546b51ecf0b | 233 | gBitBuf |= getOctet(FFCheck); |
XkLi | 0:c546b51ecf0b | 234 | |
XkLi | 0:c546b51ecf0b | 235 | gBitBuf <<= (8 - gBitsLeft); |
XkLi | 0:c546b51ecf0b | 236 | |
XkLi | 0:c546b51ecf0b | 237 | ret = (ret & 0xFF00) | (gBitBuf >> 8); |
XkLi | 0:c546b51ecf0b | 238 | } |
XkLi | 0:c546b51ecf0b | 239 | |
XkLi | 0:c546b51ecf0b | 240 | if (gBitsLeft < numBits) |
XkLi | 0:c546b51ecf0b | 241 | { |
XkLi | 0:c546b51ecf0b | 242 | gBitBuf <<= gBitsLeft; |
XkLi | 0:c546b51ecf0b | 243 | |
XkLi | 0:c546b51ecf0b | 244 | gBitBuf |= getOctet(FFCheck); |
XkLi | 0:c546b51ecf0b | 245 | |
XkLi | 0:c546b51ecf0b | 246 | gBitBuf <<= (numBits - gBitsLeft); |
XkLi | 0:c546b51ecf0b | 247 | |
XkLi | 0:c546b51ecf0b | 248 | gBitsLeft = 8 - (numBits - gBitsLeft); |
XkLi | 0:c546b51ecf0b | 249 | } |
XkLi | 0:c546b51ecf0b | 250 | else |
XkLi | 0:c546b51ecf0b | 251 | { |
XkLi | 0:c546b51ecf0b | 252 | gBitsLeft = (uint8)(gBitsLeft - numBits); |
XkLi | 0:c546b51ecf0b | 253 | gBitBuf <<= numBits; |
XkLi | 0:c546b51ecf0b | 254 | } |
XkLi | 0:c546b51ecf0b | 255 | |
XkLi | 0:c546b51ecf0b | 256 | return ret >> (16 - origBits); |
XkLi | 0:c546b51ecf0b | 257 | } |
XkLi | 0:c546b51ecf0b | 258 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 259 | static uint16 getBits1(uint8 numBits) |
XkLi | 0:c546b51ecf0b | 260 | { |
XkLi | 0:c546b51ecf0b | 261 | return getBits(numBits, 0); |
XkLi | 0:c546b51ecf0b | 262 | } |
XkLi | 0:c546b51ecf0b | 263 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 264 | static uint16 getBits2(uint8 numBits) |
XkLi | 0:c546b51ecf0b | 265 | { |
XkLi | 0:c546b51ecf0b | 266 | return getBits(numBits, 1); |
XkLi | 0:c546b51ecf0b | 267 | } |
XkLi | 0:c546b51ecf0b | 268 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 269 | static uint8 getBit(void) |
XkLi | 0:c546b51ecf0b | 270 | { |
XkLi | 0:c546b51ecf0b | 271 | uint8 ret = 0; |
XkLi | 0:c546b51ecf0b | 272 | if (gBitBuf & 0x8000) |
XkLi | 0:c546b51ecf0b | 273 | ret = 1; |
XkLi | 0:c546b51ecf0b | 274 | |
XkLi | 0:c546b51ecf0b | 275 | if (!gBitsLeft) |
XkLi | 0:c546b51ecf0b | 276 | { |
XkLi | 0:c546b51ecf0b | 277 | gBitBuf |= getOctet(1); |
XkLi | 0:c546b51ecf0b | 278 | |
XkLi | 0:c546b51ecf0b | 279 | gBitsLeft += 8; |
XkLi | 0:c546b51ecf0b | 280 | } |
XkLi | 0:c546b51ecf0b | 281 | |
XkLi | 0:c546b51ecf0b | 282 | gBitsLeft--; |
XkLi | 0:c546b51ecf0b | 283 | gBitBuf <<= 1; |
XkLi | 0:c546b51ecf0b | 284 | |
XkLi | 0:c546b51ecf0b | 285 | return ret; |
XkLi | 0:c546b51ecf0b | 286 | } |
XkLi | 0:c546b51ecf0b | 287 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 288 | static uint16 getExtendTest(uint8 i) |
XkLi | 0:c546b51ecf0b | 289 | { |
XkLi | 0:c546b51ecf0b | 290 | switch (i) |
XkLi | 0:c546b51ecf0b | 291 | { |
XkLi | 0:c546b51ecf0b | 292 | case 0: return 0; |
XkLi | 0:c546b51ecf0b | 293 | case 1: return 0x0001; |
XkLi | 0:c546b51ecf0b | 294 | case 2: return 0x0002; |
XkLi | 0:c546b51ecf0b | 295 | case 3: return 0x0004; |
XkLi | 0:c546b51ecf0b | 296 | case 4: return 0x0008; |
XkLi | 0:c546b51ecf0b | 297 | case 5: return 0x0010; |
XkLi | 0:c546b51ecf0b | 298 | case 6: return 0x0020; |
XkLi | 0:c546b51ecf0b | 299 | case 7: return 0x0040; |
XkLi | 0:c546b51ecf0b | 300 | case 8: return 0x0080; |
XkLi | 0:c546b51ecf0b | 301 | case 9: return 0x0100; |
XkLi | 0:c546b51ecf0b | 302 | case 10: return 0x0200; |
XkLi | 0:c546b51ecf0b | 303 | case 11: return 0x0400; |
XkLi | 0:c546b51ecf0b | 304 | case 12: return 0x0800; |
XkLi | 0:c546b51ecf0b | 305 | case 13: return 0x1000; |
XkLi | 0:c546b51ecf0b | 306 | case 14: return 0x2000; |
XkLi | 0:c546b51ecf0b | 307 | case 15: return 0x4000; |
XkLi | 0:c546b51ecf0b | 308 | default: return 0; |
XkLi | 0:c546b51ecf0b | 309 | } |
XkLi | 0:c546b51ecf0b | 310 | } |
XkLi | 0:c546b51ecf0b | 311 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 312 | static int16 getExtendOffset(uint8 i) |
XkLi | 0:c546b51ecf0b | 313 | { |
XkLi | 0:c546b51ecf0b | 314 | switch (i) |
XkLi | 0:c546b51ecf0b | 315 | { |
XkLi | 0:c546b51ecf0b | 316 | case 0: return 0; |
XkLi | 0:c546b51ecf0b | 317 | case 1: return ((-1)<<1) + 1; |
XkLi | 0:c546b51ecf0b | 318 | case 2: return ((-1)<<2) + 1; |
XkLi | 0:c546b51ecf0b | 319 | case 3: return ((-1)<<3) + 1; |
XkLi | 0:c546b51ecf0b | 320 | case 4: return ((-1)<<4) + 1; |
XkLi | 0:c546b51ecf0b | 321 | case 5: return ((-1)<<5) + 1; |
XkLi | 0:c546b51ecf0b | 322 | case 6: return ((-1)<<6) + 1; |
XkLi | 0:c546b51ecf0b | 323 | case 7: return ((-1)<<7) + 1; |
XkLi | 0:c546b51ecf0b | 324 | case 8: return ((-1)<<8) + 1; |
XkLi | 0:c546b51ecf0b | 325 | case 9: return ((-1)<<9) + 1; |
XkLi | 0:c546b51ecf0b | 326 | case 10: return ((-1)<<10) + 1; |
XkLi | 0:c546b51ecf0b | 327 | case 11: return ((-1)<<11) + 1; |
XkLi | 0:c546b51ecf0b | 328 | case 12: return ((-1)<<12) + 1; |
XkLi | 0:c546b51ecf0b | 329 | case 13: return ((-1)<<13) + 1; |
XkLi | 0:c546b51ecf0b | 330 | case 14: return ((-1)<<14) + 1; |
XkLi | 0:c546b51ecf0b | 331 | case 15: return ((-1)<<15) + 1; |
XkLi | 0:c546b51ecf0b | 332 | default: return 0; |
XkLi | 0:c546b51ecf0b | 333 | } |
XkLi | 0:c546b51ecf0b | 334 | }; |
XkLi | 0:c546b51ecf0b | 335 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 336 | static int16 huffExtend(uint16 x, uint8 s) |
XkLi | 0:c546b51ecf0b | 337 | { |
XkLi | 0:c546b51ecf0b | 338 | return ((x < getExtendTest(s)) ? ((int16)x + getExtendOffset(s)) : (int16)x); |
XkLi | 0:c546b51ecf0b | 339 | } |
XkLi | 0:c546b51ecf0b | 340 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 341 | static uint8 huffDecode(const HuffTable* pHuffTable, const uint8* pHuffVal) |
XkLi | 0:c546b51ecf0b | 342 | { |
XkLi | 0:c546b51ecf0b | 343 | uint8 i = 0; |
XkLi | 0:c546b51ecf0b | 344 | uint8 j; |
XkLi | 0:c546b51ecf0b | 345 | uint16 code = getBit(); |
XkLi | 0:c546b51ecf0b | 346 | |
XkLi | 0:c546b51ecf0b | 347 | for ( ; ; ) |
XkLi | 0:c546b51ecf0b | 348 | { |
XkLi | 0:c546b51ecf0b | 349 | uint16 maxCode; |
XkLi | 0:c546b51ecf0b | 350 | |
XkLi | 0:c546b51ecf0b | 351 | if (i == 16) |
XkLi | 0:c546b51ecf0b | 352 | return 0; |
XkLi | 0:c546b51ecf0b | 353 | |
XkLi | 0:c546b51ecf0b | 354 | maxCode = pHuffTable->mMaxCode[i]; |
XkLi | 0:c546b51ecf0b | 355 | if ((code <= maxCode) && (maxCode != 0xFFFF)) |
XkLi | 0:c546b51ecf0b | 356 | break; |
XkLi | 0:c546b51ecf0b | 357 | |
XkLi | 0:c546b51ecf0b | 358 | i++; |
XkLi | 0:c546b51ecf0b | 359 | code <<= 1; |
XkLi | 0:c546b51ecf0b | 360 | code |= getBit(); |
XkLi | 0:c546b51ecf0b | 361 | } |
XkLi | 0:c546b51ecf0b | 362 | |
XkLi | 0:c546b51ecf0b | 363 | j = pHuffTable->mValPtr[i]; |
XkLi | 0:c546b51ecf0b | 364 | j = (uint8)(j + (code - pHuffTable->mMinCode[i])); |
XkLi | 0:c546b51ecf0b | 365 | |
XkLi | 0:c546b51ecf0b | 366 | return pHuffVal[j]; |
XkLi | 0:c546b51ecf0b | 367 | } |
XkLi | 0:c546b51ecf0b | 368 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 369 | static void huffCreate(const uint8* pBits, HuffTable* pHuffTable) |
XkLi | 0:c546b51ecf0b | 370 | { |
XkLi | 0:c546b51ecf0b | 371 | uint8 i = 0; |
XkLi | 0:c546b51ecf0b | 372 | uint8 j = 0; |
XkLi | 0:c546b51ecf0b | 373 | |
XkLi | 0:c546b51ecf0b | 374 | uint16 code = 0; |
XkLi | 0:c546b51ecf0b | 375 | |
XkLi | 0:c546b51ecf0b | 376 | for ( ; ; ) |
XkLi | 0:c546b51ecf0b | 377 | { |
XkLi | 0:c546b51ecf0b | 378 | uint8 num = pBits[i]; |
XkLi | 0:c546b51ecf0b | 379 | |
XkLi | 0:c546b51ecf0b | 380 | if (!num) |
XkLi | 0:c546b51ecf0b | 381 | { |
XkLi | 0:c546b51ecf0b | 382 | pHuffTable->mMinCode[i] = 0x0000; |
XkLi | 0:c546b51ecf0b | 383 | pHuffTable->mMaxCode[i] = 0xFFFF; |
XkLi | 0:c546b51ecf0b | 384 | pHuffTable->mValPtr[i] = 0; |
XkLi | 0:c546b51ecf0b | 385 | } |
XkLi | 0:c546b51ecf0b | 386 | else |
XkLi | 0:c546b51ecf0b | 387 | { |
XkLi | 0:c546b51ecf0b | 388 | pHuffTable->mMinCode[i] = code; |
XkLi | 0:c546b51ecf0b | 389 | pHuffTable->mMaxCode[i] = code + num - 1; |
XkLi | 0:c546b51ecf0b | 390 | pHuffTable->mValPtr[i] = j; |
XkLi | 0:c546b51ecf0b | 391 | |
XkLi | 0:c546b51ecf0b | 392 | j = (uint8)(j + num); |
XkLi | 0:c546b51ecf0b | 393 | |
XkLi | 0:c546b51ecf0b | 394 | code = (uint16)(code + num); |
XkLi | 0:c546b51ecf0b | 395 | } |
XkLi | 0:c546b51ecf0b | 396 | |
XkLi | 0:c546b51ecf0b | 397 | code <<= 1; |
XkLi | 0:c546b51ecf0b | 398 | |
XkLi | 0:c546b51ecf0b | 399 | i++; |
XkLi | 0:c546b51ecf0b | 400 | if (i > 15) |
XkLi | 0:c546b51ecf0b | 401 | break; |
XkLi | 0:c546b51ecf0b | 402 | } |
XkLi | 0:c546b51ecf0b | 403 | } |
XkLi | 0:c546b51ecf0b | 404 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 405 | static HuffTable* getHuffTable(uint8 index) |
XkLi | 0:c546b51ecf0b | 406 | { |
XkLi | 0:c546b51ecf0b | 407 | // 0-1 = DC |
XkLi | 0:c546b51ecf0b | 408 | // 2-3 = AC |
XkLi | 0:c546b51ecf0b | 409 | switch (index) |
XkLi | 0:c546b51ecf0b | 410 | { |
XkLi | 0:c546b51ecf0b | 411 | case 0: return &gHuffTab0; |
XkLi | 0:c546b51ecf0b | 412 | case 1: return &gHuffTab1; |
XkLi | 0:c546b51ecf0b | 413 | case 2: return &gHuffTab2; |
XkLi | 0:c546b51ecf0b | 414 | case 3: return &gHuffTab3; |
XkLi | 0:c546b51ecf0b | 415 | default: return 0; |
XkLi | 0:c546b51ecf0b | 416 | } |
XkLi | 0:c546b51ecf0b | 417 | } |
XkLi | 0:c546b51ecf0b | 418 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 419 | static uint8* getHuffVal(uint8 index) |
XkLi | 0:c546b51ecf0b | 420 | { |
XkLi | 0:c546b51ecf0b | 421 | // 0-1 = DC |
XkLi | 0:c546b51ecf0b | 422 | // 2-3 = AC |
XkLi | 0:c546b51ecf0b | 423 | switch (index) |
XkLi | 0:c546b51ecf0b | 424 | { |
XkLi | 0:c546b51ecf0b | 425 | case 0: return gHuffVal0; |
XkLi | 0:c546b51ecf0b | 426 | case 1: return gHuffVal1; |
XkLi | 0:c546b51ecf0b | 427 | case 2: return gHuffVal2; |
XkLi | 0:c546b51ecf0b | 428 | case 3: return gHuffVal3; |
XkLi | 0:c546b51ecf0b | 429 | default: return 0; |
XkLi | 0:c546b51ecf0b | 430 | } |
XkLi | 0:c546b51ecf0b | 431 | } |
XkLi | 0:c546b51ecf0b | 432 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 433 | static uint16 getMaxHuffCodes(uint8 index) |
XkLi | 0:c546b51ecf0b | 434 | { |
XkLi | 0:c546b51ecf0b | 435 | return (index < 2) ? 12 : 255; |
XkLi | 0:c546b51ecf0b | 436 | } |
XkLi | 0:c546b51ecf0b | 437 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 438 | static uint8 readDHTMarker(void) |
XkLi | 0:c546b51ecf0b | 439 | { |
XkLi | 0:c546b51ecf0b | 440 | uint8 bits[16]; |
XkLi | 0:c546b51ecf0b | 441 | uint16 left = getBits1(16); |
XkLi | 0:c546b51ecf0b | 442 | |
XkLi | 0:c546b51ecf0b | 443 | if (left < 2) |
XkLi | 0:c546b51ecf0b | 444 | return PJPG_BAD_DHT_MARKER; |
XkLi | 0:c546b51ecf0b | 445 | |
XkLi | 0:c546b51ecf0b | 446 | left -= 2; |
XkLi | 0:c546b51ecf0b | 447 | |
XkLi | 0:c546b51ecf0b | 448 | while (left) |
XkLi | 0:c546b51ecf0b | 449 | { |
XkLi | 0:c546b51ecf0b | 450 | uint8 i, tableIndex, index; |
XkLi | 0:c546b51ecf0b | 451 | uint8* pHuffVal; |
XkLi | 0:c546b51ecf0b | 452 | HuffTable* pHuffTable; |
XkLi | 0:c546b51ecf0b | 453 | uint16 count, totalRead; |
XkLi | 0:c546b51ecf0b | 454 | |
XkLi | 0:c546b51ecf0b | 455 | index = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 456 | |
XkLi | 0:c546b51ecf0b | 457 | if ( ((index & 0xF) > 1) || ((index & 0xF0) > 0x10) ) |
XkLi | 0:c546b51ecf0b | 458 | return PJPG_BAD_DHT_INDEX; |
XkLi | 0:c546b51ecf0b | 459 | |
XkLi | 0:c546b51ecf0b | 460 | tableIndex = ((index >> 3) & 2) + (index & 1); |
XkLi | 0:c546b51ecf0b | 461 | |
XkLi | 0:c546b51ecf0b | 462 | pHuffTable = getHuffTable(tableIndex); |
XkLi | 0:c546b51ecf0b | 463 | pHuffVal = getHuffVal(tableIndex); |
XkLi | 0:c546b51ecf0b | 464 | |
XkLi | 0:c546b51ecf0b | 465 | gValidHuffTables |= (1 << tableIndex); |
XkLi | 0:c546b51ecf0b | 466 | |
XkLi | 0:c546b51ecf0b | 467 | count = 0; |
XkLi | 0:c546b51ecf0b | 468 | for (i = 0; i <= 15; i++) |
XkLi | 0:c546b51ecf0b | 469 | { |
XkLi | 0:c546b51ecf0b | 470 | uint8 n = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 471 | bits[i] = n; |
XkLi | 0:c546b51ecf0b | 472 | count = (uint16)(count + n); |
XkLi | 0:c546b51ecf0b | 473 | } |
XkLi | 0:c546b51ecf0b | 474 | |
XkLi | 0:c546b51ecf0b | 475 | if (count > getMaxHuffCodes(tableIndex)) |
XkLi | 0:c546b51ecf0b | 476 | return PJPG_BAD_DHT_COUNTS; |
XkLi | 0:c546b51ecf0b | 477 | |
XkLi | 0:c546b51ecf0b | 478 | for (i = 0; i < count; i++) |
XkLi | 0:c546b51ecf0b | 479 | pHuffVal[i] = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 480 | |
XkLi | 0:c546b51ecf0b | 481 | totalRead = 1 + 16 + count; |
XkLi | 0:c546b51ecf0b | 482 | |
XkLi | 0:c546b51ecf0b | 483 | if (left < totalRead) |
XkLi | 0:c546b51ecf0b | 484 | return PJPG_BAD_DHT_MARKER; |
XkLi | 0:c546b51ecf0b | 485 | |
XkLi | 0:c546b51ecf0b | 486 | left = (uint16)(left - totalRead); |
XkLi | 0:c546b51ecf0b | 487 | |
XkLi | 0:c546b51ecf0b | 488 | huffCreate(bits, pHuffTable); |
XkLi | 0:c546b51ecf0b | 489 | } |
XkLi | 0:c546b51ecf0b | 490 | |
XkLi | 0:c546b51ecf0b | 491 | return 0; |
XkLi | 0:c546b51ecf0b | 492 | } |
XkLi | 0:c546b51ecf0b | 493 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 494 | static void createWinogradQuant(int16* pQuant); |
XkLi | 0:c546b51ecf0b | 495 | |
XkLi | 0:c546b51ecf0b | 496 | static uint8 readDQTMarker(void) |
XkLi | 0:c546b51ecf0b | 497 | { |
XkLi | 0:c546b51ecf0b | 498 | uint16 left = getBits1(16); |
XkLi | 0:c546b51ecf0b | 499 | |
XkLi | 0:c546b51ecf0b | 500 | if (left < 2) |
XkLi | 0:c546b51ecf0b | 501 | return PJPG_BAD_DQT_MARKER; |
XkLi | 0:c546b51ecf0b | 502 | |
XkLi | 0:c546b51ecf0b | 503 | left -= 2; |
XkLi | 0:c546b51ecf0b | 504 | |
XkLi | 0:c546b51ecf0b | 505 | while (left) |
XkLi | 0:c546b51ecf0b | 506 | { |
XkLi | 0:c546b51ecf0b | 507 | uint8 i; |
XkLi | 0:c546b51ecf0b | 508 | uint8 n = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 509 | uint8 prec = n >> 4; |
XkLi | 0:c546b51ecf0b | 510 | uint16 totalRead; |
XkLi | 0:c546b51ecf0b | 511 | |
XkLi | 0:c546b51ecf0b | 512 | n &= 0x0F; |
XkLi | 0:c546b51ecf0b | 513 | |
XkLi | 0:c546b51ecf0b | 514 | if (n > 1) |
XkLi | 0:c546b51ecf0b | 515 | return PJPG_BAD_DQT_TABLE; |
XkLi | 0:c546b51ecf0b | 516 | |
XkLi | 0:c546b51ecf0b | 517 | gValidQuantTables |= (n ? 2 : 1); |
XkLi | 0:c546b51ecf0b | 518 | |
XkLi | 0:c546b51ecf0b | 519 | // read quantization entries, in zag order |
XkLi | 0:c546b51ecf0b | 520 | for (i = 0; i < 64; i++) |
XkLi | 0:c546b51ecf0b | 521 | { |
XkLi | 0:c546b51ecf0b | 522 | uint16 temp = getBits1(8); |
XkLi | 0:c546b51ecf0b | 523 | |
XkLi | 0:c546b51ecf0b | 524 | if (prec) |
XkLi | 0:c546b51ecf0b | 525 | temp = (temp << 8) + getBits1(8); |
XkLi | 0:c546b51ecf0b | 526 | |
XkLi | 0:c546b51ecf0b | 527 | if (n) |
XkLi | 0:c546b51ecf0b | 528 | gQuant1[i] = (int16)temp; |
XkLi | 0:c546b51ecf0b | 529 | else |
XkLi | 0:c546b51ecf0b | 530 | gQuant0[i] = (int16)temp; |
XkLi | 0:c546b51ecf0b | 531 | } |
XkLi | 0:c546b51ecf0b | 532 | |
XkLi | 0:c546b51ecf0b | 533 | createWinogradQuant(n ? gQuant1 : gQuant0); |
XkLi | 0:c546b51ecf0b | 534 | |
XkLi | 0:c546b51ecf0b | 535 | totalRead = 64 + 1; |
XkLi | 0:c546b51ecf0b | 536 | |
XkLi | 0:c546b51ecf0b | 537 | if (prec) |
XkLi | 0:c546b51ecf0b | 538 | totalRead += 64; |
XkLi | 0:c546b51ecf0b | 539 | |
XkLi | 0:c546b51ecf0b | 540 | if (left < totalRead) |
XkLi | 0:c546b51ecf0b | 541 | return PJPG_BAD_DQT_LENGTH; |
XkLi | 0:c546b51ecf0b | 542 | |
XkLi | 0:c546b51ecf0b | 543 | left = (uint16)(left - totalRead); |
XkLi | 0:c546b51ecf0b | 544 | } |
XkLi | 0:c546b51ecf0b | 545 | |
XkLi | 0:c546b51ecf0b | 546 | return 0; |
XkLi | 0:c546b51ecf0b | 547 | } |
XkLi | 0:c546b51ecf0b | 548 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 549 | static uint8 readSOFMarker(void) |
XkLi | 0:c546b51ecf0b | 550 | { |
XkLi | 0:c546b51ecf0b | 551 | uint8 i; |
XkLi | 0:c546b51ecf0b | 552 | uint16 left = getBits1(16); |
XkLi | 0:c546b51ecf0b | 553 | |
XkLi | 0:c546b51ecf0b | 554 | if (getBits1(8) != 8) |
XkLi | 0:c546b51ecf0b | 555 | return PJPG_BAD_PRECISION; |
XkLi | 0:c546b51ecf0b | 556 | |
XkLi | 0:c546b51ecf0b | 557 | gImageYSize = getBits1(16); |
XkLi | 0:c546b51ecf0b | 558 | |
XkLi | 0:c546b51ecf0b | 559 | if ((!gImageYSize) || (gImageYSize > PJPG_MAX_HEIGHT)) |
XkLi | 0:c546b51ecf0b | 560 | return PJPG_BAD_HEIGHT; |
XkLi | 0:c546b51ecf0b | 561 | |
XkLi | 0:c546b51ecf0b | 562 | gImageXSize = getBits1(16); |
XkLi | 0:c546b51ecf0b | 563 | |
XkLi | 0:c546b51ecf0b | 564 | if ((!gImageXSize) || (gImageXSize > PJPG_MAX_WIDTH)) |
XkLi | 0:c546b51ecf0b | 565 | return PJPG_BAD_WIDTH; |
XkLi | 0:c546b51ecf0b | 566 | |
XkLi | 0:c546b51ecf0b | 567 | gCompsInFrame = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 568 | |
XkLi | 0:c546b51ecf0b | 569 | if (gCompsInFrame > 3) |
XkLi | 0:c546b51ecf0b | 570 | return PJPG_TOO_MANY_COMPONENTS; |
XkLi | 0:c546b51ecf0b | 571 | |
XkLi | 0:c546b51ecf0b | 572 | if (left != (gCompsInFrame + gCompsInFrame + gCompsInFrame + 8)) |
XkLi | 0:c546b51ecf0b | 573 | return PJPG_BAD_SOF_LENGTH; |
XkLi | 0:c546b51ecf0b | 574 | |
XkLi | 0:c546b51ecf0b | 575 | for (i = 0; i < gCompsInFrame; i++) |
XkLi | 0:c546b51ecf0b | 576 | { |
XkLi | 0:c546b51ecf0b | 577 | gCompIdent[i] = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 578 | gCompHSamp[i] = (uint8)getBits1(4); |
XkLi | 0:c546b51ecf0b | 579 | gCompVSamp[i] = (uint8)getBits1(4); |
XkLi | 0:c546b51ecf0b | 580 | gCompQuant[i] = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 581 | |
XkLi | 0:c546b51ecf0b | 582 | if (gCompQuant[i] > 1) |
XkLi | 0:c546b51ecf0b | 583 | return PJPG_UNSUPPORTED_QUANT_TABLE; |
XkLi | 0:c546b51ecf0b | 584 | } |
XkLi | 0:c546b51ecf0b | 585 | |
XkLi | 0:c546b51ecf0b | 586 | return 0; |
XkLi | 0:c546b51ecf0b | 587 | } |
XkLi | 0:c546b51ecf0b | 588 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 589 | // Used to skip unrecognized markers. |
XkLi | 0:c546b51ecf0b | 590 | static uint8 skipVariableMarker(void) |
XkLi | 0:c546b51ecf0b | 591 | { |
XkLi | 0:c546b51ecf0b | 592 | uint16 left = getBits1(16); |
XkLi | 0:c546b51ecf0b | 593 | |
XkLi | 0:c546b51ecf0b | 594 | if (left < 2) |
XkLi | 0:c546b51ecf0b | 595 | return PJPG_BAD_VARIABLE_MARKER; |
XkLi | 0:c546b51ecf0b | 596 | |
XkLi | 0:c546b51ecf0b | 597 | left -= 2; |
XkLi | 0:c546b51ecf0b | 598 | |
XkLi | 0:c546b51ecf0b | 599 | while (left) |
XkLi | 0:c546b51ecf0b | 600 | { |
XkLi | 0:c546b51ecf0b | 601 | getBits1(8); |
XkLi | 0:c546b51ecf0b | 602 | left--; |
XkLi | 0:c546b51ecf0b | 603 | } |
XkLi | 0:c546b51ecf0b | 604 | |
XkLi | 0:c546b51ecf0b | 605 | return 0; |
XkLi | 0:c546b51ecf0b | 606 | } |
XkLi | 0:c546b51ecf0b | 607 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 608 | // Read a define restart interval (DRI) marker. |
XkLi | 0:c546b51ecf0b | 609 | static uint8 readDRIMarker(void) |
XkLi | 0:c546b51ecf0b | 610 | { |
XkLi | 0:c546b51ecf0b | 611 | if (getBits1(16) != 4) |
XkLi | 0:c546b51ecf0b | 612 | return PJPG_BAD_DRI_LENGTH; |
XkLi | 0:c546b51ecf0b | 613 | |
XkLi | 0:c546b51ecf0b | 614 | gRestartInterval = getBits1(16); |
XkLi | 0:c546b51ecf0b | 615 | |
XkLi | 0:c546b51ecf0b | 616 | return 0; |
XkLi | 0:c546b51ecf0b | 617 | } |
XkLi | 0:c546b51ecf0b | 618 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 619 | // Read a start of scan (SOS) marker. |
XkLi | 0:c546b51ecf0b | 620 | static uint8 readSOSMarker(void) |
XkLi | 0:c546b51ecf0b | 621 | { |
XkLi | 0:c546b51ecf0b | 622 | uint8 i; |
XkLi | 0:c546b51ecf0b | 623 | uint16 left = getBits1(16); |
XkLi | 0:c546b51ecf0b | 624 | uint8 spectral_start, spectral_end, successive_high, successive_low; |
XkLi | 0:c546b51ecf0b | 625 | |
XkLi | 0:c546b51ecf0b | 626 | gCompsInScan = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 627 | |
XkLi | 0:c546b51ecf0b | 628 | left -= 3; |
XkLi | 0:c546b51ecf0b | 629 | |
XkLi | 0:c546b51ecf0b | 630 | if ( (left != (gCompsInScan + gCompsInScan + 3)) || (gCompsInScan < 1) || (gCompsInScan > PJPG_MAXCOMPSINSCAN) ) |
XkLi | 0:c546b51ecf0b | 631 | return PJPG_BAD_SOS_LENGTH; |
XkLi | 0:c546b51ecf0b | 632 | |
XkLi | 0:c546b51ecf0b | 633 | for (i = 0; i < gCompsInScan; i++) |
XkLi | 0:c546b51ecf0b | 634 | { |
XkLi | 0:c546b51ecf0b | 635 | uint8 cc = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 636 | uint8 c = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 637 | uint8 ci; |
XkLi | 0:c546b51ecf0b | 638 | |
XkLi | 0:c546b51ecf0b | 639 | left -= 2; |
XkLi | 0:c546b51ecf0b | 640 | |
XkLi | 0:c546b51ecf0b | 641 | for (ci = 0; ci < gCompsInFrame; ci++) |
XkLi | 0:c546b51ecf0b | 642 | if (cc == gCompIdent[ci]) |
XkLi | 0:c546b51ecf0b | 643 | break; |
XkLi | 0:c546b51ecf0b | 644 | |
XkLi | 0:c546b51ecf0b | 645 | if (ci >= gCompsInFrame) |
XkLi | 0:c546b51ecf0b | 646 | return PJPG_BAD_SOS_COMP_ID; |
XkLi | 0:c546b51ecf0b | 647 | |
XkLi | 0:c546b51ecf0b | 648 | gCompList[i] = ci; |
XkLi | 0:c546b51ecf0b | 649 | gCompDCTab[ci] = (c >> 4) & 15; |
XkLi | 0:c546b51ecf0b | 650 | gCompACTab[ci] = (c & 15); |
XkLi | 0:c546b51ecf0b | 651 | } |
XkLi | 0:c546b51ecf0b | 652 | |
XkLi | 0:c546b51ecf0b | 653 | spectral_start = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 654 | spectral_end = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 655 | successive_high = (uint8)getBits1(4); |
XkLi | 0:c546b51ecf0b | 656 | successive_low = (uint8)getBits1(4); |
XkLi | 0:c546b51ecf0b | 657 | |
XkLi | 0:c546b51ecf0b | 658 | left -= 3; |
XkLi | 0:c546b51ecf0b | 659 | |
XkLi | 0:c546b51ecf0b | 660 | while (left) |
XkLi | 0:c546b51ecf0b | 661 | { |
XkLi | 0:c546b51ecf0b | 662 | getBits1(8); |
XkLi | 0:c546b51ecf0b | 663 | left--; |
XkLi | 0:c546b51ecf0b | 664 | } |
XkLi | 0:c546b51ecf0b | 665 | |
XkLi | 0:c546b51ecf0b | 666 | return 0; |
XkLi | 0:c546b51ecf0b | 667 | } |
XkLi | 0:c546b51ecf0b | 668 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 669 | static uint8 nextMarker(void) |
XkLi | 0:c546b51ecf0b | 670 | { |
XkLi | 0:c546b51ecf0b | 671 | uint8 c; |
XkLi | 0:c546b51ecf0b | 672 | uint8 bytes = 0; |
XkLi | 0:c546b51ecf0b | 673 | |
XkLi | 0:c546b51ecf0b | 674 | do |
XkLi | 0:c546b51ecf0b | 675 | { |
XkLi | 0:c546b51ecf0b | 676 | do |
XkLi | 0:c546b51ecf0b | 677 | { |
XkLi | 0:c546b51ecf0b | 678 | bytes++; |
XkLi | 0:c546b51ecf0b | 679 | |
XkLi | 0:c546b51ecf0b | 680 | c = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 681 | |
XkLi | 0:c546b51ecf0b | 682 | } while (c != 0xFF); |
XkLi | 0:c546b51ecf0b | 683 | |
XkLi | 0:c546b51ecf0b | 684 | do |
XkLi | 0:c546b51ecf0b | 685 | { |
XkLi | 0:c546b51ecf0b | 686 | c = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 687 | |
XkLi | 0:c546b51ecf0b | 688 | } while (c == 0xFF); |
XkLi | 0:c546b51ecf0b | 689 | |
XkLi | 0:c546b51ecf0b | 690 | } while (c == 0); |
XkLi | 0:c546b51ecf0b | 691 | |
XkLi | 0:c546b51ecf0b | 692 | // If bytes > 0 here, there where extra bytes before the marker (not good). |
XkLi | 0:c546b51ecf0b | 693 | |
XkLi | 0:c546b51ecf0b | 694 | return c; |
XkLi | 0:c546b51ecf0b | 695 | } |
XkLi | 0:c546b51ecf0b | 696 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 697 | // Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is |
XkLi | 0:c546b51ecf0b | 698 | // encountered. |
XkLi | 0:c546b51ecf0b | 699 | static uint8 processMarkers(uint8* pMarker) |
XkLi | 0:c546b51ecf0b | 700 | { |
XkLi | 0:c546b51ecf0b | 701 | for ( ; ; ) |
XkLi | 0:c546b51ecf0b | 702 | { |
XkLi | 0:c546b51ecf0b | 703 | uint8 c = nextMarker(); |
XkLi | 0:c546b51ecf0b | 704 | |
XkLi | 0:c546b51ecf0b | 705 | switch (c) |
XkLi | 0:c546b51ecf0b | 706 | { |
XkLi | 0:c546b51ecf0b | 707 | case M_SOF0: |
XkLi | 0:c546b51ecf0b | 708 | case M_SOF1: |
XkLi | 0:c546b51ecf0b | 709 | case M_SOF2: |
XkLi | 0:c546b51ecf0b | 710 | case M_SOF3: |
XkLi | 0:c546b51ecf0b | 711 | case M_SOF5: |
XkLi | 0:c546b51ecf0b | 712 | case M_SOF6: |
XkLi | 0:c546b51ecf0b | 713 | case M_SOF7: |
XkLi | 0:c546b51ecf0b | 714 | // case M_JPG: |
XkLi | 0:c546b51ecf0b | 715 | case M_SOF9: |
XkLi | 0:c546b51ecf0b | 716 | case M_SOF10: |
XkLi | 0:c546b51ecf0b | 717 | case M_SOF11: |
XkLi | 0:c546b51ecf0b | 718 | case M_SOF13: |
XkLi | 0:c546b51ecf0b | 719 | case M_SOF14: |
XkLi | 0:c546b51ecf0b | 720 | case M_SOF15: |
XkLi | 0:c546b51ecf0b | 721 | case M_SOI: |
XkLi | 0:c546b51ecf0b | 722 | case M_EOI: |
XkLi | 0:c546b51ecf0b | 723 | case M_SOS: |
XkLi | 0:c546b51ecf0b | 724 | { |
XkLi | 0:c546b51ecf0b | 725 | *pMarker = c; |
XkLi | 0:c546b51ecf0b | 726 | return 0; |
XkLi | 0:c546b51ecf0b | 727 | } |
XkLi | 0:c546b51ecf0b | 728 | case M_DHT: |
XkLi | 0:c546b51ecf0b | 729 | { |
XkLi | 0:c546b51ecf0b | 730 | readDHTMarker(); |
XkLi | 0:c546b51ecf0b | 731 | break; |
XkLi | 0:c546b51ecf0b | 732 | } |
XkLi | 0:c546b51ecf0b | 733 | // Sorry, no arithmitic support at this time. Dumb patents! |
XkLi | 0:c546b51ecf0b | 734 | case M_DAC: |
XkLi | 0:c546b51ecf0b | 735 | { |
XkLi | 0:c546b51ecf0b | 736 | return PJPG_NO_ARITHMITIC_SUPPORT; |
XkLi | 0:c546b51ecf0b | 737 | } |
XkLi | 0:c546b51ecf0b | 738 | case M_DQT: |
XkLi | 0:c546b51ecf0b | 739 | { |
XkLi | 0:c546b51ecf0b | 740 | readDQTMarker(); |
XkLi | 0:c546b51ecf0b | 741 | break; |
XkLi | 0:c546b51ecf0b | 742 | } |
XkLi | 0:c546b51ecf0b | 743 | case M_DRI: |
XkLi | 0:c546b51ecf0b | 744 | { |
XkLi | 0:c546b51ecf0b | 745 | readDRIMarker(); |
XkLi | 0:c546b51ecf0b | 746 | break; |
XkLi | 0:c546b51ecf0b | 747 | } |
XkLi | 0:c546b51ecf0b | 748 | //case M_APP0: /* no need to read the JFIF marker */ |
XkLi | 0:c546b51ecf0b | 749 | |
XkLi | 0:c546b51ecf0b | 750 | case M_JPG: |
XkLi | 0:c546b51ecf0b | 751 | case M_RST0: /* no parameters */ |
XkLi | 0:c546b51ecf0b | 752 | case M_RST1: |
XkLi | 0:c546b51ecf0b | 753 | case M_RST2: |
XkLi | 0:c546b51ecf0b | 754 | case M_RST3: |
XkLi | 0:c546b51ecf0b | 755 | case M_RST4: |
XkLi | 0:c546b51ecf0b | 756 | case M_RST5: |
XkLi | 0:c546b51ecf0b | 757 | case M_RST6: |
XkLi | 0:c546b51ecf0b | 758 | case M_RST7: |
XkLi | 0:c546b51ecf0b | 759 | case M_TEM: |
XkLi | 0:c546b51ecf0b | 760 | { |
XkLi | 0:c546b51ecf0b | 761 | return PJPG_UNEXPECTED_MARKER; |
XkLi | 0:c546b51ecf0b | 762 | } |
XkLi | 0:c546b51ecf0b | 763 | default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */ |
XkLi | 0:c546b51ecf0b | 764 | { |
XkLi | 0:c546b51ecf0b | 765 | skipVariableMarker(); |
XkLi | 0:c546b51ecf0b | 766 | break; |
XkLi | 0:c546b51ecf0b | 767 | } |
XkLi | 0:c546b51ecf0b | 768 | } |
XkLi | 0:c546b51ecf0b | 769 | } |
XkLi | 0:c546b51ecf0b | 770 | // return 0; |
XkLi | 0:c546b51ecf0b | 771 | } |
XkLi | 0:c546b51ecf0b | 772 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 773 | // Finds the start of image (SOI) marker. |
XkLi | 0:c546b51ecf0b | 774 | static uint8 locateSOIMarker(void) |
XkLi | 0:c546b51ecf0b | 775 | { |
XkLi | 0:c546b51ecf0b | 776 | uint16 bytesleft; |
XkLi | 0:c546b51ecf0b | 777 | |
XkLi | 0:c546b51ecf0b | 778 | uint8 lastchar = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 779 | |
XkLi | 0:c546b51ecf0b | 780 | uint8 thischar = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 781 | |
XkLi | 0:c546b51ecf0b | 782 | /* ok if it's a normal JPEG file without a special header */ |
XkLi | 0:c546b51ecf0b | 783 | |
XkLi | 0:c546b51ecf0b | 784 | if ((lastchar == 0xFF) && (thischar == M_SOI)) |
XkLi | 0:c546b51ecf0b | 785 | return 0; |
XkLi | 0:c546b51ecf0b | 786 | |
XkLi | 0:c546b51ecf0b | 787 | bytesleft = 4096; //512; |
XkLi | 0:c546b51ecf0b | 788 | |
XkLi | 0:c546b51ecf0b | 789 | for ( ; ; ) |
XkLi | 0:c546b51ecf0b | 790 | { |
XkLi | 0:c546b51ecf0b | 791 | if (--bytesleft == 0) |
XkLi | 0:c546b51ecf0b | 792 | return PJPG_NOT_JPEG; |
XkLi | 0:c546b51ecf0b | 793 | |
XkLi | 0:c546b51ecf0b | 794 | lastchar = thischar; |
XkLi | 0:c546b51ecf0b | 795 | |
XkLi | 0:c546b51ecf0b | 796 | thischar = (uint8)getBits1(8); |
XkLi | 0:c546b51ecf0b | 797 | |
XkLi | 0:c546b51ecf0b | 798 | if (lastchar == 0xFF) |
XkLi | 0:c546b51ecf0b | 799 | { |
XkLi | 0:c546b51ecf0b | 800 | if (thischar == M_SOI) |
XkLi | 0:c546b51ecf0b | 801 | break; |
XkLi | 0:c546b51ecf0b | 802 | else if (thischar == M_EOI) //getBits1 will keep returning M_EOI if we read past the end |
XkLi | 0:c546b51ecf0b | 803 | return PJPG_NOT_JPEG; |
XkLi | 0:c546b51ecf0b | 804 | } |
XkLi | 0:c546b51ecf0b | 805 | } |
XkLi | 0:c546b51ecf0b | 806 | |
XkLi | 0:c546b51ecf0b | 807 | /* Check the next character after marker: if it's not 0xFF, it can't |
XkLi | 0:c546b51ecf0b | 808 | be the start of the next marker, so the file is bad */ |
XkLi | 0:c546b51ecf0b | 809 | |
XkLi | 0:c546b51ecf0b | 810 | thischar = (uint8)((gBitBuf >> 8) & 0xFF); |
XkLi | 0:c546b51ecf0b | 811 | |
XkLi | 0:c546b51ecf0b | 812 | if (thischar != 0xFF) |
XkLi | 0:c546b51ecf0b | 813 | return PJPG_NOT_JPEG; |
XkLi | 0:c546b51ecf0b | 814 | |
XkLi | 0:c546b51ecf0b | 815 | return 0; |
XkLi | 0:c546b51ecf0b | 816 | } |
XkLi | 0:c546b51ecf0b | 817 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 818 | // Find a start of frame (SOF) marker. |
XkLi | 0:c546b51ecf0b | 819 | static uint8 locateSOFMarker(void) |
XkLi | 0:c546b51ecf0b | 820 | { |
XkLi | 0:c546b51ecf0b | 821 | uint8 c; |
XkLi | 0:c546b51ecf0b | 822 | |
XkLi | 0:c546b51ecf0b | 823 | uint8 status = locateSOIMarker(); |
XkLi | 0:c546b51ecf0b | 824 | if (status) |
XkLi | 0:c546b51ecf0b | 825 | return status; |
XkLi | 0:c546b51ecf0b | 826 | |
XkLi | 0:c546b51ecf0b | 827 | status = processMarkers(&c); |
XkLi | 0:c546b51ecf0b | 828 | if (status) |
XkLi | 0:c546b51ecf0b | 829 | return status; |
XkLi | 0:c546b51ecf0b | 830 | |
XkLi | 0:c546b51ecf0b | 831 | switch (c) |
XkLi | 0:c546b51ecf0b | 832 | { |
XkLi | 0:c546b51ecf0b | 833 | case M_SOF2: |
XkLi | 0:c546b51ecf0b | 834 | { |
XkLi | 0:c546b51ecf0b | 835 | return PJPG_UNSUPPORTED_MODE; |
XkLi | 0:c546b51ecf0b | 836 | } |
XkLi | 0:c546b51ecf0b | 837 | case M_SOF0: /* baseline DCT */ |
XkLi | 0:c546b51ecf0b | 838 | { |
XkLi | 0:c546b51ecf0b | 839 | status = readSOFMarker(); |
XkLi | 0:c546b51ecf0b | 840 | if (status) |
XkLi | 0:c546b51ecf0b | 841 | return status; |
XkLi | 0:c546b51ecf0b | 842 | |
XkLi | 0:c546b51ecf0b | 843 | break; |
XkLi | 0:c546b51ecf0b | 844 | } |
XkLi | 0:c546b51ecf0b | 845 | case M_SOF9: |
XkLi | 0:c546b51ecf0b | 846 | { |
XkLi | 0:c546b51ecf0b | 847 | return PJPG_NO_ARITHMITIC_SUPPORT; |
XkLi | 0:c546b51ecf0b | 848 | } |
XkLi | 0:c546b51ecf0b | 849 | case M_SOF1: /* extended sequential DCT */ |
XkLi | 0:c546b51ecf0b | 850 | default: |
XkLi | 0:c546b51ecf0b | 851 | { |
XkLi | 0:c546b51ecf0b | 852 | return PJPG_UNSUPPORTED_MARKER; |
XkLi | 0:c546b51ecf0b | 853 | } |
XkLi | 0:c546b51ecf0b | 854 | } |
XkLi | 0:c546b51ecf0b | 855 | |
XkLi | 0:c546b51ecf0b | 856 | return 0; |
XkLi | 0:c546b51ecf0b | 857 | } |
XkLi | 0:c546b51ecf0b | 858 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 859 | // Find a start of scan (SOS) marker. |
XkLi | 0:c546b51ecf0b | 860 | static uint8 locateSOSMarker(uint8* pFoundEOI) |
XkLi | 0:c546b51ecf0b | 861 | { |
XkLi | 0:c546b51ecf0b | 862 | uint8 c; |
XkLi | 0:c546b51ecf0b | 863 | uint8 status; |
XkLi | 0:c546b51ecf0b | 864 | |
XkLi | 0:c546b51ecf0b | 865 | *pFoundEOI = 0; |
XkLi | 0:c546b51ecf0b | 866 | |
XkLi | 0:c546b51ecf0b | 867 | status = processMarkers(&c); |
XkLi | 0:c546b51ecf0b | 868 | if (status) |
XkLi | 0:c546b51ecf0b | 869 | return status; |
XkLi | 0:c546b51ecf0b | 870 | |
XkLi | 0:c546b51ecf0b | 871 | if (c == M_EOI) |
XkLi | 0:c546b51ecf0b | 872 | { |
XkLi | 0:c546b51ecf0b | 873 | *pFoundEOI = 1; |
XkLi | 0:c546b51ecf0b | 874 | return 0; |
XkLi | 0:c546b51ecf0b | 875 | } |
XkLi | 0:c546b51ecf0b | 876 | else if (c != M_SOS) |
XkLi | 0:c546b51ecf0b | 877 | return PJPG_UNEXPECTED_MARKER; |
XkLi | 0:c546b51ecf0b | 878 | |
XkLi | 0:c546b51ecf0b | 879 | return readSOSMarker(); |
XkLi | 0:c546b51ecf0b | 880 | } |
XkLi | 0:c546b51ecf0b | 881 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 882 | static uint8 init(void) |
XkLi | 0:c546b51ecf0b | 883 | { |
XkLi | 0:c546b51ecf0b | 884 | gImageXSize = 0; |
XkLi | 0:c546b51ecf0b | 885 | gImageYSize = 0; |
XkLi | 0:c546b51ecf0b | 886 | gCompsInFrame = 0; |
XkLi | 0:c546b51ecf0b | 887 | gRestartInterval = 0; |
XkLi | 0:c546b51ecf0b | 888 | gCompsInScan = 0; |
XkLi | 0:c546b51ecf0b | 889 | gValidHuffTables = 0; |
XkLi | 0:c546b51ecf0b | 890 | gValidQuantTables = 0; |
XkLi | 0:c546b51ecf0b | 891 | gTemFlag = 0; |
XkLi | 0:c546b51ecf0b | 892 | gInBufOfs = 0; |
XkLi | 0:c546b51ecf0b | 893 | gInBufLeft = 0; |
XkLi | 0:c546b51ecf0b | 894 | gBitBuf = 0; |
XkLi | 0:c546b51ecf0b | 895 | gBitsLeft = 8; |
XkLi | 0:c546b51ecf0b | 896 | |
XkLi | 0:c546b51ecf0b | 897 | getBits1(8); |
XkLi | 0:c546b51ecf0b | 898 | getBits1(8); |
XkLi | 0:c546b51ecf0b | 899 | |
XkLi | 0:c546b51ecf0b | 900 | return 0; |
XkLi | 0:c546b51ecf0b | 901 | } |
XkLi | 0:c546b51ecf0b | 902 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 903 | // This method throws back into the stream any bytes that where read |
XkLi | 0:c546b51ecf0b | 904 | // into the bit buffer during initial marker scanning. |
XkLi | 0:c546b51ecf0b | 905 | static void fixInBuffer(void) |
XkLi | 0:c546b51ecf0b | 906 | { |
XkLi | 0:c546b51ecf0b | 907 | /* In case any 0xFF's where pulled into the buffer during marker scanning */ |
XkLi | 0:c546b51ecf0b | 908 | |
XkLi | 0:c546b51ecf0b | 909 | if (gBitsLeft > 0) |
XkLi | 0:c546b51ecf0b | 910 | stuffChar((uint8)gBitBuf); |
XkLi | 0:c546b51ecf0b | 911 | |
XkLi | 0:c546b51ecf0b | 912 | stuffChar((uint8)(gBitBuf >> 8)); |
XkLi | 0:c546b51ecf0b | 913 | |
XkLi | 0:c546b51ecf0b | 914 | gBitsLeft = 8; |
XkLi | 0:c546b51ecf0b | 915 | getBits2(8); |
XkLi | 0:c546b51ecf0b | 916 | getBits2(8); |
XkLi | 0:c546b51ecf0b | 917 | } |
XkLi | 0:c546b51ecf0b | 918 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 919 | // Restart interval processing. |
XkLi | 0:c546b51ecf0b | 920 | static uint8 processRestart(void) |
XkLi | 0:c546b51ecf0b | 921 | { |
XkLi | 0:c546b51ecf0b | 922 | // Let's scan a little bit to find the marker, but not _too_ far. |
XkLi | 0:c546b51ecf0b | 923 | // 1536 is a "fudge factor" that determines how much to scan. |
XkLi | 0:c546b51ecf0b | 924 | uint16 i; |
XkLi | 0:c546b51ecf0b | 925 | uint8 c = 0; |
XkLi | 0:c546b51ecf0b | 926 | |
XkLi | 0:c546b51ecf0b | 927 | for (i = 1536; i > 0; i--) |
XkLi | 0:c546b51ecf0b | 928 | if (getChar() == 0xFF) |
XkLi | 0:c546b51ecf0b | 929 | break; |
XkLi | 0:c546b51ecf0b | 930 | |
XkLi | 0:c546b51ecf0b | 931 | if (i == 0) |
XkLi | 0:c546b51ecf0b | 932 | return PJPG_BAD_RESTART_MARKER; |
XkLi | 0:c546b51ecf0b | 933 | |
XkLi | 0:c546b51ecf0b | 934 | for ( ; i > 0; i--) |
XkLi | 0:c546b51ecf0b | 935 | if ((c = getChar()) != 0xFF) |
XkLi | 0:c546b51ecf0b | 936 | break; |
XkLi | 0:c546b51ecf0b | 937 | |
XkLi | 0:c546b51ecf0b | 938 | if (i == 0) |
XkLi | 0:c546b51ecf0b | 939 | return PJPG_BAD_RESTART_MARKER; |
XkLi | 0:c546b51ecf0b | 940 | |
XkLi | 0:c546b51ecf0b | 941 | // Is it the expected marker? If not, something bad happened. |
XkLi | 0:c546b51ecf0b | 942 | if (c != (gNextRestartNum + M_RST0)) |
XkLi | 0:c546b51ecf0b | 943 | return PJPG_BAD_RESTART_MARKER; |
XkLi | 0:c546b51ecf0b | 944 | |
XkLi | 0:c546b51ecf0b | 945 | // Reset each component's DC prediction values. |
XkLi | 0:c546b51ecf0b | 946 | gLastDC[0] = 0; |
XkLi | 0:c546b51ecf0b | 947 | gLastDC[1] = 0; |
XkLi | 0:c546b51ecf0b | 948 | gLastDC[2] = 0; |
XkLi | 0:c546b51ecf0b | 949 | |
XkLi | 0:c546b51ecf0b | 950 | gRestartsLeft = gRestartInterval; |
XkLi | 0:c546b51ecf0b | 951 | |
XkLi | 0:c546b51ecf0b | 952 | gNextRestartNum = (gNextRestartNum + 1) & 7; |
XkLi | 0:c546b51ecf0b | 953 | |
XkLi | 0:c546b51ecf0b | 954 | // Get the bit buffer going again... |
XkLi | 0:c546b51ecf0b | 955 | |
XkLi | 0:c546b51ecf0b | 956 | gBitsLeft = 8; |
XkLi | 0:c546b51ecf0b | 957 | getBits2(8); |
XkLi | 0:c546b51ecf0b | 958 | getBits2(8); |
XkLi | 0:c546b51ecf0b | 959 | |
XkLi | 0:c546b51ecf0b | 960 | return 0; |
XkLi | 0:c546b51ecf0b | 961 | } |
XkLi | 0:c546b51ecf0b | 962 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 963 | static uint8 findEOI(void) |
XkLi | 0:c546b51ecf0b | 964 | { |
XkLi | 0:c546b51ecf0b | 965 | uint8 c; |
XkLi | 0:c546b51ecf0b | 966 | uint8 status; |
XkLi | 0:c546b51ecf0b | 967 | |
XkLi | 0:c546b51ecf0b | 968 | // Prime the bit buffer |
XkLi | 0:c546b51ecf0b | 969 | gBitsLeft = 8; |
XkLi | 0:c546b51ecf0b | 970 | getBits1(8); |
XkLi | 0:c546b51ecf0b | 971 | getBits1(8); |
XkLi | 0:c546b51ecf0b | 972 | |
XkLi | 0:c546b51ecf0b | 973 | // The next marker _should_ be EOI |
XkLi | 0:c546b51ecf0b | 974 | status = processMarkers(&c); |
XkLi | 0:c546b51ecf0b | 975 | if (status) |
XkLi | 0:c546b51ecf0b | 976 | return status; |
XkLi | 0:c546b51ecf0b | 977 | |
XkLi | 0:c546b51ecf0b | 978 | //gTotalBytesRead -= in_buf_left; |
XkLi | 0:c546b51ecf0b | 979 | if (c != M_EOI) |
XkLi | 0:c546b51ecf0b | 980 | return PJPG_UNEXPECTED_MARKER; |
XkLi | 0:c546b51ecf0b | 981 | |
XkLi | 0:c546b51ecf0b | 982 | return 0; |
XkLi | 0:c546b51ecf0b | 983 | } |
XkLi | 0:c546b51ecf0b | 984 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 985 | static uint8 checkHuffTables(void) |
XkLi | 0:c546b51ecf0b | 986 | { |
XkLi | 0:c546b51ecf0b | 987 | uint8 i; |
XkLi | 0:c546b51ecf0b | 988 | |
XkLi | 0:c546b51ecf0b | 989 | for (i = 0; i < gCompsInScan; i++) |
XkLi | 0:c546b51ecf0b | 990 | { |
XkLi | 0:c546b51ecf0b | 991 | uint8 compDCTab = gCompDCTab[gCompList[i]]; |
XkLi | 0:c546b51ecf0b | 992 | uint8 compACTab = gCompACTab[gCompList[i]] + 2; |
XkLi | 0:c546b51ecf0b | 993 | |
XkLi | 0:c546b51ecf0b | 994 | if ( ((gValidHuffTables & (1 << compDCTab)) == 0) || |
XkLi | 0:c546b51ecf0b | 995 | ((gValidHuffTables & (1 << compACTab)) == 0) ) |
XkLi | 0:c546b51ecf0b | 996 | return PJPG_UNDEFINED_HUFF_TABLE; |
XkLi | 0:c546b51ecf0b | 997 | } |
XkLi | 0:c546b51ecf0b | 998 | |
XkLi | 0:c546b51ecf0b | 999 | return 0; |
XkLi | 0:c546b51ecf0b | 1000 | } |
XkLi | 0:c546b51ecf0b | 1001 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 1002 | static uint8 checkQuantTables(void) |
XkLi | 0:c546b51ecf0b | 1003 | { |
XkLi | 0:c546b51ecf0b | 1004 | uint8 i; |
XkLi | 0:c546b51ecf0b | 1005 | |
XkLi | 0:c546b51ecf0b | 1006 | for (i = 0; i < gCompsInScan; i++) |
XkLi | 0:c546b51ecf0b | 1007 | { |
XkLi | 0:c546b51ecf0b | 1008 | uint8 compQuantMask = gCompQuant[gCompList[i]] ? 2 : 1; |
XkLi | 0:c546b51ecf0b | 1009 | |
XkLi | 0:c546b51ecf0b | 1010 | if ((gValidQuantTables & compQuantMask) == 0) |
XkLi | 0:c546b51ecf0b | 1011 | return PJPG_UNDEFINED_QUANT_TABLE; |
XkLi | 0:c546b51ecf0b | 1012 | } |
XkLi | 0:c546b51ecf0b | 1013 | |
XkLi | 0:c546b51ecf0b | 1014 | return 0; |
XkLi | 0:c546b51ecf0b | 1015 | } |
XkLi | 0:c546b51ecf0b | 1016 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 1017 | static uint8 initScan(void) |
XkLi | 0:c546b51ecf0b | 1018 | { |
XkLi | 0:c546b51ecf0b | 1019 | uint8 foundEOI; |
XkLi | 0:c546b51ecf0b | 1020 | uint8 status = locateSOSMarker(&foundEOI); |
XkLi | 0:c546b51ecf0b | 1021 | if (status) |
XkLi | 0:c546b51ecf0b | 1022 | return status; |
XkLi | 0:c546b51ecf0b | 1023 | if (foundEOI) |
XkLi | 0:c546b51ecf0b | 1024 | return PJPG_UNEXPECTED_MARKER; |
XkLi | 0:c546b51ecf0b | 1025 | |
XkLi | 0:c546b51ecf0b | 1026 | status = checkHuffTables(); |
XkLi | 0:c546b51ecf0b | 1027 | if (status) |
XkLi | 0:c546b51ecf0b | 1028 | return status; |
XkLi | 0:c546b51ecf0b | 1029 | |
XkLi | 0:c546b51ecf0b | 1030 | status = checkQuantTables(); |
XkLi | 0:c546b51ecf0b | 1031 | if (status) |
XkLi | 0:c546b51ecf0b | 1032 | return status; |
XkLi | 0:c546b51ecf0b | 1033 | |
XkLi | 0:c546b51ecf0b | 1034 | gLastDC[0] = 0; |
XkLi | 0:c546b51ecf0b | 1035 | gLastDC[1] = 0; |
XkLi | 0:c546b51ecf0b | 1036 | gLastDC[2] = 0; |
XkLi | 0:c546b51ecf0b | 1037 | |
XkLi | 0:c546b51ecf0b | 1038 | if (gRestartInterval) |
XkLi | 0:c546b51ecf0b | 1039 | { |
XkLi | 0:c546b51ecf0b | 1040 | gRestartsLeft = gRestartInterval; |
XkLi | 0:c546b51ecf0b | 1041 | gNextRestartNum = 0; |
XkLi | 0:c546b51ecf0b | 1042 | } |
XkLi | 0:c546b51ecf0b | 1043 | |
XkLi | 0:c546b51ecf0b | 1044 | fixInBuffer(); |
XkLi | 0:c546b51ecf0b | 1045 | |
XkLi | 0:c546b51ecf0b | 1046 | return 0; |
XkLi | 0:c546b51ecf0b | 1047 | } |
XkLi | 0:c546b51ecf0b | 1048 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 1049 | static uint8 initFrame(void) |
XkLi | 0:c546b51ecf0b | 1050 | { |
XkLi | 0:c546b51ecf0b | 1051 | if (gCompsInFrame == 1) |
XkLi | 0:c546b51ecf0b | 1052 | { |
XkLi | 0:c546b51ecf0b | 1053 | if ((gCompHSamp[0] != 1) || (gCompVSamp[0] != 1)) |
XkLi | 0:c546b51ecf0b | 1054 | return PJPG_UNSUPPORTED_SAMP_FACTORS; |
XkLi | 0:c546b51ecf0b | 1055 | |
XkLi | 0:c546b51ecf0b | 1056 | gScanType = PJPG_GRAYSCALE; |
XkLi | 0:c546b51ecf0b | 1057 | |
XkLi | 0:c546b51ecf0b | 1058 | gMaxBlocksPerMCU = 1; |
XkLi | 0:c546b51ecf0b | 1059 | gMCUOrg[0] = 0; |
XkLi | 0:c546b51ecf0b | 1060 | |
XkLi | 0:c546b51ecf0b | 1061 | gMaxMCUXSize = 8; |
XkLi | 0:c546b51ecf0b | 1062 | gMaxMCUYSize = 8; |
XkLi | 0:c546b51ecf0b | 1063 | } |
XkLi | 0:c546b51ecf0b | 1064 | else if (gCompsInFrame == 3) |
XkLi | 0:c546b51ecf0b | 1065 | { |
XkLi | 0:c546b51ecf0b | 1066 | if ( ((gCompHSamp[1] != 1) || (gCompVSamp[1] != 1)) || |
XkLi | 0:c546b51ecf0b | 1067 | ((gCompHSamp[2] != 1) || (gCompVSamp[2] != 1)) ) |
XkLi | 0:c546b51ecf0b | 1068 | return PJPG_UNSUPPORTED_SAMP_FACTORS; |
XkLi | 0:c546b51ecf0b | 1069 | |
XkLi | 0:c546b51ecf0b | 1070 | if ((gCompHSamp[0] == 1) && (gCompVSamp[0] == 1)) |
XkLi | 0:c546b51ecf0b | 1071 | { |
XkLi | 0:c546b51ecf0b | 1072 | gScanType = PJPG_YH1V1; |
XkLi | 0:c546b51ecf0b | 1073 | |
XkLi | 0:c546b51ecf0b | 1074 | gMaxBlocksPerMCU = 3; |
XkLi | 0:c546b51ecf0b | 1075 | gMCUOrg[0] = 0; |
XkLi | 0:c546b51ecf0b | 1076 | gMCUOrg[1] = 1; |
XkLi | 0:c546b51ecf0b | 1077 | gMCUOrg[2] = 2; |
XkLi | 0:c546b51ecf0b | 1078 | |
XkLi | 0:c546b51ecf0b | 1079 | gMaxMCUXSize = 8; |
XkLi | 0:c546b51ecf0b | 1080 | gMaxMCUYSize = 8; |
XkLi | 0:c546b51ecf0b | 1081 | } |
XkLi | 0:c546b51ecf0b | 1082 | else if ((gCompHSamp[0] == 2) && (gCompVSamp[0] == 2)) |
XkLi | 0:c546b51ecf0b | 1083 | { |
XkLi | 0:c546b51ecf0b | 1084 | gScanType = PJPG_YH2V2; |
XkLi | 0:c546b51ecf0b | 1085 | |
XkLi | 0:c546b51ecf0b | 1086 | gMaxBlocksPerMCU = 6; |
XkLi | 0:c546b51ecf0b | 1087 | gMCUOrg[0] = 0; |
XkLi | 0:c546b51ecf0b | 1088 | gMCUOrg[1] = 0; |
XkLi | 0:c546b51ecf0b | 1089 | gMCUOrg[2] = 0; |
XkLi | 0:c546b51ecf0b | 1090 | gMCUOrg[3] = 0; |
XkLi | 0:c546b51ecf0b | 1091 | gMCUOrg[4] = 1; |
XkLi | 0:c546b51ecf0b | 1092 | gMCUOrg[5] = 2; |
XkLi | 0:c546b51ecf0b | 1093 | |
XkLi | 0:c546b51ecf0b | 1094 | gMaxMCUXSize = 16; |
XkLi | 0:c546b51ecf0b | 1095 | gMaxMCUYSize = 16; |
XkLi | 0:c546b51ecf0b | 1096 | } |
XkLi | 0:c546b51ecf0b | 1097 | else |
XkLi | 0:c546b51ecf0b | 1098 | return PJPG_UNSUPPORTED_SAMP_FACTORS; |
XkLi | 0:c546b51ecf0b | 1099 | } |
XkLi | 0:c546b51ecf0b | 1100 | else |
XkLi | 0:c546b51ecf0b | 1101 | return PJPG_UNSUPPORTED_COLORSPACE; |
XkLi | 0:c546b51ecf0b | 1102 | |
XkLi | 0:c546b51ecf0b | 1103 | gMaxMCUSPerRow = (gImageXSize + (gMaxMCUXSize - 1)) >> ((gMaxMCUXSize == 8) ? 3 : 4); |
XkLi | 0:c546b51ecf0b | 1104 | gMaxMCUSPerCol = (gImageYSize + (gMaxMCUYSize - 1)) >> ((gMaxMCUYSize == 8) ? 3 : 4); |
XkLi | 0:c546b51ecf0b | 1105 | |
XkLi | 0:c546b51ecf0b | 1106 | gNumMCUSRemaining = gMaxMCUSPerRow * gMaxMCUSPerCol; |
XkLi | 0:c546b51ecf0b | 1107 | |
XkLi | 0:c546b51ecf0b | 1108 | return 0; |
XkLi | 0:c546b51ecf0b | 1109 | } |
XkLi | 0:c546b51ecf0b | 1110 | /*----------------------------------------------------------------------------*/ |
XkLi | 0:c546b51ecf0b | 1111 | #define DCT_SCALE_BITS 7 |
XkLi | 0:c546b51ecf0b | 1112 | |
XkLi | 0:c546b51ecf0b | 1113 | #define DCT_SCALE (1U << DCT_SCALE_BITS) |
XkLi | 0:c546b51ecf0b | 1114 | |
XkLi | 0:c546b51ecf0b | 1115 | #define DESCALE(x) (((x) + (1U << (DCT_SCALE_BITS - 1))) >> DCT_SCALE_BITS) |
XkLi | 0:c546b51ecf0b | 1116 | |
XkLi | 0:c546b51ecf0b | 1117 | #define WFIX(x) ((x) * DCT_SCALE + 0.5f) |
XkLi | 0:c546b51ecf0b | 1118 | |
XkLi | 0:c546b51ecf0b | 1119 | #define WINOGRAD_QUANT_SCALE_BITS 10 |
XkLi | 0:c546b51ecf0b | 1120 | |
XkLi | 0:c546b51ecf0b | 1121 | const uint8 gWinogradQuant[] = |
XkLi | 0:c546b51ecf0b | 1122 | { |
XkLi | 0:c546b51ecf0b | 1123 | 128, 178, 178, 167, 246, 167, 151, 232, |
XkLi | 0:c546b51ecf0b | 1124 | 232, 151, 128, 209, 219, 209, 128, 101, |
XkLi | 0:c546b51ecf0b | 1125 | 178, 197, 197, 178, 101, 69, 139, 167, |
XkLi | 0:c546b51ecf0b | 1126 | 177, 167, 139, 69, 35, 96, 131, 151, |
XkLi | 0:c546b51ecf0b | 1127 | 151, 131, 96, 35, 49, 91, 118, 128, |
XkLi | 0:c546b51ecf0b | 1128 | 118, 91, 49, 46, 81, 101, 101, 81, |
XkLi | 0:c546b51ecf0b | 1129 | 46, 42, 69, 79, 69, 42, 35, 54, |
XkLi | 0:c546b51ecf0b | 1130 | 54, 35, 28, 37, 28, 19, 19, 10, |
XkLi | 0:c546b51ecf0b | 1131 | }; |
XkLi | 0:c546b51ecf0b | 1132 | |
XkLi | 0:c546b51ecf0b | 1133 | static void createWinogradQuant(int16* pQuant) |
XkLi | 0:c546b51ecf0b | 1134 | { |
XkLi | 0:c546b51ecf0b | 1135 | uint8 i; |
XkLi | 0:c546b51ecf0b | 1136 | |
XkLi | 0:c546b51ecf0b | 1137 | for (i = 0; i < 64; i++) |
XkLi | 0:c546b51ecf0b | 1138 | { |
XkLi | 0:c546b51ecf0b | 1139 | long x = pQuant[i]; |
XkLi | 0:c546b51ecf0b | 1140 | x *= gWinogradQuant[i]; |
XkLi | 0:c546b51ecf0b | 1141 | pQuant[i] = (int16)((x + (1 << (WINOGRAD_QUANT_SCALE_BITS - DCT_SCALE_BITS - 1))) >> (WINOGRAD_QUANT_SCALE_BITS - DCT_SCALE_BITS)); |
XkLi | 0:c546b51ecf0b | 1142 | } |
XkLi | 0:c546b51ecf0b | 1143 | } |
XkLi | 0:c546b51ecf0b | 1144 | |
XkLi | 0:c546b51ecf0b | 1145 | // 1/cos(4*pi/16) |
XkLi | 0:c546b51ecf0b | 1146 | // 362, 256+106 |
XkLi | 0:c546b51ecf0b | 1147 | #define b1 362 |
XkLi | 0:c546b51ecf0b | 1148 | |
XkLi | 0:c546b51ecf0b | 1149 | // 1/cos(6*pi/16) |
XkLi | 0:c546b51ecf0b | 1150 | // 669, 256+256+157 |
XkLi | 0:c546b51ecf0b | 1151 | #define b2 669 |
XkLi | 0:c546b51ecf0b | 1152 | |
XkLi | 0:c546b51ecf0b | 1153 | // 1/cos(4*pi/16) |
XkLi | 0:c546b51ecf0b | 1154 | // 362, 256+106 |
XkLi | 0:c546b51ecf0b | 1155 | #define b3 362 |
XkLi | 0:c546b51ecf0b | 1156 | |
XkLi | 0:c546b51ecf0b | 1157 | // 1/cos(2*pi/16) |
XkLi | 0:c546b51ecf0b | 1158 | // 277, 256+21 |
XkLi | 0:c546b51ecf0b | 1159 | #define b4 277 |
XkLi | 0:c546b51ecf0b | 1160 | |
XkLi | 0:c546b51ecf0b | 1161 | // 1/(cos(2*pi/16) + cos(6*pi/16)) |
XkLi | 0:c546b51ecf0b | 1162 | // 196, 196 |
XkLi | 0:c546b51ecf0b | 1163 | #define b5 196 |
XkLi | 0:c546b51ecf0b | 1164 | |
XkLi | 0:c546b51ecf0b | 1165 | static int16 imul_b1_b3(int16 w) |
XkLi | 0:c546b51ecf0b | 1166 | { |
XkLi | 0:c546b51ecf0b | 1167 | long x = (w * 362L); |
XkLi | 0:c546b51ecf0b | 1168 | x += 128L; |
XkLi | 0:c546b51ecf0b | 1169 | return (int16)(x >> 8); |
XkLi | 0:c546b51ecf0b | 1170 | } |
XkLi | 0:c546b51ecf0b | 1171 | |
XkLi | 0:c546b51ecf0b | 1172 | static int16 imul_b2(int16 w) |
XkLi | 0:c546b51ecf0b | 1173 | { |
XkLi | 0:c546b51ecf0b | 1174 | long x = (w * 669L); |
XkLi | 0:c546b51ecf0b | 1175 | x += 128L; |
XkLi | 0:c546b51ecf0b | 1176 | return (int16)(x >> 8); |
XkLi | 0:c546b51ecf0b | 1177 | } |
XkLi | 0:c546b51ecf0b | 1178 | |
XkLi | 0:c546b51ecf0b | 1179 | static int16 imul_b4(int16 w) |
XkLi | 0:c546b51ecf0b | 1180 | { |
XkLi | 0:c546b51ecf0b | 1181 | long x = (w * 277L); |
XkLi | 0:c546b51ecf0b | 1182 | x += 128L; |
XkLi | 0:c546b51ecf0b | 1183 | return (int16)(x >> 8); |
XkLi | 0:c546b51ecf0b | 1184 | } |
XkLi | 0:c546b51ecf0b | 1185 | |
XkLi | 0:c546b51ecf0b | 1186 | static int16 imul_b5(int16 w) |
XkLi | 0:c546b51ecf0b | 1187 | { |
XkLi | 0:c546b51ecf0b | 1188 | long x = (w * 196L); |
XkLi | 0:c546b51ecf0b | 1189 | x += 128L; |
XkLi | 0:c546b51ecf0b | 1190 | return (int16)(x >> 8); |
XkLi | 0:c546b51ecf0b | 1191 | } |
XkLi | 0:c546b51ecf0b | 1192 | |
XkLi | 0:c546b51ecf0b | 1193 | static uint8 clamp(int16 s) |
XkLi | 0:c546b51ecf0b | 1194 | { |
XkLi | 0:c546b51ecf0b | 1195 | if ((uint16)s > 255U) |
XkLi | 0:c546b51ecf0b | 1196 | { |
XkLi | 0:c546b51ecf0b | 1197 | if (s < 0) |
XkLi | 0:c546b51ecf0b | 1198 | return 0; |
XkLi | 0:c546b51ecf0b | 1199 | else if (s > 255) |
XkLi | 0:c546b51ecf0b | 1200 | return 255; |
XkLi | 0:c546b51ecf0b | 1201 | } |
XkLi | 0:c546b51ecf0b | 1202 | |
XkLi | 0:c546b51ecf0b | 1203 | return (uint8)s; |
XkLi | 0:c546b51ecf0b | 1204 | } |
XkLi | 0:c546b51ecf0b | 1205 | |
XkLi | 0:c546b51ecf0b | 1206 | static void idctRows(void) |
XkLi | 0:c546b51ecf0b | 1207 | { |
XkLi | 0:c546b51ecf0b | 1208 | uint8 i; |
XkLi | 0:c546b51ecf0b | 1209 | int16* pSrc = gCoeffBuf; |
XkLi | 0:c546b51ecf0b | 1210 | |
XkLi | 0:c546b51ecf0b | 1211 | for (i = 0; i < 8; i++) |
XkLi | 0:c546b51ecf0b | 1212 | { |
XkLi | 0:c546b51ecf0b | 1213 | int16 src4 = *(pSrc+5); |
XkLi | 0:c546b51ecf0b | 1214 | int16 src7 = *(pSrc+3); |
XkLi | 0:c546b51ecf0b | 1215 | int16 x4 = src4 - src7; |
XkLi | 0:c546b51ecf0b | 1216 | int16 x7 = src4 + src7; |
XkLi | 0:c546b51ecf0b | 1217 | |
XkLi | 0:c546b51ecf0b | 1218 | int16 src5 = *(pSrc+1); |
XkLi | 0:c546b51ecf0b | 1219 | int16 src6 = *(pSrc+7); |
XkLi | 0:c546b51ecf0b | 1220 | int16 x5 = src5 + src6; |
XkLi | 0:c546b51ecf0b | 1221 | int16 x6 = src5 - src6; |
XkLi | 0:c546b51ecf0b | 1222 | |
XkLi | 0:c546b51ecf0b | 1223 | int16 tmp1 = imul_b5(x4 - x6); |
XkLi | 0:c546b51ecf0b | 1224 | int16 stg26 = imul_b4(x6) - tmp1; |
XkLi | 0:c546b51ecf0b | 1225 | |
XkLi | 0:c546b51ecf0b | 1226 | int16 x24 = tmp1 - imul_b2(x4); |
XkLi | 0:c546b51ecf0b | 1227 | |
XkLi | 0:c546b51ecf0b | 1228 | int16 x15 = x5 - x7; |
XkLi | 0:c546b51ecf0b | 1229 | int16 x17 = x5 + x7; |
XkLi | 0:c546b51ecf0b | 1230 | |
XkLi | 0:c546b51ecf0b | 1231 | int16 tmp2 = stg26 - x17; |
XkLi | 0:c546b51ecf0b | 1232 | int16 tmp3 = imul_b1_b3(x15) - tmp2; |
XkLi | 0:c546b51ecf0b | 1233 | int16 x44 = tmp3 + x24; |
XkLi | 0:c546b51ecf0b | 1234 | |
XkLi | 0:c546b51ecf0b | 1235 | int16 src0 = *(pSrc+0); |
XkLi | 0:c546b51ecf0b | 1236 | int16 src1 = *(pSrc+4); |
XkLi | 0:c546b51ecf0b | 1237 | int16 x30 = src0 + src1; |
XkLi | 0:c546b51ecf0b | 1238 | int16 x31 = src0 - src1; |
XkLi | 0:c546b51ecf0b | 1239 | |
XkLi | 0:c546b51ecf0b | 1240 | int16 src2 = *(pSrc+2); |
XkLi | 0:c546b51ecf0b | 1241 | int16 src3 = *(pSrc+6); |
XkLi | 0:c546b51ecf0b | 1242 | int16 x12 = src2 - src3; |
XkLi | 0:c546b51ecf0b | 1243 | int16 x13 = src2 + src3; |
XkLi | 0:c546b51ecf0b | 1244 | |
XkLi | 0:c546b51ecf0b | 1245 | int16 x32 = imul_b1_b3(x12) - x13; |
XkLi | 0:c546b51ecf0b | 1246 | |
XkLi | 0:c546b51ecf0b | 1247 | int16 x40 = x30 + x13; |
XkLi | 0:c546b51ecf0b | 1248 | int16 x43 = x30 - x13; |
XkLi | 0:c546b51ecf0b | 1249 | int16 x41 = x31 + x32; |
XkLi | 0:c546b51ecf0b | 1250 | int16 x42 = x31 - x32; |
XkLi | 0:c546b51ecf0b | 1251 | |
XkLi | 0:c546b51ecf0b | 1252 | *(pSrc+0) = x40 + x17; |
XkLi | 0:c546b51ecf0b | 1253 | *(pSrc+1) = x41 + tmp2; |
XkLi | 0:c546b51ecf0b | 1254 | *(pSrc+2) = x42 + tmp3; |
XkLi | 0:c546b51ecf0b | 1255 | *(pSrc+3) = x43 - x44; |
XkLi | 0:c546b51ecf0b | 1256 | *(pSrc+4) = x43 + x44; |
XkLi | 0:c546b51ecf0b | 1257 | *(pSrc+5) = x42 - tmp3; |
XkLi | 0:c546b51ecf0b | 1258 | *(pSrc+6) = x41 - tmp2; |
XkLi | 0:c546b51ecf0b | 1259 | *(pSrc+7) = x40 - x17; |
XkLi | 0:c546b51ecf0b | 1260 | |
XkLi | 0:c546b51ecf0b | 1261 | pSrc += 8; |
XkLi | 0:c546b51ecf0b | 1262 | } |
XkLi | 0:c546b51ecf0b | 1263 | } |
XkLi | 0:c546b51ecf0b | 1264 | |
XkLi | 0:c546b51ecf0b | 1265 | static void idctCols(void) |
XkLi | 0:c546b51ecf0b | 1266 | { |
XkLi | 0:c546b51ecf0b | 1267 | uint8 i; |
XkLi | 0:c546b51ecf0b | 1268 | |
XkLi | 0:c546b51ecf0b | 1269 | int16* pSrc = gCoeffBuf; |
XkLi | 0:c546b51ecf0b | 1270 | |
XkLi | 0:c546b51ecf0b | 1271 | for (i = 0; i < 8; i++) |
XkLi | 0:c546b51ecf0b | 1272 | { |
XkLi | 0:c546b51ecf0b | 1273 | int16 src4 = *(pSrc+5*8); |
XkLi | 0:c546b51ecf0b | 1274 | int16 src7 = *(pSrc+3*8); |
XkLi | 0:c546b51ecf0b | 1275 | int16 x4 = src4 - src7; |
XkLi | 0:c546b51ecf0b | 1276 | int16 x7 = src4 + src7; |
XkLi | 0:c546b51ecf0b | 1277 | |
XkLi | 0:c546b51ecf0b | 1278 | int16 src5 = *(pSrc+1*8); |
XkLi | 0:c546b51ecf0b | 1279 | int16 src6 = *(pSrc+7*8); |
XkLi | 0:c546b51ecf0b | 1280 | int16 x5 = src5 + src6; |
XkLi | 0:c546b51ecf0b | 1281 | int16 x6 = src5 - src6; |
XkLi | 0:c546b51ecf0b | 1282 | |
XkLi | 0:c546b51ecf0b | 1283 | int16 tmp1 = imul_b5(x4 - x6); |
XkLi | 0:c546b51ecf0b | 1284 | int16 stg26 = imul_b4(x6) - tmp1; |
XkLi | 0:c546b51ecf0b | 1285 | |
XkLi | 0:c546b51ecf0b | 1286 | int16 x24 = tmp1 - imul_b2(x4); |
XkLi | 0:c546b51ecf0b | 1287 | |
XkLi | 0:c546b51ecf0b | 1288 | int16 x15 = x5 - x7; |
XkLi | 0:c546b51ecf0b | 1289 | int16 x17 = x5 + x7; |
XkLi | 0:c546b51ecf0b | 1290 | |
XkLi | 0:c546b51ecf0b | 1291 | int16 tmp2 = stg26 - x17; |
XkLi | 0:c546b51ecf0b | 1292 | int16 tmp3 = imul_b1_b3(x15) - tmp2; |
XkLi | 0:c546b51ecf0b | 1293 | int16 x44 = tmp3 + x24; |
XkLi | 0:c546b51ecf0b | 1294 | |
XkLi | 0:c546b51ecf0b | 1295 | int16 src0 = *(pSrc+0*8); |
XkLi | 0:c546b51ecf0b | 1296 | int16 src1 = *(pSrc+4*8); |
XkLi | 0:c546b51ecf0b | 1297 | int16 x30 = src0 + src1; |
XkLi | 0:c546b51ecf0b | 1298 | int16 x31 = src0 - src1; |
XkLi | 0:c546b51ecf0b | 1299 | |
XkLi | 0:c546b51ecf0b | 1300 | int16 src2 = *(pSrc+2*8); |
XkLi | 0:c546b51ecf0b | 1301 | int16 src3 = *(pSrc+6*8); |
XkLi | 0:c546b51ecf0b | 1302 | int16 x12 = src2 - src3; |
XkLi | 0:c546b51ecf0b | 1303 | int16 x13 = src2 + src3; |
XkLi | 0:c546b51ecf0b | 1304 | |
XkLi | 0:c546b51ecf0b | 1305 | int16 x32 = imul_b1_b3(x12) - x13; |
XkLi | 0:c546b51ecf0b | 1306 | |
XkLi | 0:c546b51ecf0b | 1307 | int16 x40 = x30 + x13; |
XkLi | 0:c546b51ecf0b | 1308 | int16 x43 = x30 - x13; |
XkLi | 0:c546b51ecf0b | 1309 | int16 x41 = x31 + x32; |
XkLi | 0:c546b51ecf0b | 1310 | int16 x42 = x31 - x32; |
XkLi | 0:c546b51ecf0b | 1311 | |
XkLi | 0:c546b51ecf0b | 1312 | *(pSrc+0*8) = clamp(DESCALE(x40 + x17) + 128); |
XkLi | 0:c546b51ecf0b | 1313 | *(pSrc+1*8) = clamp(DESCALE(x41 + tmp2) + 128); |
XkLi | 0:c546b51ecf0b | 1314 | *(pSrc+2*8) = clamp(DESCALE(x42 + tmp3) + 128); |
XkLi | 0:c546b51ecf0b | 1315 | *(pSrc+3*8) = clamp(DESCALE(x43 - x44) + 128); |
XkLi | 0:c546b51ecf0b | 1316 | *(pSrc+4*8) = clamp(DESCALE(x43 + x44) + 128); |
XkLi | 0:c546b51ecf0b | 1317 | *(pSrc+5*8) = clamp(DESCALE(x42 - tmp3) + 128); |
XkLi | 0:c546b51ecf0b | 1318 | *(pSrc+6*8) = clamp(DESCALE(x41 - tmp2) + 128); |
XkLi | 0:c546b51ecf0b | 1319 | *(pSrc+7*8) = clamp(DESCALE(x40 - x17) + 128); |
XkLi | 0:c546b51ecf0b | 1320 | |
XkLi | 0:c546b51ecf0b | 1321 | pSrc++; |
XkLi | 0:c546b51ecf0b | 1322 | } |
XkLi | 0:c546b51ecf0b | 1323 | } |
XkLi | 0:c546b51ecf0b | 1324 | |
XkLi | 0:c546b51ecf0b | 1325 | /*----------------------------------------------------------------------------*/ |
XkLi | 0:c546b51ecf0b | 1326 | static uint8 addAndClamp(uint8 a, int16 b) |
XkLi | 0:c546b51ecf0b | 1327 | { |
XkLi | 0:c546b51ecf0b | 1328 | b = a + b; |
XkLi | 0:c546b51ecf0b | 1329 | |
XkLi | 0:c546b51ecf0b | 1330 | if ((uint16)b > 255U) |
XkLi | 0:c546b51ecf0b | 1331 | { |
XkLi | 0:c546b51ecf0b | 1332 | if (b < 0) |
XkLi | 0:c546b51ecf0b | 1333 | return 0; |
XkLi | 0:c546b51ecf0b | 1334 | else if (b > 255) |
XkLi | 0:c546b51ecf0b | 1335 | return 255; |
XkLi | 0:c546b51ecf0b | 1336 | } |
XkLi | 0:c546b51ecf0b | 1337 | |
XkLi | 0:c546b51ecf0b | 1338 | return (uint8)b; |
XkLi | 0:c546b51ecf0b | 1339 | } |
XkLi | 0:c546b51ecf0b | 1340 | /*----------------------------------------------------------------------------*/ |
XkLi | 0:c546b51ecf0b | 1341 | static uint8 subAndClamp(uint8 a, int16 b) |
XkLi | 0:c546b51ecf0b | 1342 | { |
XkLi | 0:c546b51ecf0b | 1343 | b = a - b; |
XkLi | 0:c546b51ecf0b | 1344 | |
XkLi | 0:c546b51ecf0b | 1345 | if ((uint16)b > 255U) |
XkLi | 0:c546b51ecf0b | 1346 | { |
XkLi | 0:c546b51ecf0b | 1347 | if (b < 0) |
XkLi | 0:c546b51ecf0b | 1348 | return 0; |
XkLi | 0:c546b51ecf0b | 1349 | else if (b > 255) |
XkLi | 0:c546b51ecf0b | 1350 | return 255; |
XkLi | 0:c546b51ecf0b | 1351 | } |
XkLi | 0:c546b51ecf0b | 1352 | |
XkLi | 0:c546b51ecf0b | 1353 | return (uint8)b; |
XkLi | 0:c546b51ecf0b | 1354 | } |
XkLi | 0:c546b51ecf0b | 1355 | /*----------------------------------------------------------------------------*/ |
XkLi | 0:c546b51ecf0b | 1356 | // 103/256 |
XkLi | 0:c546b51ecf0b | 1357 | //R = Y + 1.402 (Cr-128) |
XkLi | 0:c546b51ecf0b | 1358 | |
XkLi | 0:c546b51ecf0b | 1359 | // 88/256, 183/256 |
XkLi | 0:c546b51ecf0b | 1360 | //G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128) |
XkLi | 0:c546b51ecf0b | 1361 | |
XkLi | 0:c546b51ecf0b | 1362 | // 198/256 |
XkLi | 0:c546b51ecf0b | 1363 | //B = Y + 1.772 (Cb-128) |
XkLi | 0:c546b51ecf0b | 1364 | /*----------------------------------------------------------------------------*/ |
XkLi | 0:c546b51ecf0b | 1365 | static void upsampleCb(uint8 srcOfs, uint8 dstOfs) |
XkLi | 0:c546b51ecf0b | 1366 | { |
XkLi | 0:c546b51ecf0b | 1367 | // Cb - affects G and B |
XkLi | 0:c546b51ecf0b | 1368 | uint8 x, y; |
XkLi | 0:c546b51ecf0b | 1369 | int16* pSrc = gCoeffBuf + srcOfs; |
XkLi | 0:c546b51ecf0b | 1370 | uint8* pDstG = gMCUBufG + dstOfs; |
XkLi | 0:c546b51ecf0b | 1371 | uint8* pDstB = gMCUBufB + dstOfs; |
XkLi | 0:c546b51ecf0b | 1372 | for (y = 0; y < 4; y++) |
XkLi | 0:c546b51ecf0b | 1373 | { |
XkLi | 0:c546b51ecf0b | 1374 | for (x = 0; x < 4; x++) |
XkLi | 0:c546b51ecf0b | 1375 | { |
XkLi | 0:c546b51ecf0b | 1376 | uint8 cb = (uint8)*pSrc++; |
XkLi | 0:c546b51ecf0b | 1377 | int16 cbG, cbB; |
XkLi | 0:c546b51ecf0b | 1378 | |
XkLi | 0:c546b51ecf0b | 1379 | cbG = ((cb * 88U) >> 8U) - 44U; |
XkLi | 0:c546b51ecf0b | 1380 | pDstG[0] = subAndClamp(pDstG[0], cbG); |
XkLi | 0:c546b51ecf0b | 1381 | pDstG[1] = subAndClamp(pDstG[1], cbG); |
XkLi | 0:c546b51ecf0b | 1382 | pDstG[8] = subAndClamp(pDstG[8], cbG); |
XkLi | 0:c546b51ecf0b | 1383 | pDstG[9] = subAndClamp(pDstG[9], cbG); |
XkLi | 0:c546b51ecf0b | 1384 | |
XkLi | 0:c546b51ecf0b | 1385 | cbB = (cb + ((cb * 198U) >> 8U)) - 227U; |
XkLi | 0:c546b51ecf0b | 1386 | pDstB[0] = addAndClamp(pDstB[0], cbB); |
XkLi | 0:c546b51ecf0b | 1387 | pDstB[1] = addAndClamp(pDstB[1], cbB); |
XkLi | 0:c546b51ecf0b | 1388 | pDstB[8] = addAndClamp(pDstB[8], cbB); |
XkLi | 0:c546b51ecf0b | 1389 | pDstB[9] = addAndClamp(pDstB[9], cbB); |
XkLi | 0:c546b51ecf0b | 1390 | |
XkLi | 0:c546b51ecf0b | 1391 | pDstG += 2; |
XkLi | 0:c546b51ecf0b | 1392 | pDstB += 2; |
XkLi | 0:c546b51ecf0b | 1393 | } |
XkLi | 0:c546b51ecf0b | 1394 | |
XkLi | 0:c546b51ecf0b | 1395 | pSrc = pSrc - 4 + 8; |
XkLi | 0:c546b51ecf0b | 1396 | pDstG = pDstG - 8 + 16; |
XkLi | 0:c546b51ecf0b | 1397 | pDstB = pDstB - 8 + 16; |
XkLi | 0:c546b51ecf0b | 1398 | } |
XkLi | 0:c546b51ecf0b | 1399 | } |
XkLi | 0:c546b51ecf0b | 1400 | /*----------------------------------------------------------------------------*/ |
XkLi | 0:c546b51ecf0b | 1401 | // 103/256 |
XkLi | 0:c546b51ecf0b | 1402 | //R = Y + 1.402 (Cr-128) |
XkLi | 0:c546b51ecf0b | 1403 | |
XkLi | 0:c546b51ecf0b | 1404 | // 88/256, 183/256 |
XkLi | 0:c546b51ecf0b | 1405 | //G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128) |
XkLi | 0:c546b51ecf0b | 1406 | |
XkLi | 0:c546b51ecf0b | 1407 | // 198/256 |
XkLi | 0:c546b51ecf0b | 1408 | //B = Y + 1.772 (Cb-128) |
XkLi | 0:c546b51ecf0b | 1409 | /*----------------------------------------------------------------------------*/ |
XkLi | 0:c546b51ecf0b | 1410 | static void upsampleCr(uint8 srcOfs, uint8 dstOfs) |
XkLi | 0:c546b51ecf0b | 1411 | { |
XkLi | 0:c546b51ecf0b | 1412 | // Cr - affects R and G |
XkLi | 0:c546b51ecf0b | 1413 | uint8 x, y; |
XkLi | 0:c546b51ecf0b | 1414 | int16* pSrc = gCoeffBuf + srcOfs; |
XkLi | 0:c546b51ecf0b | 1415 | uint8* pDstR = gMCUBufR + dstOfs; |
XkLi | 0:c546b51ecf0b | 1416 | uint8* pDstG = gMCUBufG + dstOfs; |
XkLi | 0:c546b51ecf0b | 1417 | for (y = 0; y < 4; y++) |
XkLi | 0:c546b51ecf0b | 1418 | { |
XkLi | 0:c546b51ecf0b | 1419 | for (x = 0; x < 4; x++) |
XkLi | 0:c546b51ecf0b | 1420 | { |
XkLi | 0:c546b51ecf0b | 1421 | uint8 cr = (uint8)*pSrc++; |
XkLi | 0:c546b51ecf0b | 1422 | int16 crR, crG; |
XkLi | 0:c546b51ecf0b | 1423 | |
XkLi | 0:c546b51ecf0b | 1424 | crR = (cr + ((cr * 103U) >> 8U)) - 179; |
XkLi | 0:c546b51ecf0b | 1425 | pDstR[0] = addAndClamp(pDstR[0], crR); |
XkLi | 0:c546b51ecf0b | 1426 | pDstR[1] = addAndClamp(pDstR[1], crR); |
XkLi | 0:c546b51ecf0b | 1427 | pDstR[8] = addAndClamp(pDstR[8], crR); |
XkLi | 0:c546b51ecf0b | 1428 | pDstR[9] = addAndClamp(pDstR[9], crR); |
XkLi | 0:c546b51ecf0b | 1429 | |
XkLi | 0:c546b51ecf0b | 1430 | crG = ((cr * 183U) >> 8U) - 91; |
XkLi | 0:c546b51ecf0b | 1431 | pDstG[0] = subAndClamp(pDstG[0], crG); |
XkLi | 0:c546b51ecf0b | 1432 | pDstG[1] = subAndClamp(pDstG[1], crG); |
XkLi | 0:c546b51ecf0b | 1433 | pDstG[8] = subAndClamp(pDstG[8], crG); |
XkLi | 0:c546b51ecf0b | 1434 | pDstG[9] = subAndClamp(pDstG[9], crG); |
XkLi | 0:c546b51ecf0b | 1435 | |
XkLi | 0:c546b51ecf0b | 1436 | pDstR += 2; |
XkLi | 0:c546b51ecf0b | 1437 | pDstG += 2; |
XkLi | 0:c546b51ecf0b | 1438 | } |
XkLi | 0:c546b51ecf0b | 1439 | |
XkLi | 0:c546b51ecf0b | 1440 | pSrc = pSrc - 4 + 8; |
XkLi | 0:c546b51ecf0b | 1441 | pDstR = pDstR - 8 + 16; |
XkLi | 0:c546b51ecf0b | 1442 | pDstG = pDstG - 8 + 16; |
XkLi | 0:c546b51ecf0b | 1443 | } |
XkLi | 0:c546b51ecf0b | 1444 | } |
XkLi | 0:c546b51ecf0b | 1445 | /*----------------------------------------------------------------------------*/ |
XkLi | 0:c546b51ecf0b | 1446 | static void copyY(uint8 dstOfs) |
XkLi | 0:c546b51ecf0b | 1447 | { |
XkLi | 0:c546b51ecf0b | 1448 | uint8 i; |
XkLi | 0:c546b51ecf0b | 1449 | uint8* pRDst = gMCUBufR + dstOfs; |
XkLi | 0:c546b51ecf0b | 1450 | uint8* pGDst = gMCUBufG + dstOfs; |
XkLi | 0:c546b51ecf0b | 1451 | uint8* pBDst = gMCUBufB + dstOfs; |
XkLi | 0:c546b51ecf0b | 1452 | int16* pSrc = gCoeffBuf; |
XkLi | 0:c546b51ecf0b | 1453 | |
XkLi | 0:c546b51ecf0b | 1454 | for (i = 64; i > 0; i--) |
XkLi | 0:c546b51ecf0b | 1455 | { |
XkLi | 0:c546b51ecf0b | 1456 | uint8 c = (uint8)*pSrc++; |
XkLi | 0:c546b51ecf0b | 1457 | |
XkLi | 0:c546b51ecf0b | 1458 | *pRDst++ = c; |
XkLi | 0:c546b51ecf0b | 1459 | *pGDst++ = c; |
XkLi | 0:c546b51ecf0b | 1460 | *pBDst++ = c; |
XkLi | 0:c546b51ecf0b | 1461 | } |
XkLi | 0:c546b51ecf0b | 1462 | } |
XkLi | 0:c546b51ecf0b | 1463 | /*----------------------------------------------------------------------------*/ |
XkLi | 0:c546b51ecf0b | 1464 | static void convertCb(uint8 dstOfs) |
XkLi | 0:c546b51ecf0b | 1465 | { |
XkLi | 0:c546b51ecf0b | 1466 | uint8 i; |
XkLi | 0:c546b51ecf0b | 1467 | uint8* pDstG = gMCUBufG + dstOfs; |
XkLi | 0:c546b51ecf0b | 1468 | uint8* pDstB = gMCUBufB + dstOfs; |
XkLi | 0:c546b51ecf0b | 1469 | int16* pSrc = gCoeffBuf; |
XkLi | 0:c546b51ecf0b | 1470 | |
XkLi | 0:c546b51ecf0b | 1471 | for (i = 64; i > 0; i--) |
XkLi | 0:c546b51ecf0b | 1472 | { |
XkLi | 0:c546b51ecf0b | 1473 | uint8 cb = (uint8)*pSrc++; |
XkLi | 0:c546b51ecf0b | 1474 | int16 cbG, cbB; |
XkLi | 0:c546b51ecf0b | 1475 | |
XkLi | 0:c546b51ecf0b | 1476 | cbG = ((cb * 88U) >> 8U) - 44U; |
XkLi | 0:c546b51ecf0b | 1477 | *pDstG++ = subAndClamp(pDstG[0], cbG); |
XkLi | 0:c546b51ecf0b | 1478 | |
XkLi | 0:c546b51ecf0b | 1479 | cbB = (cb + ((cb * 198U) >> 8U)) - 227U; |
XkLi | 0:c546b51ecf0b | 1480 | *pDstB++ = addAndClamp(pDstB[0], cbB); |
XkLi | 0:c546b51ecf0b | 1481 | } |
XkLi | 0:c546b51ecf0b | 1482 | } |
XkLi | 0:c546b51ecf0b | 1483 | /*----------------------------------------------------------------------------*/ |
XkLi | 0:c546b51ecf0b | 1484 | static void convertCr(uint8 dstOfs) |
XkLi | 0:c546b51ecf0b | 1485 | { |
XkLi | 0:c546b51ecf0b | 1486 | uint8 i; |
XkLi | 0:c546b51ecf0b | 1487 | uint8* pDstR = gMCUBufR + dstOfs; |
XkLi | 0:c546b51ecf0b | 1488 | uint8* pDstG = gMCUBufG + dstOfs; |
XkLi | 0:c546b51ecf0b | 1489 | int16* pSrc = gCoeffBuf; |
XkLi | 0:c546b51ecf0b | 1490 | |
XkLi | 0:c546b51ecf0b | 1491 | for (i = 64; i > 0; i--) |
XkLi | 0:c546b51ecf0b | 1492 | { |
XkLi | 0:c546b51ecf0b | 1493 | uint8 cr = (uint8)*pSrc++; |
XkLi | 0:c546b51ecf0b | 1494 | int16 crR, crG; |
XkLi | 0:c546b51ecf0b | 1495 | |
XkLi | 0:c546b51ecf0b | 1496 | crR = (cr + ((cr * 103U) >> 8U)) - 179; |
XkLi | 0:c546b51ecf0b | 1497 | *pDstR++ = addAndClamp(pDstR[0], crR); |
XkLi | 0:c546b51ecf0b | 1498 | |
XkLi | 0:c546b51ecf0b | 1499 | crG = ((cr * 183U) >> 8U) - 91; |
XkLi | 0:c546b51ecf0b | 1500 | *pDstG++ = subAndClamp(pDstG[0], crG); |
XkLi | 0:c546b51ecf0b | 1501 | } |
XkLi | 0:c546b51ecf0b | 1502 | } |
XkLi | 0:c546b51ecf0b | 1503 | /*----------------------------------------------------------------------------*/ |
XkLi | 0:c546b51ecf0b | 1504 | static void transformBlock(uint8 mcuBlock) |
XkLi | 0:c546b51ecf0b | 1505 | { |
XkLi | 0:c546b51ecf0b | 1506 | idctRows(); |
XkLi | 0:c546b51ecf0b | 1507 | idctCols(); |
XkLi | 0:c546b51ecf0b | 1508 | |
XkLi | 0:c546b51ecf0b | 1509 | switch (gScanType) |
XkLi | 0:c546b51ecf0b | 1510 | { |
XkLi | 0:c546b51ecf0b | 1511 | case PJPG_GRAYSCALE: |
XkLi | 0:c546b51ecf0b | 1512 | { |
XkLi | 0:c546b51ecf0b | 1513 | copyY(0); |
XkLi | 0:c546b51ecf0b | 1514 | break; |
XkLi | 0:c546b51ecf0b | 1515 | } |
XkLi | 0:c546b51ecf0b | 1516 | case PJPG_YH1V1: |
XkLi | 0:c546b51ecf0b | 1517 | { |
XkLi | 0:c546b51ecf0b | 1518 | switch (mcuBlock) |
XkLi | 0:c546b51ecf0b | 1519 | { |
XkLi | 0:c546b51ecf0b | 1520 | case 0: |
XkLi | 0:c546b51ecf0b | 1521 | { |
XkLi | 0:c546b51ecf0b | 1522 | copyY(0); |
XkLi | 0:c546b51ecf0b | 1523 | break; |
XkLi | 0:c546b51ecf0b | 1524 | } |
XkLi | 0:c546b51ecf0b | 1525 | case 1: |
XkLi | 0:c546b51ecf0b | 1526 | { |
XkLi | 0:c546b51ecf0b | 1527 | convertCb(0); |
XkLi | 0:c546b51ecf0b | 1528 | break; |
XkLi | 0:c546b51ecf0b | 1529 | } |
XkLi | 0:c546b51ecf0b | 1530 | case 2: |
XkLi | 0:c546b51ecf0b | 1531 | { |
XkLi | 0:c546b51ecf0b | 1532 | convertCr(0); |
XkLi | 0:c546b51ecf0b | 1533 | break; |
XkLi | 0:c546b51ecf0b | 1534 | } |
XkLi | 0:c546b51ecf0b | 1535 | } |
XkLi | 0:c546b51ecf0b | 1536 | |
XkLi | 0:c546b51ecf0b | 1537 | break; |
XkLi | 0:c546b51ecf0b | 1538 | } |
XkLi | 0:c546b51ecf0b | 1539 | case PJPG_YH2V2: |
XkLi | 0:c546b51ecf0b | 1540 | { |
XkLi | 0:c546b51ecf0b | 1541 | switch (mcuBlock) |
XkLi | 0:c546b51ecf0b | 1542 | { |
XkLi | 0:c546b51ecf0b | 1543 | case 0: |
XkLi | 0:c546b51ecf0b | 1544 | { |
XkLi | 0:c546b51ecf0b | 1545 | copyY(0); |
XkLi | 0:c546b51ecf0b | 1546 | break; |
XkLi | 0:c546b51ecf0b | 1547 | } |
XkLi | 0:c546b51ecf0b | 1548 | case 1: |
XkLi | 0:c546b51ecf0b | 1549 | { |
XkLi | 0:c546b51ecf0b | 1550 | copyY(64); |
XkLi | 0:c546b51ecf0b | 1551 | break; |
XkLi | 0:c546b51ecf0b | 1552 | } |
XkLi | 0:c546b51ecf0b | 1553 | case 2: |
XkLi | 0:c546b51ecf0b | 1554 | { |
XkLi | 0:c546b51ecf0b | 1555 | copyY(128); |
XkLi | 0:c546b51ecf0b | 1556 | break; |
XkLi | 0:c546b51ecf0b | 1557 | } |
XkLi | 0:c546b51ecf0b | 1558 | case 3: |
XkLi | 0:c546b51ecf0b | 1559 | { |
XkLi | 0:c546b51ecf0b | 1560 | copyY(192); |
XkLi | 0:c546b51ecf0b | 1561 | break; |
XkLi | 0:c546b51ecf0b | 1562 | } |
XkLi | 0:c546b51ecf0b | 1563 | case 4: |
XkLi | 0:c546b51ecf0b | 1564 | { |
XkLi | 0:c546b51ecf0b | 1565 | upsampleCb(0, 0); |
XkLi | 0:c546b51ecf0b | 1566 | upsampleCb(4, 64); |
XkLi | 0:c546b51ecf0b | 1567 | upsampleCb(4*8, 128); |
XkLi | 0:c546b51ecf0b | 1568 | upsampleCb(4+4*8, 192); |
XkLi | 0:c546b51ecf0b | 1569 | break; |
XkLi | 0:c546b51ecf0b | 1570 | } |
XkLi | 0:c546b51ecf0b | 1571 | case 5: |
XkLi | 0:c546b51ecf0b | 1572 | { |
XkLi | 0:c546b51ecf0b | 1573 | upsampleCr(0, 0); |
XkLi | 0:c546b51ecf0b | 1574 | upsampleCr(4, 64); |
XkLi | 0:c546b51ecf0b | 1575 | upsampleCr(4*8, 128); |
XkLi | 0:c546b51ecf0b | 1576 | upsampleCr(4+4*8, 192); |
XkLi | 0:c546b51ecf0b | 1577 | break; |
XkLi | 0:c546b51ecf0b | 1578 | } |
XkLi | 0:c546b51ecf0b | 1579 | } |
XkLi | 0:c546b51ecf0b | 1580 | } |
XkLi | 0:c546b51ecf0b | 1581 | } |
XkLi | 0:c546b51ecf0b | 1582 | } |
XkLi | 0:c546b51ecf0b | 1583 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 1584 | static uint8 decodeNextMCU(void) |
XkLi | 0:c546b51ecf0b | 1585 | { |
XkLi | 0:c546b51ecf0b | 1586 | uint8 status; |
XkLi | 0:c546b51ecf0b | 1587 | uint8 mcuBlock; |
XkLi | 0:c546b51ecf0b | 1588 | |
XkLi | 0:c546b51ecf0b | 1589 | if (gRestartInterval) |
XkLi | 0:c546b51ecf0b | 1590 | { |
XkLi | 0:c546b51ecf0b | 1591 | if (gRestartsLeft == 0) |
XkLi | 0:c546b51ecf0b | 1592 | { |
XkLi | 0:c546b51ecf0b | 1593 | status = processRestart(); |
XkLi | 0:c546b51ecf0b | 1594 | if (status) |
XkLi | 0:c546b51ecf0b | 1595 | return status; |
XkLi | 0:c546b51ecf0b | 1596 | } |
XkLi | 0:c546b51ecf0b | 1597 | gRestartsLeft--; |
XkLi | 0:c546b51ecf0b | 1598 | } |
XkLi | 0:c546b51ecf0b | 1599 | |
XkLi | 0:c546b51ecf0b | 1600 | for (mcuBlock = 0; mcuBlock < gMaxBlocksPerMCU; mcuBlock++) |
XkLi | 0:c546b51ecf0b | 1601 | { |
XkLi | 0:c546b51ecf0b | 1602 | uint8 componentID = gMCUOrg[mcuBlock]; |
XkLi | 0:c546b51ecf0b | 1603 | uint8 compQuant = gCompQuant[componentID]; |
XkLi | 0:c546b51ecf0b | 1604 | uint8 compDCTab = gCompDCTab[componentID]; |
XkLi | 0:c546b51ecf0b | 1605 | uint8 numExtraBits, compACTab, k; |
XkLi | 0:c546b51ecf0b | 1606 | const int16* pQ = compQuant ? gQuant1 : gQuant0; |
XkLi | 0:c546b51ecf0b | 1607 | uint16 r, dc; |
XkLi | 0:c546b51ecf0b | 1608 | |
XkLi | 0:c546b51ecf0b | 1609 | uint8 s = huffDecode(compDCTab ? &gHuffTab1 : &gHuffTab0, compDCTab ? gHuffVal1 : gHuffVal0); |
XkLi | 0:c546b51ecf0b | 1610 | |
XkLi | 0:c546b51ecf0b | 1611 | r = 0; |
XkLi | 0:c546b51ecf0b | 1612 | numExtraBits = s & 0xF; |
XkLi | 0:c546b51ecf0b | 1613 | if (numExtraBits) |
XkLi | 0:c546b51ecf0b | 1614 | r = getBits2(numExtraBits); |
XkLi | 0:c546b51ecf0b | 1615 | dc = huffExtend(r, s); |
XkLi | 0:c546b51ecf0b | 1616 | |
XkLi | 0:c546b51ecf0b | 1617 | dc = dc + gLastDC[componentID]; |
XkLi | 0:c546b51ecf0b | 1618 | gLastDC[componentID] = dc; |
XkLi | 0:c546b51ecf0b | 1619 | |
XkLi | 0:c546b51ecf0b | 1620 | gCoeffBuf[0] = dc * pQ[0]; |
XkLi | 0:c546b51ecf0b | 1621 | |
XkLi | 0:c546b51ecf0b | 1622 | compACTab = gCompACTab[componentID]; |
XkLi | 0:c546b51ecf0b | 1623 | |
XkLi | 0:c546b51ecf0b | 1624 | for (k = 1; k < 64; k++) |
XkLi | 0:c546b51ecf0b | 1625 | { |
XkLi | 0:c546b51ecf0b | 1626 | uint16 extraBits; |
XkLi | 0:c546b51ecf0b | 1627 | |
XkLi | 0:c546b51ecf0b | 1628 | s = huffDecode(compACTab ? &gHuffTab3 : &gHuffTab2, compACTab ? gHuffVal3 : gHuffVal2); |
XkLi | 0:c546b51ecf0b | 1629 | |
XkLi | 0:c546b51ecf0b | 1630 | extraBits = 0; |
XkLi | 0:c546b51ecf0b | 1631 | numExtraBits = s & 0xF; |
XkLi | 0:c546b51ecf0b | 1632 | if (numExtraBits) |
XkLi | 0:c546b51ecf0b | 1633 | extraBits = getBits2(numExtraBits); |
XkLi | 0:c546b51ecf0b | 1634 | |
XkLi | 0:c546b51ecf0b | 1635 | r = s >> 4; |
XkLi | 0:c546b51ecf0b | 1636 | s &= 15; |
XkLi | 0:c546b51ecf0b | 1637 | |
XkLi | 0:c546b51ecf0b | 1638 | if (s) |
XkLi | 0:c546b51ecf0b | 1639 | { |
XkLi | 0:c546b51ecf0b | 1640 | int16 ac; |
XkLi | 0:c546b51ecf0b | 1641 | |
XkLi | 0:c546b51ecf0b | 1642 | if (r) |
XkLi | 0:c546b51ecf0b | 1643 | { |
XkLi | 0:c546b51ecf0b | 1644 | if ((k + r) > 63) |
XkLi | 0:c546b51ecf0b | 1645 | return PJPG_DECODE_ERROR; |
XkLi | 0:c546b51ecf0b | 1646 | |
XkLi | 0:c546b51ecf0b | 1647 | while (r) |
XkLi | 0:c546b51ecf0b | 1648 | { |
XkLi | 0:c546b51ecf0b | 1649 | gCoeffBuf[ZAG[k++]] = 0; |
XkLi | 0:c546b51ecf0b | 1650 | r--; |
XkLi | 0:c546b51ecf0b | 1651 | } |
XkLi | 0:c546b51ecf0b | 1652 | } |
XkLi | 0:c546b51ecf0b | 1653 | |
XkLi | 0:c546b51ecf0b | 1654 | ac = huffExtend(extraBits, s); |
XkLi | 0:c546b51ecf0b | 1655 | |
XkLi | 0:c546b51ecf0b | 1656 | gCoeffBuf[ZAG[k]] = ac * pQ[k]; |
XkLi | 0:c546b51ecf0b | 1657 | } |
XkLi | 0:c546b51ecf0b | 1658 | else |
XkLi | 0:c546b51ecf0b | 1659 | { |
XkLi | 0:c546b51ecf0b | 1660 | if (r == 15) |
XkLi | 0:c546b51ecf0b | 1661 | { |
XkLi | 0:c546b51ecf0b | 1662 | if ((k + 16) > 64) |
XkLi | 0:c546b51ecf0b | 1663 | return PJPG_DECODE_ERROR; |
XkLi | 0:c546b51ecf0b | 1664 | |
XkLi | 0:c546b51ecf0b | 1665 | for (r = 16; r > 0; r--) |
XkLi | 0:c546b51ecf0b | 1666 | gCoeffBuf[ZAG[k++]] = 0; |
XkLi | 0:c546b51ecf0b | 1667 | |
XkLi | 0:c546b51ecf0b | 1668 | k--; // - 1 because the loop counter is k |
XkLi | 0:c546b51ecf0b | 1669 | } |
XkLi | 0:c546b51ecf0b | 1670 | else |
XkLi | 0:c546b51ecf0b | 1671 | break; |
XkLi | 0:c546b51ecf0b | 1672 | } |
XkLi | 0:c546b51ecf0b | 1673 | } |
XkLi | 0:c546b51ecf0b | 1674 | |
XkLi | 0:c546b51ecf0b | 1675 | while (k < 64) |
XkLi | 0:c546b51ecf0b | 1676 | gCoeffBuf[ZAG[k++]] = 0; |
XkLi | 0:c546b51ecf0b | 1677 | |
XkLi | 0:c546b51ecf0b | 1678 | transformBlock(mcuBlock); |
XkLi | 0:c546b51ecf0b | 1679 | } |
XkLi | 0:c546b51ecf0b | 1680 | |
XkLi | 0:c546b51ecf0b | 1681 | return 0; |
XkLi | 0:c546b51ecf0b | 1682 | } |
XkLi | 0:c546b51ecf0b | 1683 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 1684 | unsigned char pjpeg_decode_mcu(void) |
XkLi | 0:c546b51ecf0b | 1685 | { |
XkLi | 0:c546b51ecf0b | 1686 | uint8 status; |
XkLi | 0:c546b51ecf0b | 1687 | |
XkLi | 0:c546b51ecf0b | 1688 | if (!gNumMCUSRemaining) |
XkLi | 0:c546b51ecf0b | 1689 | return PJPG_NO_MORE_BLOCKS; |
XkLi | 0:c546b51ecf0b | 1690 | |
XkLi | 0:c546b51ecf0b | 1691 | status = decodeNextMCU(); |
XkLi | 0:c546b51ecf0b | 1692 | if (status) |
XkLi | 0:c546b51ecf0b | 1693 | return status; |
XkLi | 0:c546b51ecf0b | 1694 | |
XkLi | 0:c546b51ecf0b | 1695 | gNumMCUSRemaining--; |
XkLi | 0:c546b51ecf0b | 1696 | |
XkLi | 0:c546b51ecf0b | 1697 | return 0; |
XkLi | 0:c546b51ecf0b | 1698 | } |
XkLi | 0:c546b51ecf0b | 1699 | //------------------------------------------------------------------------------ |
XkLi | 0:c546b51ecf0b | 1700 | unsigned char pjpeg_decode_init(pjpeg_image_info_t *pInfo, pjpeg_need_bytes_callback_t pNeed_bytes_callback, void *pCallback_data) |
XkLi | 0:c546b51ecf0b | 1701 | { |
XkLi | 0:c546b51ecf0b | 1702 | uint8 status; |
XkLi | 0:c546b51ecf0b | 1703 | |
XkLi | 0:c546b51ecf0b | 1704 | g_pNeedBytesCallback = pNeed_bytes_callback; |
XkLi | 0:c546b51ecf0b | 1705 | g_pCallback_data = pCallback_data; |
XkLi | 0:c546b51ecf0b | 1706 | |
XkLi | 0:c546b51ecf0b | 1707 | status = init(); |
XkLi | 0:c546b51ecf0b | 1708 | if (status) |
XkLi | 0:c546b51ecf0b | 1709 | return status; |
XkLi | 0:c546b51ecf0b | 1710 | |
XkLi | 0:c546b51ecf0b | 1711 | status = locateSOFMarker(); |
XkLi | 0:c546b51ecf0b | 1712 | if (status) |
XkLi | 0:c546b51ecf0b | 1713 | return status; |
XkLi | 0:c546b51ecf0b | 1714 | |
XkLi | 0:c546b51ecf0b | 1715 | status = initFrame(); |
XkLi | 0:c546b51ecf0b | 1716 | if (status) |
XkLi | 0:c546b51ecf0b | 1717 | return status; |
XkLi | 0:c546b51ecf0b | 1718 | |
XkLi | 0:c546b51ecf0b | 1719 | status = initScan(); |
XkLi | 0:c546b51ecf0b | 1720 | if (status) |
XkLi | 0:c546b51ecf0b | 1721 | return status; |
XkLi | 0:c546b51ecf0b | 1722 | |
XkLi | 0:c546b51ecf0b | 1723 | pInfo->m_width = gImageXSize; |
XkLi | 0:c546b51ecf0b | 1724 | pInfo->m_height = gImageYSize; |
XkLi | 0:c546b51ecf0b | 1725 | pInfo->m_comps = gCompsInFrame; |
XkLi | 0:c546b51ecf0b | 1726 | pInfo->m_scanType = gScanType; |
XkLi | 0:c546b51ecf0b | 1727 | pInfo->m_MCUSPerRow = gMaxMCUSPerRow; |
XkLi | 0:c546b51ecf0b | 1728 | pInfo->m_MCUSPerCol = gMaxMCUSPerCol; |
XkLi | 0:c546b51ecf0b | 1729 | pInfo->m_MCUWidth = gMaxMCUXSize; |
XkLi | 0:c546b51ecf0b | 1730 | pInfo->m_MCUHeight = gMaxMCUYSize; |
XkLi | 0:c546b51ecf0b | 1731 | pInfo->m_pMCUBufR = gMCUBufR; |
XkLi | 0:c546b51ecf0b | 1732 | pInfo->m_pMCUBufG = gMCUBufG; |
XkLi | 0:c546b51ecf0b | 1733 | pInfo->m_pMCUBufB = gMCUBufB; |
XkLi | 0:c546b51ecf0b | 1734 | |
XkLi | 0:c546b51ecf0b | 1735 | return 0; |
XkLi | 0:c546b51ecf0b | 1736 | } |