
Final
Dependencies: DebounceIn NokiaLCD WiflyInterface mbed
Fork of Websocket_Wifly_HelloWorld by
Revision 3:3c7906d60f89, committed 2012-12-13
- Comitter:
- Ifrah
- Date:
- Thu Dec 13 23:59:40 2012 +0000
- Parent:
- 2:c69a06fe81c0
- Child:
- 4:6ed9c8bb82c3
- Commit message:
- Getting Google Maps based on the GPS coordinates
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DebounceIn.lib Thu Dec 13 23:59:40 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/AjK/code/DebounceIn/#91a2e988ba9d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GPS.cpp Thu Dec 13 23:59:40 2012 +0000 @@ -0,0 +1,137 @@ +/* mbed EM-406 GPS Module Library + * Copyright (c) 2008-2010, sford + * + * 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 "GPS.h" + +GPS::GPS(PinName tx, PinName rx) : _gps(tx, rx) { + _gps.baud(4800); + longitude = 0.0; + latitude = 0.0; +} + +int GPS::sample() { + float time; + char ns, ew; + int lock; + + //return 1; //testing by Jigar + while (1) { + getline(); + //printf("\n\rentered the GPS.sample while loop \n\r %s\n\r", msg); + + + // Check if it is a GPGGA msg (matches both locked and non-locked msg) + // $GPGGA,000116.031,,,,,0,00,,,M,0.0,M,,0000*52 + /* + eg3. $GPGGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 1 = UTC of Position + 2 = Latitude + 3 = N or S + 4 = Longitude + 5 = E or W + 6 = GPS quality indicator (0=invalid; 1=GPS fix; 2=Diff. GPS fix) + 7 = Number of satellites in use [not those in view] + 8 = Horizontal dilution of position + 9 = Antenna altitude above/below mean sea level (geoid) + 10 = Meters (Antenna height unit) + 11 = Geoidal separation (Diff. between WGS-84 earth ellipsoid and + mean sea level. -=geoid is below WGS-84 ellipsoid) + 12 = Meters (Units of geoidal separation) + 13 = Age in seconds since last update from diff. reference station + 14 = Diff. reference station ID# + 15 = Checksum + + */ + // if (sscanf(msg, "GPGGA,%f,%f,%c,%f,%c,%*d,%*d, %*f,%*f,%*f,%*f,%*f,%*f,%d ", &time, &latitude, &ns, &longitude, &ew, &lock) >= 1) { + if(sscanf(msg, "GPGGA,%f,%f,%c,%f,%c,%d", &time, &latitude, &ns, &longitude, &ew, &lock) >= 1) { + + if (!lock) { + longitude = 0.0; + latitude = 0.0; + return 0; + } else { + if (ns == 'S') { + latitude *= -1.0; + } + if (ew == 'W') { + longitude *= -1.0; + } + float degrees = trunc(latitude / 100.0f); + float minutes = latitude - (degrees * 100.0f); + latitude = degrees + minutes / 60.0f; + degrees = trunc(longitude / 100.0f ); //degrees = trunc(longitude / 100.0f * 0.01f); + minutes = longitude - (degrees * 100.0f); + longitude = degrees + minutes / 60.0f; + return 1; + } + } + } +} + +float GPS::trunc(float v) { + if (v < 0.0) { + v*= -1.0; + v = floor(v); + v*=-1.0; + } else { + v = floor(v); + } + return v; +} + +void GPS::getline() { + + while (_gps.getc() != '$'); // wait for the start of a line + // printf("entered the getline loop\n\r"); + for (int i=0; i<256; i++) { + msg[i] = _gps.getc(); + if (msg[i] == '\r') { + msg[i] = 0; + return; + } + } + error("Overflowed message limit"); +} + +/* +$GPRMC,000115.039,V,,,,,,,291006,,*2C +$GPGGA,000116.031,,,,,0,00,,,M,0.0,M,,0000*52 +$GPGSA,A,1,,,,,,,,,,,,,,,*1E +$GPGSV,3,1,12,20,00,000,,10,00,000,,31,00,000,,27,00,000,*7C +$GPGSV,3,2,12,19,00,000,,07,00,000,,04,00,000,,24,00,000,*76 +$GPGSV,3,3,12,16,00,000,,28,00,000,,26,00,000,,29,00,000,*78 +$GPRMC,000116.031,V,,,,,,,291006,,*27 +$GPGGA,000117.035,,,,,0,00,,,M,0.0,M,,0000*57 +$GPGSA,A,1,,,,,,,,,,,,,,,*1E +$GPRMC,000117.035,V,,,,,,,291006,,*22 +$GPGGA,000118.039,,,,,0,00,,,M,0.0,M,,0000*54 +$GPGSA,A,1,,,,,,,,,,,,,,,*1E +$GPRMC,000118.039,V,,,,,,,291006,,*21 +$GPGGA,000119.035,,,,,0,00,,,M,0.0,M,,0000*59 +$GPGSA,A,1,,,,,,,,,,,,,,,*1E +$GPRMC,000119.035,V,,,,,,,291006,,*2C +$GPGGA,000120.037,,,,,0,00,,,M,0.0,M,,0000*51 +$GPGSA,A,1,,,,,,,,,,,,,,,*1E +$GPRMC,000120.037,V,,,,,,,291006,,*24 + +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GPS.h Thu Dec 13 23:59:40 2012 +0000 @@ -0,0 +1,57 @@ +/* mbed EM-406 GPS Module Library + * Copyright (c) 2008-2010, sford + * + * 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 "mbed.h" + +#ifndef MBED_GPS_H +#define MBED_GPS_H + +/** A GPS interface for reading from a Globalsat EM-406 GPS Module */ +class GPS { +public: + + /** Create the GPS interface, connected to the specified serial port + */ + GPS(PinName tx, PinName rx); + + /** Sample the incoming GPS data, returning whether there is a lock + * + * @return 1 if there was a lock when the sample was taken (and therefore .longitude and .latitude are valid), else 0 + */ + int sample(); + + /** The longitude (call sample() to set) */ + float longitude; + + /** The latitude (call sample() to set) */ + float latitude; + +private: + float trunc(float v); + void getline(); + + Serial _gps; + char msg[256]; + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NokiaLCD.lib Thu Dec 13 23:59:40 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/donde/code/NokiaLCD/#d829f93abd27
--- a/WebSocketClient.lib Fri Aug 24 14:06:31 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/samux/code/WebSocketClient/#466f90b7849a
--- a/WiflyInterface.lib Fri Aug 24 14:06:31 2012 +0000 +++ b/WiflyInterface.lib Thu Dec 13 23:59:40 2012 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/mbed_official/code/WiflyInterface/#fb4494783863 +http://mbed.org/users/mbed_official/code/WiflyInterface/#8e54830d0df7
--- a/main.cpp Fri Aug 24 14:06:31 2012 +0000 +++ b/main.cpp Thu Dec 13 23:59:40 2012 +0000 @@ -1,28 +1,224 @@ #include "mbed.h" #include "WiflyInterface.h" -#include "Websocket.h" +#include "NokiaLCD.h" +#include "picojpeg.h" +#include "DebounceIn.h" +#include "GPS.h" +#include <vector> +#define DEFAULTZOOM 15 /* wifly interface: -* - p9 and p10 are for the serial communication -* - p19 is for the reset pin -* - p26 is for the connection status -* - "mbed" is the ssid of the network -* - "password" is the password +* - p13 and p14 are for the serial communication +* - p28 is for the reset pin +* - p27 is for the connection status +* - 5th field is the ssid of the network +* - 6th field is the password * - WPA is the security */ -WiflyInterface wifly(p9, p10, p19, p26, "mbed", "password", WPA); + +WiflyInterface wifly(p13, p14, p28, p27, "GTother", "GeorgeP@1927", WPA); +Serial pc(USBTX,USBRX); +LocalFileSystem local("local");// Create the local filesystem under the name "local" +GPS gps(p9, p10); +DebounceIn ZoomIn(p18); +DebounceIn Refresh(p19); +DebounceIn ZoomOut(p20); +FILE *jpegfile; +int jpeg_filesize = 0; +int jpeg_filepos = 0; +NokiaLCD lcd(p5, p7, p8, p11, NokiaLCD::LCD6610); +int zoom = DEFAULTZOOM; + + +unsigned char pjpeg_need_bytes_callback(unsigned char* pBuf, unsigned char buf_size, unsigned char *pBytes_actually_read, void *pCallback_data) +{ + unsigned int n = min((unsigned int)(jpeg_filesize - jpeg_filepos), (unsigned int)buf_size); + if (n && (fread(pBuf, 1, n, jpegfile) != n)) + return PJPG_STREAM_READ_ERROR; + *pBytes_actually_read = (unsigned char)(n); + jpeg_filepos += n; + return 0; +} + +void ReadJPEGFromFile(const char *filename, NokiaLCD *lcd) +{ + pjpeg_image_info_t imageInfo; + jpegfile = fopen(filename,"rb"); + if(!jpegfile) { + pc.printf("File not Found: %s\n\r",filename); + } + fseek(jpegfile, 0, SEEK_END); + jpeg_filesize = ftell(jpegfile); + jpeg_filepos = 0; + fseek(jpegfile, 0, SEEK_SET); + int status = pjpeg_decode_init(&imageInfo, pjpeg_need_bytes_callback, NULL); + //const unsigned int row_pitch = imageInfo.m_width * imageInfo.m_comps; + int mcu_x = 0; + int mcu_y = 0; + + for ( ; ; ) { + status = pjpeg_decode_mcu(); + + if (status) { + if (status != PJPG_NO_MORE_BLOCKS) { + //pc.printf("pjpeg_decode_mcu() failed with status %u\n", status); + fclose(jpegfile); + return; + } -int main() { - wifly.init(); //Use DHCP - while (!wifly.connect()); - printf("IP Address is %s\n\r", wifly.getIPAddress()); + break; + } + + if (mcu_y >= imageInfo.m_MCUSPerCol) { + fclose(jpegfile); + return; + } + + // Copy MCU's pixel blocks into the destination bitmap. + + for (int y = 0; y < imageInfo.m_MCUHeight; y += 8) { + const int by_limit = min(8, imageInfo.m_height - (mcu_y * imageInfo.m_MCUHeight + y)); + for (int x = 0; x < imageInfo.m_MCUWidth; x += 8) { + + unsigned int src_ofs = (x * 8U) + (y * 16U); + const unsigned char *pSrcR = imageInfo.m_pMCUBufR + src_ofs; + const unsigned char *pSrcG = imageInfo.m_pMCUBufG + src_ofs; + const unsigned char *pSrcB = imageInfo.m_pMCUBufB + src_ofs; + + const int bx_limit = min(8, imageInfo.m_width - (mcu_x * imageInfo.m_MCUWidth + x)); + + if (imageInfo.m_scanType == PJPG_GRAYSCALE) { + for (int by = 0; by < by_limit; by++) { + for (int bx = 0; bx < bx_limit; bx++) { + unsigned int color = ((*pSrcR++) << 16); + (*lcd).pixel(mcu_x*imageInfo.m_MCUWidth+x+bx,mcu_y*imageInfo.m_MCUHeight+y+by,color); + } + pSrcR += (8 - bx_limit); + } + } else { + for (int by = 0; by < by_limit; by++) { + for (int bx = 0; bx < bx_limit; bx++) { + unsigned int color = ((*pSrcR++) << 16) | ((*pSrcG++) << 8) | (*pSrcB++); + (*lcd).pixel((130-imageInfo.m_width)/2+mcu_x*imageInfo.m_MCUWidth+x+bx,(130-imageInfo.m_height)/2+mcu_y*imageInfo.m_MCUHeight+y+by,color); + } + + pSrcR += (8 - bx_limit); + pSrcG += (8 - bx_limit); + pSrcB += (8 - bx_limit); + + } + } + } + } + + mcu_x++; + if (mcu_x == imageInfo.m_MCUSPerRow) { + mcu_x = 0; + mcu_y++; + } + } - Websocket ws("ws://sockets.mbed.org:443/ws/demo/wo"); - while (!ws.connect()); + fclose(jpegfile); +} + +void wiflyConnect() +{ + wifly.disconnect(); + wifly.init(); + while (!wifly.connect()) { + pc.printf("waiting\n\r"); + }// join the network +} + +void getNewImage(float latitude, float longitude, int zoom) +{ + TCPSocketConnection sock; + sock.connect("maps.googleapis.com", 80); + int ret = 0; + int total_bytes = 0; + char http_cmd[300]; + sprintf(http_cmd, "GET /maps/api/staticmap?center=%f%%2C%f&zoom=%d&size=130x130&sensor=true&format=jpg-baseline HTTP/1.0\n\n",latitude,longitude,zoom); + sock.send_all(http_cmd, sizeof(http_cmd)-1); - while (1) { - ws.send("WebSocket Hello World over Wifly"); - wait(1.0); + sock.set_blocking(false,10000); + char buffer[300]; + FILE* pFile; + pc.printf("%s\n\r",http_cmd); + pFile = fopen ("/local/image.jpg","w"); + pc.printf("Opening File\n\r"); + bool found_start = false; + bool found_end = false; + while (true) { + ret = sock.receive(buffer, sizeof(buffer)-1); + if (ret <= 0) { + pc.printf("Ret < 0. Break. \n\r"); + //wiflyConnect(); + break; + } + buffer[ret] = '\0'; + total_bytes += ret; + pc.printf("Received %d chars from server, total %d: %s\n\r", ret,total_bytes, buffer); + if(found_start) { + for(int i=1; i<ret; i++) { + if(buffer[i-1]==0xFF && buffer[i]==0xD9) { //jpg file end at FFD9 + pc.printf("found end. \n\r"); + fwrite(buffer,1,i+1,pFile); + found_end = true; + break; + } + } + if(!found_end) + fwrite(buffer,1,ret,pFile); + else { + pc.printf("Found Start and End. Break. \n\r"); + break; + } + + } else { + for(int i=1; i<ret; i++) { + if(buffer[i-1]==0xFF && buffer[i]==0xD8) { //jpg file starts from FFD8 + pc.printf("found start.\n\r"); + fwrite(&buffer[i-1],1,ret-i+1,pFile); + found_start = true; + break; + } + } + } } + + fclose (pFile); + pc.printf("Closing File\n\r"); + sock.close(); + lcd.cls(); + ReadJPEGFromFile("/local/IMAGE.JPG", &lcd); +} + +int main() +{ + pc.printf("Hello\n\r"); + wifly.init(); //Use DHCP + while (!wifly.connect()) { + pc.printf("waiting\n\r"); + }// join the network + pc.printf("IP Address is %s\n", wifly.getIPAddress()); + + float longitude = 0.0; + float latitude = 0.0; + while(1) { + if(gps.sample()) { + // pc.printf("I'm at %f, %f\n", gps.longitude, gps.latitude); + longitude = gps.longitude; + latitude = gps.latitude; + } else { + pc.printf("Oh Dear! No lock :(\n"); + } + if(Refresh) + getNewImage(latitude,longitude,zoom); + else if(ZoomIn) + getNewImage(latitude,longitude,++zoom); + else if(ZoomOut) + getNewImage(latitude,longitude,--zoom); + } + wifly.disconnect(); } \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/picojpeg/picojpeg.c Thu Dec 13 23:59:40 2012 +0000 @@ -0,0 +1,1736 @@ +//------------------------------------------------------------------------------ +// picojpeg v1.0 - Public domain, Rich Geldreich <richgel99@gmail.com> +// Last modified Nov. 27, 2010 +//------------------------------------------------------------------------------ +#include "picojpeg.h" +//------------------------------------------------------------------------------ +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef signed char int8; +typedef signed short int16; +//------------------------------------------------------------------------------ +// Change as needed - the PJPG_MAX_WIDTH/PJPG_MAX_HEIGHT checks are only present +// to quickly detect bogus files. +#define PJPG_MAX_WIDTH 16384 +#define PJPG_MAX_HEIGHT 16384 + +#define PJPG_MAXCOMPSINSCAN 3 +//------------------------------------------------------------------------------ +typedef enum +{ + M_SOF0 = 0xC0, + M_SOF1 = 0xC1, + M_SOF2 = 0xC2, + M_SOF3 = 0xC3, + + M_SOF5 = 0xC5, + M_SOF6 = 0xC6, + M_SOF7 = 0xC7, + + M_JPG = 0xC8, + M_SOF9 = 0xC9, + M_SOF10 = 0xCA, + M_SOF11 = 0xCB, + + M_SOF13 = 0xCD, + M_SOF14 = 0xCE, + M_SOF15 = 0xCF, + + M_DHT = 0xC4, + + M_DAC = 0xCC, + + M_RST0 = 0xD0, + M_RST1 = 0xD1, + M_RST2 = 0xD2, + M_RST3 = 0xD3, + M_RST4 = 0xD4, + M_RST5 = 0xD5, + M_RST6 = 0xD6, + M_RST7 = 0xD7, + + M_SOI = 0xD8, + M_EOI = 0xD9, + M_SOS = 0xDA, + M_DQT = 0xDB, + M_DNL = 0xDC, + M_DRI = 0xDD, + M_DHP = 0xDE, + M_EXP = 0xDF, + + M_APP0 = 0xE0, + M_APP15 = 0xEF, + + M_JPG0 = 0xF0, + M_JPG13 = 0xFD, + M_COM = 0xFE, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + +#define RST0 0xD0 +//------------------------------------------------------------------------------ +const int8 ZAG[] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, +}; +//------------------------------------------------------------------------------ +// 128 bytes +static int16 gCoeffBuf[8*8]; + +// 8*8*4 bytes * 3 = 768 +static uint8 gMCUBufR[256]; +static uint8 gMCUBufG[256]; +static uint8 gMCUBufB[256]; + +// 256 bytes +static int16 gQuant0[8*8]; +static int16 gQuant1[8*8]; + +// 6 bytes +static int16 gLastDC[3]; + +typedef struct HuffTableT +{ + uint16 mMinCode[16]; + uint16 mMaxCode[16]; + uint8 mValPtr[16]; +} HuffTable; + +// DC - 192 +static HuffTable gHuffTab0; + +static uint8 gHuffVal0[16]; + +static HuffTable gHuffTab1; +static uint8 gHuffVal1[16]; + +// AC - 672 +static HuffTable gHuffTab2; +static uint8 gHuffVal2[256]; + +static HuffTable gHuffTab3; +static uint8 gHuffVal3[256]; + +static uint8 gValidHuffTables; +static uint8 gValidQuantTables; + +static uint8 gTemFlag; +#define MAX_IN_BUF_SIZE 256 +static uint8 gInBuf[MAX_IN_BUF_SIZE]; +static uint8 gInBufOfs; +static uint8 gInBufLeft; + +static uint16 gBitBuf; +static uint8 gBitsLeft; +//------------------------------------------------------------------------------ +static uint16 gImageXSize; +static uint16 gImageYSize; +static uint8 gCompsInFrame; +static uint8 gCompIdent[3]; +static uint8 gCompHSamp[3]; +static uint8 gCompVSamp[3]; +static uint8 gCompQuant[3]; + +static uint16 gRestartInterval; +static uint16 gNextRestartNum; +static uint16 gRestartsLeft; + +static uint8 gCompsInScan; +static uint8 gCompList[3]; +static uint8 gCompDCTab[3]; // 0,1 +static uint8 gCompACTab[3]; // 0,1 + +static pjpeg_scan_type_t gScanType; + +static uint8 gMaxBlocksPerMCU; +static uint8 gMaxMCUXSize; +static uint8 gMaxMCUYSize; +static uint16 gMaxMCUSPerRow; +static uint16 gMaxMCUSPerCol; +static uint16 gNumMCUSRemaining; +static uint8 gMCUOrg[6]; + +static pjpeg_need_bytes_callback_t g_pNeedBytesCallback; +static void *g_pCallback_data; +//------------------------------------------------------------------------------ +static uint8 fillInBuf(void) +{ + unsigned char status; + + // Reserve a few bytes at the beginning of the buffer for putting back ("stuffing") chars. + gInBufOfs = 4; + gInBufLeft = 0; + + status = (*g_pNeedBytesCallback)(gInBuf + gInBufOfs, MAX_IN_BUF_SIZE - gInBufOfs, &gInBufLeft, g_pCallback_data); + if (status) + return status; + + return 0; +} +//------------------------------------------------------------------------------ +static uint8 getChar(void) +{ + if (!gInBufLeft) + { + fillInBuf(); + if (!gInBufLeft) + { + gTemFlag = ~gTemFlag; + return gTemFlag ? 0xFF : 0xD9; + } + } + + gInBufLeft--; + return gInBuf[gInBufOfs++]; +} +//------------------------------------------------------------------------------ +static void stuffChar(uint8 i) +{ + gInBufOfs--; + gInBuf[gInBufOfs] = i; + gInBufLeft++; +} +//------------------------------------------------------------------------------ +static uint8 getOctet(uint8 FFCheck) +{ + uint8 c = getChar(); + + if ((FFCheck) && (c == 0xFF)) + { + uint8 n = getChar(); + + if (n) + { + stuffChar(n); + stuffChar(0xFF); + } + } + + return c; +} +//------------------------------------------------------------------------------ +static uint16 getBits(uint8 numBits, uint8 FFCheck) +{ + uint8 origBits = numBits; + uint16 ret = gBitBuf; + + if (numBits > 8) + { + numBits -= 8; + + gBitBuf <<= gBitsLeft; + + gBitBuf |= getOctet(FFCheck); + + gBitBuf <<= (8 - gBitsLeft); + + ret = (ret & 0xFF00) | (gBitBuf >> 8); + } + + if (gBitsLeft < numBits) + { + gBitBuf <<= gBitsLeft; + + gBitBuf |= getOctet(FFCheck); + + gBitBuf <<= (numBits - gBitsLeft); + + gBitsLeft = 8 - (numBits - gBitsLeft); + } + else + { + gBitsLeft = (uint8)(gBitsLeft - numBits); + gBitBuf <<= numBits; + } + + return ret >> (16 - origBits); +} +//------------------------------------------------------------------------------ +static uint16 getBits1(uint8 numBits) +{ + return getBits(numBits, 0); +} +//------------------------------------------------------------------------------ +static uint16 getBits2(uint8 numBits) +{ + return getBits(numBits, 1); +} +//------------------------------------------------------------------------------ +static uint8 getBit(void) +{ + uint8 ret = 0; + if (gBitBuf & 0x8000) + ret = 1; + + if (!gBitsLeft) + { + gBitBuf |= getOctet(1); + + gBitsLeft += 8; + } + + gBitsLeft--; + gBitBuf <<= 1; + + return ret; +} +//------------------------------------------------------------------------------ +static uint16 getExtendTest(uint8 i) +{ + switch (i) + { + case 0: return 0; + case 1: return 0x0001; + case 2: return 0x0002; + case 3: return 0x0004; + case 4: return 0x0008; + case 5: return 0x0010; + case 6: return 0x0020; + case 7: return 0x0040; + case 8: return 0x0080; + case 9: return 0x0100; + case 10: return 0x0200; + case 11: return 0x0400; + case 12: return 0x0800; + case 13: return 0x1000; + case 14: return 0x2000; + case 15: return 0x4000; + default: return 0; + } +} +//------------------------------------------------------------------------------ +static int16 getExtendOffset(uint8 i) +{ + switch (i) + { + case 0: return 0; + case 1: return ((-1)<<1) + 1; + case 2: return ((-1)<<2) + 1; + case 3: return ((-1)<<3) + 1; + case 4: return ((-1)<<4) + 1; + case 5: return ((-1)<<5) + 1; + case 6: return ((-1)<<6) + 1; + case 7: return ((-1)<<7) + 1; + case 8: return ((-1)<<8) + 1; + case 9: return ((-1)<<9) + 1; + case 10: return ((-1)<<10) + 1; + case 11: return ((-1)<<11) + 1; + case 12: return ((-1)<<12) + 1; + case 13: return ((-1)<<13) + 1; + case 14: return ((-1)<<14) + 1; + case 15: return ((-1)<<15) + 1; + default: return 0; + } +}; +//------------------------------------------------------------------------------ +static int16 huffExtend(uint16 x, uint8 s) +{ + return ((x < getExtendTest(s)) ? ((int16)x + getExtendOffset(s)) : (int16)x); +} +//------------------------------------------------------------------------------ +static uint8 huffDecode(const HuffTable* pHuffTable, const uint8* pHuffVal) +{ + uint8 i = 0; + uint8 j; + uint16 code = getBit(); + + for ( ; ; ) + { + uint16 maxCode; + + if (i == 16) + return 0; + + maxCode = pHuffTable->mMaxCode[i]; + if ((code <= maxCode) && (maxCode != 0xFFFF)) + break; + + i++; + code <<= 1; + code |= getBit(); + } + + j = pHuffTable->mValPtr[i]; + j = (uint8)(j + (code - pHuffTable->mMinCode[i])); + + return pHuffVal[j]; +} +//------------------------------------------------------------------------------ +static void huffCreate(const uint8* pBits, HuffTable* pHuffTable) +{ + uint8 i = 0; + uint8 j = 0; + + uint16 code = 0; + + for ( ; ; ) + { + uint8 num = pBits[i]; + + if (!num) + { + pHuffTable->mMinCode[i] = 0x0000; + pHuffTable->mMaxCode[i] = 0xFFFF; + pHuffTable->mValPtr[i] = 0; + } + else + { + pHuffTable->mMinCode[i] = code; + pHuffTable->mMaxCode[i] = code + num - 1; + pHuffTable->mValPtr[i] = j; + + j = (uint8)(j + num); + + code = (uint16)(code + num); + } + + code <<= 1; + + i++; + if (i > 15) + break; + } +} +//------------------------------------------------------------------------------ +static HuffTable* getHuffTable(uint8 index) +{ + // 0-1 = DC + // 2-3 = AC + switch (index) + { + case 0: return &gHuffTab0; + case 1: return &gHuffTab1; + case 2: return &gHuffTab2; + case 3: return &gHuffTab3; + default: return 0; + } +} +//------------------------------------------------------------------------------ +static uint8* getHuffVal(uint8 index) +{ + // 0-1 = DC + // 2-3 = AC + switch (index) + { + case 0: return gHuffVal0; + case 1: return gHuffVal1; + case 2: return gHuffVal2; + case 3: return gHuffVal3; + default: return 0; + } +} +//------------------------------------------------------------------------------ +static uint16 getMaxHuffCodes(uint8 index) +{ + return (index < 2) ? 12 : 255; +} +//------------------------------------------------------------------------------ +static uint8 readDHTMarker(void) +{ + uint8 bits[16]; + uint16 left = getBits1(16); + + if (left < 2) + return PJPG_BAD_DHT_MARKER; + + left -= 2; + + while (left) + { + uint8 i, tableIndex, index; + uint8* pHuffVal; + HuffTable* pHuffTable; + uint16 count, totalRead; + + index = (uint8)getBits1(8); + + if ( ((index & 0xF) > 1) || ((index & 0xF0) > 0x10) ) + return PJPG_BAD_DHT_INDEX; + + tableIndex = ((index >> 3) & 2) + (index & 1); + + pHuffTable = getHuffTable(tableIndex); + pHuffVal = getHuffVal(tableIndex); + + gValidHuffTables |= (1 << tableIndex); + + count = 0; + for (i = 0; i <= 15; i++) + { + uint8 n = (uint8)getBits1(8); + bits[i] = n; + count = (uint16)(count + n); + } + + if (count > getMaxHuffCodes(tableIndex)) + return PJPG_BAD_DHT_COUNTS; + + for (i = 0; i < count; i++) + pHuffVal[i] = (uint8)getBits1(8); + + totalRead = 1 + 16 + count; + + if (left < totalRead) + return PJPG_BAD_DHT_MARKER; + + left = (uint16)(left - totalRead); + + huffCreate(bits, pHuffTable); + } + + return 0; +} +//------------------------------------------------------------------------------ +static void createWinogradQuant(int16* pQuant); + +static uint8 readDQTMarker(void) +{ + uint16 left = getBits1(16); + + if (left < 2) + return PJPG_BAD_DQT_MARKER; + + left -= 2; + + while (left) + { + uint8 i; + uint8 n = (uint8)getBits1(8); + uint8 prec = n >> 4; + uint16 totalRead; + + n &= 0x0F; + + if (n > 1) + return PJPG_BAD_DQT_TABLE; + + gValidQuantTables |= (n ? 2 : 1); + + // read quantization entries, in zag order + for (i = 0; i < 64; i++) + { + uint16 temp = getBits1(8); + + if (prec) + temp = (temp << 8) + getBits1(8); + + if (n) + gQuant1[i] = (int16)temp; + else + gQuant0[i] = (int16)temp; + } + + createWinogradQuant(n ? gQuant1 : gQuant0); + + totalRead = 64 + 1; + + if (prec) + totalRead += 64; + + if (left < totalRead) + return PJPG_BAD_DQT_LENGTH; + + left = (uint16)(left - totalRead); + } + + return 0; +} +//------------------------------------------------------------------------------ +static uint8 readSOFMarker(void) +{ + uint8 i; + uint16 left = getBits1(16); + + if (getBits1(8) != 8) + return PJPG_BAD_PRECISION; + + gImageYSize = getBits1(16); + + if ((!gImageYSize) || (gImageYSize > PJPG_MAX_HEIGHT)) + return PJPG_BAD_HEIGHT; + + gImageXSize = getBits1(16); + + if ((!gImageXSize) || (gImageXSize > PJPG_MAX_WIDTH)) + return PJPG_BAD_WIDTH; + + gCompsInFrame = (uint8)getBits1(8); + + if (gCompsInFrame > 3) + return PJPG_TOO_MANY_COMPONENTS; + + if (left != (gCompsInFrame + gCompsInFrame + gCompsInFrame + 8)) + return PJPG_BAD_SOF_LENGTH; + + for (i = 0; i < gCompsInFrame; i++) + { + gCompIdent[i] = (uint8)getBits1(8); + gCompHSamp[i] = (uint8)getBits1(4); + gCompVSamp[i] = (uint8)getBits1(4); + gCompQuant[i] = (uint8)getBits1(8); + + if (gCompQuant[i] > 1) + return PJPG_UNSUPPORTED_QUANT_TABLE; + } + + return 0; +} +//------------------------------------------------------------------------------ +// Used to skip unrecognized markers. +static uint8 skipVariableMarker(void) +{ + uint16 left = getBits1(16); + + if (left < 2) + return PJPG_BAD_VARIABLE_MARKER; + + left -= 2; + + while (left) + { + getBits1(8); + left--; + } + + return 0; +} +//------------------------------------------------------------------------------ +// Read a define restart interval (DRI) marker. +static uint8 readDRIMarker(void) +{ + if (getBits1(16) != 4) + return PJPG_BAD_DRI_LENGTH; + + gRestartInterval = getBits1(16); + + return 0; +} +//------------------------------------------------------------------------------ +// Read a start of scan (SOS) marker. +static uint8 readSOSMarker(void) +{ + uint8 i; + uint16 left = getBits1(16); + uint8 spectral_start, spectral_end, successive_high, successive_low; + + gCompsInScan = (uint8)getBits1(8); + + left -= 3; + + if ( (left != (gCompsInScan + gCompsInScan + 3)) || (gCompsInScan < 1) || (gCompsInScan > PJPG_MAXCOMPSINSCAN) ) + return PJPG_BAD_SOS_LENGTH; + + for (i = 0; i < gCompsInScan; i++) + { + uint8 cc = (uint8)getBits1(8); + uint8 c = (uint8)getBits1(8); + uint8 ci; + + left -= 2; + + for (ci = 0; ci < gCompsInFrame; ci++) + if (cc == gCompIdent[ci]) + break; + + if (ci >= gCompsInFrame) + return PJPG_BAD_SOS_COMP_ID; + + gCompList[i] = ci; + gCompDCTab[ci] = (c >> 4) & 15; + gCompACTab[ci] = (c & 15); + } + + spectral_start = (uint8)getBits1(8); + spectral_end = (uint8)getBits1(8); + successive_high = (uint8)getBits1(4); + successive_low = (uint8)getBits1(4); + + left -= 3; + + while (left) + { + getBits1(8); + left--; + } + + return 0; +} +//------------------------------------------------------------------------------ +static uint8 nextMarker(void) +{ + uint8 c; + uint8 bytes = 0; + + do + { + do + { + bytes++; + + c = (uint8)getBits1(8); + + } while (c != 0xFF); + + do + { + c = (uint8)getBits1(8); + + } while (c == 0xFF); + + } while (c == 0); + + // If bytes > 0 here, there where extra bytes before the marker (not good). + + return c; +} +//------------------------------------------------------------------------------ +// Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is +// encountered. +static uint8 processMarkers(uint8* pMarker) +{ + for ( ; ; ) + { + uint8 c = nextMarker(); + + switch (c) + { + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: + // case M_JPG: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + case M_SOI: + case M_EOI: + case M_SOS: + { + *pMarker = c; + return 0; + } + case M_DHT: + { + readDHTMarker(); + break; + } + // Sorry, no arithmitic support at this time. Dumb patents! + case M_DAC: + { + return PJPG_NO_ARITHMITIC_SUPPORT; + } + case M_DQT: + { + readDQTMarker(); + break; + } + case M_DRI: + { + readDRIMarker(); + break; + } + //case M_APP0: /* no need to read the JFIF marker */ + + case M_JPG: + case M_RST0: /* no parameters */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + { + return PJPG_UNEXPECTED_MARKER; + } + default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */ + { + skipVariableMarker(); + break; + } + } + } +// return 0; +} +//------------------------------------------------------------------------------ +// Finds the start of image (SOI) marker. +static uint8 locateSOIMarker(void) +{ + uint16 bytesleft; + + uint8 lastchar = (uint8)getBits1(8); + + uint8 thischar = (uint8)getBits1(8); + + /* ok if it's a normal JPEG file without a special header */ + + if ((lastchar == 0xFF) && (thischar == M_SOI)) + return 0; + + bytesleft = 4096; //512; + + for ( ; ; ) + { + if (--bytesleft == 0) + return PJPG_NOT_JPEG; + + lastchar = thischar; + + thischar = (uint8)getBits1(8); + + if (lastchar == 0xFF) + { + if (thischar == M_SOI) + break; + else if (thischar == M_EOI) //getBits1 will keep returning M_EOI if we read past the end + return PJPG_NOT_JPEG; + } + } + + /* Check the next character after marker: if it's not 0xFF, it can't + be the start of the next marker, so the file is bad */ + + thischar = (uint8)((gBitBuf >> 8) & 0xFF); + + if (thischar != 0xFF) + return PJPG_NOT_JPEG; + + return 0; +} +//------------------------------------------------------------------------------ +// Find a start of frame (SOF) marker. +static uint8 locateSOFMarker(void) +{ + uint8 c; + + uint8 status = locateSOIMarker(); + if (status) + return status; + + status = processMarkers(&c); + if (status) + return status; + + switch (c) + { + case M_SOF2: + { + return PJPG_UNSUPPORTED_MODE; + } + case M_SOF0: /* baseline DCT */ + { + status = readSOFMarker(); + if (status) + return status; + + break; + } + case M_SOF9: + { + return PJPG_NO_ARITHMITIC_SUPPORT; + } + case M_SOF1: /* extended sequential DCT */ + default: + { + return PJPG_UNSUPPORTED_MARKER; + } + } + + return 0; +} +//------------------------------------------------------------------------------ +// Find a start of scan (SOS) marker. +static uint8 locateSOSMarker(uint8* pFoundEOI) +{ + uint8 c; + uint8 status; + + *pFoundEOI = 0; + + status = processMarkers(&c); + if (status) + return status; + + if (c == M_EOI) + { + *pFoundEOI = 1; + return 0; + } + else if (c != M_SOS) + return PJPG_UNEXPECTED_MARKER; + + return readSOSMarker(); +} +//------------------------------------------------------------------------------ +static uint8 init(void) +{ + gImageXSize = 0; + gImageYSize = 0; + gCompsInFrame = 0; + gRestartInterval = 0; + gCompsInScan = 0; + gValidHuffTables = 0; + gValidQuantTables = 0; + gTemFlag = 0; + gInBufOfs = 0; + gInBufLeft = 0; + gBitBuf = 0; + gBitsLeft = 8; + + getBits1(8); + getBits1(8); + + return 0; +} +//------------------------------------------------------------------------------ +// This method throws back into the stream any bytes that where read +// into the bit buffer during initial marker scanning. +static void fixInBuffer(void) +{ + /* In case any 0xFF's where pulled into the buffer during marker scanning */ + + if (gBitsLeft > 0) + stuffChar((uint8)gBitBuf); + + stuffChar((uint8)(gBitBuf >> 8)); + + gBitsLeft = 8; + getBits2(8); + getBits2(8); +} +//------------------------------------------------------------------------------ +// Restart interval processing. +static uint8 processRestart(void) +{ + // Let's scan a little bit to find the marker, but not _too_ far. + // 1536 is a "fudge factor" that determines how much to scan. + uint16 i; + uint8 c = 0; + + for (i = 1536; i > 0; i--) + if (getChar() == 0xFF) + break; + + if (i == 0) + return PJPG_BAD_RESTART_MARKER; + + for ( ; i > 0; i--) + if ((c = getChar()) != 0xFF) + break; + + if (i == 0) + return PJPG_BAD_RESTART_MARKER; + + // Is it the expected marker? If not, something bad happened. + if (c != (gNextRestartNum + M_RST0)) + return PJPG_BAD_RESTART_MARKER; + + // Reset each component's DC prediction values. + gLastDC[0] = 0; + gLastDC[1] = 0; + gLastDC[2] = 0; + + gRestartsLeft = gRestartInterval; + + gNextRestartNum = (gNextRestartNum + 1) & 7; + + // Get the bit buffer going again... + + gBitsLeft = 8; + getBits2(8); + getBits2(8); + + return 0; +} +//------------------------------------------------------------------------------ +static uint8 findEOI(void) +{ + uint8 c; + uint8 status; + + // Prime the bit buffer + gBitsLeft = 8; + getBits1(8); + getBits1(8); + + // The next marker _should_ be EOI + status = processMarkers(&c); + if (status) + return status; + + //gTotalBytesRead -= in_buf_left; + if (c != M_EOI) + return PJPG_UNEXPECTED_MARKER; + + return 0; +} +//------------------------------------------------------------------------------ +static uint8 checkHuffTables(void) +{ + uint8 i; + + for (i = 0; i < gCompsInScan; i++) + { + uint8 compDCTab = gCompDCTab[gCompList[i]]; + uint8 compACTab = gCompACTab[gCompList[i]] + 2; + + if ( ((gValidHuffTables & (1 << compDCTab)) == 0) || + ((gValidHuffTables & (1 << compACTab)) == 0) ) + return PJPG_UNDEFINED_HUFF_TABLE; + } + + return 0; +} +//------------------------------------------------------------------------------ +static uint8 checkQuantTables(void) +{ + uint8 i; + + for (i = 0; i < gCompsInScan; i++) + { + uint8 compQuantMask = gCompQuant[gCompList[i]] ? 2 : 1; + + if ((gValidQuantTables & compQuantMask) == 0) + return PJPG_UNDEFINED_QUANT_TABLE; + } + + return 0; +} +//------------------------------------------------------------------------------ +static uint8 initScan(void) +{ + uint8 foundEOI; + uint8 status = locateSOSMarker(&foundEOI); + if (status) + return status; + if (foundEOI) + return PJPG_UNEXPECTED_MARKER; + + status = checkHuffTables(); + if (status) + return status; + + status = checkQuantTables(); + if (status) + return status; + + gLastDC[0] = 0; + gLastDC[1] = 0; + gLastDC[2] = 0; + + if (gRestartInterval) + { + gRestartsLeft = gRestartInterval; + gNextRestartNum = 0; + } + + fixInBuffer(); + + return 0; +} +//------------------------------------------------------------------------------ +static uint8 initFrame(void) +{ + if (gCompsInFrame == 1) + { + if ((gCompHSamp[0] != 1) || (gCompVSamp[0] != 1)) + return PJPG_UNSUPPORTED_SAMP_FACTORS; + + gScanType = PJPG_GRAYSCALE; + + gMaxBlocksPerMCU = 1; + gMCUOrg[0] = 0; + + gMaxMCUXSize = 8; + gMaxMCUYSize = 8; + } + else if (gCompsInFrame == 3) + { + if ( ((gCompHSamp[1] != 1) || (gCompVSamp[1] != 1)) || + ((gCompHSamp[2] != 1) || (gCompVSamp[2] != 1)) ) + return PJPG_UNSUPPORTED_SAMP_FACTORS; + + if ((gCompHSamp[0] == 1) && (gCompVSamp[0] == 1)) + { + gScanType = PJPG_YH1V1; + + gMaxBlocksPerMCU = 3; + gMCUOrg[0] = 0; + gMCUOrg[1] = 1; + gMCUOrg[2] = 2; + + gMaxMCUXSize = 8; + gMaxMCUYSize = 8; + } + else if ((gCompHSamp[0] == 2) && (gCompVSamp[0] == 2)) + { + gScanType = PJPG_YH2V2; + + gMaxBlocksPerMCU = 6; + gMCUOrg[0] = 0; + gMCUOrg[1] = 0; + gMCUOrg[2] = 0; + gMCUOrg[3] = 0; + gMCUOrg[4] = 1; + gMCUOrg[5] = 2; + + gMaxMCUXSize = 16; + gMaxMCUYSize = 16; + } + else + return PJPG_UNSUPPORTED_SAMP_FACTORS; + } + else + return PJPG_UNSUPPORTED_COLORSPACE; + + gMaxMCUSPerRow = (gImageXSize + (gMaxMCUXSize - 1)) >> ((gMaxMCUXSize == 8) ? 3 : 4); + gMaxMCUSPerCol = (gImageYSize + (gMaxMCUYSize - 1)) >> ((gMaxMCUYSize == 8) ? 3 : 4); + + gNumMCUSRemaining = gMaxMCUSPerRow * gMaxMCUSPerCol; + + return 0; +} +/*----------------------------------------------------------------------------*/ +#define DCT_SCALE_BITS 7 + +#define DCT_SCALE (1U << DCT_SCALE_BITS) + +#define DESCALE(x) (((x) + (1U << (DCT_SCALE_BITS - 1))) >> DCT_SCALE_BITS) + +#define WFIX(x) ((x) * DCT_SCALE + 0.5f) + +#define WINOGRAD_QUANT_SCALE_BITS 10 + +const uint8 gWinogradQuant[] = +{ + 128, 178, 178, 167, 246, 167, 151, 232, + 232, 151, 128, 209, 219, 209, 128, 101, + 178, 197, 197, 178, 101, 69, 139, 167, + 177, 167, 139, 69, 35, 96, 131, 151, + 151, 131, 96, 35, 49, 91, 118, 128, + 118, 91, 49, 46, 81, 101, 101, 81, + 46, 42, 69, 79, 69, 42, 35, 54, + 54, 35, 28, 37, 28, 19, 19, 10, +}; + +static void createWinogradQuant(int16* pQuant) +{ + uint8 i; + + for (i = 0; i < 64; i++) + { + long x = pQuant[i]; + x *= gWinogradQuant[i]; + pQuant[i] = (int16)((x + (1 << (WINOGRAD_QUANT_SCALE_BITS - DCT_SCALE_BITS - 1))) >> (WINOGRAD_QUANT_SCALE_BITS - DCT_SCALE_BITS)); + } +} + +// 1/cos(4*pi/16) +// 362, 256+106 +#define b1 362 + +// 1/cos(6*pi/16) +// 669, 256+256+157 +#define b2 669 + +// 1/cos(4*pi/16) +// 362, 256+106 +#define b3 362 + +// 1/cos(2*pi/16) +// 277, 256+21 +#define b4 277 + +// 1/(cos(2*pi/16) + cos(6*pi/16)) +// 196, 196 +#define b5 196 + +static int16 imul_b1_b3(int16 w) +{ + long x = (w * 362L); + x += 128L; + return (int16)(x >> 8); +} + +static int16 imul_b2(int16 w) +{ + long x = (w * 669L); + x += 128L; + return (int16)(x >> 8); +} + +static int16 imul_b4(int16 w) +{ + long x = (w * 277L); + x += 128L; + return (int16)(x >> 8); +} + +static int16 imul_b5(int16 w) +{ + long x = (w * 196L); + x += 128L; + return (int16)(x >> 8); +} + +static uint8 clamp(int16 s) +{ + if ((uint16)s > 255U) + { + if (s < 0) + return 0; + else if (s > 255) + return 255; + } + + return (uint8)s; +} + +static void idctRows(void) +{ + uint8 i; + int16* pSrc = gCoeffBuf; + + for (i = 0; i < 8; i++) + { + int16 src4 = *(pSrc+5); + int16 src7 = *(pSrc+3); + int16 x4 = src4 - src7; + int16 x7 = src4 + src7; + + int16 src5 = *(pSrc+1); + int16 src6 = *(pSrc+7); + int16 x5 = src5 + src6; + int16 x6 = src5 - src6; + + int16 tmp1 = imul_b5(x4 - x6); + int16 stg26 = imul_b4(x6) - tmp1; + + int16 x24 = tmp1 - imul_b2(x4); + + int16 x15 = x5 - x7; + int16 x17 = x5 + x7; + + int16 tmp2 = stg26 - x17; + int16 tmp3 = imul_b1_b3(x15) - tmp2; + int16 x44 = tmp3 + x24; + + int16 src0 = *(pSrc+0); + int16 src1 = *(pSrc+4); + int16 x30 = src0 + src1; + int16 x31 = src0 - src1; + + int16 src2 = *(pSrc+2); + int16 src3 = *(pSrc+6); + int16 x12 = src2 - src3; + int16 x13 = src2 + src3; + + int16 x32 = imul_b1_b3(x12) - x13; + + int16 x40 = x30 + x13; + int16 x43 = x30 - x13; + int16 x41 = x31 + x32; + int16 x42 = x31 - x32; + + *(pSrc+0) = x40 + x17; + *(pSrc+1) = x41 + tmp2; + *(pSrc+2) = x42 + tmp3; + *(pSrc+3) = x43 - x44; + *(pSrc+4) = x43 + x44; + *(pSrc+5) = x42 - tmp3; + *(pSrc+6) = x41 - tmp2; + *(pSrc+7) = x40 - x17; + + pSrc += 8; + } +} + +static void idctCols(void) +{ + uint8 i; + + int16* pSrc = gCoeffBuf; + + for (i = 0; i < 8; i++) + { + int16 src4 = *(pSrc+5*8); + int16 src7 = *(pSrc+3*8); + int16 x4 = src4 - src7; + int16 x7 = src4 + src7; + + int16 src5 = *(pSrc+1*8); + int16 src6 = *(pSrc+7*8); + int16 x5 = src5 + src6; + int16 x6 = src5 - src6; + + int16 tmp1 = imul_b5(x4 - x6); + int16 stg26 = imul_b4(x6) - tmp1; + + int16 x24 = tmp1 - imul_b2(x4); + + int16 x15 = x5 - x7; + int16 x17 = x5 + x7; + + int16 tmp2 = stg26 - x17; + int16 tmp3 = imul_b1_b3(x15) - tmp2; + int16 x44 = tmp3 + x24; + + int16 src0 = *(pSrc+0*8); + int16 src1 = *(pSrc+4*8); + int16 x30 = src0 + src1; + int16 x31 = src0 - src1; + + int16 src2 = *(pSrc+2*8); + int16 src3 = *(pSrc+6*8); + int16 x12 = src2 - src3; + int16 x13 = src2 + src3; + + int16 x32 = imul_b1_b3(x12) - x13; + + int16 x40 = x30 + x13; + int16 x43 = x30 - x13; + int16 x41 = x31 + x32; + int16 x42 = x31 - x32; + + *(pSrc+0*8) = clamp(DESCALE(x40 + x17) + 128); + *(pSrc+1*8) = clamp(DESCALE(x41 + tmp2) + 128); + *(pSrc+2*8) = clamp(DESCALE(x42 + tmp3) + 128); + *(pSrc+3*8) = clamp(DESCALE(x43 - x44) + 128); + *(pSrc+4*8) = clamp(DESCALE(x43 + x44) + 128); + *(pSrc+5*8) = clamp(DESCALE(x42 - tmp3) + 128); + *(pSrc+6*8) = clamp(DESCALE(x41 - tmp2) + 128); + *(pSrc+7*8) = clamp(DESCALE(x40 - x17) + 128); + + pSrc++; + } +} + +/*----------------------------------------------------------------------------*/ +static uint8 addAndClamp(uint8 a, int16 b) +{ + b = a + b; + + if ((uint16)b > 255U) + { + if (b < 0) + return 0; + else if (b > 255) + return 255; + } + + return (uint8)b; +} +/*----------------------------------------------------------------------------*/ +static uint8 subAndClamp(uint8 a, int16 b) +{ + b = a - b; + + if ((uint16)b > 255U) + { + if (b < 0) + return 0; + else if (b > 255) + return 255; + } + + return (uint8)b; +} +/*----------------------------------------------------------------------------*/ +// 103/256 +//R = Y + 1.402 (Cr-128) + +// 88/256, 183/256 +//G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128) + +// 198/256 +//B = Y + 1.772 (Cb-128) +/*----------------------------------------------------------------------------*/ +static void upsampleCb(uint8 srcOfs, uint8 dstOfs) +{ + // Cb - affects G and B + uint8 x, y; + int16* pSrc = gCoeffBuf + srcOfs; + uint8* pDstG = gMCUBufG + dstOfs; + uint8* pDstB = gMCUBufB + dstOfs; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 4; x++) + { + uint8 cb = (uint8)*pSrc++; + int16 cbG, cbB; + + cbG = ((cb * 88U) >> 8U) - 44U; + pDstG[0] = subAndClamp(pDstG[0], cbG); + pDstG[1] = subAndClamp(pDstG[1], cbG); + pDstG[8] = subAndClamp(pDstG[8], cbG); + pDstG[9] = subAndClamp(pDstG[9], cbG); + + cbB = (cb + ((cb * 198U) >> 8U)) - 227U; + pDstB[0] = addAndClamp(pDstB[0], cbB); + pDstB[1] = addAndClamp(pDstB[1], cbB); + pDstB[8] = addAndClamp(pDstB[8], cbB); + pDstB[9] = addAndClamp(pDstB[9], cbB); + + pDstG += 2; + pDstB += 2; + } + + pSrc = pSrc - 4 + 8; + pDstG = pDstG - 8 + 16; + pDstB = pDstB - 8 + 16; + } +} +/*----------------------------------------------------------------------------*/ +// 103/256 +//R = Y + 1.402 (Cr-128) + +// 88/256, 183/256 +//G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128) + +// 198/256 +//B = Y + 1.772 (Cb-128) +/*----------------------------------------------------------------------------*/ +static void upsampleCr(uint8 srcOfs, uint8 dstOfs) +{ + // Cr - affects R and G + uint8 x, y; + int16* pSrc = gCoeffBuf + srcOfs; + uint8* pDstR = gMCUBufR + dstOfs; + uint8* pDstG = gMCUBufG + dstOfs; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 4; x++) + { + uint8 cr = (uint8)*pSrc++; + int16 crR, crG; + + crR = (cr + ((cr * 103U) >> 8U)) - 179; + pDstR[0] = addAndClamp(pDstR[0], crR); + pDstR[1] = addAndClamp(pDstR[1], crR); + pDstR[8] = addAndClamp(pDstR[8], crR); + pDstR[9] = addAndClamp(pDstR[9], crR); + + crG = ((cr * 183U) >> 8U) - 91; + pDstG[0] = subAndClamp(pDstG[0], crG); + pDstG[1] = subAndClamp(pDstG[1], crG); + pDstG[8] = subAndClamp(pDstG[8], crG); + pDstG[9] = subAndClamp(pDstG[9], crG); + + pDstR += 2; + pDstG += 2; + } + + pSrc = pSrc - 4 + 8; + pDstR = pDstR - 8 + 16; + pDstG = pDstG - 8 + 16; + } +} +/*----------------------------------------------------------------------------*/ +static void copyY(uint8 dstOfs) +{ + uint8 i; + uint8* pRDst = gMCUBufR + dstOfs; + uint8* pGDst = gMCUBufG + dstOfs; + uint8* pBDst = gMCUBufB + dstOfs; + int16* pSrc = gCoeffBuf; + + for (i = 64; i > 0; i--) + { + uint8 c = (uint8)*pSrc++; + + *pRDst++ = c; + *pGDst++ = c; + *pBDst++ = c; + } +} +/*----------------------------------------------------------------------------*/ +static void convertCb(uint8 dstOfs) +{ + uint8 i; + uint8* pDstG = gMCUBufG + dstOfs; + uint8* pDstB = gMCUBufB + dstOfs; + int16* pSrc = gCoeffBuf; + + for (i = 64; i > 0; i--) + { + uint8 cb = (uint8)*pSrc++; + int16 cbG, cbB; + + cbG = ((cb * 88U) >> 8U) - 44U; + *pDstG++ = subAndClamp(pDstG[0], cbG); + + cbB = (cb + ((cb * 198U) >> 8U)) - 227U; + *pDstB++ = addAndClamp(pDstB[0], cbB); + } +} +/*----------------------------------------------------------------------------*/ +static void convertCr(uint8 dstOfs) +{ + uint8 i; + uint8* pDstR = gMCUBufR + dstOfs; + uint8* pDstG = gMCUBufG + dstOfs; + int16* pSrc = gCoeffBuf; + + for (i = 64; i > 0; i--) + { + uint8 cr = (uint8)*pSrc++; + int16 crR, crG; + + crR = (cr + ((cr * 103U) >> 8U)) - 179; + *pDstR++ = addAndClamp(pDstR[0], crR); + + crG = ((cr * 183U) >> 8U) - 91; + *pDstG++ = subAndClamp(pDstG[0], crG); + } +} +/*----------------------------------------------------------------------------*/ +static void transformBlock(uint8 mcuBlock) +{ + idctRows(); + idctCols(); + + switch (gScanType) + { + case PJPG_GRAYSCALE: + { + copyY(0); + break; + } + case PJPG_YH1V1: + { + switch (mcuBlock) + { + case 0: + { + copyY(0); + break; + } + case 1: + { + convertCb(0); + break; + } + case 2: + { + convertCr(0); + break; + } + } + + break; + } + case PJPG_YH2V2: + { + switch (mcuBlock) + { + case 0: + { + copyY(0); + break; + } + case 1: + { + copyY(64); + break; + } + case 2: + { + copyY(128); + break; + } + case 3: + { + copyY(192); + break; + } + case 4: + { + upsampleCb(0, 0); + upsampleCb(4, 64); + upsampleCb(4*8, 128); + upsampleCb(4+4*8, 192); + break; + } + case 5: + { + upsampleCr(0, 0); + upsampleCr(4, 64); + upsampleCr(4*8, 128); + upsampleCr(4+4*8, 192); + break; + } + } + } + } +} +//------------------------------------------------------------------------------ +static uint8 decodeNextMCU(void) +{ + uint8 status; + uint8 mcuBlock; + + if (gRestartInterval) + { + if (gRestartsLeft == 0) + { + status = processRestart(); + if (status) + return status; + } + gRestartsLeft--; + } + + for (mcuBlock = 0; mcuBlock < gMaxBlocksPerMCU; mcuBlock++) + { + uint8 componentID = gMCUOrg[mcuBlock]; + uint8 compQuant = gCompQuant[componentID]; + uint8 compDCTab = gCompDCTab[componentID]; + uint8 numExtraBits, compACTab, k; + const int16* pQ = compQuant ? gQuant1 : gQuant0; + uint16 r, dc; + + uint8 s = huffDecode(compDCTab ? &gHuffTab1 : &gHuffTab0, compDCTab ? gHuffVal1 : gHuffVal0); + + r = 0; + numExtraBits = s & 0xF; + if (numExtraBits) + r = getBits2(numExtraBits); + dc = huffExtend(r, s); + + dc = dc + gLastDC[componentID]; + gLastDC[componentID] = dc; + + gCoeffBuf[0] = dc * pQ[0]; + + compACTab = gCompACTab[componentID]; + + for (k = 1; k < 64; k++) + { + uint16 extraBits; + + s = huffDecode(compACTab ? &gHuffTab3 : &gHuffTab2, compACTab ? gHuffVal3 : gHuffVal2); + + extraBits = 0; + numExtraBits = s & 0xF; + if (numExtraBits) + extraBits = getBits2(numExtraBits); + + r = s >> 4; + s &= 15; + + if (s) + { + int16 ac; + + if (r) + { + if ((k + r) > 63) + return PJPG_DECODE_ERROR; + + while (r) + { + gCoeffBuf[ZAG[k++]] = 0; + r--; + } + } + + ac = huffExtend(extraBits, s); + + gCoeffBuf[ZAG[k]] = ac * pQ[k]; + } + else + { + if (r == 15) + { + if ((k + 16) > 64) + return PJPG_DECODE_ERROR; + + for (r = 16; r > 0; r--) + gCoeffBuf[ZAG[k++]] = 0; + + k--; // - 1 because the loop counter is k + } + else + break; + } + } + + while (k < 64) + gCoeffBuf[ZAG[k++]] = 0; + + transformBlock(mcuBlock); + } + + return 0; +} +//------------------------------------------------------------------------------ +unsigned char pjpeg_decode_mcu(void) +{ + uint8 status; + + if (!gNumMCUSRemaining) + return PJPG_NO_MORE_BLOCKS; + + status = decodeNextMCU(); + if (status) + return status; + + gNumMCUSRemaining--; + + return 0; +} +//------------------------------------------------------------------------------ +unsigned char pjpeg_decode_init(pjpeg_image_info_t *pInfo, pjpeg_need_bytes_callback_t pNeed_bytes_callback, void *pCallback_data) +{ + uint8 status; + + g_pNeedBytesCallback = pNeed_bytes_callback; + g_pCallback_data = pCallback_data; + + status = init(); + if (status) + return status; + + status = locateSOFMarker(); + if (status) + return status; + + status = initFrame(); + if (status) + return status; + + status = initScan(); + if (status) + return status; + + pInfo->m_width = gImageXSize; + pInfo->m_height = gImageYSize; + pInfo->m_comps = gCompsInFrame; + pInfo->m_scanType = gScanType; + pInfo->m_MCUSPerRow = gMaxMCUSPerRow; + pInfo->m_MCUSPerCol = gMaxMCUSPerCol; + pInfo->m_MCUWidth = gMaxMCUXSize; + pInfo->m_MCUHeight = gMaxMCUYSize; + pInfo->m_pMCUBufR = gMCUBufR; + pInfo->m_pMCUBufG = gMCUBufG; + pInfo->m_pMCUBufB = gMCUBufB; + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/picojpeg/picojpeg.h Thu Dec 13 23:59:40 2012 +0000 @@ -0,0 +1,102 @@ +//------------------------------------------------------------------------------ +// picojpeg v1.0 - Public domain, Rich Geldreich <richgel99@gmail.com> +//------------------------------------------------------------------------------ +#ifndef PICOJPEG_H +#define PICOJPEG_H + +#ifdef __cplusplus +extern "C" { +#endif + +// Error codes +enum +{ + PJPG_NO_MORE_BLOCKS = 1, + PJPG_BAD_DHT_COUNTS, + PJPG_BAD_DHT_INDEX, + PJPG_BAD_DHT_MARKER, + PJPG_BAD_DQT_MARKER, + PJPG_BAD_DQT_TABLE, + PJPG_BAD_PRECISION, + PJPG_BAD_HEIGHT, + PJPG_BAD_WIDTH, + PJPG_TOO_MANY_COMPONENTS, + PJPG_BAD_SOF_LENGTH, + PJPG_BAD_VARIABLE_MARKER, + PJPG_BAD_DRI_LENGTH, + PJPG_BAD_SOS_LENGTH, + PJPG_BAD_SOS_COMP_ID, + PJPG_W_EXTRA_BYTES_BEFORE_MARKER, + PJPG_NO_ARITHMITIC_SUPPORT, + PJPG_UNEXPECTED_MARKER, + PJPG_NOT_JPEG, + PJPG_UNSUPPORTED_MARKER, + PJPG_BAD_DQT_LENGTH, + PJPG_TOO_MANY_BLOCKS, + PJPG_UNDEFINED_QUANT_TABLE, + PJPG_UNDEFINED_HUFF_TABLE, + PJPG_NOT_SINGLE_SCAN, + PJPG_UNSUPPORTED_COLORSPACE, + PJPG_UNSUPPORTED_SAMP_FACTORS, + PJPG_DECODE_ERROR, + PJPG_BAD_RESTART_MARKER, + PJPG_ASSERTION_ERROR, + PJPG_BAD_SOS_SPECTRAL, + PJPG_BAD_SOS_SUCCESSIVE, + PJPG_STREAM_READ_ERROR, + PJPG_NOTENOUGHMEM, + PJPG_UNSUPPORTED_COMP_IDENT, + PJPG_UNSUPPORTED_QUANT_TABLE, + PJPG_UNSUPPORTED_MODE, +}; + +// Scan types - currently only GRAYSCALE, YH1V1, and YH2V2 are actually supported. +typedef enum +{ + PJPG_GRAYSCALE, + PJPG_YH1V1, + PJPG_YH2V1, + PJPG_YH1V2, + PJPG_YH2V2 +} pjpeg_scan_type_t; + +typedef struct +{ + // Image resolution + int m_width; + int m_height; + // Number of components (1 or 3) + int m_comps; + // Total number of minimum coded units (MCU's) per row/col. + int m_MCUSPerRow; + int m_MCUSPerCol; + // Scan type + pjpeg_scan_type_t m_scanType; + // MCU width/height in pixels + int m_MCUWidth; + int m_MCUHeight; + // Pointers to internal MCU pixel component buffers. + // These buffers Will be filled with pixels each time pjpegDecodeMCU() is called successfully. + // Each MCU consists of (m_MCUWidth/8)*(m_MCUHeight/8) blocks (currently either 1 for greyscale/no subsampling, or 4 for H2V2 sampling factors), where each block is a contiguous array of 64 (8x8) bytes. + // For greyscale images, only the values in m_pMCUBufR are valid. + unsigned char *m_pMCUBufR; + unsigned char *m_pMCUBufG; + unsigned char *m_pMCUBufB; +} pjpeg_image_info_t; + +typedef unsigned char (*pjpeg_need_bytes_callback_t)(unsigned char* pBuf, unsigned char buf_size, unsigned char *pBytes_actually_read, void *pCallback_data); + +// Initializes the decompressor. Returns 0 on success, or one of the above error codes on failure. +// pNeed_bytes_callback will be called to fill the decompressor's internal input buffer. +// Not thread safe. +unsigned char pjpeg_decode_init(pjpeg_image_info_t *pInfo, pjpeg_need_bytes_callback_t pNeed_bytes_callback, void *pCallback_data); + +// Decompresses the file's next MCU. Returns 0 on success, PJPG_NO_MORE_BLOCKS if no more blocks are available, or an error code. +// Must be called a total of m_MCUSPerRow*m_MCUSPerCol times to completely decompress the image. +unsigned char pjpeg_decode_mcu(void); + +#ifdef __cplusplus +} +#endif + +#endif // PICOJPEG_H