From 331f9f3e6c273fc38be64381e38ee18aaccd4b4a Mon Sep 17 00:00:00 2001 From: kazu Date: Sun, 28 Feb 2021 20:46:38 +0100 Subject: [PATCH] added code for mp3 and jpeg parsing added interface for data sources --- .gitignore | 7 + data/formats/DataSourceFile.h | 42 + data/formats/DataSourceMemory.h | 38 + data/formats/DataSourcePosixFile.h | 50 + data/formats/jpeg/JPEGDEC.cpp | 199 ++ data/formats/jpeg/JPEGDEC.h | 259 +++ data/formats/jpeg/jpeg.c | 3436 ++++++++++++++++++++++++++++ data/formats/jpeg/readme.md | 1 + data/formats/jpeg/test.cpp | 24 + data/formats/mp3/minimp3.h | 1855 +++++++++++++++ data/formats/mp3/readme.md | 1 + 11 files changed, 5912 insertions(+) create mode 100644 .gitignore create mode 100644 data/formats/DataSourceFile.h create mode 100644 data/formats/DataSourceMemory.h create mode 100644 data/formats/DataSourcePosixFile.h create mode 100644 data/formats/jpeg/JPEGDEC.cpp create mode 100644 data/formats/jpeg/JPEGDEC.h create mode 100644 data/formats/jpeg/jpeg.c create mode 100644 data/formats/jpeg/readme.md create mode 100644 data/formats/jpeg/test.cpp create mode 100644 data/formats/mp3/minimp3.h create mode 100644 data/formats/mp3/readme.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3bcb8cc --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.pdf +*.PDF +*.tar.gz + +build-* +a.out +CMakeLists.txt.* diff --git a/data/formats/DataSourceFile.h b/data/formats/DataSourceFile.h new file mode 100644 index 0000000..569e5da --- /dev/null +++ b/data/formats/DataSourceFile.h @@ -0,0 +1,42 @@ +#pragma once + +#include "../../ext/sd/File.h" + +/** data source using our filesystem */ +class DataSourceFile { + + File* f; + +public: + + /** empty ctor */ + DataSourceFile() : f(nullptr) { + + } + + /** ctor with the filesystem file to wrap */ + DataSourceFile(File& f) : f(&f) { + + } + + /** get the current position */ + uint32_t curPos() const { + return f->curPos(); + } + + /** seek to the given position */ + void seekTo(uint32_t newPos) { + f->seekTo(newPos); + } + + /** read x bytes from the input into dst */ + uint32_t read(uint32_t size, uint8_t* dst) { + return f->read(size, dst); + } + + /** read an entity */ + template void readType(T& dst) { + read(sizeof(T), (uint8_t*)&dst); + } + +}; diff --git a/data/formats/DataSourceMemory.h b/data/formats/DataSourceMemory.h new file mode 100644 index 0000000..6a4e139 --- /dev/null +++ b/data/formats/DataSourceMemory.h @@ -0,0 +1,38 @@ +#pragma once + +/** data source wrapping the memory */ +template class DataSourceMemory { + + const uint8_t* src; + const uint32_t len; + uint32_t pos; + +public: + + /** ctor with the memory region */ + DataSourceMemory(const uint8_t* src, const uint32_t len) : src(src), len(len) { + + } + + /** get the current position */ + uint32_t curPos() const { + return pos; + } + + /** seek to the given position */ + void seekTo(uint32_t newPos) { + pos = newPos; + } + + /** read an entity */ + template void readType(T& dst) { + read(sizeof(T), &dst); + } + + /** read x bytes from the input into dst */ + template void read(uint32_t size, T* dst) { + memcpy(dst, &src[pos], size); + pos += size; + } + +}; diff --git a/data/formats/DataSourcePosixFile.h b/data/formats/DataSourcePosixFile.h new file mode 100644 index 0000000..5a53236 --- /dev/null +++ b/data/formats/DataSourcePosixFile.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +/** file on the desktop (posix) filesystem */ +class DataSourcePosixFile { + + FILE* f = nullptr; + +public: + + DataSourcePosixFile() { + + } + + DataSourcePosixFile(const char* file) { + f = fopen(file, "rw"); + if (!f) { + throw std::runtime_error(std::string("failed to open file: ") + file); + } + } + + ~DataSourcePosixFile() { + if (f) {fclose(f);} + } + + uint32_t curPos() const { + return ftell(f); + } + + void seekTo(uint32_t pos) { + fseek(f, pos, SEEK_SET); + } + + uint32_t read(uint32_t bytes, uint8_t* dst) { + return fread(dst, bytes, 1, f) * bytes; + } + + uint32_t write(uint32_t bytes, const uint8_t* src) { + return fwrite(src, bytes, 1, f) * bytes; + } + + /** read an entity */ + template void readType(T& dst) { + read(sizeof(T), (uint8_t*) &dst); + } + +}; diff --git a/data/formats/jpeg/JPEGDEC.cpp b/data/formats/jpeg/JPEGDEC.cpp new file mode 100644 index 0000000..de2b302 --- /dev/null +++ b/data/formats/jpeg/JPEGDEC.cpp @@ -0,0 +1,199 @@ +// +// JPEG Decoder +// +// written by Larry Bank +// bitbank@pobox.com +// Arduino port started 8/2/2020 +// Original JPEG code written 26+ years ago :) +// The goal of this code is to decode baseline JPEG images +// using no more than 18K of RAM (if sent directly to an LCD display) +// +// Copyright 2020 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== +// +#include "JPEGDEC.h" + +// forward references +JPEG_STATIC int JPEGInit(JPEGIMAGE *pJPEG); +JPEG_STATIC int JPEGParseInfo(JPEGIMAGE *pPage, int bExtractThumb); +JPEG_STATIC void JPEGGetMoreData(JPEGIMAGE *pPage); +JPEG_STATIC int DecodeJPEG(JPEGIMAGE *pImage); + +// Include the C code which does the actual work +#include "jpeg.c" + +void JPEGDEC::setPixelType(int iType) +{ + if (iType >= 0 && iType < INVALID_PIXEL_TYPE) + _jpeg.ucPixelType = (uint8_t)iType; + else + _jpeg.iError = JPEG_INVALID_PARAMETER; +} /* setPixelType() */ + +void JPEGDEC::setMaxOutputSize(int iMaxMCUs) +{ + if (iMaxMCUs < 1) + iMaxMCUs = 1; // don't allow invalid value + _jpeg.iMaxMCUs = iMaxMCUs; +} /* setMaxOutputSize() */ +// +// Memory initialization +// +int JPEGDEC::openRAM(uint8_t *pData, int iDataSize, JPEG_DRAW_CALLBACK *pfnDraw) +{ + memset(&_jpeg, 0, sizeof(JPEGIMAGE)); + _jpeg.ucMemType = JPEG_MEM_RAM; + _jpeg.pfnRead = readRAM; + _jpeg.pfnSeek = seekMem; + _jpeg.pfnDraw = pfnDraw; + _jpeg.pfnOpen = NULL; + _jpeg.pfnClose = NULL; + _jpeg.JPEGFile.iSize = iDataSize; + _jpeg.JPEGFile.pData = pData; + _jpeg.iMaxMCUs = 1000; // set to an unnaturally high value to start + return JPEGInit(&_jpeg); +} /* openRAM() */ + +int JPEGDEC::openFLASH(uint8_t *pData, int iDataSize, JPEG_DRAW_CALLBACK *pfnDraw) +{ + memset(&_jpeg, 0, sizeof(JPEGIMAGE)); + _jpeg.ucMemType = JPEG_MEM_FLASH; + _jpeg.pfnRead = readFLASH; + _jpeg.pfnSeek = seekMem; + _jpeg.pfnDraw = pfnDraw; + _jpeg.pfnOpen = NULL; + _jpeg.pfnClose = NULL; + _jpeg.JPEGFile.iSize = iDataSize; + _jpeg.JPEGFile.pData = pData; + _jpeg.iMaxMCUs = 1000; // set to an unnaturally high value to start + return JPEGInit(&_jpeg); +} /* openRAM() */ + +int JPEGDEC::getOrientation() +{ + return (int)_jpeg.ucOrientation; +} /* getOrientation() */ + +int JPEGDEC::getLastError() +{ + return _jpeg.iError; +} /* getLastError() */ + +int JPEGDEC::getWidth() +{ + return _jpeg.iWidth; +} /* getWidth() */ + +int JPEGDEC::getHeight() +{ + return _jpeg.iHeight; +} /* getHeight() */ + +int JPEGDEC::hasThumb() +{ + return (int)_jpeg.ucHasThumb; +} /* hasThumb() */ + +int JPEGDEC::getThumbWidth() +{ + return _jpeg.iThumbWidth; +} /* getThumbWidth() */ + +int JPEGDEC::getThumbHeight() +{ + return _jpeg.iThumbHeight; +} /* getThumbHeight() */ + +int JPEGDEC::getBpp() +{ + return (int)_jpeg.ucBpp; +} /* getBpp() */ + +int JPEGDEC::getSubSample() +{ + return (int)_jpeg.ucSubSample; +} /* getSubSample() */ + +// +// File (SD/MMC) based initialization +// +int JPEGDEC::open(const char *szFilename, JPEG_OPEN_CALLBACK *pfnOpen, JPEG_CLOSE_CALLBACK *pfnClose, JPEG_READ_CALLBACK *pfnRead, JPEG_SEEK_CALLBACK *pfnSeek, JPEG_DRAW_CALLBACK *pfnDraw) +{ + memset(&_jpeg, 0, sizeof(JPEGIMAGE)); + _jpeg.pfnRead = pfnRead; + _jpeg.pfnSeek = pfnSeek; + _jpeg.pfnDraw = pfnDraw; + _jpeg.pfnOpen = pfnOpen; + _jpeg.pfnClose = pfnClose; + _jpeg.iMaxMCUs = 1000; // set to an unnaturally high value to start + _jpeg.JPEGFile.fHandle = (*pfnOpen)(szFilename, &_jpeg.JPEGFile.iSize); + if (_jpeg.JPEGFile.fHandle == NULL) + return 0; + return JPEGInit(&_jpeg); + +} /* open() */ + +#ifdef FS_H +static int32_t FileRead(JPEGFILE *handle, uint8_t *buffer, int32_t length) +{ + return ((File *)(handle->fHandle))->read(buffer, length); +} +static int32_t FileSeek(JPEGFILE *handle, int32_t position) +{ + return ((File *)(handle->fHandle))->seek(position); +} +static void FileClose(void *handle) +{ + ((File *)handle)->close(); +} + +int JPEGDEC::open(File &file, JPEG_DRAW_CALLBACK *pfnDraw) +{ + if (!file) return 0; + memset(&_jpeg, 0, sizeof(JPEGIMAGE)); + _jpeg.pfnRead = FileRead; + _jpeg.pfnSeek = FileSeek; + _jpeg.pfnClose = FileClose; + _jpeg.pfnDraw = pfnDraw; + _jpeg.iMaxMCUs = 1000; + _jpeg.JPEGFile.fHandle = &file; + _jpeg.JPEGFile.iSize = file.size(); + return JPEGInit(&_jpeg); +} +#endif // FS_H + +void JPEGDEC::close() +{ + if (_jpeg.pfnClose) + (*_jpeg.pfnClose)(_jpeg.JPEGFile.fHandle); +} /* close() */ + +// +// Decode the image +// returns: +// 1 = good result +// 0 = error +// +int JPEGDEC::decode(int x, int y, int iOptions) +{ + _jpeg.iXOffset = x; + _jpeg.iYOffset = y; + _jpeg.iOptions = iOptions; + return DecodeJPEG(&_jpeg); +} /* decode() */ + +int JPEGDEC::decodeDither(uint8_t *pDither, int iOptions) +{ + _jpeg.iOptions = iOptions; + _jpeg.pDitherBuffer = pDither; + return DecodeJPEG(&_jpeg); +} diff --git a/data/formats/jpeg/JPEGDEC.h b/data/formats/jpeg/JPEGDEC.h new file mode 100644 index 0000000..d93fd55 --- /dev/null +++ b/data/formats/jpeg/JPEGDEC.h @@ -0,0 +1,259 @@ +// +// Copyright 2020 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== +// +#ifndef __JPEGDEC__ +#define __JPEGDEC__ +#if defined( __MACH__ ) || defined( __LINUX__ ) || defined( __MCUXPRESSO ) +#include +#include +#include +#include +#else +#include +#endif +#ifndef PROGMEM +#define memcpy_P memcpy +#define PROGMEM +#endif +// +// JPEG Decoder +// Written by Larry Bank +// Copyright (c) 2020 BitBank Software, Inc. +// +// Designed to decode baseline JPEG images (8 or 24-bpp) +// using less than 22K of RAM +// + +/* Defines and variables */ +#define FILE_HIGHWATER 1536 +#define JPEG_FILE_BUF_SIZE 2048 +#define HUFF_TABLEN 273 +#define HUFF11SIZE (1<<11) +#define DC_TABLE_SIZE 1024 +#define DCTSIZE 64 +#define MAX_MCU_COUNT 6 +#define MAX_COMPS_IN_SCAN 4 +#define MAX_BUFFERED_PIXELS 2048 + +// Decoder options +#define JPEG_AUTO_ROTATE 1 +#define JPEG_SCALE_HALF 2 +#define JPEG_SCALE_QUARTER 4 +#define JPEG_SCALE_EIGHTH 8 +#define JPEG_LE_PIXELS 16 +#define JPEG_EXIF_THUMBNAIL 32 +#define JPEG_LUMA_ONLY 64 + +#define MCU0 (DCTSIZE * 0) +#define MCU1 (DCTSIZE * 1) +#define MCU2 (DCTSIZE * 2) +#define MCU3 (DCTSIZE * 3) +#define MCU4 (DCTSIZE * 4) +#define MCU5 (DCTSIZE * 5) + +// Pixel types (defaults to little endian RGB565) +enum { + RGB565_LITTLE_ENDIAN = 0, + RGB565_BIG_ENDIAN, + EIGHT_BIT_GRAYSCALE, + FOUR_BIT_DITHERED, + TWO_BIT_DITHERED, + ONE_BIT_DITHERED, + INVALID_PIXEL_TYPE +}; + +enum { + JPEG_MEM_RAM=0, + JPEG_MEM_FLASH +}; + +// Error codes returned by getLastError() +enum { + JPEG_SUCCESS = 0, + JPEG_INVALID_PARAMETER, + JPEG_DECODE_ERROR, + JPEG_UNSUPPORTED_FEATURE, + JPEG_INVALID_FILE +}; + +typedef struct buffered_bits +{ +unsigned char *pBuf; // buffer pointer +uint32_t ulBits; // buffered bits +uint32_t ulBitOff; // current bit offset +} BUFFERED_BITS; + +typedef struct jpeg_file_tag +{ + int32_t iPos; // current file position + int32_t iSize; // file size + uint8_t *pData; // memory file pointer + void * fHandle; // class pointer to File/SdFat or whatever you want +} JPEGFILE; + +typedef struct jpeg_draw_tag +{ + int x, y; // upper left corner of current MCU + int iWidth, iHeight; // size of this MCU + int iBpp; // bit depth of the pixels (8 or 16) + uint16_t *pPixels; // 16-bit pixels +} JPEGDRAW; + +// Callback function prototypes +typedef int32_t (JPEG_READ_CALLBACK)(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen); +typedef int32_t (JPEG_SEEK_CALLBACK)(JPEGFILE *pFile, int32_t iPosition); +typedef int (JPEG_DRAW_CALLBACK)(JPEGDRAW *pDraw); +typedef void * (JPEG_OPEN_CALLBACK)(const char *szFilename, int32_t *pFileSize); +typedef void (JPEG_CLOSE_CALLBACK)(void *pHandle); + +/* JPEG color component info */ +typedef struct _jpegcompinfo +{ +// These values are fixed over the whole image +// For compression, they must be supplied by the user interface +// for decompression, they are read from the SOF marker. +unsigned char component_needed; /* do we need the value of this component? */ +unsigned char component_id; /* identifier for this component (0..255) */ +unsigned char component_index; /* its index in SOF or cinfo->comp_info[] */ +//unsigned char h_samp_factor; /* horizontal sampling factor (1..4) */ +//unsigned char v_samp_factor; /* vertical sampling factor (1..4) */ +unsigned char quant_tbl_no; /* quantization table selector (0..3) */ +// These values may vary between scans +// For compression, they must be supplied by the user interface +// for decompression, they are read from the SOS marker. +unsigned char dc_tbl_no; /* DC entropy table selector (0..3) */ +unsigned char ac_tbl_no; /* AC entropy table selector (0..3) */ +// These values are computed during compression or decompression startup +//int true_comp_width; /* component's image width in samples */ +//int true_comp_height; /* component's image height in samples */ +// the above are the logical dimensions of the downsampled image +// These values are computed before starting a scan of the component +//int MCU_width; /* number of blocks per MCU, horizontally */ +//int MCU_height; /* number of blocks per MCU, vertically */ +//int MCU_blocks; /* MCU_width * MCU_height */ +//int downsampled_width; /* image width in samples, after expansion */ +//int downsampled_height; /* image height in samples, after expansion */ +// the above are the true_comp_xxx values rounded up to multiples of +// the MCU dimensions; these are the working dimensions of the array +// as it is passed through the DCT or IDCT step. NOTE: these values +// differ depending on whether the component is interleaved or not!! +// This flag is used only for decompression. In cases where some of the +// components will be ignored (eg grayscale output from YCbCr image), +// we can skip IDCT etc. computations for the unused components. +} JPEGCOMPINFO; + +// +// our private structure to hold a JPEG image decode state +// +typedef struct jpeg_image_tag +{ + int iWidth, iHeight; // image size + int iThumbWidth, iThumbHeight; // thumbnail size (if present) + int iThumbData; // offset to image data + int iXOffset, iYOffset; // placement on the display + uint8_t ucBpp, ucSubSample, ucHuffTableUsed; + uint8_t ucMode, ucOrientation, ucHasThumb, b11Bit; + uint8_t ucComponentsInScan, cApproxBitsLow, cApproxBitsHigh; + uint8_t iScanStart, iScanEnd, ucFF, ucNumComponents; + uint8_t ucACTable, ucDCTable, ucMaxACCol, ucMaxACRow; + uint8_t ucMemType, ucPixelType; + int iEXIF; // Offset to EXIF 'TIFF' file + int iError; + int iOptions; + int iVLCOff; // current VLC data offset + int iVLCSize; // current quantity of data in the VLC buffer + int iResInterval, iResCount; // restart interval + int iMaxMCUs; // max MCUs of pixels per JPEGDraw call + JPEG_READ_CALLBACK *pfnRead; + JPEG_SEEK_CALLBACK *pfnSeek; + JPEG_DRAW_CALLBACK *pfnDraw; + JPEG_OPEN_CALLBACK *pfnOpen; + JPEG_CLOSE_CALLBACK *pfnClose; + JPEGCOMPINFO JPCI[MAX_COMPS_IN_SCAN]; /* Max color components */ + JPEGFILE JPEGFile; + BUFFERED_BITS bb; + uint8_t *pDitherBuffer; // provided externally to do Floyd-Steinberg dithering + uint16_t usPixels[MAX_BUFFERED_PIXELS]; + int16_t sMCUs[DCTSIZE * MAX_MCU_COUNT]; // 4:2:0 needs 6 DCT blocks per MCU + int16_t sQuantTable[DCTSIZE*4]; // quantization tables + uint8_t ucFileBuf[JPEG_FILE_BUF_SIZE]; // holds temp data and pixel stack + uint8_t ucHuffDC[DC_TABLE_SIZE * 2]; // up to 2 'short' tables + uint16_t usHuffAC[HUFF11SIZE * 2]; +} JPEGIMAGE; + +#ifdef __cplusplus +#if defined(__has_include) && __has_include() +#include "FS.h" +#endif +#define JPEG_STATIC static +// +// The JPEGDEC class wraps portable C code which does the actual work +// +class JPEGDEC +{ + public: + int openRAM(uint8_t *pData, int iDataSize, JPEG_DRAW_CALLBACK *pfnDraw); + int openFLASH(uint8_t *pData, int iDataSize, JPEG_DRAW_CALLBACK *pfnDraw); + int open(const char *szFilename, JPEG_OPEN_CALLBACK *pfnOpen, JPEG_CLOSE_CALLBACK *pfnClose, JPEG_READ_CALLBACK *pfnRead, JPEG_SEEK_CALLBACK *pfnSeek, JPEG_DRAW_CALLBACK *pfnDraw); +#ifdef FS_H + int open(File &file, JPEG_DRAW_CALLBACK *pfnDraw); +#endif + void close(); + int decode(int x, int y, int iOptions); + int decodeDither(uint8_t *pDither, int iOptions); + int getOrientation(); + int getWidth(); + int getHeight(); + int getBpp(); + int getSubSample(); + int hasThumb(); + int getThumbWidth(); + int getThumbHeight(); + int getLastError(); + void setPixelType(int iType); // defaults to little endian + void setMaxOutputSize(int iMaxMCUs); + + private: + JPEGIMAGE _jpeg; +}; +#else +#define JPEG_STATIC +int JPEG_openRAM(JPEGIMAGE *pJPEG, uint8_t *pData, int iDataSize, JPEG_DRAW_CALLBACK *pfnDraw); +int JPEG_openFile(JPEGIMAGE *pJPEG, const char *szFilename, JPEG_DRAW_CALLBACK *pfnDraw); +int JPEG_getWidth(JPEGIMAGE *pJPEG); +int JPEG_getHeight(JPEGIMAGE *pJPEG); +int JPEG_decode(JPEGIMAGE *pJPEG, int x, int y, int iOptions); +int JPEG_decodeDither(JPEGIMAGE *pJPEG, uint8_t *pDither, int iOptions); +void JPEG_close(JPEGIMAGE *pJPEG); +int JPEG_getLastError(JPEGIMAGE *pJPEG); +int JPEG_getOrientation(JPEGIMAGE *pJPEG); +int JPEG_getBpp(JPEGIMAGE *pJPEG); +int JPEG_getSubSample(JPEGIMAGE *pJPEG); +int JPEG_hasThumb(JPEGIMAGE *pJPEG); +int JPEG_getThumbWidth(JPEGIMAGE *pJPEG); +int JPEG_getThumbHeight(JPEGIMAGE *pJPEG); +int JPEG_getLastError(JPEGIMAGE *pJPEG); +void JPEG_setPixelType(JPEGIMAGE *pJPEG, int iType); // defaults to little endian +void JPEG_setMaxOutputSize(JPEGIMAGE *pJPEG, int iMaxMCUs); +#endif // __cplusplus + +// Due to unaligned memory causing an exception, we have to do these macros the slow way +#define INTELSHORT(p) ((*p) + (*(p+1)<<8)) +#define INTELLONG(p) ((*p) + (*(p+1)<<8) + (*(p+2)<<16) + (*(p+3)<<24)) +#define MOTOSHORT(p) (((*(p))<<8) + (*(p+1))) +#define MOTOLONG(p) (((*p)<<24) + ((*(p+1))<<16) + ((*(p+2))<<8) + (*(p+3))) + +// Must be a 32-bit target processor +#define REGISTER_WIDTH 32 + +#endif // __JPEGDEC__ diff --git a/data/formats/jpeg/jpeg.c b/data/formats/jpeg/jpeg.c new file mode 100644 index 0000000..4c5c4fb --- /dev/null +++ b/data/formats/jpeg/jpeg.c @@ -0,0 +1,3436 @@ +// +// JPEG Decoder +// +// written by Larry Bank +// bitbank@pobox.com +// Arduino port started 8/2/2020 +// Original JPEG code written 26+ years ago :) +// The goal of this code is to decode baseline JPEG images +// using no more than 18K of RAM (if sent directly to an LCD display) +// +// Copyright 2020 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== +// +#include "JPEGDEC.h" + +// forward references +static int JPEGInit(JPEGIMAGE *pJPEG); +static int JPEGParseInfo(JPEGIMAGE *pPage, int bExtractThumb); +static void JPEGGetMoreData(JPEGIMAGE *pPage); +static int DecodeJPEG(JPEGIMAGE *pImage); +static int32_t readRAM(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen); +static int32_t seekMem(JPEGFILE *pFile, int32_t iPosition); +static int32_t readFile(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen); +static int32_t seekFile(JPEGFILE *pFile, int32_t iPosition); +static void closeFile(void *handle); +static void JPEGDither(JPEGIMAGE *pJPEG, int iWidth, int iHeight); +/* JPEG tables */ +// zigzag ordering of DCT coefficients +static const unsigned char cZigZag[64] = {0,1,5,6,14,15,27,28, + 2,4,7,13,16,26,29,42, + 3,8,12,17,25,30,41,43, + 9,11,18,24,31,40,44,53, + 10,19,23,32,39,45,52,54, + 20,22,33,38,46,51,55,60, + 21,34,37,47,50,56,59,61, + 35,36,48,49,57,58,62,63}; + +// un-zigzag ordering +static const unsigned char cZigZag2[64] = {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}; + +// For AA&N IDCT method, multipliers are equal to quantization +// coefficients scaled by scalefactor[row]*scalefactor[col], where +// scalefactor[0] = 1 +// scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 +// For integer operation, the multiplier table is to be scaled by +// IFAST_SCALE_BITS. +static const int iScaleBits[64] = {16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247}; +// +// Range clip and shift for RGB565 output +// input value is 0 to 255, then another 256 for overflow to FF, then 512 more for negative values wrapping around +// Trims a few instructions off the final output stage +// +static const uint8_t ucRangeTable[] = {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, + 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, + 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, + 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, + 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, + 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, + 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f}; + +// +// Convert 8-bit grayscale into RGB565 +// +static const uint16_t usGrayTo565[] = {0x0000,0x0000,0x0000,0x0000,0x0020,0x0020,0x0020,0x0020, // 0 + 0x0841,0x0841,0x0841,0x0841,0x0861,0x0861,0x0861,0x0861, + 0x1082,0x1082,0x1082,0x1082,0x10a2,0x10a2,0x10a2,0x10a2, + 0x18c3,0x18c3,0x18c3,0x18c3,0x18e3,0x18e3,0x18e3,0x18e3, + 0x2104,0x2104,0x2104,0x2104,0x2124,0x2124,0x2124,0x2124, + 0x2945,0x2945,0x2945,0x2945,0x2965,0x2965,0x2965,0x2965, + 0x3186,0x3186,0x3186,0x3186,0x31a6,0x31a6,0x31a6,0x31a6, + 0x39c7,0x39c7,0x39c7,0x39c7,0x39e7,0x39e7,0x39e7,0x39e7, + 0x4208,0x4208,0x4208,0x4208,0x4228,0x4228,0x4228,0x4228, + 0x4a49,0x4a49,0x4a49,0x4a49,0x4a69,0x4a69,0x4a69,0x4a69, + 0x528a,0x528a,0x528a,0x528a,0x52aa,0x52aa,0x52aa,0x52aa, + 0x5acb,0x5acb,0x5acb,0x5acb,0x5aeb,0x5aeb,0x5aeb,0x5aeb, + 0x630c,0x630c,0x630c,0x630c,0x632c,0x632c,0x632c,0x632c, + 0x6b4d,0x6b4d,0x6b4d,0x6b4d,0x6b6d,0x6b6d,0x6b6d,0x6b6d, + 0x738e,0x738e,0x738e,0x738e,0x73ae,0x73ae,0x73ae,0x73ae, + 0x7bcf,0x7bcf,0x7bcf,0x7bcf,0x7bef,0x7bef,0x7bef,0x7bef, + 0x8410,0x8410,0x8410,0x8410,0x8430,0x8430,0x8430,0x8430, + 0x8c51,0x8c51,0x8c51,0x8c51,0x8c71,0x8c71,0x8c71,0x8c71, + 0x9492,0x9492,0x9492,0x9492,0x94b2,0x94b2,0x94b2,0x94b2, + 0x9cd3,0x9cd3,0x9cd3,0x9cd3,0x9cf3,0x9cf3,0x9cf3,0x9cf3, + 0xa514,0xa514,0xa514,0xa514,0xa534,0xa534,0xa534,0xa534, + 0xad55,0xad55,0xad55,0xad55,0xad75,0xad75,0xad75,0xad75, + 0xb596,0xb596,0xb596,0xb596,0xb5b6,0xb5b6,0xb5b6,0xb5b6, + 0xbdd7,0xbdd7,0xbdd7,0xbdd7,0xbdf7,0xbdf7,0xbdf7,0xbdf7, + 0xc618,0xc618,0xc618,0xc618,0xc638,0xc638,0xc638,0xc638, + 0xce59,0xce59,0xce59,0xce59,0xce79,0xce79,0xce79,0xce79, + 0xd69a,0xd69a,0xd69a,0xd69a,0xd6ba,0xd6ba,0xd6ba,0xd6ba, + 0xdedb,0xdedb,0xdedb,0xdedb,0xdefb,0xdefb,0xdefb,0xdefb, + 0xe71c,0xe71c,0xe71c,0xe71c,0xe73c,0xe73c,0xe73c,0xe73c, + 0xef5d,0xef5d,0xef5d,0xef5d,0xef7d,0xef7d,0xef7d,0xef7d, + 0xf79e,0xf79e,0xf79e,0xf79e,0xf7be,0xf7be,0xf7be,0xf7be, + 0xffdf,0xffdf,0xffdf,0xffdf,0xffff,0xffff,0xffff,0xffff}; +// +// Clip and convert red value into 5-bits for RGB565 +// +static const uint16_t usRangeTableR[] = {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // 0 + 0x0800,0x0800,0x0800,0x0800,0x0800,0x0800,0x0800,0x0800, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800, + 0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000,0x2000, + 0x2800,0x2800,0x2800,0x2800,0x2800,0x2800,0x2800,0x2800, + 0x3000,0x3000,0x3000,0x3000,0x3000,0x3000,0x3000,0x3000, + 0x3800,0x3800,0x3800,0x3800,0x3800,0x3800,0x3800,0x3800, + 0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000,0x4000, + 0x4800,0x4800,0x4800,0x4800,0x4800,0x4800,0x4800,0x4800, + 0x5000,0x5000,0x5000,0x5000,0x5000,0x5000,0x5000,0x5000, + 0x5800,0x5800,0x5800,0x5800,0x5800,0x5800,0x5800,0x5800, + 0x6000,0x6000,0x6000,0x6000,0x6000,0x6000,0x6000,0x6000, + 0x6800,0x6800,0x6800,0x6800,0x6800,0x6800,0x6800,0x6800, + 0x7000,0x7000,0x7000,0x7000,0x7000,0x7000,0x7000,0x7000, + 0x7800,0x7800,0x7800,0x7800,0x7800,0x7800,0x7800,0x7800, + 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, + 0x8800,0x8800,0x8800,0x8800,0x8800,0x8800,0x8800,0x8800, + 0x9000,0x9000,0x9000,0x9000,0x9000,0x9000,0x9000,0x9000, + 0x9800,0x9800,0x9800,0x9800,0x9800,0x9800,0x9800,0x9800, + 0xa000,0xa000,0xa000,0xa000,0xa000,0xa000,0xa000,0xa000, + 0xa800,0xa800,0xa800,0xa800,0xa800,0xa800,0xa800,0xa800, + 0xb000,0xb000,0xb000,0xb000,0xb000,0xb000,0xb000,0xb000, + 0xb800,0xb800,0xb800,0xb800,0xb800,0xb800,0xb800,0xb800, + 0xc000,0xc000,0xc000,0xc000,0xc000,0xc000,0xc000,0xc000, + 0xc800,0xc800,0xc800,0xc800,0xc800,0xc800,0xc800,0xc800, + 0xd000,0xd000,0xd000,0xd000,0xd000,0xd000,0xd000,0xd000, + 0xd800,0xd800,0xd800,0xd800,0xd800,0xd800,0xd800,0xd800, + 0xe000,0xe000,0xe000,0xe000,0xe000,0xe000,0xe000,0xe000, + 0xe800,0xe800,0xe800,0xe800,0xe800,0xe800,0xe800,0xe800, + 0xf000,0xf000,0xf000,0xf000,0xf000,0xf000,0xf000,0xf000, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, // 256 + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800,0xf800, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 512 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 768 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +// +// Clip and convert green value into 5-bits for RGB565 +// +static const uint16_t usRangeTableG[] = {0x0000,0x0000,0x0000,0x0000,0x0020,0x0020,0x0020,0x0020, // 0 + 0x0040,0x0040,0x0040,0x0040,0x0060,0x0060,0x0060,0x0060, + 0x0080,0x0080,0x0080,0x0080,0x00a0,0x00a0,0x00a0,0x00a0, + 0x00c0,0x00c0,0x00c0,0x00c0,0x00e0,0x00e0,0x00e0,0x00e0, + 0x0100,0x0100,0x0100,0x0100,0x0120,0x0120,0x0120,0x0120, + 0x0140,0x0140,0x0140,0x0140,0x0160,0x0160,0x0160,0x0160, + 0x0180,0x0180,0x0180,0x0180,0x01a0,0x01a0,0x01a0,0x01a0, + 0x01c0,0x01c0,0x01c0,0x01c0,0x01e0,0x01e0,0x01e0,0x01e0, + 0x0200,0x0200,0x0200,0x0200,0x0220,0x0220,0x0220,0x0220, + 0x0240,0x0240,0x0240,0x0240,0x0260,0x0260,0x0260,0x0260, + 0x0280,0x0280,0x0280,0x0280,0x02a0,0x02a0,0x02a0,0x02a0, + 0x02c0,0x02c0,0x02c0,0x02c0,0x02e0,0x02e0,0x02e0,0x02e0, + 0x0300,0x0300,0x0300,0x0300,0x0320,0x0320,0x0320,0x0320, + 0x0340,0x0340,0x0340,0x0340,0x0360,0x0360,0x0360,0x0360, + 0x0380,0x0380,0x0380,0x0380,0x03a0,0x03a0,0x03a0,0x03a0, + 0x03c0,0x03c0,0x03c0,0x03c0,0x03e0,0x03e0,0x03e0,0x03e0, + 0x0400,0x0400,0x0400,0x0400,0x0420,0x0420,0x0420,0x0420, + 0x0440,0x0440,0x0440,0x0440,0x0460,0x0460,0x0460,0x0460, + 0x0480,0x0480,0x0480,0x0480,0x04a0,0x04a0,0x04a0,0x04a0, + 0x04c0,0x04c0,0x04c0,0x04c0,0x04e0,0x04e0,0x04e0,0x04e0, + 0x0500,0x0500,0x0500,0x0500,0x0520,0x0520,0x0520,0x0520, + 0x0540,0x0540,0x0540,0x0540,0x0560,0x0560,0x0560,0x0560, + 0x0580,0x0580,0x0580,0x0580,0x05a0,0x05a0,0x05a0,0x05a0, + 0x05c0,0x05c0,0x05c0,0x05c0,0x05e0,0x05e0,0x05e0,0x05e0, + 0x0600,0x0600,0x0600,0x0600,0x0620,0x0620,0x0620,0x0620, + 0x0640,0x0640,0x0640,0x0640,0x0660,0x0660,0x0660,0x0660, + 0x0680,0x0680,0x0680,0x0680,0x06a0,0x06a0,0x06a0,0x06a0, + 0x06c0,0x06c0,0x06c0,0x06c0,0x06e0,0x06e0,0x06e0,0x06e0, + 0x0700,0x0700,0x0700,0x0700,0x0720,0x0720,0x0720,0x0720, + 0x0740,0x0740,0x0740,0x0740,0x0760,0x0760,0x0760,0x0760, + 0x0780,0x0780,0x0780,0x0780,0x07a0,0x07a0,0x07a0,0x07a0, + 0x07c0,0x07c0,0x07c0,0x07c0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, // 256 + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0,0x07e0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 512 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 768 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +// +// Clip and convert blue value into 5-bits for RGB565 +// +static const uint16_t usRangeTableB[] = {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, // 0 + 0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001, + 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004, + 0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007, + 0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x000a,0x000a,0x000a,0x000a,0x000a,0x000a,0x000a,0x000a, + 0x000b,0x000b,0x000b,0x000b,0x000b,0x000b,0x000b,0x000b, + 0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000e,0x000e,0x000e,0x000e,0x000e,0x000e,0x000e,0x000e, + 0x000f,0x000f,0x000f,0x000f,0x000f,0x000f,0x000f,0x000f, + 0x0010,0x0010,0x0010,0x0010,0x0010,0x0010,0x0010,0x0010, + 0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011, + 0x0012,0x0012,0x0012,0x0012,0x0012,0x0012,0x0012,0x0012, + 0x0013,0x0013,0x0013,0x0013,0x0013,0x0013,0x0013,0x0013, + 0x0014,0x0014,0x0014,0x0014,0x0014,0x0014,0x0014,0x0014, + 0x0015,0x0015,0x0015,0x0015,0x0015,0x0015,0x0015,0x0015, + 0x0016,0x0016,0x0016,0x0016,0x0016,0x0016,0x0016,0x0016, + 0x0017,0x0017,0x0017,0x0017,0x0017,0x0017,0x0017,0x0017, + 0x0018,0x0018,0x0018,0x0018,0x0018,0x0018,0x0018,0x0018, + 0x0019,0x0019,0x0019,0x0019,0x0019,0x0019,0x0019,0x0019, + 0x001a,0x001a,0x001a,0x001a,0x001a,0x001a,0x001a,0x001a, + 0x001b,0x001b,0x001b,0x001b,0x001b,0x001b,0x001b,0x001b, + 0x001c,0x001c,0x001c,0x001c,0x001c,0x001c,0x001c,0x001c, + 0x001d,0x001d,0x001d,0x001d,0x001d,0x001d,0x001d,0x001d, + 0x001e,0x001e,0x001e,0x001e,0x001e,0x001e,0x001e,0x001e, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, // 256 + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 512 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 768 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +#if defined( __LINUX__ ) || defined( __MCUXPRESSO ) +// +// API for C +// + +// +// Memory initialization +// +int JPEG_openRAM(JPEGIMAGE *pJPEG, uint8_t *pData, int iDataSize, JPEG_DRAW_CALLBACK *pfnDraw) +{ + memset(pJPEG, 0, sizeof(JPEGIMAGE)); + pJPEG->ucMemType = JPEG_MEM_RAM; + pJPEG->pfnRead = readRAM; + pJPEG->pfnSeek = seekMem; + pJPEG->pfnDraw = pfnDraw; + pJPEG->pfnOpen = NULL; + pJPEG->pfnClose = NULL; + pJPEG->JPEGFile.iSize = iDataSize; + pJPEG->JPEGFile.pData = pData; + pJPEG->iMaxMCUs = 1000; // set to an unnaturally high value to start + return JPEGInit(pJPEG); +} /* JPEG_openRAM() */ +// +// File initialization +// +int JPEG_openFile(JPEGIMAGE *pJPEG, const char *szFilename, JPEG_DRAW_CALLBACK *pfnDraw) +{ + memset(pJPEG, 0, sizeof(JPEGIMAGE)); + pJPEG->ucMemType = JPEG_MEM_RAM; + pJPEG->pfnRead = readFile; + pJPEG->pfnSeek = seekFile; + pJPEG->pfnDraw = pfnDraw; + pJPEG->pfnOpen = NULL; + pJPEG->pfnClose = closeFile; + pJPEG->iMaxMCUs = 1000; // set to an unnaturally high value to start + pJPEG->JPEGFile.fHandle = fopen(szFilename, "r+b"); + if (pJPEG->JPEGFile.fHandle == NULL) + return 0; + fseek((FILE *)pJPEG->JPEGFile.fHandle, 0, SEEK_END); + pJPEG->JPEGFile.iSize = (int)ftell((FILE *)pJPEG->JPEGFile.fHandle); + fseek((FILE *)pJPEG->JPEGFile.fHandle, 0, SEEK_SET); + return JPEGInit(pJPEG); +} /* JPEG_openFile() */ + +int JPEG_getLastError(JPEGIMAGE *pJPEG) +{ + return pJPEG->iError; +} /* JPEG_getLastError() */ + +int JPEG_getWidth(JPEGIMAGE *pJPEG) +{ + return pJPEG->iWidth; +} /* JPEG_getWidth() */ + +int JPEG_getHeight(JPEGIMAGE *pJPEG) +{ + return pJPEG->iHeight; +} /* JPEG_getHeight() */ + +int JPEG_getOrientation(JPEGIMAGE *pJPEG) +{ + return (int)pJPEG->ucOrientation; +} /* JPEG_getOrientation() */ + +int JPEG_getBpp(JPEGIMAGE *pJPEG) +{ + return (int)pJPEG->ucBpp; +} /* JPEG_getBpp() */ +int JPEG_getSubSample(JPEGIMAGE *pJPEG) +{ + return (int)pJPEG->ucSubSample; +} /* JPEG_getSubSample() */ +int JPEG_hasThumb(JPEGIMAGE *pJPEG) +{ + return (int)pJPEG->ucHasThumb; +} /* JPEG_hasThumb() */ +int JPEG_getThumbWidth(JPEGIMAGE *pJPEG) +{ + return pJPEG->iThumbWidth; +} /* JPEG_getThumbWidth() */ +int JPEG_getThumbHeight(JPEGIMAGE *pJPEG) +{ + return pJPEG->iThumbHeight; +} /* JPEG_getThumbHeight() */ +void JPEG_setPixelType(JPEGIMAGE *pJPEG, int iType) +{ + pJPEG->ucPixelType = (uint8_t)iType; +} /* JPEG_setPixelType() */ +void JPEG_setMaxOutputSize(JPEGIMAGE *pJPEG, int iMaxMCUs) +{ + if (iMaxMCUs < 1) + iMaxMCUs = 1; // don't allow invalid value + pJPEG->iMaxMCUs = iMaxMCUs; +} /* JPEG_setMaxOutputSize() */ + +int JPEG_decode(JPEGIMAGE *pJPEG, int x, int y, int iOptions) +{ + pJPEG->iXOffset = x; + pJPEG->iYOffset = y; + pJPEG->iOptions = iOptions; + return DecodeJPEG(pJPEG); +} /* JPEG_decode() */ + +int JPEG_decodeDither(JPEGIMAGE *pJPEG, uint8_t *pDither, int iOptions) +{ + pJPEG->iOptions = iOptions; + pJPEG->pDitherBuffer = pDither; + return DecodeJPEG(pJPEG); +} /* JPEG_decodeDither() */ + +void JPEG_close(JPEGIMAGE *pJPEG) +{ + if (pJPEG->pfnClose) + (*pJPEG->pfnClose)(pJPEG->JPEGFile.fHandle); +} /* JPEG_close() */ + +#endif // !__cplusplus +// +// Helper functions for memory based images +// +static int32_t readRAM(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen) +{ + int32_t iBytesRead; + + iBytesRead = iLen; + if ((pFile->iSize - pFile->iPos) < iLen) + iBytesRead = pFile->iSize - pFile->iPos; + if (iBytesRead <= 0) + return 0; + memcpy(pBuf, &pFile->pData[pFile->iPos], iBytesRead); + pFile->iPos += iBytesRead; + return iBytesRead; +} /* readRAM() */ + +static int32_t readFLASH(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen) +{ + int32_t iBytesRead; + + iBytesRead = iLen; + if ((pFile->iSize - pFile->iPos) < iLen) + iBytesRead = pFile->iSize - pFile->iPos; + if (iBytesRead <= 0) + return 0; + memcpy_P(pBuf, &pFile->pData[pFile->iPos], iBytesRead); + pFile->iPos += iBytesRead; + return iBytesRead; +} /* readFLASH() */ + +static int32_t seekMem(JPEGFILE *pFile, int32_t iPosition) +{ + if (iPosition < 0) iPosition = 0; + else if (iPosition >= pFile->iSize) iPosition = pFile->iSize-1; + pFile->iPos = iPosition; + return iPosition; +} /* seekMem() */ + +#if defined( __LINUX__ ) || defined( __MCUXPRESSO ) + +static void closeFile(void *handle) +{ + fclose((FILE *)handle); +} /* closeFile() */ + +static int32_t seekFile(JPEGFILE *pFile, int32_t iPosition) +{ + if (iPosition < 0) iPosition = 0; + else if (iPosition >= pFile->iSize) iPosition = pFile->iSize-1; + pFile->iPos = iPosition; + fseek((FILE *)pFile->fHandle, iPosition, SEEK_SET); + return iPosition; +} /* seekFile() */ + +static int32_t readFile(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen) +{ + int32_t iBytesRead; + + iBytesRead = iLen; + if ((pFile->iSize - pFile->iPos) < iLen) + iBytesRead = pFile->iSize - pFile->iPos; + if (iBytesRead <= 0) + return 0; + iBytesRead = (int)fread(pBuf, 1, iBytesRead, (FILE *)pFile->fHandle); + pFile->iPos += iBytesRead; + return iBytesRead; +} /* readFile() */ + +#endif // __LINUX__ +// +// The following functions are written in plain C and have no +// 3rd party dependencies, not even the C runtime library +// +// +// Initialize a JPEG file and callback access from a file on SD or memory +// returns 1 for success, 0 for failure +// Fills in the basic image info fields of the JPEGIMAGE structure +// +static int JPEGInit(JPEGIMAGE *pJPEG) +{ + return JPEGParseInfo(pJPEG, 0); // gather info for image +} /* JPEGInit() */ +// +// Unpack the Huffman tables +// +static int JPEGGetHuffTables(uint8_t *pBuf, int iLen, JPEGIMAGE *pJPEG) +{ + int i, j, iOffset, iTableOffset; + uint8_t ucTable, *pHuffVals; + + iOffset = 0; + pHuffVals = (uint8_t *)pJPEG->usPixels; // temp holding area to save RAM + while (iLen > 17) // while there are tables to copy (we may have combined more than 1 table together) + { + ucTable = pBuf[iOffset++]; // get table index + if (ucTable & 0x10) // convert AC offset of 0x10 into offset of 4 + ucTable ^= 0x14; + pJPEG->ucHuffTableUsed |= (1 << ucTable); // mark this table as being defined + if (ucTable <= 7) // tables are 0-3, AC+DC + { + iTableOffset = ucTable * HUFF_TABLEN; + j = 0; // total bits + for (i=0; i<16; i++) + { + j += pBuf[iOffset]; + pHuffVals[iTableOffset+i] = pBuf[iOffset++]; + } + iLen -= 17; // subtract length of bit lengths + if (j == 0 || j > 256 || j > iLen) // bogus bit lengths + { + return -1; + } + iTableOffset += 16; + for (i=0; ib11Bit = 1; // indicate we're using the bigger A/C decode tables + // first do DC components (up to 4 tables of 12-bit codes) + // we can save time and memory for the DC codes by knowing that there exist short codes (<= 6 bits) + // and long codes (>6 bits, but the first 5 bits are 1's). This allows us to create 2 tables: a 6-bit and 7 or 8-bit + // to handle any DC codes + iMaxLength = 12; // assume DC codes can be 12-bits + iMaxMask = 0x7f; // lower 7 bits after truncate 5 leading 1's + if (pJPEG->ucMode == 0xc3) // create 13-bit tables for lossless mode + { + iMaxLength = 13; + iMaxMask = 0xff; + } + for (iTable = 0; iTable < 2; iTable++) + { + if (pJPEG->ucHuffTableUsed & (1<huffdcFast[iTable] = (int *)PILIOAlloc(0x180); // short table = 128 bytes, long table = 256 bytes + pucShort = (unsigned char *)&pJPEG->ucHuffDC[iTable*DC_TABLE_SIZE]; + // pJPEG->huffdc[iTable] = pJPEG->huffdcFast[iTable] + 0x20; // 0x20 longs = 128 bytes + pucLong = (unsigned char *)&pJPEG->ucHuffDC[iTable*DC_TABLE_SIZE + 128]; + pBits = &pJPEG->ucHuffVals[iTable * HUFF_TABLEN]; + p = pBits; + p += 16; // point to bit data + cc = 0; // start with a code of 0 + for (iBitNum = 1; iBitNum <= 16; iBitNum++) + { + iLen = *pBits++; // get number of codes for this bit length + if (iBitNum > iMaxLength && iLen > 0) // we can't handle codes longer a certain length + { + return -1; + } + while (iLen) + { + // if (iBitNum > 6) // do long table + if ((cc >> (iBitNum-5)) == 0x1f) // first 5 bits are 1 - use long table + { + count = iMaxLength - iBitNum; + codestart = cc << count; + pucTable = &pucLong[codestart & iMaxMask]; // use lower 7/8 bits of code + } + else // do short table + { + count = 6 - iBitNum; + if (count < 0) + return -1; // DEBUG - something went wrong + codestart = cc << count; + pucTable = &pucShort[codestart]; + } + ucCode = *p++; // get actual huffman code + if (ucCode == 16 && pJPEG->ucMode == 0xc3) // lossless mode + { + // in lossless mode, this code won't fit in 4 bits, so save it's length in the next slot + ucCode = 255; + pucLong[256] = (unsigned char)iBitNum; + } + // does precalculating the DC value save time on ARM? +#ifndef USE_ARM_ASM + if (ucCode != 0 && (ucCode + iBitNum) <= 6 && pJPEG->ucMode != 0xc2) // we can fit the magnitude value in the code lookup (not for progressive) + { + int k, iLoop; + unsigned char ucCoeff; + unsigned char *d = &pucTable[512]; + unsigned char ucMag = ucCode; + ucCode |= ((iBitNum+ucCode) << 4); // add magnitude bits to length + repeat = 1<ucHuffTableUsed & (1<<(iTable+4))) // if this table is defined + { + pBits = &pJPEG->ucHuffVals[(iTable+4) * HUFF_TABLEN]; + p = pBits; + p += 16; // point to bit data + pShort = &pJPEG->usHuffAC[iTable*HUFF11SIZE]; + pLong = &pJPEG->usHuffAC[iTable*HUFF11SIZE + 1024]; // long codes start here + cc = 0; // start with a code of 0 + // construct the decode table + for (iBitNum = 1; iBitNum <= 16; iBitNum++) + { + iLen = *pBits++; // get number of codes for this bit length + while (iLen) + { + if ((cc >> (iBitNum-4)) == 0xf) // first 4 bits are 1 - use long table + { + count = 16 - iBitNum; + codestart = cc << count; + pTable = &pLong[codestart & 0xfff]; // use lower 12 bits of code + } + else + { + count = 12 - iBitNum; + if (count < 0) // a 13-bit? code - that doesn't fit our optimized scheme, see if we can do a bigger table version + { + return -1; // DEBUG - fatal error, we currently don't support it + } + codestart = cc << count; + pTable = &pShort[codestart]; // 11 bits or shorter + } + code = *p++; // get actual huffman code + if (bThumbnail && code != 0) // add "extra" bits to code length since we skip these codes + { + // get rid of extra bits in code and add increment (1) for AC index + code = ((iBitNum+(code & 0xf)) << 8) | ((code >> 4)+1); + } + else + { + code |= (iBitNum << 8); + } + if (count) // do it as dwords to save time + { + repeat = 1 << (count-1); // store as dwords (/2) + ul = code | (code << 16); + pLongTable = (uint32_t *)pTable; + for (j=0; jusPixels; + for (j=0; j<4; j++) + { + if (pJPEG->ucHuffTableUsed & (1 << j)) + iTablesUsed++; + } + // first do DC components (up to 4 tables of 12-bit codes) + // we can save time and memory for the DC codes by knowing that there exist short codes (<= 6 bits) + // and long codes (>6 bits, but the first 5 bits are 1's). This allows us to create 2 tables: a 6-bit and 7 or 8-bit + // to handle any DC codes + iMaxLength = 12; // assume DC codes can be 12-bits + iMaxMask = 0x7f; // lower 7 bits after truncate 5 leading 1's + for (iTable = 0; iTable < 4; iTable++) + { + if (pJPEG->ucHuffTableUsed & (1 << iTable)) + { + // pJPEG->huffdcFast[iTable] = (int *)PILIOAlloc(0x180); // short table = 128 bytes, long table = 256 bytes + pucShort = &pJPEG->ucHuffDC[iTable*DC_TABLE_SIZE]; + // pJPEG->huffdc[iTable] = pJPEG->huffdcFast[iTable] + 0x20; // 0x20 longs = 128 bytes + pucLong = &pJPEG->ucHuffDC[iTable*DC_TABLE_SIZE + 128]; + pBits = &pHuffVals[iTable * HUFF_TABLEN]; + p = pBits; + p += 16; // point to bit data + cc = 0; // start with a code of 0 + for (iBitNum = 1; iBitNum <= 16; iBitNum++) + { + iLen = *pBits++; // get number of codes for this bit length + if (iBitNum > iMaxLength && iLen > 0) // we can't handle codes longer a certain length + { + return 0; + } + while (iLen) + { + // if (iBitNum > 6) // do long table + if ((cc >> (iBitNum-5)) == 0x1f) // first 5 bits are 1 - use long table + { + count = iMaxLength - iBitNum; + codestart = cc << count; + pucTable = &pucLong[codestart & iMaxMask]; // use lower 7/8 bits of code + } + else // do short table + { + count = 6 - iBitNum; + if (count < 0) + return 0; // DEBUG - something went wrong + codestart = cc << count; + pucTable = &pucShort[codestart]; + } + ucCode = *p++; // get actual huffman code + // does precalculating the DC value save time on ARM? +#ifndef USE_ARM_ASM + if (ucCode != 0 && (ucCode + iBitNum) <= 6 && pJPEG->ucMode != 0xc2) // we can fit the magnitude value in the code lookup (not for progressive) + { + int k, iLoop; + unsigned char ucCoeff; + unsigned char *d = &pucTable[512]; + unsigned char ucMag = ucCode; + ucCode |= ((iBitNum+ucCode) << 4); // add magnitude bits to length + repeat = 1<ucHuffTableUsed & (1 << (iTable+4))) // if this table is defined + { + pBits = &pHuffVals[(iTable+4) * HUFF_TABLEN]; + p = pBits; + p += 16; // point to bit data + pShort = &pJPEG->usHuffAC[iTable*HUFF11SIZE]; + pLong = &pJPEG->usHuffAC[iTable*HUFF11SIZE + 1024]; + cc = 0; // start with a code of 0 + // construct the decode table + for (iBitNum = 1; iBitNum <= 16; iBitNum++) + { + iLen = *pBits++; // get number of codes for this bit length + while (iLen) + { + if ((cc >> (iBitNum-6)) == 0x3f) // first 6 bits are 1 - use long table + { + count = 16 - iBitNum; + codestart = cc << count; + pTable = &pLong[codestart & 0x3ff]; // use lower 10 bits of code + } + else + { + count = 10 - iBitNum; + if (count < 0) // an 11/12-bit? code - that doesn't fit our optimized scheme, see if we can do a bigger table version + { + if (count == -1 && iTablesUsed <= 4) // we need to create "slow" tables + { // DEBUG +// j = JPEGMakeHuffTables_Slow(pJPEG, bThumbnail); + return 0; + } + else + return 0; // DEBUG - fatal error, more than 2 big tables we currently don't support + } + codestart = cc << count; + pTable = &pShort[codestart]; // 10 bits or shorter + } + code = *p++; // get actual huffman code + if (bThumbnail && code != 0) // add "extra" bits to code length since we skip these codes + { + // get rid of extra bits in code and add increment (1) for AC index + code = ((iBitNum+(code & 0xf)) << 8) | ((code >> 4)+1); + } +#ifdef BOGUS // precalculating the AC coeff makes it run slightly slower + else if ((code & 0xf) != 0 && (code + iBitNum) <= 10) // we can fit the magnitude value + huffman code in a single read + { + int k, iLoop; + unsigned short usCoeff; + unsigned short *d = &pTable[4096]; // use unused table slots 2+3 for extra coeff data + unsigned char ucMag = (unsigned char)(code & 0xf); + code |= ((iBitNum + (code & 0xf)) << 8); // add magnitude bits to length + repeat = 1< 1) + { + iType = 4; + } + switch (iType) + { + case 3: /* Short */ + i = TIFFSHORT(p+8, bMotorola); + break; + case 4: /* Long */ + case 7: // undefined (treat it as a long since it's usually a multibyte buffer) + i = TIFFLONG(p+8, bMotorola); + break; + case 6: // signed byte + i = (signed char)p[8]; + break; + case 2: /* ASCII */ + case 5: /* Unsigned Rational */ + case 10: /* Signed Rational */ + i = TIFFLONG(p+8, bMotorola); + break; + default: /* to suppress compiler warning */ + i = 0; + break; + } + return i; + +} /* TIFFVALUE() */ +static void GetTIFFInfo(JPEGIMAGE *pPage, int bMotorola, int iOffset) +{ + int iTag, iTagCount, i; + uint8_t *cBuf = pPage->ucFileBuf; + + iTagCount = TIFFSHORT(&cBuf[iOffset], bMotorola); /* Number of tags in this dir */ + if (iTagCount < 1 || iTagCount > 256) // invalid tag count + return; /* Bad header info */ + /*--- Search the TIFF tags ---*/ + for (i=0; iucOrientation = TIFFVALUE(p, bMotorola); + } + else if (iTag == 256) // width of thumbnail + { + pPage->iThumbWidth = TIFFVALUE(p, bMotorola); + } + else if (iTag == 257) // height of thumbnail + { + pPage->iThumbHeight = TIFFVALUE(p, bMotorola); + } + else if (iTag == 513) // offset to JPEG data + { + pPage->iThumbData = TIFFVALUE(p, bMotorola); + } + } +} /* GetTIFFInfo() */ + +static int JPEGGetSOS(JPEGIMAGE *pJPEG, int *iOff) +{ + int16_t sLen; + int iOffset = *iOff; + int i, j; + uint8_t uc,c,cc; + uint8_t *buf = pJPEG->ucFileBuf; + + sLen = MOTOSHORT(&buf[iOffset]); + iOffset += 2; + + // Assume no components in this scan + for (i=0; i<4; i++) + pJPEG->JPCI[i].component_needed = 0; + + uc = buf[iOffset++]; // get number of components + pJPEG->ucComponentsInScan = uc; + sLen -= 3; + if (uc < 1 || uc > MAX_COMPS_IN_SCAN || sLen != (uc*2+3)) // check length of data packet + return 1; // error + for (i=0; iJPCI[j].component_id == cc) + break; + } + if (j == 4) // error, not found + return 1; + if ((c & 0xf) > 3 || (c & 0xf0) > 0x30) + return 1; // bogus table numbers + pJPEG->JPCI[j].dc_tbl_no = c >> 4; + pJPEG->JPCI[j].ac_tbl_no = c & 0xf; + pJPEG->JPCI[j].component_needed = 1; // mark this component as being included in the scan + } + pJPEG->iScanStart = buf[iOffset++]; // Get the scan start (or lossless predictor) for this scan + pJPEG->iScanEnd = buf[iOffset++]; // Get the scan end for this scan + c = buf[iOffset++]; // successive approximation bits + pJPEG->cApproxBitsLow = c & 0xf; // also point transform in lossless mode + pJPEG->cApproxBitsHigh = c >> 4; + + *iOff = iOffset; + return 0; + +} /* JPEGGetSOS() */ +// +// Remove markers from the data stream to allow faster decode +// Stuffed zeros and restart interval markers aren't needed to properly decode +// the data, but they make reading VLC data slower, so I pull them out first +// +static int JPEGFilter(uint8_t *pBuf, uint8_t *d, int iLen, uint8_t *bFF) +{ + // since we have the entire jpeg buffer in memory already, we can just change it in place + unsigned char c, *s, *pEnd, *pStart; + + pStart = d; + s = pBuf; + pEnd = &s[iLen-1]; // stop just shy of the end to not miss a final marker/stuffed 0 + if (*bFF) // last byte was a FF, check the next one + { + if (s[0] == 0) // stuffed 0, keep the FF + *d++ = 0xff; + s++; + *bFF = 0; + } + while (s < pEnd) + { + c = *d++ = *s++; + if (c == 0xff) // marker or stuffed zeros? + { + if (s[0] != 0) // it's a marker, skip both + { + d--; + } + s++; // for stuffed 0's, store the FF, skip the 00 + } + } + if (s == pEnd) // need to test the last byte + { + c = s[0]; + if (c == 0xff) // last byte is FF, take care of it next time through + *bFF = 1; // take care of it next time through + else + *d++ = c; // nope, just store it + } + return (int)(d-pStart); // filtered output length +} /* JPEGFilter() */ +// +// Read and filter more VLC data for decoding +// +static void JPEGGetMoreData(JPEGIMAGE *pPage) +{ + int iDelta = pPage->iVLCSize - pPage->iVLCOff; +// printf("Getting more data...size=%d, off=%d\n", pPage->iVLCSize, pPage->iVLCOff); + // move any existing data down + if (iDelta >= (JPEG_FILE_BUF_SIZE-64) || iDelta < 0) + return; // buffer is already full; no need to read more data + if (pPage->iVLCOff != 0) + { + memcpy(pPage->ucFileBuf, &pPage->ucFileBuf[pPage->iVLCOff], pPage->iVLCSize - pPage->iVLCOff); + pPage->iVLCSize -= pPage->iVLCOff; + pPage->iVLCOff = 0; + pPage->bb.pBuf = pPage->ucFileBuf; // reset VLC source pointer too + } + if (pPage->JPEGFile.iPos < pPage->JPEGFile.iSize && pPage->iVLCSize < JPEG_FILE_BUF_SIZE-64) + { + int i; + // Try to read enough to fill the buffer + i = (*pPage->pfnRead)(&pPage->JPEGFile, &pPage->ucFileBuf[pPage->iVLCSize], JPEG_FILE_BUF_SIZE - pPage->iVLCSize); // max length we can read + // Filter out the markers + pPage->iVLCSize += JPEGFilter(&pPage->ucFileBuf[pPage->iVLCSize], &pPage->ucFileBuf[pPage->iVLCSize], i, &pPage->ucFF); + } +} /* JPEGGetMoreData() */ + +// +// Parse the JPEG header, gather necessary info to decode the image +// Returns 1 for success, 0 for failure +// +static int JPEGParseInfo(JPEGIMAGE *pPage, int bExtractThumb) +{ + int iBytesRead; + int i, iOffset, iTableOffset; + uint8_t ucTable, *s = pPage->ucFileBuf; + uint16_t usMarker, usLen = 0; + int iFilePos = 0; + + if (bExtractThumb) // seek to the start of the thumbnail image + { + iFilePos = pPage->iThumbData; + (*pPage->pfnSeek)(&pPage->JPEGFile, iFilePos); + } + iBytesRead = (*pPage->pfnRead)(&pPage->JPEGFile, s, JPEG_FILE_BUF_SIZE); + if (iBytesRead < 256) // a JPEG file this tiny? probably bad + { + pPage->iError = JPEG_INVALID_FILE; + return 0; + } + iFilePos += iBytesRead; + if (MOTOSHORT(pPage->ucFileBuf) != 0xffd8) + { + pPage->iError = JPEG_INVALID_FILE; + return 0; // not a JPEG file + } + iOffset = 2; /* Start at offset of first marker */ + usMarker = 0; /* Search for SOFx (start of frame) marker */ + while (usMarker != 0xffda && iOffset < pPage->JPEGFile.iSize) + { + if (iOffset >= JPEG_FILE_BUF_SIZE/2) // too close to the end, read more data + { + // Do we need to seek first? + if (iOffset >= JPEG_FILE_BUF_SIZE) + { + iFilePos += (iOffset - iBytesRead); + iOffset = 0; + (*pPage->pfnSeek)(&pPage->JPEGFile, iFilePos); + iBytesRead = 0; // throw away any old data + } + // move existing bytes down + if (iOffset) + { + memcpy(pPage->ucFileBuf, &pPage->ucFileBuf[iOffset], iBytesRead - iOffset); + iBytesRead -= iOffset; + iOffset = 0; + } + i = (*pPage->pfnRead)(&pPage->JPEGFile, &pPage->ucFileBuf[iBytesRead], JPEG_FILE_BUF_SIZE-iBytesRead); + iFilePos += i; + iBytesRead += i; + } + usMarker = MOTOSHORT(&s[iOffset]); + iOffset += 2; + usLen = MOTOSHORT(&s[iOffset]); // marker length + + if (usMarker < 0xffc0 || usMarker == 0xffff) // invalid marker, could be generated by "Arles Image Web Page Creator" or Accusoft + { + iOffset++; + continue; // skip 1 byte and try to resync + } + switch (usMarker) + { + case 0xffc1: + case 0xffc2: + case 0xffc3: + pPage->iError = JPEG_UNSUPPORTED_FEATURE; + return 0; // currently unsupported modes + + case 0xffe1: // App1 (EXIF?) + if (s[iOffset+2] == 'E' && s[iOffset+3] == 'x' && (s[iOffset+8] == 'M' || s[iOffset+8] == 'I')) // the EXIF data we want + { + int bMotorola, IFD, iTagCount; + pPage->iEXIF = iFilePos - iBytesRead + iOffset + 8; // start of TIFF file + // Get the orientation value (if present) + bMotorola = (s[iOffset+8] == 'M'); + IFD = TIFFLONG(&s[iOffset+12], bMotorola); + iTagCount = TIFFSHORT(&s[iOffset+16], bMotorola); + GetTIFFInfo(pPage, bMotorola, IFD+iOffset+8); + // The second IFD defines the thumbnail (if present) + if (iTagCount >= 1 && iTagCount < 32) // valid number of tags for EXIF data 'page' + { + // point to next IFD + IFD += (12 * iTagCount) + 2; + IFD = TIFFLONG(&s[IFD + iOffset + 8], bMotorola); + if (IFD != 0) // Thumbnail present? + { + pPage->ucHasThumb = 1; + GetTIFFInfo(pPage, bMotorola, IFD+iOffset+8); // info for second 'page' of TIFF + pPage->iThumbData += iOffset + 8; // absolute offset in the file + } + } + } + break; + case 0xffc0: // SOFx - start of frame + pPage->ucMode = (uint8_t)usMarker; + pPage->ucBpp = s[iOffset+2]; // bits per sample + pPage->iHeight = MOTOSHORT(&s[iOffset+3]); + pPage->iWidth = MOTOSHORT(&s[iOffset+5]); + pPage->ucNumComponents = s[iOffset+7]; + pPage->ucBpp = pPage->ucBpp * pPage->ucNumComponents; /* Bpp = number of components * bits per sample */ + if (pPage->ucNumComponents == 1) + pPage->ucSubSample = 0; // use this to differentiate from color 1:1 + else + { + usLen -= 8; + iOffset += 8; +// pPage->ucSubSample = s[iOffset+9]; // subsampling option for the second color component + for (i=0; iucNumComponents; i++) + { + uint8_t ucSamp; + pPage->JPCI[i].component_id = s[iOffset++]; + pPage->JPCI[i].component_index = (unsigned char)i; + ucSamp = s[iOffset++]; // get the h+v sampling factor + if (i == 0) // Y component? + pPage->ucSubSample = ucSamp; +// pPage->JPCI[i].h_samp_factor = ucSamp >> 4; +// pPage->JPCI[i].v_samp_factor = ucSamp & 0xf; + pPage->JPCI[i].quant_tbl_no = s[iOffset++]; // quantization table number + usLen -= 3; + } + } + break; + case 0xffdd: // Restart Interval + if (usLen == 4) + pPage->iResInterval = MOTOSHORT(&s[iOffset+2]); + break; + case 0xffc4: /* M_DHT */ // get Huffman tables + iOffset += 2; // skip length + usLen -= 2; // subtract length length + if (JPEGGetHuffTables(&s[iOffset], usLen, pPage) != 0) // bad tables? + { + pPage->iError = JPEG_DECODE_ERROR; + return 0; // error + } + break; + case 0xffdb: /* M_DQT */ + /* Get the quantization tables */ + /* first byte has PPPPNNNN where P = precision and N = table number 0-3 */ + iOffset += 2; // skip length + usLen -= 2; // subtract length length + while (usLen > 0) + { + ucTable = s[iOffset++]; // table number + if ((ucTable & 0xf) > 3) // invalid table number + { + pPage->iError = JPEG_DECODE_ERROR; + return 0; + } + iTableOffset = (ucTable & 0xf) * DCTSIZE; + if (ucTable & 0xf0) // if word precision + { + for (i=0; isQuantTable[i+iTableOffset] = MOTOSHORT(&s[iOffset]); + iOffset += 2; + } + usLen -= (DCTSIZE*2 + 1); + } + else // byte precision + { + for (i=0; isQuantTable[i+iTableOffset] = (unsigned short)s[iOffset++]; + } + usLen -= (DCTSIZE + 1); + } + } + break; + } // switch on JPEG marker + iOffset += usLen; + } // while + if (usMarker == 0xffda) // start of image + { + if (pPage->ucBpp != 8) // need to match up table IDs + { + iOffset -= usLen; + JPEGGetSOS(pPage, &iOffset); // get Start-Of-Scan info for decoding + } + if (!JPEGMakeHuffTables(pPage, 0)) //int bThumbnail) DEBUG + { + pPage->iError = JPEG_UNSUPPORTED_FEATURE; + return 0; + } + // Now the offset points to the start of compressed data + i = JPEGFilter(&pPage->ucFileBuf[iOffset], pPage->ucFileBuf, iBytesRead-iOffset, &pPage->ucFF); + pPage->iVLCOff = 0; + pPage->iVLCSize = i; + JPEGGetMoreData(pPage); // read more VLC data + return 1; + } + pPage->iError = JPEG_DECODE_ERROR; + return 0; +} /* JPEGParseInfo() */ +// +// Fix and reorder the quantization table for faster decoding.* +// +static void JPEGFixQuantD(JPEGIMAGE *pJPEG) +{ + int iTable, iTableOffset; + signed short sTemp[DCTSIZE]; + int i; + uint16_t *p; + + for (iTable=0; iTableucNumComponents; iTable++) + { + iTableOffset = iTable * DCTSIZE; + p = (uint16_t *)&pJPEG->sQuantTable[iTableOffset]; + for (i=0; isQuantTable[iTableOffset], sTemp, DCTSIZE*sizeof(short)); // copy back to original spot + + // Prescale for DCT multiplication + p = (uint16_t *)&pJPEG->sQuantTable[iTableOffset]; + for (i=0; i> 12); + } + } +} /* JPEGFixQuantD() */ +// +// Decode the 64 coefficients of the current DCT block +// +static int JPEGDecodeMCU(JPEGIMAGE *pJPEG, int iMCU, int *iDCPredictor) +{ + uint32_t ulCode, ulTemp; + uint8_t *pZig; + signed char cCoeff; + unsigned short *pFast; + unsigned char ucHuff, *pucFast; + uint32_t usHuff; // this prevents an unnecessary & 65535 for shorts + uint32_t ulBitOff, ulBits; // local copies to allow compiler to use register vars + uint8_t *pBuf, *pEnd, *pEnd2; + signed short *pMCU = &pJPEG->sMCUs[iMCU]; + uint8_t ucMaxACCol, ucMaxACRow; + + #define MIN_DCT_THRESHOLD 8 + + ulBitOff = pJPEG->bb.ulBitOff; + ulBits = pJPEG->bb.ulBits; + pBuf = pJPEG->bb.pBuf; + + pZig = (unsigned char *)&cZigZag2[1]; + pEnd = (unsigned char *)&cZigZag2[64]; + + if (ulBitOff > (REGISTER_WIDTH-17)) // need to get more data + { + pBuf += (ulBitOff >> 3); + ulBitOff &= 7; + ulBits = MOTOLONG(pBuf); + } + if (pJPEG->iOptions & (JPEG_SCALE_QUARTER | JPEG_SCALE_EIGHTH)) // reduced size DCT + { + pMCU[1] = pMCU[8] = pMCU[9] = 0; + pEnd2 = (uint8_t *)&cZigZag2[5]; // we only need to store the 4 elements we care about + } + else + { + memset(pMCU, 0, 64*sizeof(short)); // pre-fill with zero since we may skip coefficients + pEnd2 = (uint8_t *)&cZigZag2[64]; + } + ucMaxACCol = ucMaxACRow = 0; + pZig = (unsigned char *)&cZigZag2[1]; + pEnd = (unsigned char *)&cZigZag2[64]; + + // get the DC component + pucFast = &pJPEG->ucHuffDC[pJPEG->ucDCTable * DC_TABLE_SIZE]; + ulCode = (ulBits >> (REGISTER_WIDTH - 12 - ulBitOff)) & 0xfff; // get as lower 12 bits + if (ulCode >= 0xf80) // it's a long code + ulCode = (ulCode & 0xff); // point to long table and trim to 7-bits + 0x80 offset into long table + else + ulCode >>= 6; // it's a short code, use first 6 bits only + ucHuff = pucFast[ulCode]; + cCoeff = (signed char)pucFast[ulCode+512]; // get pre-calculated extra bits for "small" values + if (ucHuff == 0) // invalid code + return -1; + ulBitOff += (ucHuff >> 4); // add the Huffman length + ucHuff &= 0xf; // get the actual code (SSSS) + if (ucHuff) // if there is a change to the DC value + { // get the 'extra' bits + if (cCoeff) + { + (*iDCPredictor) += cCoeff; + } + else + { + if (ulBitOff > (REGISTER_WIDTH - 17)) // need to get more data + { + pBuf += (ulBitOff >> 3); + ulBitOff &= 7; + ulBits = MOTOLONG(pBuf); + } + ulCode = ulBits << ulBitOff; + ulTemp = ~(uint32_t)(((int32_t)ulCode)>>31); // slide sign bit across other 31 bits + ulCode >>= (REGISTER_WIDTH - ucHuff); + ulCode -= ulTemp>>(REGISTER_WIDTH-ucHuff); + ulBitOff += ucHuff; // add bit length + (*iDCPredictor) += (int)ulCode; + } + } + pMCU[0] = (short)*iDCPredictor; // store in MCU[0] + // Now get the other 63 AC coefficients + pFast = &pJPEG->usHuffAC[pJPEG->ucACTable * HUFF11SIZE]; + if (pJPEG->b11Bit) // 11-bit "slow" tables used + { +// if (pJPEG->pHuffACFast == pJPEG->huffacFast[1]) // second table +// pFast = &pJPEG->ucAltHuff[0]; + while (pZig < pEnd) + { + if (ulBitOff >(REGISTER_WIDTH - 17)) // need to get more data + { + pBuf += (ulBitOff >> 3); + ulBitOff &= 7; + ulBits = MOTOLONG(pBuf); + } + ulCode = (ulBits >> (REGISTER_WIDTH - 16 - ulBitOff)) & 0xffff; // get as lower 16 bits + if (ulCode >= 0xf000) // first 4 bits = 1, use long table + ulCode = (ulCode & 0x1fff); + else + ulCode >>= 4; // use lower 12 bits (short table) + usHuff = pFast[ulCode]; + if (usHuff == 0) // invalid code + return -1; + ulBitOff += (usHuff >> 8); // add length + usHuff &= 0xff; // get code (RRRR/SSSS) + if (usHuff == 0) // no more AC components + { + goto mcu_done; + } + if (ulBitOff > (REGISTER_WIDTH - 17)) // need to get more data + { + pBuf += (ulBitOff >> 3); + ulBitOff &= 7; + ulBits = MOTOLONG(pBuf); + } + pZig += (usHuff >> 4); // get the skip amount (RRRR) + usHuff &= 0xf; // get (SSSS) - extra length + if (pZig < pEnd && usHuff) // && piHisto) + { + ulCode = ulBits << ulBitOff; + ulTemp = ~(uint32_t) (((int32_t) ulCode) >> (REGISTER_WIDTH-1)); // slide sign bit across other 63 bits + ulCode >>= (REGISTER_WIDTH - usHuff); + ulCode -= ulTemp >> (REGISTER_WIDTH - usHuff); + ucMaxACCol |= 1<<(*pZig & 7); // keep track of occupied columns + if (*pZig >= 0x20) // if more than 4 rows used in a col, mark it + ucMaxACRow |= 1<<(*pZig & 7); // keep track of the max AC term row + pMCU[*pZig] = (signed short)ulCode; // store AC coefficient (already reordered) + } + ulBitOff += usHuff; // add (SSSS) extra length + pZig++; + } // while + } + else // 10-bit "fast" tables used + { + while (pZig < pEnd) + { + if (ulBitOff >(REGISTER_WIDTH - 17)) // need to get more data + { + pBuf += (ulBitOff >> 3); + ulBitOff &= 7; + ulBits = MOTOLONG(pBuf); + } + ulCode = (ulBits >> (REGISTER_WIDTH - 16 - ulBitOff)) & 0xffff; // get as lower 16 bits + if (ulCode >= 0xfc00) // first 6 bits = 1, use long table + ulCode = (ulCode & 0x7ff); // (ulCode & 0x3ff) + 0x400; + else + ulCode >>= 6; // use lower 10 bits (short table) + usHuff = pFast[ulCode]; + if (usHuff == 0) // invalid code + return -1; + ulBitOff += (usHuff >> 8); // add length + usHuff &= 0xff; // get code (RRRR/SSSS) + if (usHuff == 0) // no more AC components + { + goto mcu_done; + } + if (ulBitOff >(REGISTER_WIDTH - 17)) // need to get more data + { + pBuf += (ulBitOff >> 3); + ulBitOff &= 7; + ulBits = MOTOLONG(pBuf); + } + pZig += (usHuff >> 4); // get the skip amount (RRRR) + usHuff &= 0xf; // get (SSSS) - extra length + if (pZig < pEnd2 && usHuff) + { + ulCode = ulBits << ulBitOff; + ulTemp = ~(uint32_t) (((int32_t) ulCode) >> (REGISTER_WIDTH-1)); // slide sign bit across other 63 bits + ulCode >>= (REGISTER_WIDTH - usHuff); + ulCode -= ulTemp >> (REGISTER_WIDTH - usHuff); + ucMaxACCol |= 1<<(*pZig & 7); // keep track of occupied columns + if (*pZig >= 0x20) // if more than 4 rows used in a col, mark it + ucMaxACRow |= 1<<(*pZig & 7); // keep track of the max AC term row + pMCU[*pZig] = (signed short)ulCode; // store AC coefficient (already reordered) + } + ulBitOff += usHuff; // add (SSSS) extra length + pZig++; + } // while + } // 10-bit tables +mcu_done: + pJPEG->bb.pBuf = pBuf; + pJPEG->iVLCOff = (int)(pBuf - pJPEG->ucFileBuf); + pJPEG->bb.ulBitOff = ulBitOff; + pJPEG->bb.ulBits = ulBits; + pJPEG->ucMaxACCol = ucMaxACCol; + pJPEG->ucMaxACRow = ucMaxACRow; // DEBUG + return 0; +} /* JPEGDecodeMCU() */ +// +// Inverse DCT +// +static void JPEGIDCT(JPEGIMAGE *pJPEG, int iMCUOffset, int iQuantTable, int iACFlags) +{ + int iRow; + unsigned char ucColMask; + int iCol; + signed int tmp6,tmp7,tmp10,tmp11,tmp12,tmp13; + signed int z5,z10,z11,z12,z13; + signed int tmp0,tmp1,tmp2,tmp3,tmp4,tmp5; + signed short *pQuant; + unsigned char *pOutput; + unsigned char ucMaxACRow, ucMaxACCol; + int16_t *pMCUSrc = &pJPEG->sMCUs[iMCUOffset]; + + ucMaxACRow = (unsigned char)(iACFlags >> 8); + ucMaxACCol = iACFlags & 0xff; + + // my shortcut method appears to violate patent 20020080052 + // but the patent is invalidated by prior art: + // http://netilium.org/~mad/dtj/DTJ/DTJK04/ + pQuant = &pJPEG->sQuantTable[iQuantTable * DCTSIZE]; + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) // special case + { + /* Column 0 */ + tmp4 = pMCUSrc[0] * pQuant[0]; + tmp5 = pMCUSrc[8] * pQuant[8]; + tmp0 = tmp4 + tmp5; + tmp2 = tmp4 - tmp5; + /* Column 1 */ + tmp4 = pMCUSrc[1] * pQuant[1]; + tmp5 = pMCUSrc[9] * pQuant[9]; + tmp1 = tmp4 + tmp5; + tmp3 = tmp4 - tmp5; + /* Pass 2: process 2 rows, store into output array. */ + /* Row 0 */ + pOutput = (unsigned char *)pMCUSrc; // store output pixels back into MCU + pOutput[0] = ucRangeTable[(((tmp0 + tmp1)>>5) & 0x3ff)]; + pOutput[1] = ucRangeTable[(((tmp0 - tmp1)>>5) & 0x3ff)]; + /* Row 1 */ + pOutput[2] = ucRangeTable[(((tmp2 + tmp3)>>5) & 0x3ff)]; + pOutput[3] = ucRangeTable[(((tmp2 - tmp3)>>5) & 0x3ff)]; + return; + } + // do columns first + ucColMask = ucMaxACCol | 1; // column 0 must always be calculated + for (iCol = 0; iCol < 8 && ucColMask; iCol++) + { + if (ucColMask & (1<>8); // used to be 362 - 1 (256) + tmp0 = tmp10 + tmp1; + tmp3 = tmp10 - tmp1; + tmp1 = tmp10 + tmp12; + tmp2 = tmp10 - tmp12; + // odd part + tmp4 = pMCUSrc[iCol+8] * pQuant[iCol+8]; // get 1st row + tmp5 = pMCUSrc[iCol+24]; + if (tmp5) // this value is usually 0 + { + tmp5 *= pQuant[iCol+24]; // get 3rd row + tmp7 = tmp4 + tmp5; + tmp11 = (((tmp4 - tmp5) * 362) >> 8); // 362>>8 = 1.414213562 + z5 = (((tmp4-tmp5) * 473) >> 8); // 473>>8 = 1.8477 + tmp12 = ((-tmp5 * -669)>>8) + z5; // -669>>8 = -2.6131259 + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp10 = ((tmp4 * 277)>>8) - z5; // 277>>8 = 1.08239 + tmp4 = tmp10 + tmp5; + } + else // simpler case when we only have 1 odd row to calculate + { + tmp7 = tmp4; + tmp5 = (145*tmp4) >> 8; + tmp6 = (217*tmp4) >> 8; + tmp4 = (-51*tmp4) >> 8; + } + pMCUSrc[iCol] = (short)(tmp0 + tmp7); // row0 + pMCUSrc[iCol+8] = (short)(tmp1 + tmp6); // row 1 + pMCUSrc[iCol+16] = (short)(tmp2 + tmp5); // row 2 + pMCUSrc[iCol+24] = (short)(tmp3 - tmp4); // row 3 + pMCUSrc[iCol+32] = (short)(tmp3 + tmp4); // row 4 + pMCUSrc[iCol+40] = (short)(tmp2 - tmp5); // row 5 + pMCUSrc[iCol+48] = (short)(tmp1 - tmp6); // row 6 + pMCUSrc[iCol+56] = (short)(tmp0 - tmp7); // row 7 + } + else // need to do full column calculation + { + // even part + tmp0 = pMCUSrc[iCol] * pQuant[iCol]; + tmp2 = pMCUSrc[iCol+32]; // get 4th row + if (tmp2) // 4th row is most likely 0 + { + tmp2 = tmp2 * pQuant[iCol+32]; + tmp10 = tmp0 + tmp2; + tmp11 = tmp0 - tmp2; + } + else + { + tmp10 = tmp11 = tmp0; + } + tmp1 = pMCUSrc[iCol+16] * pQuant[iCol+16]; // get 2nd row + tmp3 = pMCUSrc[iCol+48]; // get 6th row + if (tmp3) // 6th row is most likely 0 + { + tmp3 = tmp3 * pQuant[iCol+48]; + tmp13 = tmp1 + tmp3; + tmp12 = (((tmp1 - tmp3) * 362) >> 8) - tmp13; // 362>>8 = 1.414213562 + } + else + { + tmp13 = tmp1; + tmp12 = ((tmp1*362)>>8) - tmp1; + } + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + // odd part + tmp5 = pMCUSrc[iCol+24] * pQuant[iCol+24]; // get 3rd row + tmp6 = pMCUSrc[iCol+40]; // get 5th row + if (tmp6) // very likely that row 5 = 0 + { + tmp6 = tmp6 * pQuant[iCol+40]; + z13 = tmp6 + tmp5; + z10 = tmp6 - tmp5; + } + else + { + z13 = tmp5; + z10 = -tmp5; + } + tmp4 = pMCUSrc[iCol+8] * pQuant[iCol+8]; // get 1st row + tmp7 = pMCUSrc[iCol+56]; // get 7th row + if (tmp7) // very likely that row 7 = 0 + { + tmp7 = tmp7 * pQuant[iCol+56]; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + } + else + { + z11 = z12 = tmp4; + } + tmp7 = z11 + z13; + tmp11 = (((z11 - z13) * 362) >> 8); // 362>>8 = 1.414213562 + z5 = (((z10 + z12) * 473) >> 8); // 473>>8 = 1.8477 + tmp12 = ((z10 * -669)>>8) + z5; // -669>>8 = -2.6131259 + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp10 = ((z12 * 277)>>8) - z5; // 277>>8 = 1.08239 + tmp4 = tmp10 + tmp5; + pMCUSrc[iCol] = (short)(tmp0 + tmp7); // row0 + pMCUSrc[iCol+8] = (short)(tmp1 + tmp6); // row 1 + pMCUSrc[iCol+16] = (short)(tmp2 + tmp5); // row 2 + pMCUSrc[iCol+24] = (short)(tmp3 - tmp4); // row 3 + pMCUSrc[iCol+32] = (short)(tmp3 + tmp4); // row 4 + pMCUSrc[iCol+40] = (short)(tmp2 - tmp5); // row 5 + pMCUSrc[iCol+48] = (short)(tmp1 - tmp6); // row 6 + pMCUSrc[iCol+56] = (short)(tmp0 - tmp7); // row 7 + } // full calculation needed + } // if column has data in it + } // for each column + // now do rows + pOutput = (unsigned char *)pMCUSrc; // store output pixels back into MCU + for (iRow=0; iRow<64; iRow+=8) // all rows must be calculated + { + // even part + if (ucMaxACCol < 0x10) // quick and dirty calculation (right 4 columns are all 0's) + { + if (ucMaxACCol < 0x04) // very likely case (1 or 2 columns occupied) + { + // even part + tmp0 = tmp1 = tmp2 = tmp3 = pMCUSrc[iRow+0]; + // odd part + tmp7 = pMCUSrc[iRow+1]; + tmp6 = (tmp7 * 217)>>8; // * 0.8477 + tmp5 = (tmp7 * 145)>>8; // * 0.5663 + tmp4 = -((tmp7 * 51)>>8); // * -0.199 + } + else + { + tmp10 = pMCUSrc[iRow+0]; + tmp13 = pMCUSrc[iRow+2]; + tmp12 = ((tmp13 * 106)>>8); // 2-6 * 1.414 + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp10 + tmp12; + tmp2 = tmp10 - tmp12; + // odd part + z13 = pMCUSrc[iRow+3]; + z11 = pMCUSrc[iRow+1]; + tmp7 = z11 + z13; + tmp11 = ((z11 - z13)*362)>>8; // * 1.414 + z5 = ((z11 - z13)*473)>>8; // * 1.8477 + tmp10 = ((z11*277)>>8) - z5; // * 1.08239 + tmp12 = ((z13*669)>>8) + z5; // * 2.61312 + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + } + } + else // need to do the full calculation + { + tmp10 = pMCUSrc[iRow+0] + pMCUSrc[iRow+4]; + tmp11 = pMCUSrc[iRow+0] - pMCUSrc[iRow+4]; + tmp13 = pMCUSrc[iRow+2] + pMCUSrc[iRow+6]; + tmp12 = (((pMCUSrc[iRow+2] - pMCUSrc[iRow+6]) * 362)>>8) - tmp13; // 2-6 * 1.414 + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + // odd part + z13 = pMCUSrc[iRow+5] + pMCUSrc[iRow+3]; + z10 = pMCUSrc[iRow+5] - pMCUSrc[iRow+3]; + z11 = pMCUSrc[iRow+1] + pMCUSrc[iRow+7]; + z12 = pMCUSrc[iRow+1] - pMCUSrc[iRow+7]; + tmp7 = z11 + z13; + tmp11 = ((z11 - z13)*362)>>8; // * 1.414 + z5 = ((z10 + z12)*473)>>8; // * 1.8477 + tmp10 = ((z12*277)>>8) - z5; // * 1.08239 + tmp12 = ((z10*-669)>>8) + z5; // * 2.61312 + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + } + // final output stage - scale down and range limit + pOutput[0] = ucRangeTable[(((tmp0 + tmp7)>>5) & 0x3ff)]; + pOutput[1] = ucRangeTable[(((tmp1 + tmp6)>>5) & 0x3ff)]; + pOutput[2] = ucRangeTable[(((tmp2 + tmp5)>>5) & 0x3ff)]; + pOutput[3] = ucRangeTable[(((tmp3 - tmp4)>>5) & 0x3ff)]; + pOutput[4] = ucRangeTable[(((tmp3 + tmp4)>>5) & 0x3ff)]; + pOutput[5] = ucRangeTable[(((tmp2 - tmp5)>>5) & 0x3ff)]; + pOutput[6] = ucRangeTable[(((tmp1 - tmp6)>>5) & 0x3ff)]; + pOutput[7] = ucRangeTable[(((tmp0 - tmp7)>>5) & 0x3ff)]; + pOutput += 8; + } // for each row +} /* JPEGIDCT() */ +static void JPEGPutMCU8BitGray(JPEGIMAGE *pJPEG, int x, int iPitch) +{ + int i, j, xcount, ycount; + uint8_t *pDest, *pSrc = (uint8_t *)&pJPEG->sMCUs[0]; + + if (pJPEG->pDitherBuffer) + pDest = &pJPEG->pDitherBuffer[x]; + else + pDest = (uint8_t *)&pJPEG->usPixels[x/2]; + + if (pJPEG->ucSubSample <= 0x11) // single Y + { + if (pJPEG->iOptions & JPEG_SCALE_HALF) // special handling of 1/2 size (pixel averaging) + { + int pix; + for (i=0; i<4; i++) + { + for (j=0; j<4; j++) + { + pix = (pSrc[0] + pSrc[1] + pSrc[8] + pSrc[9] + 2) >> 2; // average 2x2 block + pDest[j] = (uint8_t)pix; + pSrc += 2; + } + pSrc += 8; // skip extra line + pDest += iPitch; + } + return; + } + xcount = ycount = 8; // debug + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + xcount = ycount = 2; + else if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + xcount = ycount = 1; + for (i=0; iucSubSample == 0x21) // stacked horizontally + { + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { + // only 2 pixels emitted + pDest[0] = pSrc[0]; + pDest[1] = pSrc[128]; + return; + } /* 1/8 */ + if (pJPEG->iOptions & JPEG_SCALE_HALF) + { + for (i=0; i<4; i++) + { + for (j=0; j<4; j++) + { + int pix; + pix = (pSrc[j*2] + pSrc[j*2+1] + pSrc[j*2 + 8] + pSrc[j*2 + 9] + 2) >> 2; + pDest[j] = (uint8_t)pix; + pix = (pSrc[j*2 + 128] + pSrc[j*2+129] + pSrc[j*2 + 136] + pSrc[j*2 + 137] + 2) >> 2; + pDest[j+4] = (uint8_t)pix; + } + pSrc += 16; + pDest += iPitch; + } + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + { + // each MCU contributes a 2x2 block + pDest[0] = pSrc[0]; // Y0 + pDest[1] = pSrc[1]; + pDest[iPitch] = pSrc[2]; + pDest[iPitch+1] = pSrc[3]; + + pDest[2] = pSrc[128]; // Y` + pDest[3] = pSrc[129]; + pDest[iPitch+2] = pSrc[130]; + pDest[iPitch+3] = pSrc[131]; + return; + } + for (i=0; i<8; i++) + { + for (j=0; j<8; j++) + { + pDest[j] = pSrc[j]; + pDest[j+8] = pSrc[128 + j]; + } + pSrc += 8; + pDest += iPitch; + } + } // 0x21 + if (pJPEG->ucSubSample == 0x12) // stacked vertically + { + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { + // only 2 pixels emitted + pDest[0] = pSrc[0]; + pDest[iPitch] = pSrc[128]; + return; + } /* 1/8 */ + if (pJPEG->iOptions & JPEG_SCALE_HALF) + { + for (i=0; i<4; i++) + { + for (j=0; j<4; j++) + { + int pix; + pix = (pSrc[j*2] + pSrc[j*2+1] + pSrc[j*2 + 8] + pSrc[j*2 + 9] + 2) >> 2; + pDest[j] = (uint8_t)pix; + pix = (pSrc[j*2 + 128] + pSrc[j*2+129] + pSrc[j*2 + 136] + pSrc[j*2 + 137] + 2) >> 2; + pDest[4*iPitch+j] = (uint8_t)pix; + } + pSrc += 16; + pDest += iPitch; + } + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + { + // each MCU contributes a 2x2 block + pDest[0] = pSrc[0]; // Y0 + pDest[1] = pSrc[1]; + pDest[iPitch] = pSrc[2]; + pDest[iPitch+1] = pSrc[3]; + + pDest[iPitch*2] = pSrc[128]; // Y` + pDest[iPitch*2+1] = pSrc[129]; + pDest[iPitch*3] = pSrc[130]; + pDest[iPitch*3+1] = pSrc[131]; + return; + } + for (i=0; i<8; i++) + { + for (j=0; j<8; j++) + { + pDest[j] = pSrc[j]; + pDest[8*iPitch + j] = pSrc[128 + j]; + } + pSrc += 8; + pDest += iPitch; + } + } // 0x12 + if (pJPEG->ucSubSample == 0x22) + { + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { + // each MCU contributes 1 pixel + pDest[0] = pSrc[0]; // Y0 + pDest[1] = pSrc[128]; // Y1 + pDest[iPitch] = pSrc[256]; // Y2 + pDest[iPitch + 1] = pSrc[384]; // Y3 + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + { + // each MCU contributes 2x2 pixels + pDest[0] = pSrc[0]; // Y0 + pDest[1] = pSrc[1]; + pDest[iPitch] = pSrc[2]; + pDest[iPitch+1] = pSrc[3]; + + pDest[2] = pSrc[128]; // Y1 + pDest[3] = pSrc[129]; + pDest[iPitch+2] = pSrc[130]; + pDest[iPitch+3] = pSrc[131]; + + pDest[iPitch*2] = pSrc[256]; // Y2 + pDest[iPitch*2+1] = pSrc[257]; + pDest[iPitch*3] = pSrc[258]; + pDest[iPitch*3+1] = pSrc[259]; + + pDest[iPitch*2+2] = pSrc[384]; // Y3 + pDest[iPitch*2+3] = pSrc[385]; + pDest[iPitch*3+2] = pSrc[386]; + pDest[iPitch*3+3] = pSrc[387]; + return; + } + if (pJPEG->iOptions & JPEG_SCALE_HALF) + { + for (i=0; i<4; i++) + { + for (j=0; j<4; j++) + { + int pix; + pix = (pSrc[j*2] + pSrc[j*2+1] + pSrc[j*2 + 8] + pSrc[j*2 + 9] + 2) >> 2; + pDest[j] = (uint8_t)pix; // Y0 + pix = (pSrc[j*2+128] + pSrc[j*2+129] + pSrc[j*2 + 136] + pSrc[j*2 + 137] + 2) >> 2; + pDest[j+4] = (uint8_t)pix; // Y1 + pix = (pSrc[j*2+256] + pSrc[j*2+257] + pSrc[j*2 + 264] + pSrc[j*2 + 265] + 2) >> 2; + pDest[iPitch*4 + j] = (uint8_t)pix; // Y2 + pix = (pSrc[j*2+384] + pSrc[j*2+385] + pSrc[j*2 + 392] + pSrc[j*2 + 393] + 2) >> 2; + pDest[iPitch*4 + j + 4] = (uint8_t)pix; // Y3 + } + pSrc += 16; + pDest += iPitch; + } + return; + } + for (i=0; i<8; i++) + { + for (j=0; j<8; j++) + { + pDest[j] = pSrc[j]; // Y0 + pDest[j+8] = pSrc[j+128]; // Y1 + pDest[iPitch*8 + j] = pSrc[j+256]; // Y2 + pDest[iPitch*8 + j + 8] = pSrc[j + 384]; // Y3 + } + pSrc += 8; + pDest += iPitch; + } + } // 0x22 +} /* JPEGMPutMCU8BitGray() */ + +static void JPEGPutMCUGray(JPEGIMAGE *pJPEG, int x, int iPitch) +{ + uint16_t *usDest = (uint16_t *)&pJPEG->usPixels[x]; + int i, j, xcount, ycount; + uint8_t *pSrc = (uint8_t *)&pJPEG->sMCUs[0]; + + if (pJPEG->iOptions & JPEG_SCALE_HALF) // special handling of 1/2 size (pixel averaging) + { + int pix; + for (i=0; i<4; i++) + { + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + for (j=0; j<4; j++) + { + pix = (pSrc[0] + pSrc[1] + pSrc[8] + pSrc[9] + 2) >> 2; // average 2x2 block + usDest[i] = usGrayTo565[pix]; + pSrc += 2; + } + } + else + { + for (j=0; j<4; j++) + { + pix = (pSrc[0] + pSrc[1] + pSrc[8] + pSrc[9] + 2) >> 2; // average 2x2 block + usDest[i] = __builtin_bswap16(usGrayTo565[pix]); + pSrc += 2; + } + } + pSrc += 8; // skip extra line + usDest += iPitch; + } + return; + } + xcount = ycount = 8; // debug + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + xcount = ycount = 2; + else if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + xcount = ycount = 1; + for (i=0; iucPixelType == RGB565_LITTLE_ENDIAN) + { + for (j=0; j> 12) & 0x3ff]; // blue pixel + usPixel |= usRangeTableG[((iCBG + iCRG + iY) >> 12) & 0x3ff]; // green pixel + usPixel |= usRangeTableR[((iCRR + iY) >> 12) & 0x3ff]; // red pixel + pDest[0] = usPixel; +} /* JPEGPixelLE() */ + +static void JPEGPixelBE(uint16_t *pDest, int iY, int iCb, int iCr) +{ + int iCBB, iCBG, iCRG, iCRR; + unsigned short usPixel; + + iCBB = 7258 * (iCb-0x80); + iCBG = -1409 * (iCb-0x80); + iCRG = -2925 * (iCr-0x80); + iCRR = 5742 * (iCr-0x80); + usPixel = usRangeTableB[((iCBB + iY) >> 12) & 0x3ff]; // blue pixel + usPixel |= usRangeTableG[((iCBG + iCRG + iY) >> 12) & 0x3ff]; // green pixel + usPixel |= usRangeTableR[((iCRR + iY) >> 12) & 0x3ff]; // red pixel + pDest[0] = __builtin_bswap16(usPixel); +} /* JPEGPixelBE() */ + +static void JPEGPixel2LE(uint16_t *pDest, int iY1, int iY2, int iCb, int iCr) +{ + int iCBB, iCBG, iCRG, iCRR; + uint32_t ulPixel1, ulPixel2; + + iCBB = 7258 * (iCb-0x80); + iCBG = -1409 * (iCb-0x80); + iCRG = -2925 * (iCr-0x80); + iCRR = 5742 * (iCr-0x80); + ulPixel1 = usRangeTableB[((iCBB + iY1) >> 12) & 0x3ff]; // blue pixel + ulPixel1 |= usRangeTableG[((iCBG + iCRG + iY1) >> 12) & 0x3ff]; // green pixel + ulPixel1 |= usRangeTableR[((iCRR + iY1) >> 12) & 0x3ff]; // red pixel + + ulPixel2 = usRangeTableB[((iCBB + iY2) >> 12) & 0x3ff]; // blue pixel + ulPixel2 |= usRangeTableG[((iCBG + iCRG + iY2) >> 12) & 0x3ff]; // green pixel + ulPixel2 |= usRangeTableR[((iCRR + iY2) >> 12) & 0x3ff]; // red pixel + *(uint32_t *)&pDest[0] = (ulPixel1 | (ulPixel2<<16)); +} /* JPEGPixel2LE() */ + +static void JPEGPixel2BE(uint16_t *pDest, int iY1, int iY2, int iCb, int iCr) +{ + int iCBB, iCBG, iCRG, iCRR; + uint32_t ulPixel1, ulPixel2; + + iCBB = 7258 * (iCb-0x80); + iCBG = -1409 * (iCb-0x80); + iCRG = -2925 * (iCr-0x80); + iCRR = 5742 * (iCr-0x80); + ulPixel1 = usRangeTableB[((iCBB + iY1) >> 12) & 0x3ff]; // blue pixel + ulPixel1 |= usRangeTableG[((iCBG + iCRG + iY1) >> 12) & 0x3ff]; // green pixel + ulPixel1 |= usRangeTableR[((iCRR + iY1) >> 12) & 0x3ff]; // red pixel + + ulPixel2 = usRangeTableB[((iCBB + iY2) >> 12) & 0x3ff]; // blue pixel + ulPixel2 |= usRangeTableG[((iCBG + iCRG + iY2) >> 12) & 0x3ff]; // green pixel + ulPixel2 |= usRangeTableR[((iCRR + iY2) >> 12) & 0x3ff]; // red pixel + *(uint32_t *)&pDest[0] = __builtin_bswap16(ulPixel1) | (__builtin_bswap16(ulPixel2)<<16); +} /* JPEGPixel2BE() */ + +static void JPEGPutMCU11(JPEGIMAGE *pJPEG, int x, int iPitch) +{ + int iCr, iCb; + signed int Y; + int iCol; + int iRow; + uint8_t *pY, *pCr, *pCb; + uint16_t *pOutput = &pJPEG->usPixels[x]; + + pY = (unsigned char *)&pJPEG->sMCUs[0*DCTSIZE]; + pCb = (unsigned char *)&pJPEG->sMCUs[1*DCTSIZE]; + pCr = (unsigned char *)&pJPEG->sMCUs[2*DCTSIZE]; + + if (pJPEG->iOptions & JPEG_SCALE_HALF) + { + for (iRow=0; iRow<4; iRow++) // up to 8 rows to do + { + for (iCol=0; iCol<4; iCol++) // up to 4x2 cols to do + { + iCr = (pCr[0] + pCr[1] + pCr[8] + pCr[9] + 2) >> 2; + iCb = (pCb[0] + pCb[1] + pCb[8] + pCb[9] + 2) >> 2; + Y = (pY[0] + pY[1] + pY[8] + pY[9]) << 10; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol, Y, iCb, iCr); + else + JPEGPixelBE(pOutput+iCol, Y, iCb, iCr); + pCr += 2; + pCb += 2; + pY += 2; + } // for col + pCr += 8; + pCb += 8; + pY += 8; + pOutput += iPitch; + } // for row + return; + } + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) // special case for 1/8 scaling + { + // only 4 pixels to draw, so no looping needed + iCr = pCr[0]; + iCb = pCb[0]; + Y = (int)(pY[0]) << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput, Y, iCb, iCr); + else + JPEGPixelBE(pOutput, Y, iCb, iCr); + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) // special case for 1/4 scaling + { + // only 4 pixels to draw, so no looping needed + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelLE(pOutput, Y, iCb, iCr); + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelLE(pOutput+1, Y, iCb, iCr); + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelLE(pOutput+iPitch, Y, iCb, iCr); + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelLE(pOutput+1+iPitch, Y, iCb, iCr); + } + else + { + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelBE(pOutput, Y, iCb, iCr); + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelBE(pOutput+1, Y, iCb, iCr); + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelBE(pOutput+iPitch, Y, iCb, iCr); + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelBE(pOutput+1+iPitch, Y, iCb, iCr); + } + return; + } + for (iRow=0; iRow<8; iRow++) // up to 8 rows to do + { + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + for (iCol=0; iCol<8; iCol++) // up to 4x2 cols to do + { + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelLE(pOutput+iCol, Y, iCb, iCr); + } // for col + } + else + { + for (iCol=0; iCol<8; iCol++) // up to 4x2 cols to do + { + iCr = *pCr++; + iCb = *pCb++; + Y = (int)(*pY++) << 12; + JPEGPixelBE(pOutput+iCol, Y, iCb, iCr); + } // for col + } + pOutput += iPitch; + } // for row +} /* JPEGPutMCU11() */ + +static void JPEGPutMCU22(JPEGIMAGE *pJPEG, int x, int iPitch) +{ + uint32_t Cr,Cb; + signed int Y1, Y2, Y3, Y4; + int iRow, iCol, iXCount1, iXCount2, iYCount; + unsigned char *pY, *pCr, *pCb; + int bUseOdd1, bUseOdd2; // special case where 24bpp odd sized image can clobber first column + uint16_t *pOutput = &pJPEG->usPixels[x]; + + pY = (unsigned char *)&pJPEG->sMCUs[0*DCTSIZE]; + pCb = (unsigned char *)&pJPEG->sMCUs[4*DCTSIZE]; + pCr = (unsigned char *)&pJPEG->sMCUs[5*DCTSIZE]; + + if (pJPEG->iOptions & JPEG_SCALE_HALF) // special handling of 1/2 size (pixel averaging) + { + for (iRow=0; iRow<4; iRow++) // 16x16 becomes 8x8 of 2x2 pixels + { + for (iCol=0; iCol<4; iCol++) + { + Y1 = (pY[iCol*2] + pY[iCol*2+1] + pY[iCol*2+8] + pY[iCol*2+9]) << 10; + Cb = pCb[iCol]; + Cr = pCr[iCol]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol, Y1, Cb, Cr); // top left + else + JPEGPixelBE(pOutput+iCol, Y1, Cb, Cr); + Y1 = (pY[iCol*2+(DCTSIZE*2)] + pY[iCol*2+1+(DCTSIZE*2)] + pY[iCol*2+8+(DCTSIZE*2)] + pY[iCol*2+9+(DCTSIZE*2)]) << 10; + Cb = pCb[iCol+4]; + Cr = pCr[iCol+4]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol+4, Y1, Cb, Cr); // top right + else + JPEGPixelBE(pOutput+iCol+4, Y1, Cb, Cr); + Y1 = (pY[iCol*2+(DCTSIZE*4)] + pY[iCol*2+1+(DCTSIZE*4)] + pY[iCol*2+8+(DCTSIZE*4)] + pY[iCol*2+9+(DCTSIZE*4)]) << 10; + Cb = pCb[iCol+32]; + Cr = pCr[iCol+32]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol+iPitch*4, Y1, Cb, Cr); // bottom left + else + JPEGPixelBE(pOutput+iCol+iPitch*4, Y1, Cb, Cr); + Y1 = (pY[iCol*2+(DCTSIZE*6)] + pY[iCol*2+1+(DCTSIZE*6)] + pY[iCol*2+8+(DCTSIZE*6)] + pY[iCol*2+9+(DCTSIZE*6)]) << 10; + Cb = pCb[iCol+32+4]; + Cr = pCr[iCol+32+4]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol+4+iPitch*4, Y1, Cb, Cr); // bottom right + else + JPEGPixelBE(pOutput+iCol+4+iPitch*4, Y1, Cb, Cr); + } + pY += 8; + pCb += 8; + pCr += 8; + pOutput += iPitch; + } + return; + } + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { + Y1 = pY[0] << 12; // scale to level of conversion table + Cb = pCb[0]; + Cr = pCr[0]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput, Y1, Cb, Cr); + else + JPEGPixelBE(pOutput, Y1, Cb, Cr); + // top right block + Y1 = pY[DCTSIZE*2] << 12; // scale to level of conversion table + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput + 1, Y1, Cb, Cr); + else + JPEGPixelBE(pOutput + 1, Y1, Cb, Cr); + // bottom left block + Y1 = pY[DCTSIZE*4] << 12; // scale to level of conversion table + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iPitch, Y1, Cb, Cr); + else + JPEGPixelBE(pOutput+iPitch, Y1, Cb, Cr); + // bottom right block + Y1 = pY[DCTSIZE*6] << 12; // scale to level of conversion table + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+ 1 + iPitch, Y1, Cb, Cr); + else + JPEGPixelBE(pOutput+ 1 + iPitch, Y1, Cb, Cr); + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) // special case of 1/4 + { + for (iRow=0; iRow<2; iRow++) + { + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + for (iCol=0; iCol<2; iCol++) + { + // top left block + Y1 = pY[iCol] << 12; // scale to level of conversion table + Cb = pCb[0]; + Cr = pCr[0]; + JPEGPixelLE(pOutput + iCol, Y1, Cb, Cr); + // top right block + Y1 = pY[iCol+(DCTSIZE*2)] << 12; // scale to level of conversion table + Cb = pCb[1]; + Cr = pCr[1]; + JPEGPixelLE(pOutput + 2+iCol, Y1, Cb, Cr); + // bottom left block + Y1 = pY[iCol+DCTSIZE*4] << 12; // scale to level of conversion table + Cb = pCb[2]; + Cr = pCr[2]; + JPEGPixelLE(pOutput+iPitch*2 + iCol, Y1, Cb, Cr); + // bottom right block + Y1 = pY[iCol+DCTSIZE*6] << 12; // scale to level of conversion table + Cb = pCb[3]; + Cr = pCr[3]; + JPEGPixelLE(pOutput+iPitch*2 + 2+iCol, Y1, Cb, Cr); + } // for each column + } + else + { + for (iCol=0; iCol<2; iCol++) + { + // top left block + Y1 = pY[iCol] << 12; // scale to level of conversion table + Cb = pCb[0]; + Cr = pCr[0]; + JPEGPixelBE(pOutput + iCol, Y1, Cb, Cr); + // top right block + Y1 = pY[iCol+(DCTSIZE*2)] << 12; // scale to level of conversion table + Cb = pCb[1]; + Cr = pCr[1]; + JPEGPixelBE(pOutput + 2+iCol, Y1, Cb, Cr); + // bottom left block + Y1 = pY[iCol+DCTSIZE*4] << 12; // scale to level of conversion table + Cb = pCb[2]; + Cr = pCr[2]; + JPEGPixelBE(pOutput+iPitch*2 + iCol, Y1, Cb, Cr); + // bottom right block + Y1 = pY[iCol+DCTSIZE*6] << 12; // scale to level of conversion table + Cb = pCb[3]; + Cr = pCr[3]; + JPEGPixelBE(pOutput+iPitch*2 + 2+iCol, Y1, Cb, Cr); + } // for each column + } + pY += 2; // skip 1 line of source pixels + pOutput += iPitch; + } + return; + } + /* Convert YCC pixels into RGB pixels and store in output image */ + iYCount = 4; + bUseOdd1 = bUseOdd2 = 1; // assume odd column can be used + if ((x+15) >= pJPEG->iWidth) + { + iCol = (((pJPEG->iWidth & 15)+1) >> 1); + if (iCol >= 4) + { + iXCount1 = 4; + iXCount2 = iCol-4; + if (pJPEG->iWidth & 1 && (iXCount2 * 2) + 8 + (x * 16) > pJPEG->iWidth) + bUseOdd2 = 0; + } + else + { + iXCount1 = iCol; + iXCount2 = 0; + if (pJPEG->iWidth & 1 && (iXCount1 * 2) + (x * 16) > pJPEG->iWidth) + bUseOdd1 = 0; + } + } + else + iXCount1 = iXCount2 = 4; + for (iRow=0; iRowucPixelType == RGB565_LITTLE_ENDIAN) + { + if (bUseOdd1 || iCol != (iXCount1-1)) // only render if it won't go off the right edge + { + JPEGPixel2LE(pOutput + (iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2LE(pOutput+iPitch + (iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelLE(pOutput + (iCol<<1), Y1, Cb, Cr); + JPEGPixelLE(pOutput+iPitch + (iCol<<1), Y3, Cb, Cr); + } + } + else + { + if (bUseOdd1 || iCol != (iXCount1-1)) // only render if it won't go off the right edge + { + JPEGPixel2BE(pOutput + (iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2BE(pOutput+iPitch + (iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput + (iCol<<1), Y1, Cb, Cr); + JPEGPixelBE(pOutput+iPitch + (iCol<<1), Y3, Cb, Cr); + } + } + // for top right block + if (iCol < iXCount2) + { + Y1 = pY[iCol*2+DCTSIZE*2]; + Y2 = pY[iCol*2+1+DCTSIZE*2]; + Y3 = pY[iCol*2+8+DCTSIZE*2]; + Y4 = pY[iCol*2+9+DCTSIZE*2]; + Y1 <<= 12; // scale to level of conversion table + Y2 <<= 12; + Y3 <<= 12; + Y4 <<= 12; + Cb = pCb[iCol+4]; + Cr = pCr[iCol+4]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + if (bUseOdd2 || iCol != (iXCount2-1)) // only render if it won't go off the right edge + { + JPEGPixel2LE(pOutput + 8+(iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2LE(pOutput+iPitch + 8+(iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelLE(pOutput+ 8+(iCol<<1), Y1, Cb, Cr); + JPEGPixelLE(pOutput+iPitch+ 8+(iCol<<1), Y3, Cb, Cr); + } + } + else + { + if (bUseOdd2 || iCol != (iXCount2-1)) // only render if it won't go off the right edge + { + JPEGPixel2BE(pOutput + 8+(iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2BE(pOutput+iPitch + 8+(iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput+ 8+(iCol<<1), Y1, Cb, Cr); + JPEGPixelBE(pOutput+iPitch+ 8+(iCol<<1), Y3, Cb, Cr); + } + } + } + // for bottom left block + Y1 = pY[iCol*2+DCTSIZE*4]; + Y2 = pY[iCol*2+1+DCTSIZE*4]; + Y3 = pY[iCol*2+8+DCTSIZE*4]; + Y4 = pY[iCol*2+9+DCTSIZE*4]; + Y1 <<= 12; // scale to level of conversion table + Y2 <<= 12; + Y3 <<= 12; + Y4 <<= 12; + Cb = pCb[iCol+32]; + Cr = pCr[iCol+32]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + if (bUseOdd1 || iCol != (iXCount1-1)) // only render if it won't go off the right edge + { + JPEGPixel2LE(pOutput+iPitch*8+ (iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2LE(pOutput+iPitch*9+ (iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelLE(pOutput+iPitch*8+ (iCol<<1), Y1, Cb, Cr); + JPEGPixelLE(pOutput+iPitch*9+ (iCol<<1), Y3, Cb, Cr); + } + } + else + { + if (bUseOdd1 || iCol != (iXCount1-1)) // only render if it won't go off the right edge + { + JPEGPixel2BE(pOutput+iPitch*8+ (iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2BE(pOutput+iPitch*9+ (iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput+iPitch*8+ (iCol<<1), Y1, Cb, Cr); + JPEGPixelBE(pOutput+iPitch*9+ (iCol<<1), Y3, Cb, Cr); + } + } + // for bottom right block + if (iCol < iXCount2) + { + Y1 = pY[iCol*2+DCTSIZE*6]; + Y2 = pY[iCol*2+1+DCTSIZE*6]; + Y3 = pY[iCol*2+8+DCTSIZE*6]; + Y4 = pY[iCol*2+9+DCTSIZE*6]; + Y1 <<= 12; // scale to level of conversion table + Y2 <<= 12; + Y3 <<= 12; + Y4 <<= 12; + Cb = pCb[iCol+36]; + Cr = pCr[iCol+36]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + if (bUseOdd2 || iCol != (iXCount2-1)) // only render if it won't go off the right edge + { + JPEGPixel2LE(pOutput+iPitch*8+ 8+(iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2LE(pOutput+iPitch*9+ 8+(iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelLE(pOutput+iPitch*8+ 8+(iCol<<1), Y1, Cb, Cr); + JPEGPixelLE(pOutput+iPitch*9+ 8+(iCol<<1), Y3, Cb, Cr); + } + } + else + { + if (bUseOdd2 || iCol != (iXCount2-1)) // only render if it won't go off the right edge + { + JPEGPixel2BE(pOutput+iPitch*8+ 8+(iCol<<1), Y1, Y2, Cb, Cr); + JPEGPixel2BE(pOutput+iPitch*9+ 8+(iCol<<1), Y3, Y4, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput+iPitch*8+ 8+(iCol<<1), Y1, Cb, Cr); + JPEGPixelBE(pOutput+iPitch*9+ 8+(iCol<<1), Y3, Cb, Cr); + } + } + } + } // for each column + pY += 16; // skip to next line of source pixels + pCb += 8; + pCr += 8; + pOutput += iPitch*2; + } +} /* JPEGPutMCU22() */ + +static void JPEGPutMCU12(JPEGIMAGE *pJPEG, int x, int iPitch) +{ + uint32_t Cr,Cb; + signed int Y1, Y2; + int iRow, iCol, iXCount, iYCount; + uint8_t *pY, *pCr, *pCb; + uint16_t *pOutput = &pJPEG->usPixels[x]; + + pY = (uint8_t *)&pJPEG->sMCUs[0*DCTSIZE]; + pCb = (uint8_t *)&pJPEG->sMCUs[2*DCTSIZE]; + pCr = (uint8_t *)&pJPEG->sMCUs[3*DCTSIZE]; + + if (pJPEG->iOptions & JPEG_SCALE_HALF) + { + for (iRow=0; iRow<4; iRow++) + { + for (iCol=0; iCol<4; iCol++) + { + Y1 = (pY[0] + pY[1] + pY[8] + pY[9]) << 10; + Cb = (pCb[0] + pCb[1] + 1) >> 1; + Cr = (pCr[0] + pCr[1] + 1) >> 1; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol, Y1, Cb, Cr); + else + JPEGPixelBE(pOutput+iCol, Y1, Cb, Cr); + Y1 = (pY[DCTSIZE*2] + pY[DCTSIZE*2+1] + pY[DCTSIZE*2+8] + pY[DCTSIZE*2+9]) << 10; + Cb = (pCb[32] + pCb[33] + 1) >> 1; + Cr = (pCr[32] + pCr[33] + 1) >> 1; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol+iPitch, Y1, Cb, Cr); + else + JPEGPixelBE(pOutput+iCol+iPitch, Y1, Cb, Cr); + pCb += 2; + pCr += 2; + pY += 2; + } + pY += 8; + pOutput += iPitch*2; + } + return; + } + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { + Y1 = pY[0] << 12; + Y2 = pY[DCTSIZE*2] << 12; + Cb = pCb[0]; + Cr = pCr[0]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + JPEGPixelLE(pOutput, Y1, Cb, Cr); + JPEGPixelLE(pOutput + iPitch, Y2, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput, Y1, Cb, Cr); + JPEGPixelBE(pOutput + iPitch, Y2, Cb, Cr); + } + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + { // draw a 2x4 block + Y1 = pY[0] << 12; + Y2 = pY[2] << 12; + Cb = pCb[0]; + Cr = pCr[0]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + JPEGPixelLE(pOutput, Y1, Cb, Cr); + JPEGPixelLE(pOutput + iPitch, Y2, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput, Y1, Cb, Cr); + JPEGPixelBE(pOutput + iPitch, Y2, Cb, Cr); + } + Y1 = pY[1] << 12; + Y2 = pY[3] << 12; + Cb = pCb[1]; + Cr = pCr[1]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + JPEGPixelLE(pOutput + 1, Y1, Cb, Cr); + JPEGPixelLE(pOutput + 1 + iPitch, Y2, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput + 1, Y1, Cb, Cr); + JPEGPixelBE(pOutput + 1 + iPitch, Y2, Cb, Cr); + } + pY += DCTSIZE*2; // next Y block below + Y1 = pY[0] << 12; + Y2 = pY[2] << 12; + Cb = pCb[2]; + Cr = pCr[2]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + JPEGPixelLE(pOutput + iPitch*2, Y1, Cb, Cr); + JPEGPixelLE(pOutput + iPitch*3, Y2, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput + iPitch*2, Y1, Cb, Cr); + JPEGPixelBE(pOutput + iPitch*3, Y2, Cb, Cr); + } + Y1 = pY[1] << 12; + Y2 = pY[3] << 12; + Cb = pCb[3]; + Cr = pCr[3]; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + { + JPEGPixelLE(pOutput + 1 + iPitch*2, Y1, Cb, Cr); + JPEGPixelLE(pOutput + 1 + iPitch*3, Y2, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput + 1 + iPitch*2, Y1, Cb, Cr); + JPEGPixelBE(pOutput + 1 + iPitch*3, Y2, Cb, Cr); + } + return; + } + /* Convert YCC pixels into RGB pixels and store in output image */ + iYCount = 16; + iXCount = 8; + for (iRow=0; iRowucPixelType == RGB565_LITTLE_ENDIAN) + { + JPEGPixelLE(pOutput + iCol, Y1, Cb, Cr); + JPEGPixelLE(pOutput + iPitch + iCol, Y2, Cb, Cr); + } + else + { + JPEGPixelBE(pOutput + iCol, Y1, Cb, Cr); + JPEGPixelBE(pOutput + iPitch + iCol, Y2, Cb, Cr); + } + } + pY += 16; // skip to next 2 lines of source pixels + if (iRow == 6) // next MCU block, skip ahead to correct spot + pY += (128-64); + pCb += 8; + pCr += 8; + pOutput += iPitch*2; // next 2 lines of dest pixels + } +} /* JPEGPutMCU12() */ +static void JPEGPutMCU21(JPEGIMAGE *pJPEG, int x, int iPitch) +{ + int iCr, iCb; + signed int Y1, Y2; + int iCol; + int iRow; + uint8_t *pY, *pCr, *pCb; + uint16_t *pOutput = &pJPEG->usPixels[x]; + + pY = (uint8_t *)&pJPEG->sMCUs[0*DCTSIZE]; + pCb = (uint8_t *)&pJPEG->sMCUs[2*DCTSIZE]; + pCr = (uint8_t *)&pJPEG->sMCUs[3*DCTSIZE]; + + if (pJPEG->iOptions & JPEG_SCALE_HALF) + { + for (iRow=0; iRow<4; iRow++) + { + for (iCol=0; iCol<4; iCol++) + { // left block + iCr = (pCr[0] + pCr[8] + 1) >> 1; + iCb = (pCb[0] + pCb[8] + 1) >> 1; + Y1 = (signed int)(pY[0] + pY[1] + pY[8] + pY[9]) << 10; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol, Y1, iCb, iCr); + else + JPEGPixelBE(pOutput+iCol, Y1, iCb, iCr); + // right block + iCr = (pCr[4] + pCr[12] + 1) >> 1; + iCb = (pCb[4] + pCb[12] + 1) >> 1; + Y1 = (signed int)(pY[128] + pY[129] + pY[136] + pY[137]) << 10; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixelLE(pOutput+iCol+4, Y1, iCb, iCr); + else + JPEGPixelBE(pOutput+iCol+4, Y1, iCb, iCr); + pCb++; + pCr++; + pY += 2; + } + pCb += 12; + pCr += 12; + pY += 8; + pOutput += iPitch; + } + return; + } + if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { // draw 2 pixels + iCr = pCr[0]; + iCb = pCb[0]; + Y1 = (signed int)(pY[0]) << 12; + Y2 = (signed int)(pY[DCTSIZE*2]) << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput, Y1, Y2, iCb, iCr); + return; + } + if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + { // draw 4x2 pixels + // top left + iCr = pCr[0]; + iCb = pCb[0]; + Y1 = (signed int)(pY[0]) << 12; + Y2 = (signed int)(pY[1]) << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput, Y1, Y2, iCb, iCr); + // top right + iCr = pCr[1]; + iCb = pCb[1]; + Y1 = (signed int)pY[DCTSIZE*2] << 12; + Y2 = (signed int)pY[DCTSIZE*2+1] << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput + 2, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput + 2, Y1, Y2, iCb, iCr); + // bottom left + iCr = pCr[2]; + iCb = pCb[2]; + Y1 = (signed int)(pY[2]) << 12; + Y2 = (signed int)(pY[3]) << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput + iPitch, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput + iPitch, Y1, Y2, iCb, iCr); + // bottom right + iCr = pCr[3]; + iCb = pCb[3]; + Y1 = (signed int)pY[DCTSIZE*2+2] << 12; + Y2 = (signed int)pY[DCTSIZE*2+3] << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput + iPitch + 2, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput + iPitch + 2, Y1, Y2, iCb, iCr); + return; + } + /* Convert YCC pixels into RGB pixels and store in output image */ + for (iRow=0; iRow<8; iRow++) // up to 8 rows to do + { + for (iCol=0; iCol<4; iCol++) // up to 4x2 cols to do + { // left block + iCr = *pCr++; + iCb = *pCb++; + Y1 = (signed int)(*pY++) << 12; + Y2 = (signed int)(*pY++) << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput + iCol*2, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput + iCol*2, Y1, Y2, iCb, iCr); + // right block + iCr = pCr[3]; + iCb = pCb[3]; + Y1 = (signed int)pY[126] << 12; + Y2 = (signed int)pY[127] << 12; + if (pJPEG->ucPixelType == RGB565_LITTLE_ENDIAN) + JPEGPixel2LE(pOutput + 8 + iCol*2, Y1, Y2, iCb, iCr); + else + JPEGPixel2BE(pOutput + 8 + iCol*2, Y1, Y2, iCb, iCr); + } // for col + pCb += 4; + pCr += 4; + pOutput += iPitch; + } // for row +} /* JPEGPutMCU21() */ + +// Dither the 8-bit gray pixels into 1, 2, or 4-bit gray +static void JPEGDither(JPEGIMAGE *pJPEG, int iWidth, int iHeight) +{ +int x, y, xmask=0, iDestPitch=0; +int32_t cNew, lFErr, v=0, h; +int32_t e1,e2,e3,e4; +uint8_t cOut, ucPixelType; // forward errors for gray +uint8_t *pSrc, *pDest, *errors, *pErrors=NULL, *d, *pPixels; // destination 8bpp image +uint8_t pixelmask=0, shift=0; + + ucPixelType = pJPEG->ucPixelType; + errors = (uint8_t *)&pJPEG->usPixels[MAX_BUFFERED_PIXELS/2]; // plenty of space here + errors[0] = errors[1] = errors[2] = 0; + pDest = pSrc = pJPEG->pDitherBuffer; // write the new pixels over the original + switch (ucPixelType) + { + case FOUR_BIT_DITHERED: + iDestPitch = (iWidth+1)/2; + pixelmask = 0xf0; + shift = 4; + xmask = 1; + break; + case TWO_BIT_DITHERED: + iDestPitch = (iWidth+3)/4; + pixelmask = 0xc0; + shift = 2; + xmask = 3; + break; + case ONE_BIT_DITHERED: + iDestPitch = (iWidth+7)/8; + pixelmask = 0x80; + shift = 1; + xmask = 7; + break; + } + for (y=0; y 255) cNew = 255; // clip to uint8_t + cOut <<= shift; // pack new pixels into a byte + cOut |= (cNew >> (8-shift)); // keep top N bits + if ((x & xmask) == xmask) // store it when the byte is full + { + *d++ = cOut; + cOut = 0; + } + // calculate the Floyd-Steinberg error for this pixel + v = cNew - (cNew & pixelmask); // new error for N-bit gray output (always positive) + h = v >> 1; + e1 = (7*h)>>3; // 7/16 + e2 = h - e1; // 1/16 + e3 = (5*h) >> 3; // 5/16 + e4 = h - e3; // 3/16 + // distribute error to neighbors + lFErr = e1 + pErrors[1]; + pErrors[1] = (uint8_t)e2; + pErrors[0] += e3; + pErrors[-1] += e4; + pErrors++; + } // for x + } // for y + // copy the output to the pixel buffer for the user to access + memcpy(pJPEG->usPixels, pJPEG->pDitherBuffer, iDestPitch * iHeight); +} /* JPEGDither() */ + +// +// Decode the image +// returns 0 for error, 1 for success +// +static int DecodeJPEG(JPEGIMAGE *pJPEG) +{ + int cx, cy, x, y, mcuCX, mcuCY; + int iLum0, iLum1, iLum2, iLum3, iCr, iCb; + signed int iDCPred0, iDCPred1, iDCPred2; + int i, iQuant1, iQuant2, iQuant3, iErr; + uint8_t c; + int iMCUCount, xoff, iPitch, bThumbnail = 0; + int bContinue = 1; // early exit if the DRAW callback wants to stop + uint32_t l, *pl; + unsigned char cDCTable0, cACTable0, cDCTable1, cACTable1, cDCTable2, cACTable2; + JPEGDRAW jd; + int iMaxFill = 16, iScaleShift = 0; + + // Requested the Exif thumbnail + if (pJPEG->iOptions & JPEG_EXIF_THUMBNAIL) + { + if (pJPEG->iThumbData == 0 || pJPEG->iThumbWidth == 0) // doesn't exist + { + pJPEG->iError = JPEG_INVALID_PARAMETER; + return 0; + } + if (!JPEGParseInfo(pJPEG, 1)) // parse the embedded thumbnail file header + return 0; // something went wrong + } + // Fast downscaling options + if (pJPEG->iOptions & JPEG_SCALE_HALF) + iScaleShift = 1; + else if (pJPEG->iOptions & JPEG_SCALE_QUARTER) + { + iScaleShift = 2; + iMaxFill = 1; + } + else if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) + { + iScaleShift = 3; + iMaxFill = 1; + bThumbnail = 1; + } + + // reorder and fix the quantization table for decoding + JPEGFixQuantD(pJPEG); + pJPEG->bb.ulBits = MOTOLONG(&pJPEG->ucFileBuf[0]); // preload first 4 bytes + pJPEG->bb.pBuf = pJPEG->ucFileBuf; + pJPEG->bb.ulBitOff = 0; + + cDCTable0 = pJPEG->JPCI[0].dc_tbl_no; + cACTable0 = pJPEG->JPCI[0].ac_tbl_no; + cDCTable1 = pJPEG->JPCI[1].dc_tbl_no; + cACTable1 = pJPEG->JPCI[1].ac_tbl_no; + cDCTable2 = pJPEG->JPCI[2].dc_tbl_no; + cACTable2 = pJPEG->JPCI[2].ac_tbl_no; + iDCPred0 = iDCPred1 = iDCPred2 = mcuCX = mcuCY = 0; + + switch (pJPEG->ucSubSample) // set up the parameters for the different subsampling options + { + case 0x00: // fake value to handle grayscale + case 0x01: // fake value to handle sRGB/CMYK + case 0x11: + cx = (pJPEG->iWidth + 7) >> 3; // number of MCU blocks + cy = (pJPEG->iHeight + 7) >> 3; + iCr = MCU1; + iCb = MCU2; + mcuCX = mcuCY = 8; + break; + case 0x12: + cx = (pJPEG->iWidth + 7) >> 3; // number of MCU blocks + cy = (pJPEG->iHeight + 15) >> 4; + iCr = MCU2; + iCb = MCU3; + mcuCX = 8; + mcuCY = 16; + break; + case 0x21: + cx = (pJPEG->iWidth + 15) >> 4; // number of MCU blocks + cy = (pJPEG->iHeight + 7) >> 3; + iCr = MCU2; + iCb = MCU3; + mcuCX = 16; + mcuCY = 8; + break; + case 0x22: + cx = (pJPEG->iWidth + 15) >> 4; // number of MCU blocks + cy = (pJPEG->iHeight + 15) >> 4; + iCr = MCU4; + iCb = MCU5; + mcuCX = mcuCY = 16; + break; + default: // to suppress compiler warning + cx = cy = 0; + iCr = iCb = 0; + break; + } + // Scale down the MCUs by the requested amount + mcuCX >>= iScaleShift; + mcuCY >>= iScaleShift; + + iQuant1 = pJPEG->sQuantTable[pJPEG->JPCI[0].quant_tbl_no*DCTSIZE]; // DC quant values + iQuant2 = pJPEG->sQuantTable[pJPEG->JPCI[1].quant_tbl_no*DCTSIZE]; + iQuant3 = pJPEG->sQuantTable[pJPEG->JPCI[2].quant_tbl_no*DCTSIZE]; + // luminance values are always in these positions + iLum0 = MCU0; + iLum1 = MCU1; + iLum2 = MCU2; + iLum3 = MCU3; + iErr = 0; + pJPEG->iResCount = pJPEG->iResInterval; + // Calculate how many MCUs we can fit in the pixel buffer to maximize LCD drawing speed + iMCUCount = MAX_BUFFERED_PIXELS / (mcuCX * mcuCY); + if (pJPEG->ucPixelType == EIGHT_BIT_GRAYSCALE) + iMCUCount *= 2; // each pixel is only 1 byte + if (iMCUCount > cx) + iMCUCount = cx; // don't go wider than the image + if (iMCUCount > pJPEG->iMaxMCUs) // did the user set an upper bound on how many pixels per JPEGDraw callback? + iMCUCount = pJPEG->iMaxMCUs; + if (pJPEG->ucPixelType > EIGHT_BIT_GRAYSCALE) // dithered, override the max MCU count + iMCUCount = cx; // do the whole row + jd.iBpp = 16; + switch (pJPEG->ucPixelType) + { + case EIGHT_BIT_GRAYSCALE: + jd.iBpp = 8; + break; + case FOUR_BIT_DITHERED: + jd.iBpp = 4; + break; + case TWO_BIT_DITHERED: + jd.iBpp = 2; + break; + case ONE_BIT_DITHERED: + jd.iBpp = 1; + break; + } + jd.pPixels = pJPEG->usPixels; + jd.iHeight = mcuCY; + jd.y = pJPEG->iYOffset; + for (y = 0; y < cy && bContinue; y++, jd.y += mcuCY) + { + jd.x = pJPEG->iXOffset; + xoff = 0; // start of new LCD output group + iPitch = iMCUCount * mcuCX; // pixels per line of LCD buffer + for (x = 0; x < cx && bContinue && iErr == 0; x++) + { + pJPEG->ucACTable = cACTable0; + pJPEG->ucDCTable = cDCTable0; + // do the first luminance component + iErr = JPEGDecodeMCU(pJPEG, iLum0, &iDCPred0); + if (pJPEG->ucMaxACCol == 0 || bThumbnail) // no AC components, save some time + { + pl = (uint32_t *)&pJPEG->sMCUs[iLum0]; + c = ucRangeTable[((iDCPred0 * iQuant1) >> 5) & 0x3ff]; + l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24); + // dct stores byte values + for (i = 0; iJPCI[0].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8))); // first quantization table + } + // do the second luminance component + if (pJPEG->ucSubSample > 0x11) // subsampling + { + iErr |= JPEGDecodeMCU(pJPEG, iLum1, &iDCPred0); + if (pJPEG->ucMaxACCol == 0 || bThumbnail) // no AC components, save some time + { + c = ucRangeTable[((iDCPred0 * iQuant1) >> 5) & 0x3ff]; + l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24); + // dct stores byte values + pl = (uint32_t *)&pJPEG->sMCUs[iLum1]; + for (i = 0; iJPCI[0].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8))); // first quantization table + } + if (pJPEG->ucSubSample == 0x22) + { + iErr |= JPEGDecodeMCU(pJPEG, iLum2, &iDCPred0); + if (pJPEG->ucMaxACCol == 0 || bThumbnail) // no AC components, save some time + { + c = ucRangeTable[((iDCPred0 * iQuant1) >> 5) & 0x3ff]; + l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24); + // dct stores byte values + pl = (uint32_t *)&pJPEG->sMCUs[iLum2]; + for (i = 0; iJPCI[0].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8))); // first quantization table + } + iErr |= JPEGDecodeMCU(pJPEG, iLum3, &iDCPred0); + if (pJPEG->ucMaxACCol == 0 || bThumbnail) // no AC components, save some time + { + c = ucRangeTable[((iDCPred0 * iQuant1) >> 5) & 0x3ff]; + l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24); + // dct stores byte values + pl = (uint32_t *)&pJPEG->sMCUs[iLum3]; + for (i = 0; iJPCI[0].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8))); // first quantization table + } + } // if 2:2 subsampling + } // if subsampling used + if (pJPEG->ucSubSample && pJPEG->ucNumComponents == 3) // if color (not CMYK) + { + // first chroma + pJPEG->ucACTable = cACTable1; + pJPEG->ucDCTable = cDCTable1; + iErr |= JPEGDecodeMCU(pJPEG, iCr, &iDCPred1); + if (pJPEG->ucMaxACCol == 0 || bThumbnail) // no AC components, save some time + { + c = ucRangeTable[((iDCPred1 * iQuant2) >> 5) & 0x3ff]; + l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24); + // dct stores byte values + pl = (uint32_t *)&pJPEG->sMCUs[iCr]; + for (i = 0; iJPCI[1].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8))); // second quantization table + } + // second chroma + pJPEG->ucACTable = cACTable2; + pJPEG->ucDCTable = cDCTable2; + iErr |= JPEGDecodeMCU(pJPEG, iCb, &iDCPred2); + if (pJPEG->ucMaxACCol == 0 || bThumbnail) // no AC components, save some time + { + c = ucRangeTable[((iDCPred2 * iQuant3) >> 5) & 0x3ff]; + l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24); + // dct stores byte values + pl = (uint32_t *)&pJPEG->sMCUs[iCb]; + for (i = 0; iJPCI[2].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8))); + } + } // if color components present + if (pJPEG->ucPixelType >= EIGHT_BIT_GRAYSCALE) + { + JPEGPutMCU8BitGray(pJPEG, xoff, iPitch); + } + else + { + switch (pJPEG->ucSubSample) + { + case 0x00: // grayscale + JPEGPutMCUGray(pJPEG, xoff, iPitch); + break; + case 0x11: + JPEGPutMCU11(pJPEG, xoff, iPitch); + break; + case 0x12: + JPEGPutMCU12(pJPEG, xoff, iPitch); + break; + case 0x21: + JPEGPutMCU21(pJPEG, xoff, iPitch); + break; + case 0x22: + JPEGPutMCU22(pJPEG, xoff, iPitch); + break; + } // switch on color option + } + xoff += mcuCX; + if (xoff == iPitch || x == cx-1) // time to draw + { + xoff = 0; + jd.iWidth = iPitch; // width of each LCD block group + if (pJPEG->ucPixelType > EIGHT_BIT_GRAYSCALE) // dither to 4/2/1 bits + JPEGDither(pJPEG, cx * mcuCX, mcuCY); + bContinue = (*pJPEG->pfnDraw)(&jd); + jd.x += iPitch; + if ((cx - 1 - x) < iMCUCount) // change pitch for the last set of MCUs on this row + iPitch = (cx - 1 - x) * mcuCX; + } + if (pJPEG->iResInterval) + { + if (--pJPEG->iResCount == 0) + { + pJPEG->iResCount = pJPEG->iResInterval; + iDCPred0 = iDCPred1 = iDCPred2 = 0; // reset DC predictors + if (pJPEG->bb.ulBitOff & 7) // need to start at the next even byte + { + pJPEG->bb.ulBitOff += (8 - (pJPEG->bb.ulBitOff & 7)); // new restart interval starts on byte boundary + } + } // if restart interval needs to reset + } // if there is a restart interval + // See if we need to feed it more data + if (pJPEG->iVLCOff >= FILE_HIGHWATER) + JPEGGetMoreData(pJPEG); // need more 'filtered' VLC data + } // for x + } // for y + if (iErr != 0) + pJPEG->iError = JPEG_DECODE_ERROR; + return (iErr == 0); +} /* DecodeJPEG() */ diff --git a/data/formats/jpeg/readme.md b/data/formats/jpeg/readme.md new file mode 100644 index 0000000..e72ae14 --- /dev/null +++ b/data/formats/jpeg/readme.md @@ -0,0 +1 @@ +https://github.com/bitbank2/JPEGDEC/tree/master/src diff --git a/data/formats/jpeg/test.cpp b/data/formats/jpeg/test.cpp new file mode 100644 index 0000000..39b502d --- /dev/null +++ b/data/formats/jpeg/test.cpp @@ -0,0 +1,24 @@ +#include "JPEGDEC.h" +#include +#include "testimage.h" + +// gcc -D__LINUX__ jpeg.c JPEGDEC.cpp test.cpp + +int drawJPEG(JPEGDRAW* pDraw) { + return 1; +} + +int main(void) { + + JPEGDEC jpeg; + int res = jpeg.openRAM(aaa_jpg, aaa_jpg_len, drawJPEG); + + std::cout << res << std::endl; + + if (res) { + jpeg.setPixelType(RGB565_BIG_ENDIAN); + jpeg.decode(0, 0, 0);//40, 100, JPEG_SCALE_QUARTER | JPEG_EXIF_THUMBNAIL); + jpeg.close(); + } + +} diff --git a/data/formats/mp3/minimp3.h b/data/formats/mp3/minimp3.h new file mode 100644 index 0000000..943f22e --- /dev/null +++ b/data/formats/mp3/minimp3.h @@ -0,0 +1,1855 @@ +#ifndef MINIMP3_H +#define MINIMP3_H +/* + https://github.com/lieff/minimp3 + To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. + This software is distributed without any warranty. + See . +*/ +#include + +#define MINIMP3_MAX_SAMPLES_PER_FRAME (1152*2) + +typedef struct +{ + int frame_bytes, frame_offset, channels, hz, layer, bitrate_kbps; +} mp3dec_frame_info_t; + +typedef struct +{ + float mdct_overlap[2][9*32], qmf_state[15*2*32]; + int reserv, free_format_bytes; + unsigned char header[4], reserv_buf[511]; +} mp3dec_t; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void mp3dec_init(mp3dec_t *dec); +#ifndef MINIMP3_FLOAT_OUTPUT +typedef int16_t mp3d_sample_t; +#else /* MINIMP3_FLOAT_OUTPUT */ +typedef float mp3d_sample_t; +void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples); +#endif /* MINIMP3_FLOAT_OUTPUT */ +int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MINIMP3_H */ +#if defined(MINIMP3_IMPLEMENTATION) && !defined(_MINIMP3_IMPLEMENTATION_GUARD) +#define _MINIMP3_IMPLEMENTATION_GUARD + +#include +#include + +#define MAX_FREE_FORMAT_FRAME_SIZE 2304 /* more than ISO spec's */ +#ifndef MAX_FRAME_SYNC_MATCHES +#define MAX_FRAME_SYNC_MATCHES 10 +#endif /* MAX_FRAME_SYNC_MATCHES */ + +#define MAX_L3_FRAME_PAYLOAD_BYTES MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */ + +#define MAX_BITRESERVOIR_BYTES 511 +#define SHORT_BLOCK_TYPE 2 +#define STOP_BLOCK_TYPE 3 +#define MODE_MONO 3 +#define MODE_JOINT_STEREO 1 +#define HDR_SIZE 4 +#define HDR_IS_MONO(h) (((h[3]) & 0xC0) == 0xC0) +#define HDR_IS_MS_STEREO(h) (((h[3]) & 0xE0) == 0x60) +#define HDR_IS_FREE_FORMAT(h) (((h[2]) & 0xF0) == 0) +#define HDR_IS_CRC(h) (!((h[1]) & 1)) +#define HDR_TEST_PADDING(h) ((h[2]) & 0x2) +#define HDR_TEST_MPEG1(h) ((h[1]) & 0x8) +#define HDR_TEST_NOT_MPEG25(h) ((h[1]) & 0x10) +#define HDR_TEST_I_STEREO(h) ((h[3]) & 0x10) +#define HDR_TEST_MS_STEREO(h) ((h[3]) & 0x20) +#define HDR_GET_STEREO_MODE(h) (((h[3]) >> 6) & 3) +#define HDR_GET_STEREO_MODE_EXT(h) (((h[3]) >> 4) & 3) +#define HDR_GET_LAYER(h) (((h[1]) >> 1) & 3) +#define HDR_GET_BITRATE(h) ((h[2]) >> 4) +#define HDR_GET_SAMPLE_RATE(h) (((h[2]) >> 2) & 3) +#define HDR_GET_MY_SAMPLE_RATE(h) (HDR_GET_SAMPLE_RATE(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1))*3) +#define HDR_IS_FRAME_576(h) ((h[1] & 14) == 2) +#define HDR_IS_LAYER_1(h) ((h[1] & 6) == 6) + +#define BITS_DEQUANTIZER_OUT -1 +#define MAX_SCF (255 + BITS_DEQUANTIZER_OUT*4 - 210) +#define MAX_SCFI ((MAX_SCF + 3) & ~3) + +#define MINIMP3_MIN(a, b) ((a) > (b) ? (b) : (a)) +#define MINIMP3_MAX(a, b) ((a) < (b) ? (b) : (a)) + +#if !defined(MINIMP3_NO_SIMD) + +#if !defined(MINIMP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64)) +/* x64 always have SSE2, arm64 always have neon, no need for generic code */ +#define MINIMP3_ONLY_SIMD +#endif /* SIMD checks... */ + +#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__)) +#if defined(_MSC_VER) +#include +#endif /* defined(_MSC_VER) */ +#include +#define HAVE_SSE 1 +#define HAVE_SIMD 1 +#define VSTORE _mm_storeu_ps +#define VLD _mm_loadu_ps +#define VSET _mm_set1_ps +#define VADD _mm_add_ps +#define VSUB _mm_sub_ps +#define VMUL _mm_mul_ps +#define VMAC(a, x, y) _mm_add_ps(a, _mm_mul_ps(x, y)) +#define VMSB(a, x, y) _mm_sub_ps(a, _mm_mul_ps(x, y)) +#define VMUL_S(x, s) _mm_mul_ps(x, _mm_set1_ps(s)) +#define VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3)) +typedef __m128 f4; +#if defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) +#define minimp3_cpuid __cpuid +#else /* defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) */ +static __inline__ __attribute__((always_inline)) void minimp3_cpuid(int CPUInfo[], const int InfoType) +{ +#if defined(__PIC__) + __asm__ __volatile__( +#if defined(__x86_64__) + "push %%rbx\n" + "cpuid\n" + "xchgl %%ebx, %1\n" + "pop %%rbx\n" +#else /* defined(__x86_64__) */ + "xchgl %%ebx, %1\n" + "cpuid\n" + "xchgl %%ebx, %1\n" +#endif /* defined(__x86_64__) */ + : "=a" (CPUInfo[0]), "=r" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) + : "a" (InfoType)); +#else /* defined(__PIC__) */ + __asm__ __volatile__( + "cpuid" + : "=a" (CPUInfo[0]), "=b" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) + : "a" (InfoType)); +#endif /* defined(__PIC__)*/ +} +#endif /* defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) */ +static int have_simd(void) +{ +#ifdef MINIMP3_ONLY_SIMD + return 1; +#else /* MINIMP3_ONLY_SIMD */ + static int g_have_simd; + int CPUInfo[4]; +#ifdef MINIMP3_TEST + static int g_counter; + if (g_counter++ > 100) + return 0; +#endif /* MINIMP3_TEST */ + if (g_have_simd) + goto end; + minimp3_cpuid(CPUInfo, 0); + g_have_simd = 1; + if (CPUInfo[0] > 0) + { + minimp3_cpuid(CPUInfo, 1); + g_have_simd = (CPUInfo[3] & (1 << 26)) + 1; /* SSE2 */ + } +end: + return g_have_simd - 1; +#endif /* MINIMP3_ONLY_SIMD */ +} +#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) +#include +#define HAVE_SSE 0 +#define HAVE_SIMD 1 +#define VSTORE vst1q_f32 +#define VLD vld1q_f32 +#define VSET vmovq_n_f32 +#define VADD vaddq_f32 +#define VSUB vsubq_f32 +#define VMUL vmulq_f32 +#define VMAC(a, x, y) vmlaq_f32(a, x, y) +#define VMSB(a, x, y) vmlsq_f32(a, x, y) +#define VMUL_S(x, s) vmulq_f32(x, vmovq_n_f32(s)) +#define VREV(x) vcombine_f32(vget_high_f32(vrev64q_f32(x)), vget_low_f32(vrev64q_f32(x))) +typedef float32x4_t f4; +static int have_simd() +{ /* TODO: detect neon for !MINIMP3_ONLY_SIMD */ + return 1; +} +#else /* SIMD checks... */ +#define HAVE_SSE 0 +#define HAVE_SIMD 0 +#ifdef MINIMP3_ONLY_SIMD +#error MINIMP3_ONLY_SIMD used, but SSE/NEON not enabled +#endif /* MINIMP3_ONLY_SIMD */ +#endif /* SIMD checks... */ +#else /* !defined(MINIMP3_NO_SIMD) */ +#define HAVE_SIMD 0 +#endif /* !defined(MINIMP3_NO_SIMD) */ + +#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) +#define HAVE_ARMV6 1 +static __inline__ __attribute__((always_inline)) int32_t minimp3_clip_int16_arm(int32_t a) +{ + int32_t x = 0; + __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a)); + return x; +} +#else +#define HAVE_ARMV6 0 +#endif + +typedef struct +{ + const uint8_t *buf; + int pos, limit; +} bs_t; + +typedef struct +{ + float scf[3*64]; + uint8_t total_bands, stereo_bands, bitalloc[64], scfcod[64]; +} L12_scale_info; + +typedef struct +{ + uint8_t tab_offset, code_tab_width, band_count; +} L12_subband_alloc_t; + +typedef struct +{ + const uint8_t *sfbtab; + uint16_t part_23_length, big_values, scalefac_compress; + uint8_t global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb; + uint8_t table_select[3], region_count[3], subblock_gain[3]; + uint8_t preflag, scalefac_scale, count1_table, scfsi; +} L3_gr_info_t; + +typedef struct +{ + bs_t bs; + uint8_t maindata[MAX_BITRESERVOIR_BYTES + MAX_L3_FRAME_PAYLOAD_BYTES]; + L3_gr_info_t gr_info[4]; + float grbuf[2][576], scf[40], syn[18 + 15][2*32]; + uint8_t ist_pos[2][39]; +} mp3dec_scratch_t; + +static void bs_init(bs_t *bs, const uint8_t *data, int bytes) +{ + bs->buf = data; + bs->pos = 0; + bs->limit = bytes*8; +} + +static uint32_t get_bits(bs_t *bs, int n) +{ + uint32_t next, cache = 0, s = bs->pos & 7; + int shl = n + s; + const uint8_t *p = bs->buf + (bs->pos >> 3); + if ((bs->pos += n) > bs->limit) + return 0; + next = *p++ & (255 >> s); + while ((shl -= 8) > 0) + { + cache |= next << shl; + next = *p++; + } + return cache | (next >> -shl); +} + +static int hdr_valid(const uint8_t *h) +{ + return h[0] == 0xff && + ((h[1] & 0xF0) == 0xf0 || (h[1] & 0xFE) == 0xe2) && + (HDR_GET_LAYER(h) != 0) && + (HDR_GET_BITRATE(h) != 15) && + (HDR_GET_SAMPLE_RATE(h) != 3); +} + +static int hdr_compare(const uint8_t *h1, const uint8_t *h2) +{ + return hdr_valid(h2) && + ((h1[1] ^ h2[1]) & 0xFE) == 0 && + ((h1[2] ^ h2[2]) & 0x0C) == 0 && + !(HDR_IS_FREE_FORMAT(h1) ^ HDR_IS_FREE_FORMAT(h2)); +} + +static unsigned hdr_bitrate_kbps(const uint8_t *h) +{ + static const uint8_t halfrate[2][3][15] = { + { { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,16,24,28,32,40,48,56,64,72,80,88,96,112,128 } }, + { { 0,16,20,24,28,32,40,48,56,64,80,96,112,128,160 }, { 0,16,24,28,32,40,48,56,64,80,96,112,128,160,192 }, { 0,16,32,48,64,80,96,112,128,144,160,176,192,208,224 } }, + }; + return 2*halfrate[!!HDR_TEST_MPEG1(h)][HDR_GET_LAYER(h) - 1][HDR_GET_BITRATE(h)]; +} + +static unsigned hdr_sample_rate_hz(const uint8_t *h) +{ + static const unsigned g_hz[3] = { 44100, 48000, 32000 }; + return g_hz[HDR_GET_SAMPLE_RATE(h)] >> (int)!HDR_TEST_MPEG1(h) >> (int)!HDR_TEST_NOT_MPEG25(h); +} + +static unsigned hdr_frame_samples(const uint8_t *h) +{ + return HDR_IS_LAYER_1(h) ? 384 : (1152 >> (int)HDR_IS_FRAME_576(h)); +} + +static int hdr_frame_bytes(const uint8_t *h, int free_format_size) +{ + int frame_bytes = hdr_frame_samples(h)*hdr_bitrate_kbps(h)*125/hdr_sample_rate_hz(h); + if (HDR_IS_LAYER_1(h)) + { + frame_bytes &= ~3; /* slot align */ + } + return frame_bytes ? frame_bytes : free_format_size; +} + +static int hdr_padding(const uint8_t *h) +{ + return HDR_TEST_PADDING(h) ? (HDR_IS_LAYER_1(h) ? 4 : 1) : 0; +} + +#ifndef MINIMP3_ONLY_MP3 +static const L12_subband_alloc_t *L12_subband_alloc_table(const uint8_t *hdr, L12_scale_info *sci) +{ + const L12_subband_alloc_t *alloc; + int mode = HDR_GET_STEREO_MODE(hdr); + int nbands, stereo_bands = (mode == MODE_MONO) ? 0 : (mode == MODE_JOINT_STEREO) ? (HDR_GET_STEREO_MODE_EXT(hdr) << 2) + 4 : 32; + + if (HDR_IS_LAYER_1(hdr)) + { + static const L12_subband_alloc_t g_alloc_L1[] = { { 76, 4, 32 } }; + alloc = g_alloc_L1; + nbands = 32; + } else if (!HDR_TEST_MPEG1(hdr)) + { + static const L12_subband_alloc_t g_alloc_L2M2[] = { { 60, 4, 4 }, { 44, 3, 7 }, { 44, 2, 19 } }; + alloc = g_alloc_L2M2; + nbands = 30; + } else + { + static const L12_subband_alloc_t g_alloc_L2M1[] = { { 0, 4, 3 }, { 16, 4, 8 }, { 32, 3, 12 }, { 40, 2, 7 } }; + int sample_rate_idx = HDR_GET_SAMPLE_RATE(hdr); + unsigned kbps = hdr_bitrate_kbps(hdr) >> (int)(mode != MODE_MONO); + if (!kbps) /* free-format */ + { + kbps = 192; + } + + alloc = g_alloc_L2M1; + nbands = 27; + if (kbps < 56) + { + static const L12_subband_alloc_t g_alloc_L2M1_lowrate[] = { { 44, 4, 2 }, { 44, 3, 10 } }; + alloc = g_alloc_L2M1_lowrate; + nbands = sample_rate_idx == 2 ? 12 : 8; + } else if (kbps >= 96 && sample_rate_idx != 1) + { + nbands = 30; + } + } + + sci->total_bands = (uint8_t)nbands; + sci->stereo_bands = (uint8_t)MINIMP3_MIN(stereo_bands, nbands); + + return alloc; +} + +static void L12_read_scalefactors(bs_t *bs, uint8_t *pba, uint8_t *scfcod, int bands, float *scf) +{ + static const float g_deq_L12[18*3] = { +#define DQ(x) 9.53674316e-07f/x, 7.56931807e-07f/x, 6.00777173e-07f/x + DQ(3),DQ(7),DQ(15),DQ(31),DQ(63),DQ(127),DQ(255),DQ(511),DQ(1023),DQ(2047),DQ(4095),DQ(8191),DQ(16383),DQ(32767),DQ(65535),DQ(3),DQ(5),DQ(9) + }; + int i, m; + for (i = 0; i < bands; i++) + { + float s = 0; + int ba = *pba++; + int mask = ba ? 4 + ((19 >> scfcod[i]) & 3) : 0; + for (m = 4; m; m >>= 1) + { + if (mask & m) + { + int b = get_bits(bs, 6); + s = g_deq_L12[ba*3 - 6 + b % 3]*(1 << 21 >> b/3); + } + *scf++ = s; + } + } +} + +static void L12_read_scale_info(const uint8_t *hdr, bs_t *bs, L12_scale_info *sci) +{ + static const uint8_t g_bitalloc_code_tab[] = { + 0,17, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16, + 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,16, + 0,17,18, 3,19,4,5,16, + 0,17,18,16, + 0,17,18,19, 4,5,6, 7,8, 9,10,11,12,13,14,15, + 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,14, + 0, 2, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16 + }; + const L12_subband_alloc_t *subband_alloc = L12_subband_alloc_table(hdr, sci); + + int i, k = 0, ba_bits = 0; + const uint8_t *ba_code_tab = g_bitalloc_code_tab; + + for (i = 0; i < sci->total_bands; i++) + { + uint8_t ba; + if (i == k) + { + k += subband_alloc->band_count; + ba_bits = subband_alloc->code_tab_width; + ba_code_tab = g_bitalloc_code_tab + subband_alloc->tab_offset; + subband_alloc++; + } + ba = ba_code_tab[get_bits(bs, ba_bits)]; + sci->bitalloc[2*i] = ba; + if (i < sci->stereo_bands) + { + ba = ba_code_tab[get_bits(bs, ba_bits)]; + } + sci->bitalloc[2*i + 1] = sci->stereo_bands ? ba : 0; + } + + for (i = 0; i < 2*sci->total_bands; i++) + { + sci->scfcod[i] = sci->bitalloc[i] ? HDR_IS_LAYER_1(hdr) ? 2 : get_bits(bs, 2) : 6; + } + + L12_read_scalefactors(bs, sci->bitalloc, sci->scfcod, sci->total_bands*2, sci->scf); + + for (i = sci->stereo_bands; i < sci->total_bands; i++) + { + sci->bitalloc[2*i + 1] = 0; + } +} + +static int L12_dequantize_granule(float *grbuf, bs_t *bs, L12_scale_info *sci, int group_size) +{ + int i, j, k, choff = 576; + for (j = 0; j < 4; j++) + { + float *dst = grbuf + group_size*j; + for (i = 0; i < 2*sci->total_bands; i++) + { + int ba = sci->bitalloc[i]; + if (ba != 0) + { + if (ba < 17) + { + int half = (1 << (ba - 1)) - 1; + for (k = 0; k < group_size; k++) + { + dst[k] = (float)((int)get_bits(bs, ba) - half); + } + } else + { + unsigned mod = (2 << (ba - 17)) + 1; /* 3, 5, 9 */ + unsigned code = get_bits(bs, mod + 2 - (mod >> 3)); /* 5, 7, 10 */ + for (k = 0; k < group_size; k++, code /= mod) + { + dst[k] = (float)((int)(code % mod - mod/2)); + } + } + } + dst += choff; + choff = 18 - choff; + } + } + return group_size*4; +} + +static void L12_apply_scf_384(L12_scale_info *sci, const float *scf, float *dst) +{ + int i, k; + memcpy(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float)); + for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6) + { + for (k = 0; k < 12; k++) + { + dst[k + 0] *= scf[0]; + dst[k + 576] *= scf[3]; + } + } +} +#endif /* MINIMP3_ONLY_MP3 */ + +static int L3_read_side_info(bs_t *bs, L3_gr_info_t *gr, const uint8_t *hdr) +{ + static const uint8_t g_scf_long[8][23] = { + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 12,12,12,12,12,12,16,20,24,28,32,40,48,56,64,76,90,2,2,2,2,2,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,54,62,70,76,36,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 4,4,4,4,4,4,6,6,8,8,10,12,16,20,24,28,34,42,50,54,76,158,0 }, + { 4,4,4,4,4,4,6,6,6,8,10,12,16,18,22,28,34,40,46,54,54,192,0 }, + { 4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102,26,0 } + }; + static const uint8_t g_scf_short[8][40] = { + { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 8,8,8,8,8,8,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 }, + { 4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 }, + { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 }, + { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 }, + { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 }, + { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 } + }; + static const uint8_t g_scf_mixed[8][40] = { + { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 12,12,12,4,4,4,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 }, + { 6,6,6,6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 }, + { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 }, + { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 } + }; + + unsigned tables, scfsi = 0; + int main_data_begin, part_23_sum = 0; + int sr_idx = HDR_GET_MY_SAMPLE_RATE(hdr); sr_idx -= (sr_idx != 0); + int gr_count = HDR_IS_MONO(hdr) ? 1 : 2; + + if (HDR_TEST_MPEG1(hdr)) + { + gr_count *= 2; + main_data_begin = get_bits(bs, 9); + scfsi = get_bits(bs, 7 + gr_count); + } else + { + main_data_begin = get_bits(bs, 8 + gr_count) >> gr_count; + } + + do + { + if (HDR_IS_MONO(hdr)) + { + scfsi <<= 4; + } + gr->part_23_length = (uint16_t)get_bits(bs, 12); + part_23_sum += gr->part_23_length; + gr->big_values = (uint16_t)get_bits(bs, 9); + if (gr->big_values > 288) + { + return -1; + } + gr->global_gain = (uint8_t)get_bits(bs, 8); + gr->scalefac_compress = (uint16_t)get_bits(bs, HDR_TEST_MPEG1(hdr) ? 4 : 9); + gr->sfbtab = g_scf_long[sr_idx]; + gr->n_long_sfb = 22; + gr->n_short_sfb = 0; + if (get_bits(bs, 1)) + { + gr->block_type = (uint8_t)get_bits(bs, 2); + if (!gr->block_type) + { + return -1; + } + gr->mixed_block_flag = (uint8_t)get_bits(bs, 1); + gr->region_count[0] = 7; + gr->region_count[1] = 255; + if (gr->block_type == SHORT_BLOCK_TYPE) + { + scfsi &= 0x0F0F; + if (!gr->mixed_block_flag) + { + gr->region_count[0] = 8; + gr->sfbtab = g_scf_short[sr_idx]; + gr->n_long_sfb = 0; + gr->n_short_sfb = 39; + } else + { + gr->sfbtab = g_scf_mixed[sr_idx]; + gr->n_long_sfb = HDR_TEST_MPEG1(hdr) ? 8 : 6; + gr->n_short_sfb = 30; + } + } + tables = get_bits(bs, 10); + tables <<= 5; + gr->subblock_gain[0] = (uint8_t)get_bits(bs, 3); + gr->subblock_gain[1] = (uint8_t)get_bits(bs, 3); + gr->subblock_gain[2] = (uint8_t)get_bits(bs, 3); + } else + { + gr->block_type = 0; + gr->mixed_block_flag = 0; + tables = get_bits(bs, 15); + gr->region_count[0] = (uint8_t)get_bits(bs, 4); + gr->region_count[1] = (uint8_t)get_bits(bs, 3); + gr->region_count[2] = 255; + } + gr->table_select[0] = (uint8_t)(tables >> 10); + gr->table_select[1] = (uint8_t)((tables >> 5) & 31); + gr->table_select[2] = (uint8_t)((tables) & 31); + gr->preflag = HDR_TEST_MPEG1(hdr) ? get_bits(bs, 1) : (gr->scalefac_compress >= 500); + gr->scalefac_scale = (uint8_t)get_bits(bs, 1); + gr->count1_table = (uint8_t)get_bits(bs, 1); + gr->scfsi = (uint8_t)((scfsi >> 12) & 15); + scfsi <<= 4; + gr++; + } while(--gr_count); + + if (part_23_sum + bs->pos > bs->limit + main_data_begin*8) + { + return -1; + } + + return main_data_begin; +} + +static void L3_read_scalefactors(uint8_t *scf, uint8_t *ist_pos, const uint8_t *scf_size, const uint8_t *scf_count, bs_t *bitbuf, int scfsi) +{ + int i, k; + for (i = 0; i < 4 && scf_count[i]; i++, scfsi *= 2) + { + int cnt = scf_count[i]; + if (scfsi & 8) + { + memcpy(scf, ist_pos, cnt); + } else + { + int bits = scf_size[i]; + if (!bits) + { + memset(scf, 0, cnt); + memset(ist_pos, 0, cnt); + } else + { + int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1; + for (k = 0; k < cnt; k++) + { + int s = get_bits(bitbuf, bits); + ist_pos[k] = (s == max_scf ? -1 : s); + scf[k] = s; + } + } + } + ist_pos += cnt; + scf += cnt; + } + scf[0] = scf[1] = scf[2] = 0; +} + +static float L3_ldexp_q2(float y, int exp_q2) +{ + static const float g_expfrac[4] = { 9.31322575e-10f,7.83145814e-10f,6.58544508e-10f,5.53767716e-10f }; + int e; + do + { + e = MINIMP3_MIN(30*4, exp_q2); + y *= g_expfrac[e & 3]*(1 << 30 >> (e >> 2)); + } while ((exp_q2 -= e) > 0); + return y; +} + +static void L3_decode_scalefactors(const uint8_t *hdr, uint8_t *ist_pos, bs_t *bs, const L3_gr_info_t *gr, float *scf, int ch) +{ + static const uint8_t g_scf_partitions[3][28] = { + { 6,5,5, 5,6,5,5,5,6,5, 7,3,11,10,0,0, 7, 7, 7,0, 6, 6,6,3, 8, 8,5,0 }, + { 8,9,6,12,6,9,9,9,6,9,12,6,15,18,0,0, 6,15,12,0, 6,12,9,6, 6,18,9,0 }, + { 9,9,6,12,9,9,9,9,9,9,12,6,18,18,0,0,12,12,12,0,12, 9,9,6,15,12,9,0 } + }; + const uint8_t *scf_partition = g_scf_partitions[!!gr->n_short_sfb + !gr->n_long_sfb]; + uint8_t scf_size[4], iscf[40]; + int i, scf_shift = gr->scalefac_scale + 1, gain_exp, scfsi = gr->scfsi; + float gain; + + if (HDR_TEST_MPEG1(hdr)) + { + static const uint8_t g_scfc_decode[16] = { 0,1,2,3, 12,5,6,7, 9,10,11,13, 14,15,18,19 }; + int part = g_scfc_decode[gr->scalefac_compress]; + scf_size[1] = scf_size[0] = (uint8_t)(part >> 2); + scf_size[3] = scf_size[2] = (uint8_t)(part & 3); + } else + { + static const uint8_t g_mod[6*4] = { 5,5,4,4,5,5,4,1,4,3,1,1,5,6,6,1,4,4,4,1,4,3,1,1 }; + int k, modprod, sfc, ist = HDR_TEST_I_STEREO(hdr) && ch; + sfc = gr->scalefac_compress >> ist; + for (k = ist*3*4; sfc >= 0; sfc -= modprod, k += 4) + { + for (modprod = 1, i = 3; i >= 0; i--) + { + scf_size[i] = (uint8_t)(sfc / modprod % g_mod[k + i]); + modprod *= g_mod[k + i]; + } + } + scf_partition += k; + scfsi = -16; + } + L3_read_scalefactors(iscf, ist_pos, scf_size, scf_partition, bs, scfsi); + + if (gr->n_short_sfb) + { + int sh = 3 - scf_shift; + for (i = 0; i < gr->n_short_sfb; i += 3) + { + iscf[gr->n_long_sfb + i + 0] += gr->subblock_gain[0] << sh; + iscf[gr->n_long_sfb + i + 1] += gr->subblock_gain[1] << sh; + iscf[gr->n_long_sfb + i + 2] += gr->subblock_gain[2] << sh; + } + } else if (gr->preflag) + { + static const uint8_t g_preamp[10] = { 1,1,1,1,2,2,3,3,3,2 }; + for (i = 0; i < 10; i++) + { + iscf[11 + i] += g_preamp[i]; + } + } + + gain_exp = gr->global_gain + BITS_DEQUANTIZER_OUT*4 - 210 - (HDR_IS_MS_STEREO(hdr) ? 2 : 0); + gain = L3_ldexp_q2(1 << (MAX_SCFI/4), MAX_SCFI - gain_exp); + for (i = 0; i < (int)(gr->n_long_sfb + gr->n_short_sfb); i++) + { + scf[i] = L3_ldexp_q2(gain, iscf[i] << scf_shift); + } +} + +static const float g_pow43[129 + 16] = { + 0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f, + 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f +}; + +static float L3_pow_43(int x) +{ + float frac; + int sign, mult = 256; + + if (x < 129) + { + return g_pow43[16 + x]; + } + + if (x < 1024) + { + mult = 16; + x <<= 3; + } + + sign = 2*x & 64; + frac = (float)((x & 63) - sign) / ((x & ~63) + sign); + return g_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; +} + +static void L3_huffman(float *dst, bs_t *bs, const L3_gr_info_t *gr_info, const float *scf, int layer3gr_limit) +{ + static const int16_t tabs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 785,785,785,785,784,784,784,784,513,513,513,513,513,513,513,513,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256, + -255,1313,1298,1282,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,290,288, + -255,1313,1298,1282,769,769,769,769,529,529,529,529,529,529,529,529,528,528,528,528,528,528,528,528,512,512,512,512,512,512,512,512,290,288, + -253,-318,-351,-367,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,819,818,547,547,275,275,275,275,561,560,515,546,289,274,288,258, + -254,-287,1329,1299,1314,1312,1057,1057,1042,1042,1026,1026,784,784,784,784,529,529,529,529,529,529,529,529,769,769,769,769,768,768,768,768,563,560,306,306,291,259, + -252,-413,-477,-542,1298,-575,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-383,-399,1107,1092,1106,1061,849,849,789,789,1104,1091,773,773,1076,1075,341,340,325,309,834,804,577,577,532,532,516,516,832,818,803,816,561,561,531,531,515,546,289,289,288,258, + -252,-429,-493,-559,1057,1057,1042,1042,529,529,529,529,529,529,529,529,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,-382,1077,-415,1106,1061,1104,849,849,789,789,1091,1076,1029,1075,834,834,597,581,340,340,339,324,804,833,532,532,832,772,818,803,817,787,816,771,290,290,290,290,288,258, + -253,-349,-414,-447,-463,1329,1299,-479,1314,1312,1057,1057,1042,1042,1026,1026,785,785,785,785,784,784,784,784,769,769,769,769,768,768,768,768,-319,851,821,-335,836,850,805,849,341,340,325,336,533,533,579,579,564,564,773,832,578,548,563,516,321,276,306,291,304,259, + -251,-572,-733,-830,-863,-879,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,1396,1351,1381,1366,1395,1335,1380,-559,1334,1138,1138,1063,1063,1350,1392,1031,1031,1062,1062,1364,1363,1120,1120,1333,1348,881,881,881,881,375,374,359,373,343,358,341,325,791,791,1123,1122,-703,1105,1045,-719,865,865,790,790,774,774,1104,1029,338,293,323,308,-799,-815,833,788,772,818,803,816,322,292,307,320,561,531,515,546,289,274,288,258, + -251,-525,-605,-685,-765,-831,-846,1298,1057,1057,1312,1282,785,785,785,785,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,1399,1398,1383,1367,1382,1396,1351,-511,1381,1366,1139,1139,1079,1079,1124,1124,1364,1349,1363,1333,882,882,882,882,807,807,807,807,1094,1094,1136,1136,373,341,535,535,881,775,867,822,774,-591,324,338,-671,849,550,550,866,864,609,609,293,336,534,534,789,835,773,-751,834,804,308,307,833,788,832,772,562,562,547,547,305,275,560,515,290,290, + -252,-397,-477,-557,-622,-653,-719,-735,-750,1329,1299,1314,1057,1057,1042,1042,1312,1282,1024,1024,785,785,785,785,784,784,784,784,769,769,769,769,-383,1127,1141,1111,1126,1140,1095,1110,869,869,883,883,1079,1109,882,882,375,374,807,868,838,881,791,-463,867,822,368,263,852,837,836,-543,610,610,550,550,352,336,534,534,865,774,851,821,850,805,593,533,579,564,773,832,578,578,548,548,577,577,307,276,306,291,516,560,259,259, + -250,-2107,-2507,-2764,-2909,-2974,-3007,-3023,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-767,-1052,-1213,-1277,-1358,-1405,-1469,-1535,-1550,-1582,-1614,-1647,-1662,-1694,-1726,-1759,-1774,-1807,-1822,-1854,-1886,1565,-1919,-1935,-1951,-1967,1731,1730,1580,1717,-1983,1729,1564,-1999,1548,-2015,-2031,1715,1595,-2047,1714,-2063,1610,-2079,1609,-2095,1323,1323,1457,1457,1307,1307,1712,1547,1641,1700,1699,1594,1685,1625,1442,1442,1322,1322,-780,-973,-910,1279,1278,1277,1262,1276,1261,1275,1215,1260,1229,-959,974,974,989,989,-943,735,478,478,495,463,506,414,-1039,1003,958,1017,927,942,987,957,431,476,1272,1167,1228,-1183,1256,-1199,895,895,941,941,1242,1227,1212,1135,1014,1014,490,489,503,487,910,1013,985,925,863,894,970,955,1012,847,-1343,831,755,755,984,909,428,366,754,559,-1391,752,486,457,924,997,698,698,983,893,740,740,908,877,739,739,667,667,953,938,497,287,271,271,683,606,590,712,726,574,302,302,738,736,481,286,526,725,605,711,636,724,696,651,589,681,666,710,364,467,573,695,466,466,301,465,379,379,709,604,665,679,316,316,634,633,436,436,464,269,424,394,452,332,438,363,347,408,393,448,331,422,362,407,392,421,346,406,391,376,375,359,1441,1306,-2367,1290,-2383,1337,-2399,-2415,1426,1321,-2431,1411,1336,-2447,-2463,-2479,1169,1169,1049,1049,1424,1289,1412,1352,1319,-2495,1154,1154,1064,1064,1153,1153,416,390,360,404,403,389,344,374,373,343,358,372,327,357,342,311,356,326,1395,1394,1137,1137,1047,1047,1365,1392,1287,1379,1334,1364,1349,1378,1318,1363,792,792,792,792,1152,1152,1032,1032,1121,1121,1046,1046,1120,1120,1030,1030,-2895,1106,1061,1104,849,849,789,789,1091,1076,1029,1090,1060,1075,833,833,309,324,532,532,832,772,818,803,561,561,531,560,515,546,289,274,288,258, + -250,-1179,-1579,-1836,-1996,-2124,-2253,-2333,-2413,-2477,-2542,-2574,-2607,-2622,-2655,1314,1313,1298,1312,1282,785,785,785,785,1040,1040,1025,1025,768,768,768,768,-766,-798,-830,-862,-895,-911,-927,-943,-959,-975,-991,-1007,-1023,-1039,-1055,-1070,1724,1647,-1103,-1119,1631,1767,1662,1738,1708,1723,-1135,1780,1615,1779,1599,1677,1646,1778,1583,-1151,1777,1567,1737,1692,1765,1722,1707,1630,1751,1661,1764,1614,1736,1676,1763,1750,1645,1598,1721,1691,1762,1706,1582,1761,1566,-1167,1749,1629,767,766,751,765,494,494,735,764,719,749,734,763,447,447,748,718,477,506,431,491,446,476,461,505,415,430,475,445,504,399,460,489,414,503,383,474,429,459,502,502,746,752,488,398,501,473,413,472,486,271,480,270,-1439,-1455,1357,-1471,-1487,-1503,1341,1325,-1519,1489,1463,1403,1309,-1535,1372,1448,1418,1476,1356,1462,1387,-1551,1475,1340,1447,1402,1386,-1567,1068,1068,1474,1461,455,380,468,440,395,425,410,454,364,467,466,464,453,269,409,448,268,432,1371,1473,1432,1417,1308,1460,1355,1446,1459,1431,1083,1083,1401,1416,1458,1445,1067,1067,1370,1457,1051,1051,1291,1430,1385,1444,1354,1415,1400,1443,1082,1082,1173,1113,1186,1066,1185,1050,-1967,1158,1128,1172,1097,1171,1081,-1983,1157,1112,416,266,375,400,1170,1142,1127,1065,793,793,1169,1033,1156,1096,1141,1111,1155,1080,1126,1140,898,898,808,808,897,897,792,792,1095,1152,1032,1125,1110,1139,1079,1124,882,807,838,881,853,791,-2319,867,368,263,822,852,837,866,806,865,-2399,851,352,262,534,534,821,836,594,594,549,549,593,593,533,533,848,773,579,579,564,578,548,563,276,276,577,576,306,291,516,560,305,305,275,259, + -251,-892,-2058,-2620,-2828,-2957,-3023,-3039,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,-559,1530,-575,-591,1528,1527,1407,1526,1391,1023,1023,1023,1023,1525,1375,1268,1268,1103,1103,1087,1087,1039,1039,1523,-604,815,815,815,815,510,495,509,479,508,463,507,447,431,505,415,399,-734,-782,1262,-815,1259,1244,-831,1258,1228,-847,-863,1196,-879,1253,987,987,748,-767,493,493,462,477,414,414,686,669,478,446,461,445,474,429,487,458,412,471,1266,1264,1009,1009,799,799,-1019,-1276,-1452,-1581,-1677,-1757,-1821,-1886,-1933,-1997,1257,1257,1483,1468,1512,1422,1497,1406,1467,1496,1421,1510,1134,1134,1225,1225,1466,1451,1374,1405,1252,1252,1358,1480,1164,1164,1251,1251,1238,1238,1389,1465,-1407,1054,1101,-1423,1207,-1439,830,830,1248,1038,1237,1117,1223,1148,1236,1208,411,426,395,410,379,269,1193,1222,1132,1235,1221,1116,976,976,1192,1162,1177,1220,1131,1191,963,963,-1647,961,780,-1663,558,558,994,993,437,408,393,407,829,978,813,797,947,-1743,721,721,377,392,844,950,828,890,706,706,812,859,796,960,948,843,934,874,571,571,-1919,690,555,689,421,346,539,539,944,779,918,873,932,842,903,888,570,570,931,917,674,674,-2575,1562,-2591,1609,-2607,1654,1322,1322,1441,1441,1696,1546,1683,1593,1669,1624,1426,1426,1321,1321,1639,1680,1425,1425,1305,1305,1545,1668,1608,1623,1667,1592,1638,1666,1320,1320,1652,1607,1409,1409,1304,1304,1288,1288,1664,1637,1395,1395,1335,1335,1622,1636,1394,1394,1319,1319,1606,1621,1392,1392,1137,1137,1137,1137,345,390,360,375,404,373,1047,-2751,-2767,-2783,1062,1121,1046,-2799,1077,-2815,1106,1061,789,789,1105,1104,263,355,310,340,325,354,352,262,339,324,1091,1076,1029,1090,1060,1075,833,833,788,788,1088,1028,818,818,803,803,561,561,531,531,816,771,546,546,289,274,288,258, + -253,-317,-381,-446,-478,-509,1279,1279,-811,-1179,-1451,-1756,-1900,-2028,-2189,-2253,-2333,-2414,-2445,-2511,-2526,1313,1298,-2559,1041,1041,1040,1040,1025,1025,1024,1024,1022,1007,1021,991,1020,975,1019,959,687,687,1018,1017,671,671,655,655,1016,1015,639,639,758,758,623,623,757,607,756,591,755,575,754,559,543,543,1009,783,-575,-621,-685,-749,496,-590,750,749,734,748,974,989,1003,958,988,973,1002,942,987,957,972,1001,926,986,941,971,956,1000,910,985,925,999,894,970,-1071,-1087,-1102,1390,-1135,1436,1509,1451,1374,-1151,1405,1358,1480,1420,-1167,1507,1494,1389,1342,1465,1435,1450,1326,1505,1310,1493,1373,1479,1404,1492,1464,1419,428,443,472,397,736,526,464,464,486,457,442,471,484,482,1357,1449,1434,1478,1388,1491,1341,1490,1325,1489,1463,1403,1309,1477,1372,1448,1418,1433,1476,1356,1462,1387,-1439,1475,1340,1447,1402,1474,1324,1461,1371,1473,269,448,1432,1417,1308,1460,-1711,1459,-1727,1441,1099,1099,1446,1386,1431,1401,-1743,1289,1083,1083,1160,1160,1458,1445,1067,1067,1370,1457,1307,1430,1129,1129,1098,1098,268,432,267,416,266,400,-1887,1144,1187,1082,1173,1113,1186,1066,1050,1158,1128,1143,1172,1097,1171,1081,420,391,1157,1112,1170,1142,1127,1065,1169,1049,1156,1096,1141,1111,1155,1080,1126,1154,1064,1153,1140,1095,1048,-2159,1125,1110,1137,-2175,823,823,1139,1138,807,807,384,264,368,263,868,838,853,791,867,822,852,837,866,806,865,790,-2319,851,821,836,352,262,850,805,849,-2399,533,533,835,820,336,261,578,548,563,577,532,532,832,772,562,562,547,547,305,275,560,515,290,290,288,258 }; + static const uint8_t tab32[] = { 130,162,193,209,44,28,76,140,9,9,9,9,9,9,9,9,190,254,222,238,126,94,157,157,109,61,173,205 }; + static const uint8_t tab33[] = { 252,236,220,204,188,172,156,140,124,108,92,76,60,44,28,12 }; + static const int16_t tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 }; + static const uint8_t g_linbits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 }; + +#define PEEK_BITS(n) (bs_cache >> (32 - n)) +#define FLUSH_BITS(n) { bs_cache <<= (n); bs_sh += (n); } +#define CHECK_BITS while (bs_sh >= 0) { bs_cache |= (uint32_t)*bs_next_ptr++ << bs_sh; bs_sh -= 8; } +#define BSPOS ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh) + + float one = 0.0f; + int ireg = 0, big_val_cnt = gr_info->big_values; + const uint8_t *sfb = gr_info->sfbtab; + const uint8_t *bs_next_ptr = bs->buf + bs->pos/8; + uint32_t bs_cache = (((bs_next_ptr[0]*256u + bs_next_ptr[1])*256u + bs_next_ptr[2])*256u + bs_next_ptr[3]) << (bs->pos & 7); + int pairs_to_decode, np, bs_sh = (bs->pos & 7) - 8; + bs_next_ptr += 4; + + while (big_val_cnt > 0) + { + int tab_num = gr_info->table_select[ireg]; + int sfb_cnt = gr_info->region_count[ireg++]; + const int16_t *codebook = tabs + tabindex[tab_num]; + int linbits = g_linbits[tab_num]; + if (linbits) + { + do + { + np = *sfb++ / 2; + pairs_to_decode = MINIMP3_MIN(big_val_cnt, np); + one = *scf++; + do + { + int j, w = 5; + int leaf = codebook[PEEK_BITS(w)]; + while (leaf < 0) + { + FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[PEEK_BITS(w) - (leaf >> 3)]; + } + FLUSH_BITS(leaf >> 8); + + for (j = 0; j < 2; j++, dst++, leaf >>= 4) + { + int lsb = leaf & 0x0F; + if (lsb == 15) + { + lsb += PEEK_BITS(linbits); + FLUSH_BITS(linbits); + CHECK_BITS; + *dst = one*L3_pow_43(lsb)*((int32_t)bs_cache < 0 ? -1: 1); + } else + { + *dst = g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + } + FLUSH_BITS(lsb ? 1 : 0); + } + CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } else + { + do + { + np = *sfb++ / 2; + pairs_to_decode = MINIMP3_MIN(big_val_cnt, np); + one = *scf++; + do + { + int j, w = 5; + int leaf = codebook[PEEK_BITS(w)]; + while (leaf < 0) + { + FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[PEEK_BITS(w) - (leaf >> 3)]; + } + FLUSH_BITS(leaf >> 8); + + for (j = 0; j < 2; j++, dst++, leaf >>= 4) + { + int lsb = leaf & 0x0F; + *dst = g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + FLUSH_BITS(lsb ? 1 : 0); + } + CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } + } + + for (np = 1 - big_val_cnt;; dst += 4) + { + const uint8_t *codebook_count1 = (gr_info->count1_table) ? tab33 : tab32; + int leaf = codebook_count1[PEEK_BITS(4)]; + if (!(leaf & 8)) + { + leaf = codebook_count1[(leaf >> 3) + (bs_cache << 4 >> (32 - (leaf & 3)))]; + } + FLUSH_BITS(leaf & 7); + if (BSPOS > layer3gr_limit) + { + break; + } +#define RELOAD_SCALEFACTOR if (!--np) { np = *sfb++/2; if (!np) break; one = *scf++; } +#define DEQ_COUNT1(s) if (leaf & (128 >> s)) { dst[s] = ((int32_t)bs_cache < 0) ? -one : one; FLUSH_BITS(1) } + RELOAD_SCALEFACTOR; + DEQ_COUNT1(0); + DEQ_COUNT1(1); + RELOAD_SCALEFACTOR; + DEQ_COUNT1(2); + DEQ_COUNT1(3); + CHECK_BITS; + } + + bs->pos = layer3gr_limit; +} + +static void L3_midside_stereo(float *left, int n) +{ + int i = 0; + float *right = left + 576; +#if HAVE_SIMD + if (have_simd()) for (; i < n - 3; i += 4) + { + f4 vl = VLD(left + i); + f4 vr = VLD(right + i); + VSTORE(left + i, VADD(vl, vr)); + VSTORE(right + i, VSUB(vl, vr)); + } +#endif /* HAVE_SIMD */ + for (; i < n; i++) + { + float a = left[i]; + float b = right[i]; + left[i] = a + b; + right[i] = a - b; + } +} + +static void L3_intensity_stereo_band(float *left, int n, float kl, float kr) +{ + int i; + for (i = 0; i < n; i++) + { + left[i + 576] = left[i]*kr; + left[i] = left[i]*kl; + } +} + +static void L3_stereo_top_band(const float *right, const uint8_t *sfb, int nbands, int max_band[3]) +{ + int i, k; + + max_band[0] = max_band[1] = max_band[2] = -1; + + for (i = 0; i < nbands; i++) + { + for (k = 0; k < sfb[i]; k += 2) + { + if (right[k] != 0 || right[k + 1] != 0) + { + max_band[i % 3] = i; + break; + } + } + right += sfb[i]; + } +} + +static void L3_stereo_process(float *left, const uint8_t *ist_pos, const uint8_t *sfb, const uint8_t *hdr, int max_band[3], int mpeg2_sh) +{ + static const float g_pan[7*2] = { 0,1,0.21132487f,0.78867513f,0.36602540f,0.63397460f,0.5f,0.5f,0.63397460f,0.36602540f,0.78867513f,0.21132487f,1,0 }; + unsigned i, max_pos = HDR_TEST_MPEG1(hdr) ? 7 : 64; + + for (i = 0; sfb[i]; i++) + { + unsigned ipos = ist_pos[i]; + if ((int)i > max_band[i % 3] && ipos < max_pos) + { + float kl, kr, s = HDR_TEST_MS_STEREO(hdr) ? 1.41421356f : 1; + if (HDR_TEST_MPEG1(hdr)) + { + kl = g_pan[2*ipos]; + kr = g_pan[2*ipos + 1]; + } else + { + kl = 1; + kr = L3_ldexp_q2(1, (ipos + 1) >> 1 << mpeg2_sh); + if (ipos & 1) + { + kl = kr; + kr = 1; + } + } + L3_intensity_stereo_band(left, sfb[i], kl*s, kr*s); + } else if (HDR_TEST_MS_STEREO(hdr)) + { + L3_midside_stereo(left, sfb[i]); + } + left += sfb[i]; + } +} + +static void L3_intensity_stereo(float *left, uint8_t *ist_pos, const L3_gr_info_t *gr, const uint8_t *hdr) +{ + int max_band[3], n_sfb = gr->n_long_sfb + gr->n_short_sfb; + int i, max_blocks = gr->n_short_sfb ? 3 : 1; + + L3_stereo_top_band(left + 576, gr->sfbtab, n_sfb, max_band); + if (gr->n_long_sfb) + { + max_band[0] = max_band[1] = max_band[2] = MINIMP3_MAX(MINIMP3_MAX(max_band[0], max_band[1]), max_band[2]); + } + for (i = 0; i < max_blocks; i++) + { + int default_pos = HDR_TEST_MPEG1(hdr) ? 3 : 0; + int itop = n_sfb - max_blocks + i; + int prev = itop - max_blocks; + ist_pos[itop] = max_band[i] >= prev ? default_pos : ist_pos[prev]; + } + L3_stereo_process(left, ist_pos, gr->sfbtab, hdr, max_band, gr[1].scalefac_compress & 1); +} + +static void L3_reorder(float *grbuf, float *scratch, const uint8_t *sfb) +{ + int i, len; + float *src = grbuf, *dst = scratch; + + for (;0 != (len = *sfb); sfb += 3, src += 2*len) + { + for (i = 0; i < len; i++, src++) + { + *dst++ = src[0*len]; + *dst++ = src[1*len]; + *dst++ = src[2*len]; + } + } + memcpy(grbuf, scratch, (dst - scratch)*sizeof(float)); +} + +static void L3_antialias(float *grbuf, int nbands) +{ + static const float g_aa[2][8] = { + {0.85749293f,0.88174200f,0.94962865f,0.98331459f,0.99551782f,0.99916056f,0.99989920f,0.99999316f}, + {0.51449576f,0.47173197f,0.31337745f,0.18191320f,0.09457419f,0.04096558f,0.01419856f,0.00369997f} + }; + + for (; nbands > 0; nbands--, grbuf += 18) + { + int i = 0; +#if HAVE_SIMD + if (have_simd()) for (; i < 8; i += 4) + { + f4 vu = VLD(grbuf + 18 + i); + f4 vd = VLD(grbuf + 14 - i); + f4 vc0 = VLD(g_aa[0] + i); + f4 vc1 = VLD(g_aa[1] + i); + vd = VREV(vd); + VSTORE(grbuf + 18 + i, VSUB(VMUL(vu, vc0), VMUL(vd, vc1))); + vd = VADD(VMUL(vu, vc1), VMUL(vd, vc0)); + VSTORE(grbuf + 14 - i, VREV(vd)); + } +#endif /* HAVE_SIMD */ +#ifndef MINIMP3_ONLY_SIMD + for(; i < 8; i++) + { + float u = grbuf[18 + i]; + float d = grbuf[17 - i]; + grbuf[18 + i] = u*g_aa[0][i] - d*g_aa[1][i]; + grbuf[17 - i] = u*g_aa[1][i] + d*g_aa[0][i]; + } +#endif /* MINIMP3_ONLY_SIMD */ + } +} + +static void L3_dct3_9(float *y) +{ + float s0, s1, s2, s3, s4, s5, s6, s7, s8, t0, t2, t4; + + s0 = y[0]; s2 = y[2]; s4 = y[4]; s6 = y[6]; s8 = y[8]; + t0 = s0 + s6*0.5f; + s0 -= s6; + t4 = (s4 + s2)*0.93969262f; + t2 = (s8 + s2)*0.76604444f; + s6 = (s4 - s8)*0.17364818f; + s4 += s8 - s2; + + s2 = s0 - s4*0.5f; + y[4] = s4 + s0; + s8 = t0 - t2 + s6; + s0 = t0 - t4 + t2; + s4 = t0 + t4 - s6; + + s1 = y[1]; s3 = y[3]; s5 = y[5]; s7 = y[7]; + + s3 *= 0.86602540f; + t0 = (s5 + s1)*0.98480775f; + t4 = (s5 - s7)*0.34202014f; + t2 = (s1 + s7)*0.64278761f; + s1 = (s1 - s5 - s7)*0.86602540f; + + s5 = t0 - s3 - t2; + s7 = t4 - s3 - t0; + s3 = t4 + s3 - t2; + + y[0] = s4 - s7; + y[1] = s2 + s1; + y[2] = s0 - s3; + y[3] = s8 + s5; + y[5] = s8 - s5; + y[6] = s0 + s3; + y[7] = s2 - s1; + y[8] = s4 + s7; +} + +static void L3_imdct36(float *grbuf, float *overlap, const float *window, int nbands) +{ + int i, j; + static const float g_twid9[18] = { + 0.73727734f,0.79335334f,0.84339145f,0.88701083f,0.92387953f,0.95371695f,0.97629601f,0.99144486f,0.99904822f,0.67559021f,0.60876143f,0.53729961f,0.46174861f,0.38268343f,0.30070580f,0.21643961f,0.13052619f,0.04361938f + }; + + for (j = 0; j < nbands; j++, grbuf += 18, overlap += 9) + { + float co[9], si[9]; + co[0] = -grbuf[0]; + si[0] = grbuf[17]; + for (i = 0; i < 4; i++) + { + si[8 - 2*i] = grbuf[4*i + 1] - grbuf[4*i + 2]; + co[1 + 2*i] = grbuf[4*i + 1] + grbuf[4*i + 2]; + si[7 - 2*i] = grbuf[4*i + 4] - grbuf[4*i + 3]; + co[2 + 2*i] = -(grbuf[4*i + 3] + grbuf[4*i + 4]); + } + L3_dct3_9(co); + L3_dct3_9(si); + + si[1] = -si[1]; + si[3] = -si[3]; + si[5] = -si[5]; + si[7] = -si[7]; + + i = 0; + +#if HAVE_SIMD + if (have_simd()) for (; i < 8; i += 4) + { + f4 vovl = VLD(overlap + i); + f4 vc = VLD(co + i); + f4 vs = VLD(si + i); + f4 vr0 = VLD(g_twid9 + i); + f4 vr1 = VLD(g_twid9 + 9 + i); + f4 vw0 = VLD(window + i); + f4 vw1 = VLD(window + 9 + i); + f4 vsum = VADD(VMUL(vc, vr1), VMUL(vs, vr0)); + VSTORE(overlap + i, VSUB(VMUL(vc, vr0), VMUL(vs, vr1))); + VSTORE(grbuf + i, VSUB(VMUL(vovl, vw0), VMUL(vsum, vw1))); + vsum = VADD(VMUL(vovl, vw1), VMUL(vsum, vw0)); + VSTORE(grbuf + 14 - i, VREV(vsum)); + } +#endif /* HAVE_SIMD */ + for (; i < 9; i++) + { + float ovl = overlap[i]; + float sum = co[i]*g_twid9[9 + i] + si[i]*g_twid9[0 + i]; + overlap[i] = co[i]*g_twid9[0 + i] - si[i]*g_twid9[9 + i]; + grbuf[i] = ovl*window[0 + i] - sum*window[9 + i]; + grbuf[17 - i] = ovl*window[9 + i] + sum*window[0 + i]; + } + } +} + +static void L3_idct3(float x0, float x1, float x2, float *dst) +{ + float m1 = x1*0.86602540f; + float a1 = x0 - x2*0.5f; + dst[1] = x0 + x2; + dst[0] = a1 + m1; + dst[2] = a1 - m1; +} + +static void L3_imdct12(float *x, float *dst, float *overlap) +{ + static const float g_twid3[6] = { 0.79335334f,0.92387953f,0.99144486f, 0.60876143f,0.38268343f,0.13052619f }; + float co[3], si[3]; + int i; + + L3_idct3(-x[0], x[6] + x[3], x[12] + x[9], co); + L3_idct3(x[15], x[12] - x[9], x[6] - x[3], si); + si[1] = -si[1]; + + for (i = 0; i < 3; i++) + { + float ovl = overlap[i]; + float sum = co[i]*g_twid3[3 + i] + si[i]*g_twid3[0 + i]; + overlap[i] = co[i]*g_twid3[0 + i] - si[i]*g_twid3[3 + i]; + dst[i] = ovl*g_twid3[2 - i] - sum*g_twid3[5 - i]; + dst[5 - i] = ovl*g_twid3[5 - i] + sum*g_twid3[2 - i]; + } +} + +static void L3_imdct_short(float *grbuf, float *overlap, int nbands) +{ + for (;nbands > 0; nbands--, overlap += 9, grbuf += 18) + { + float tmp[18]; + memcpy(tmp, grbuf, sizeof(tmp)); + memcpy(grbuf, overlap, 6*sizeof(float)); + L3_imdct12(tmp, grbuf + 6, overlap + 6); + L3_imdct12(tmp + 1, grbuf + 12, overlap + 6); + L3_imdct12(tmp + 2, overlap, overlap + 6); + } +} + +static void L3_change_sign(float *grbuf) +{ + int b, i; + for (b = 0, grbuf += 18; b < 32; b += 2, grbuf += 36) + for (i = 1; i < 18; i += 2) + grbuf[i] = -grbuf[i]; +} + +static void L3_imdct_gr(float *grbuf, float *overlap, unsigned block_type, unsigned n_long_bands) +{ + static const float g_mdct_window[2][18] = { + { 0.99904822f,0.99144486f,0.97629601f,0.95371695f,0.92387953f,0.88701083f,0.84339145f,0.79335334f,0.73727734f,0.04361938f,0.13052619f,0.21643961f,0.30070580f,0.38268343f,0.46174861f,0.53729961f,0.60876143f,0.67559021f }, + { 1,1,1,1,1,1,0.99144486f,0.92387953f,0.79335334f,0,0,0,0,0,0,0.13052619f,0.38268343f,0.60876143f } + }; + if (n_long_bands) + { + L3_imdct36(grbuf, overlap, g_mdct_window[0], n_long_bands); + grbuf += 18*n_long_bands; + overlap += 9*n_long_bands; + } + if (block_type == SHORT_BLOCK_TYPE) + L3_imdct_short(grbuf, overlap, 32 - n_long_bands); + else + L3_imdct36(grbuf, overlap, g_mdct_window[block_type == STOP_BLOCK_TYPE], 32 - n_long_bands); +} + +static void L3_save_reservoir(mp3dec_t *h, mp3dec_scratch_t *s) +{ + int pos = (s->bs.pos + 7)/8u; + int remains = s->bs.limit/8u - pos; + if (remains > MAX_BITRESERVOIR_BYTES) + { + pos += remains - MAX_BITRESERVOIR_BYTES; + remains = MAX_BITRESERVOIR_BYTES; + } + if (remains > 0) + { + memmove(h->reserv_buf, s->maindata + pos, remains); + } + h->reserv = remains; +} + +static int L3_restore_reservoir(mp3dec_t *h, bs_t *bs, mp3dec_scratch_t *s, int main_data_begin) +{ + int frame_bytes = (bs->limit - bs->pos)/8; + int bytes_have = MINIMP3_MIN(h->reserv, main_data_begin); + memcpy(s->maindata, h->reserv_buf + MINIMP3_MAX(0, h->reserv - main_data_begin), MINIMP3_MIN(h->reserv, main_data_begin)); + memcpy(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes); + bs_init(&s->bs, s->maindata, bytes_have + frame_bytes); + return h->reserv >= main_data_begin; +} + +static void L3_decode(mp3dec_t *h, mp3dec_scratch_t *s, L3_gr_info_t *gr_info, int nch) +{ + int ch; + + for (ch = 0; ch < nch; ch++) + { + int layer3gr_limit = s->bs.pos + gr_info[ch].part_23_length; + L3_decode_scalefactors(h->header, s->ist_pos[ch], &s->bs, gr_info + ch, s->scf, ch); + L3_huffman(s->grbuf[ch], &s->bs, gr_info + ch, s->scf, layer3gr_limit); + } + + if (HDR_TEST_I_STEREO(h->header)) + { + L3_intensity_stereo(s->grbuf[0], s->ist_pos[1], gr_info, h->header); + } else if (HDR_IS_MS_STEREO(h->header)) + { + L3_midside_stereo(s->grbuf[0], 576); + } + + for (ch = 0; ch < nch; ch++, gr_info++) + { + int aa_bands = 31; + int n_long_bands = (gr_info->mixed_block_flag ? 2 : 0) << (int)(HDR_GET_MY_SAMPLE_RATE(h->header) == 2); + + if (gr_info->n_short_sfb) + { + aa_bands = n_long_bands - 1; + L3_reorder(s->grbuf[ch] + n_long_bands*18, s->syn[0], gr_info->sfbtab + gr_info->n_long_sfb); + } + + L3_antialias(s->grbuf[ch], aa_bands); + L3_imdct_gr(s->grbuf[ch], h->mdct_overlap[ch], gr_info->block_type, n_long_bands); + L3_change_sign(s->grbuf[ch]); + } +} + +static void mp3d_DCT_II(float *grbuf, int n) +{ + static const float g_sec[24] = { + 10.19000816f,0.50060302f,0.50241929f,3.40760851f,0.50547093f,0.52249861f,2.05778098f,0.51544732f,0.56694406f,1.48416460f,0.53104258f,0.64682180f,1.16943991f,0.55310392f,0.78815460f,0.97256821f,0.58293498f,1.06067765f,0.83934963f,0.62250412f,1.72244716f,0.74453628f,0.67480832f,5.10114861f + }; + int i, k = 0; +#if HAVE_SIMD + if (have_simd()) for (; k < n; k += 4) + { + f4 t[4][8], *x; + float *y = grbuf + k; + + for (x = t[0], i = 0; i < 8; i++, x++) + { + f4 x0 = VLD(&y[i*18]); + f4 x1 = VLD(&y[(15 - i)*18]); + f4 x2 = VLD(&y[(16 + i)*18]); + f4 x3 = VLD(&y[(31 - i)*18]); + f4 t0 = VADD(x0, x3); + f4 t1 = VADD(x1, x2); + f4 t2 = VMUL_S(VSUB(x1, x2), g_sec[3*i + 0]); + f4 t3 = VMUL_S(VSUB(x0, x3), g_sec[3*i + 1]); + x[0] = VADD(t0, t1); + x[8] = VMUL_S(VSUB(t0, t1), g_sec[3*i + 2]); + x[16] = VADD(t3, t2); + x[24] = VMUL_S(VSUB(t3, t2), g_sec[3*i + 2]); + } + for (x = t[0], i = 0; i < 4; i++, x += 8) + { + f4 x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt; + xt = VSUB(x0, x7); x0 = VADD(x0, x7); + x7 = VSUB(x1, x6); x1 = VADD(x1, x6); + x6 = VSUB(x2, x5); x2 = VADD(x2, x5); + x5 = VSUB(x3, x4); x3 = VADD(x3, x4); + x4 = VSUB(x0, x3); x0 = VADD(x0, x3); + x3 = VSUB(x1, x2); x1 = VADD(x1, x2); + x[0] = VADD(x0, x1); + x[4] = VMUL_S(VSUB(x0, x1), 0.70710677f); + x5 = VADD(x5, x6); + x6 = VMUL_S(VADD(x6, x7), 0.70710677f); + x7 = VADD(x7, xt); + x3 = VMUL_S(VADD(x3, x4), 0.70710677f); + x5 = VSUB(x5, VMUL_S(x7, 0.198912367f)); /* rotate by PI/8 */ + x7 = VADD(x7, VMUL_S(x5, 0.382683432f)); + x5 = VSUB(x5, VMUL_S(x7, 0.198912367f)); + x0 = VSUB(xt, x6); xt = VADD(xt, x6); + x[1] = VMUL_S(VADD(xt, x7), 0.50979561f); + x[2] = VMUL_S(VADD(x4, x3), 0.54119611f); + x[3] = VMUL_S(VSUB(x0, x5), 0.60134488f); + x[5] = VMUL_S(VADD(x0, x5), 0.89997619f); + x[6] = VMUL_S(VSUB(x4, x3), 1.30656302f); + x[7] = VMUL_S(VSUB(xt, x7), 2.56291556f); + } + + if (k > n - 3) + { +#if HAVE_SSE +#define VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v) +#else /* HAVE_SSE */ +#define VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18], vget_low_f32(v)) +#endif /* HAVE_SSE */ + for (i = 0; i < 7; i++, y += 4*18) + { + f4 s = VADD(t[3][i], t[3][i + 1]); + VSAVE2(0, t[0][i]); + VSAVE2(1, VADD(t[2][i], s)); + VSAVE2(2, VADD(t[1][i], t[1][i + 1])); + VSAVE2(3, VADD(t[2][1 + i], s)); + } + VSAVE2(0, t[0][7]); + VSAVE2(1, VADD(t[2][7], t[3][7])); + VSAVE2(2, t[1][7]); + VSAVE2(3, t[3][7]); + } else + { +#define VSAVE4(i, v) VSTORE(&y[i*18], v) + for (i = 0; i < 7; i++, y += 4*18) + { + f4 s = VADD(t[3][i], t[3][i + 1]); + VSAVE4(0, t[0][i]); + VSAVE4(1, VADD(t[2][i], s)); + VSAVE4(2, VADD(t[1][i], t[1][i + 1])); + VSAVE4(3, VADD(t[2][1 + i], s)); + } + VSAVE4(0, t[0][7]); + VSAVE4(1, VADD(t[2][7], t[3][7])); + VSAVE4(2, t[1][7]); + VSAVE4(3, t[3][7]); + } + } else +#endif /* HAVE_SIMD */ +#ifdef MINIMP3_ONLY_SIMD + {} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */ +#else /* MINIMP3_ONLY_SIMD */ + for (; k < n; k++) + { + float t[4][8], *x, *y = grbuf + k; + + for (x = t[0], i = 0; i < 8; i++, x++) + { + float x0 = y[i*18]; + float x1 = y[(15 - i)*18]; + float x2 = y[(16 + i)*18]; + float x3 = y[(31 - i)*18]; + float t0 = x0 + x3; + float t1 = x1 + x2; + float t2 = (x1 - x2)*g_sec[3*i + 0]; + float t3 = (x0 - x3)*g_sec[3*i + 1]; + x[0] = t0 + t1; + x[8] = (t0 - t1)*g_sec[3*i + 2]; + x[16] = t3 + t2; + x[24] = (t3 - t2)*g_sec[3*i + 2]; + } + for (x = t[0], i = 0; i < 4; i++, x += 8) + { + float x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt; + xt = x0 - x7; x0 += x7; + x7 = x1 - x6; x1 += x6; + x6 = x2 - x5; x2 += x5; + x5 = x3 - x4; x3 += x4; + x4 = x0 - x3; x0 += x3; + x3 = x1 - x2; x1 += x2; + x[0] = x0 + x1; + x[4] = (x0 - x1)*0.70710677f; + x5 = x5 + x6; + x6 = (x6 + x7)*0.70710677f; + x7 = x7 + xt; + x3 = (x3 + x4)*0.70710677f; + x5 -= x7*0.198912367f; /* rotate by PI/8 */ + x7 += x5*0.382683432f; + x5 -= x7*0.198912367f; + x0 = xt - x6; xt += x6; + x[1] = (xt + x7)*0.50979561f; + x[2] = (x4 + x3)*0.54119611f; + x[3] = (x0 - x5)*0.60134488f; + x[5] = (x0 + x5)*0.89997619f; + x[6] = (x4 - x3)*1.30656302f; + x[7] = (xt - x7)*2.56291556f; + + } + for (i = 0; i < 7; i++, y += 4*18) + { + y[0*18] = t[0][i]; + y[1*18] = t[2][i] + t[3][i] + t[3][i + 1]; + y[2*18] = t[1][i] + t[1][i + 1]; + y[3*18] = t[2][i + 1] + t[3][i] + t[3][i + 1]; + } + y[0*18] = t[0][7]; + y[1*18] = t[2][7] + t[3][7]; + y[2*18] = t[1][7]; + y[3*18] = t[3][7]; + } +#endif /* MINIMP3_ONLY_SIMD */ +} + +#ifndef MINIMP3_FLOAT_OUTPUT +static int16_t mp3d_scale_pcm(float sample) +{ +#if HAVE_ARMV6 + int32_t s32 = (int32_t)(sample + .5f); + s32 -= (s32 < 0); + int16_t s = (int16_t)minimp3_clip_int16_arm(s32); +#else + if (sample >= 32766.5) return (int16_t) 32767; + if (sample <= -32767.5) return (int16_t)-32768; + int16_t s = (int16_t)(sample + .5f); + s -= (s < 0); /* away from zero, to be compliant */ +#endif + return s; +} +#else /* MINIMP3_FLOAT_OUTPUT */ +static float mp3d_scale_pcm(float sample) +{ + return sample*(1.f/32768.f); +} +#endif /* MINIMP3_FLOAT_OUTPUT */ + +static void mp3d_synth_pair(mp3d_sample_t *pcm, int nch, const float *z) +{ + float a; + a = (z[14*64] - z[ 0]) * 29; + a += (z[ 1*64] + z[13*64]) * 213; + a += (z[12*64] - z[ 2*64]) * 459; + a += (z[ 3*64] + z[11*64]) * 2037; + a += (z[10*64] - z[ 4*64]) * 5153; + a += (z[ 5*64] + z[ 9*64]) * 6574; + a += (z[ 8*64] - z[ 6*64]) * 37489; + a += z[ 7*64] * 75038; + pcm[0] = mp3d_scale_pcm(a); + + z += 2; + a = z[14*64] * 104; + a += z[12*64] * 1567; + a += z[10*64] * 9727; + a += z[ 8*64] * 64019; + a += z[ 6*64] * -9975; + a += z[ 4*64] * -45; + a += z[ 2*64] * 146; + a += z[ 0*64] * -5; + pcm[16*nch] = mp3d_scale_pcm(a); +} + +static void mp3d_synth(float *xl, mp3d_sample_t *dstl, int nch, float *lins) +{ + int i; + float *xr = xl + 576*(nch - 1); + mp3d_sample_t *dstr = dstl + (nch - 1); + + static const float g_win[] = { + -1,26,-31,208,218,401,-519,2063,2000,4788,-5517,7134,5959,35640,-39336,74992, + -1,24,-35,202,222,347,-581,2080,1952,4425,-5879,7640,5288,33791,-41176,74856, + -1,21,-38,196,225,294,-645,2087,1893,4063,-6237,8092,4561,31947,-43006,74630, + -1,19,-41,190,227,244,-711,2085,1822,3705,-6589,8492,3776,30112,-44821,74313, + -1,17,-45,183,228,197,-779,2075,1739,3351,-6935,8840,2935,28289,-46617,73908, + -1,16,-49,176,228,153,-848,2057,1644,3004,-7271,9139,2037,26482,-48390,73415, + -2,14,-53,169,227,111,-919,2032,1535,2663,-7597,9389,1082,24694,-50137,72835, + -2,13,-58,161,224,72,-991,2001,1414,2330,-7910,9592,70,22929,-51853,72169, + -2,11,-63,154,221,36,-1064,1962,1280,2006,-8209,9750,-998,21189,-53534,71420, + -2,10,-68,147,215,2,-1137,1919,1131,1692,-8491,9863,-2122,19478,-55178,70590, + -3,9,-73,139,208,-29,-1210,1870,970,1388,-8755,9935,-3300,17799,-56778,69679, + -3,8,-79,132,200,-57,-1283,1817,794,1095,-8998,9966,-4533,16155,-58333,68692, + -4,7,-85,125,189,-83,-1356,1759,605,814,-9219,9959,-5818,14548,-59838,67629, + -4,7,-91,117,177,-106,-1428,1698,402,545,-9416,9916,-7154,12980,-61289,66494, + -5,6,-97,111,163,-127,-1498,1634,185,288,-9585,9838,-8540,11455,-62684,65290 + }; + float *zlin = lins + 15*64; + const float *w = g_win; + + zlin[4*15] = xl[18*16]; + zlin[4*15 + 1] = xr[18*16]; + zlin[4*15 + 2] = xl[0]; + zlin[4*15 + 3] = xr[0]; + + zlin[4*31] = xl[1 + 18*16]; + zlin[4*31 + 1] = xr[1 + 18*16]; + zlin[4*31 + 2] = xl[1]; + zlin[4*31 + 3] = xr[1]; + + mp3d_synth_pair(dstr, nch, lins + 4*15 + 1); + mp3d_synth_pair(dstr + 32*nch, nch, lins + 4*15 + 64 + 1); + mp3d_synth_pair(dstl, nch, lins + 4*15); + mp3d_synth_pair(dstl + 32*nch, nch, lins + 4*15 + 64); + +#if HAVE_SIMD + if (have_simd()) for (i = 14; i >= 0; i--) + { +#define VLOAD(k) f4 w0 = VSET(*w++); f4 w1 = VSET(*w++); f4 vz = VLD(&zlin[4*i - 64*k]); f4 vy = VLD(&zlin[4*i - 64*(15 - k)]); +#define V0(k) { VLOAD(k) b = VADD(VMUL(vz, w1), VMUL(vy, w0)) ; a = VSUB(VMUL(vz, w0), VMUL(vy, w1)); } +#define V1(k) { VLOAD(k) b = VADD(b, VADD(VMUL(vz, w1), VMUL(vy, w0))); a = VADD(a, VSUB(VMUL(vz, w0), VMUL(vy, w1))); } +#define V2(k) { VLOAD(k) b = VADD(b, VADD(VMUL(vz, w1), VMUL(vy, w0))); a = VADD(a, VSUB(VMUL(vy, w1), VMUL(vz, w0))); } + f4 a, b; + zlin[4*i] = xl[18*(31 - i)]; + zlin[4*i + 1] = xr[18*(31 - i)]; + zlin[4*i + 2] = xl[1 + 18*(31 - i)]; + zlin[4*i + 3] = xr[1 + 18*(31 - i)]; + zlin[4*i + 64] = xl[1 + 18*(1 + i)]; + zlin[4*i + 64 + 1] = xr[1 + 18*(1 + i)]; + zlin[4*i - 64 + 2] = xl[18*(1 + i)]; + zlin[4*i - 64 + 3] = xr[18*(1 + i)]; + + V0(0) V2(1) V1(2) V2(3) V1(4) V2(5) V1(6) V2(7) + + { +#ifndef MINIMP3_FLOAT_OUTPUT +#if HAVE_SSE + static const f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; + static const f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; + __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), + _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); + dstr[(15 - i)*nch] = _mm_extract_epi16(pcm8, 1); + dstr[(17 + i)*nch] = _mm_extract_epi16(pcm8, 5); + dstl[(15 - i)*nch] = _mm_extract_epi16(pcm8, 0); + dstl[(17 + i)*nch] = _mm_extract_epi16(pcm8, 4); + dstr[(47 - i)*nch] = _mm_extract_epi16(pcm8, 3); + dstr[(49 + i)*nch] = _mm_extract_epi16(pcm8, 7); + dstl[(47 - i)*nch] = _mm_extract_epi16(pcm8, 2); + dstl[(49 + i)*nch] = _mm_extract_epi16(pcm8, 6); +#else /* HAVE_SSE */ + int16x4_t pcma, pcmb; + a = VADD(a, VSET(0.5f)); + b = VADD(b, VSET(0.5f)); + pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, VSET(0))))); + pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, VSET(0))))); + vst1_lane_s16(dstr + (15 - i)*nch, pcma, 1); + vst1_lane_s16(dstr + (17 + i)*nch, pcmb, 1); + vst1_lane_s16(dstl + (15 - i)*nch, pcma, 0); + vst1_lane_s16(dstl + (17 + i)*nch, pcmb, 0); + vst1_lane_s16(dstr + (47 - i)*nch, pcma, 3); + vst1_lane_s16(dstr + (49 + i)*nch, pcmb, 3); + vst1_lane_s16(dstl + (47 - i)*nch, pcma, 2); + vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2); +#endif /* HAVE_SSE */ + +#else /* MINIMP3_FLOAT_OUTPUT */ + + static const f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f }; + a = VMUL(a, g_scale); + b = VMUL(b, g_scale); +#if HAVE_SSE + _mm_store_ss(dstr + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1))); + _mm_store_ss(dstr + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1))); + _mm_store_ss(dstl + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_store_ss(dstl + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_store_ss(dstr + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstr + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstl + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2))); + _mm_store_ss(dstl + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 2, 2, 2))); +#else /* HAVE_SSE */ + vst1q_lane_f32(dstr + (15 - i)*nch, a, 1); + vst1q_lane_f32(dstr + (17 + i)*nch, b, 1); + vst1q_lane_f32(dstl + (15 - i)*nch, a, 0); + vst1q_lane_f32(dstl + (17 + i)*nch, b, 0); + vst1q_lane_f32(dstr + (47 - i)*nch, a, 3); + vst1q_lane_f32(dstr + (49 + i)*nch, b, 3); + vst1q_lane_f32(dstl + (47 - i)*nch, a, 2); + vst1q_lane_f32(dstl + (49 + i)*nch, b, 2); +#endif /* HAVE_SSE */ +#endif /* MINIMP3_FLOAT_OUTPUT */ + } + } else +#endif /* HAVE_SIMD */ +#ifdef MINIMP3_ONLY_SIMD + {} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */ +#else /* MINIMP3_ONLY_SIMD */ + for (i = 14; i >= 0; i--) + { +#define LOAD(k) float w0 = *w++; float w1 = *w++; float *vz = &zlin[4*i - k*64]; float *vy = &zlin[4*i - (15 - k)*64]; +#define S0(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] = vz[j]*w1 + vy[j]*w0, a[j] = vz[j]*w0 - vy[j]*w1; } +#define S1(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vz[j]*w0 - vy[j]*w1; } +#define S2(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vy[j]*w1 - vz[j]*w0; } + float a[4], b[4]; + + zlin[4*i] = xl[18*(31 - i)]; + zlin[4*i + 1] = xr[18*(31 - i)]; + zlin[4*i + 2] = xl[1 + 18*(31 - i)]; + zlin[4*i + 3] = xr[1 + 18*(31 - i)]; + zlin[4*(i + 16)] = xl[1 + 18*(1 + i)]; + zlin[4*(i + 16) + 1] = xr[1 + 18*(1 + i)]; + zlin[4*(i - 16) + 2] = xl[18*(1 + i)]; + zlin[4*(i - 16) + 3] = xr[18*(1 + i)]; + + S0(0) S2(1) S1(2) S2(3) S1(4) S2(5) S1(6) S2(7) + + dstr[(15 - i)*nch] = mp3d_scale_pcm(a[1]); + dstr[(17 + i)*nch] = mp3d_scale_pcm(b[1]); + dstl[(15 - i)*nch] = mp3d_scale_pcm(a[0]); + dstl[(17 + i)*nch] = mp3d_scale_pcm(b[0]); + dstr[(47 - i)*nch] = mp3d_scale_pcm(a[3]); + dstr[(49 + i)*nch] = mp3d_scale_pcm(b[3]); + dstl[(47 - i)*nch] = mp3d_scale_pcm(a[2]); + dstl[(49 + i)*nch] = mp3d_scale_pcm(b[2]); + } +#endif /* MINIMP3_ONLY_SIMD */ +} + +static void mp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, mp3d_sample_t *pcm, float *lins) +{ + int i; + for (i = 0; i < nch; i++) + { + mp3d_DCT_II(grbuf + 576*i, nbands); + } + + memcpy(lins, qmf_state, sizeof(float)*15*64); + + for (i = 0; i < nbands; i += 2) + { + mp3d_synth(grbuf + i, pcm + 32*nch*i, nch, lins + i*64); + } +#ifndef MINIMP3_NONSTANDARD_BUT_LOGICAL + if (nch == 1) + { + for (i = 0; i < 15*64; i += 2) + { + qmf_state[i] = lins[nbands*64 + i]; + } + } else +#endif /* MINIMP3_NONSTANDARD_BUT_LOGICAL */ + { + memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64); + } +} + +static int mp3d_match_frame(const uint8_t *hdr, int mp3_bytes, int frame_bytes) +{ + int i, nmatch; + for (i = 0, nmatch = 0; nmatch < MAX_FRAME_SYNC_MATCHES; nmatch++) + { + i += hdr_frame_bytes(hdr + i, frame_bytes) + hdr_padding(hdr + i); + if (i + HDR_SIZE > mp3_bytes) + return nmatch > 0; + if (!hdr_compare(hdr, hdr + i)) + return 0; + } + return 1; +} + +static int mp3d_find_frame(const uint8_t *mp3, int mp3_bytes, int *free_format_bytes, int *ptr_frame_bytes) +{ + int i, k; + for (i = 0; i < mp3_bytes - HDR_SIZE; i++, mp3++) + { + if (hdr_valid(mp3)) + { + int frame_bytes = hdr_frame_bytes(mp3, *free_format_bytes); + int frame_and_padding = frame_bytes + hdr_padding(mp3); + + for (k = HDR_SIZE; !frame_bytes && k < MAX_FREE_FORMAT_FRAME_SIZE && i + 2*k < mp3_bytes - HDR_SIZE; k++) + { + if (hdr_compare(mp3, mp3 + k)) + { + int fb = k - hdr_padding(mp3); + int nextfb = fb + hdr_padding(mp3 + k); + if (i + k + nextfb + HDR_SIZE > mp3_bytes || !hdr_compare(mp3, mp3 + k + nextfb)) + continue; + frame_and_padding = k; + frame_bytes = fb; + *free_format_bytes = fb; + } + } + if ((frame_bytes && i + frame_and_padding <= mp3_bytes && + mp3d_match_frame(mp3, mp3_bytes - i, frame_bytes)) || + (!i && frame_and_padding == mp3_bytes)) + { + *ptr_frame_bytes = frame_and_padding; + return i; + } + *free_format_bytes = 0; + } + } + *ptr_frame_bytes = 0; + return mp3_bytes; +} + +void mp3dec_init(mp3dec_t *dec) +{ + dec->header[0] = 0; +} + +int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info) +{ + int i = 0, igr, frame_size = 0, success = 1; + const uint8_t *hdr; + bs_t bs_frame[1]; + mp3dec_scratch_t scratch; + + if (mp3_bytes > 4 && dec->header[0] == 0xff && hdr_compare(dec->header, mp3)) + { + frame_size = hdr_frame_bytes(mp3, dec->free_format_bytes) + hdr_padding(mp3); + if (frame_size != mp3_bytes && (frame_size + HDR_SIZE > mp3_bytes || !hdr_compare(mp3, mp3 + frame_size))) + { + frame_size = 0; + } + } + if (!frame_size) + { + memset(dec, 0, sizeof(mp3dec_t)); + i = mp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size); + if (!frame_size || i + frame_size > mp3_bytes) + { + info->frame_bytes = i; + return 0; + } + } + + hdr = mp3 + i; + memcpy(dec->header, hdr, HDR_SIZE); + info->frame_bytes = i + frame_size; + info->frame_offset = i; + info->channels = HDR_IS_MONO(hdr) ? 1 : 2; + info->hz = hdr_sample_rate_hz(hdr); + info->layer = 4 - HDR_GET_LAYER(hdr); + info->bitrate_kbps = hdr_bitrate_kbps(hdr); + + if (!pcm) + { + return hdr_frame_samples(hdr); + } + + bs_init(bs_frame, hdr + HDR_SIZE, frame_size - HDR_SIZE); + if (HDR_IS_CRC(hdr)) + { + get_bits(bs_frame, 16); + } + + if (info->layer == 3) + { + int main_data_begin = L3_read_side_info(bs_frame, scratch.gr_info, hdr); + if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit) + { + mp3dec_init(dec); + return 0; + } + success = L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin); + if (success) + { + for (igr = 0; igr < (HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm += 576*info->channels) + { + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels); + mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, pcm, scratch.syn[0]); + } + } + L3_save_reservoir(dec, &scratch); + } else + { +#ifdef MINIMP3_ONLY_MP3 + return 0; +#else /* MINIMP3_ONLY_MP3 */ + L12_scale_info sci[1]; + L12_read_scale_info(hdr, bs_frame, sci); + + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + for (i = 0, igr = 0; igr < 3; igr++) + { + if (12 == (i += L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1))) + { + i = 0; + L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]); + mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, pcm, scratch.syn[0]); + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + pcm += 384*info->channels; + } + if (bs_frame->pos > bs_frame->limit) + { + mp3dec_init(dec); + return 0; + } + } +#endif /* MINIMP3_ONLY_MP3 */ + } + return success*hdr_frame_samples(dec->header); +} + +#ifdef MINIMP3_FLOAT_OUTPUT +void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples) +{ + int i = 0; +#if HAVE_SIMD + int aligned_count = num_samples & ~7; + for(; i < aligned_count; i += 8) + { + static const f4 g_scale = { 32768.0f, 32768.0f, 32768.0f, 32768.0f }; + f4 a = VMUL(VLD(&in[i ]), g_scale); + f4 b = VMUL(VLD(&in[i+4]), g_scale); +#if HAVE_SSE + static const f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; + static const f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; + __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), + _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); + out[i ] = _mm_extract_epi16(pcm8, 0); + out[i+1] = _mm_extract_epi16(pcm8, 1); + out[i+2] = _mm_extract_epi16(pcm8, 2); + out[i+3] = _mm_extract_epi16(pcm8, 3); + out[i+4] = _mm_extract_epi16(pcm8, 4); + out[i+5] = _mm_extract_epi16(pcm8, 5); + out[i+6] = _mm_extract_epi16(pcm8, 6); + out[i+7] = _mm_extract_epi16(pcm8, 7); +#else /* HAVE_SSE */ + int16x4_t pcma, pcmb; + a = VADD(a, VSET(0.5f)); + b = VADD(b, VSET(0.5f)); + pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, VSET(0))))); + pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, VSET(0))))); + vst1_lane_s16(out+i , pcma, 0); + vst1_lane_s16(out+i+1, pcma, 1); + vst1_lane_s16(out+i+2, pcma, 2); + vst1_lane_s16(out+i+3, pcma, 3); + vst1_lane_s16(out+i+4, pcmb, 0); + vst1_lane_s16(out+i+5, pcmb, 1); + vst1_lane_s16(out+i+6, pcmb, 2); + vst1_lane_s16(out+i+7, pcmb, 3); +#endif /* HAVE_SSE */ + } +#endif /* HAVE_SIMD */ + for(; i < num_samples; i++) + { + float sample = in[i] * 32768.0f; + if (sample >= 32766.5) + out[i] = (int16_t) 32767; + else if (sample <= -32767.5) + out[i] = (int16_t)-32768; + else + { + int16_t s = (int16_t)(sample + .5f); + s -= (s < 0); /* away from zero, to be compliant */ + out[i] = s; + } + } +} +#endif /* MINIMP3_FLOAT_OUTPUT */ +#endif /* MINIMP3_IMPLEMENTATION && !_MINIMP3_IMPLEMENTATION_GUARD */ diff --git a/data/formats/mp3/readme.md b/data/formats/mp3/readme.md new file mode 100644 index 0000000..a6d53bc --- /dev/null +++ b/data/formats/mp3/readme.md @@ -0,0 +1 @@ +https://github.com/lieff/minimp3