Tasmota/lib/libesp32/JPEGDEC/linux/main.c

302 lines
8.7 KiB
C

// JPEG perf test
// Written by Larry Bank
//
// Will open an arbitrary JPEG file if passed on the command line
// or will use the sample image (tulips)
//
#include <stdint.h>
#include <string.h>
#include <time.h>
#include "JPEGDEC.h"
#include "jpeg.inl"
#include "../test_images/tulips.h"
// Human readable error messages
const char *szErrors[] = {"Success", "Invalid parameter", "Decode error", "Unsupported feature", "Invalid file"};
/* Windows BMP header for RGB565 images */
uint8_t winbmphdr_rgb565[138] =
{0x42,0x4d,0,0,0,0,0,0,0,0,0x8a,0,0,0,0x7c,0,
0,0,0,0,0,0,0,0,0,0,1,0,8,0,3,0,
0,0,0,0,0,0,0x13,0x0b,0,0,0x13,0x0b,0,0,0,0,
0,0,0,0,0,0,0,0xf8,0,0,0xe0,0x07,0,0,0x1f,0,
0,0,0,0,0,0,0x42,0x47,0x52,0x73,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0};
/* Windows BMP header for 8/24/32-bit images (54 bytes) */
uint8_t winbmphdr[54] =
{0x42,0x4d,
0,0,0,0, /* File size */
0,0,0,0,0x36,4,0,0,0x28,0,0,0,
0,0,0,0, /* Xsize */
0,0,0,0, /* Ysize */
1,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* number of planes, bits per pel */
0,0,0,0};
JPEGIMAGE jpg;
uint8_t *pFrame;
int iDestPitch;
//uint8_t ucDitherBuffer[1024 * 16];
int ucPixelType = RGB565_BIG_ENDIAN; // default output used for SPI LCDs
//
// Minimal code to save frames as Windows BMP files
//
void WriteBMP(char *fname, uint8_t *pBitmap, uint8_t *pPalette, int cx, int cy, int bpp, int iDestPitch)
{
FILE * oHandle;
int i, bsize, lsize;
uint32_t *l;
uint8_t *s;
uint8_t *ucTemp;
uint8_t *pHdr;
int iHeaderSize;
ucTemp = (uint8_t *)malloc(cx * 4);
if (bpp == 16) {
pHdr = winbmphdr_rgb565;
iHeaderSize = sizeof(winbmphdr_rgb565);
} else {
pHdr = winbmphdr;
iHeaderSize = sizeof(winbmphdr);
}
oHandle = fopen(fname, "w+b");
bsize = (cx * bpp) >> 3;
lsize = (bsize + 3) & 0xfffc; /* Width of each line */
pHdr[26] = 1; // number of planes
pHdr[28] = (uint8_t)bpp;
/* Write the BMP header */
l = (uint32_t *)&pHdr[2];
i =(cy * lsize) + iHeaderSize;
if (bpp <= 8)
i += 1024;
*l = (uint32_t)i; /* Store the file size */
l = (uint32_t *)&pHdr[34]; // data size
i = (cy * lsize);
*l = (uint32_t)i; // store data size
l = (uint32_t *)&pHdr[18];
*l = (uint32_t)cx; /* width */
*(l+1) = (uint32_t)cy; /* height */
l = (uint32_t *)&pHdr[10]; // OFFBITS
if (bpp <= 8) {
*l = iHeaderSize + 1024;
} else { // no palette
*l = iHeaderSize;
}
fwrite(pHdr, 1, iHeaderSize, oHandle);
if (bpp <= 8) {
if (pPalette == NULL) {// create a grayscale palette
int iDelta, iCount = 1<<bpp;
int iGray = 0;
iDelta = 255/(iCount-1);
for (i=0; i<iCount; i++) {
ucTemp[i*4+0] = (uint8_t)iGray;
ucTemp[i*4+1] = (uint8_t)iGray;
ucTemp[i*4+2] = (uint8_t)iGray;
ucTemp[i*4+3] = 0;
iGray += iDelta;
}
} else {
for (i=0; i<256; i++) // change palette to WinBMP format
{
ucTemp[i*4 + 0] = pPalette[(i*3)+2];
ucTemp[i*4 + 1] = pPalette[(i*3)+1];
ucTemp[i*4 + 2] = pPalette[(i*3)+0];
ucTemp[i*4 + 3] = 0;
}
}
fwrite(ucTemp, 1, 1024, oHandle);
} // palette write
/* Write the image data */
for (i=cy-1; i>=0; i--)
{
s = &pBitmap[i*iDestPitch];
if (bpp == 24) { // swap R/B for Windows BMP byte order
int j, iBpp = bpp/8;
uint8_t *d = ucTemp;
for (j=0; j<cx; j++) {
d[0] = s[2]; d[1] = s[1]; d[2] = s[0];
d += iBpp; s += iBpp;
}
fwrite(ucTemp, 1, (size_t)lsize, oHandle);
} else {
fwrite(s, 1, (size_t)lsize, oHandle);
}
}
free(ucTemp);
fclose(oHandle);
} /* WriteBMP() */
long micros(void)
{
long iTime;
struct timespec res;
clock_gettime(CLOCK_MONOTONIC, &res);
iTime = 1000000*res.tv_sec + res.tv_nsec/1000;
return iTime;
} /* micros() */
int ConvertFileTest(char *argv[], int iFraction)
{
int i, rc;
int cx, cy, bpp;
int iOption;
long lTime;
if (iFraction == 2) {
iOption = JPEG_SCALE_HALF;
} else if (iFraction == 4) {
iOption = JPEG_SCALE_QUARTER;
} else if (iFraction == 8) {
iOption = JPEG_SCALE_EIGHTH;
} else {
iOption = 0; // full size
}
ucPixelType = RGB565_LITTLE_ENDIAN; //RGB8888; // generate 32-bit pixels for a Windows BMP file
rc = JPEG_openFile(&jpg, argv[1], NULL);
if (!rc) {
printf("Error opening file %s\n", argv[1]);
return -1;
}
cx = jpg.iWidth / iFraction;
cy = jpg.iHeight / iFraction;
cx = (cx + 7) & 0xfff8; // align on at least 16-byte boundary
if (ucPixelType == RGB8888) {
iDestPitch = (cx * 4); // 32-bits per pixel
bpp = 32;
} else {
iDestPitch = cx * 2; // 16-bpp
bpp = 16;
}
i = iDestPitch * (cy+15);
pFrame = (uint8_t *)malloc(i);
if (pFrame == NULL) {
printf("Error allocating %d bytes\n", i);
return -1;
}
JPEG_setFramebuffer(&jpg, pFrame);
jpg.ucPixelType = ucPixelType;
lTime = micros();
printf("Converting %d x %d image, fraction = %d\n", cx, cy, iFraction);
if (JPEG_decode(&jpg, 0, 0, iOption)) {
lTime = micros() - lTime;
printf("JPEG decoded in %d us\n", (int)lTime);
WriteBMP(argv[2], pFrame, NULL, cx, cy, bpp, iDestPitch);
} else {
printf("Decode failed, last error = %s\n", szErrors[JPEG_getLastError(&jpg)]);
return -1;
}
JPEG_close(&jpg);
return 0;
} /* ConvertFileTest() */
int JPEGDraw(JPEGDRAW *pDraw)
{
(void)pDraw;
return 1;
}
int PerfTest(int argc, char *argv[])
{
int rc;
long lTime;
// first test full size decoding
if (argc == 1) {
rc = JPEG_openRAM(&jpg, (uint8_t *)tulips, sizeof(tulips), JPEGDraw);
} else {
rc = JPEG_openFile(&jpg, argv[1], JPEGDraw);
}
if (rc)
{
lTime = micros();
// jpg.pDitherBuffer = ucDitherBuffer; // not used in this test
jpg.ucPixelType = ucPixelType;
if (JPEG_decode(&jpg, 0, 0, 0)) { // full size
lTime = micros() - lTime;
printf("full sized decode in %d us\n", (int)lTime);
} else {
printf("Decode failed, last error = %d\n", JPEG_getLastError(&jpg));
return 0;
}
JPEG_close(&jpg);
} else {
printf("open() failed, last error = %d\n", JPEG_getLastError(&jpg));
return -1;
}
// Half size scaled test
if (argc == 2)
rc = JPEG_openFile(&jpg, argv[1], JPEGDraw);
else
rc = JPEG_openRAM(&jpg, (uint8_t *)tulips, sizeof(tulips), JPEGDraw);
if (rc)
{
lTime = micros();
if (JPEG_decode(&jpg, 0, 0, JPEG_SCALE_HALF)) { // 1/2 size
lTime = micros() - lTime;
printf("half sized decode in %d us\n", (int)lTime);
}
JPEG_close(&jpg);
}
// Quarter size scaled test
if (argc == 2)
rc = JPEG_openFile(&jpg, argv[1], JPEGDraw);
else
rc = JPEG_openRAM(&jpg, (uint8_t *)tulips, sizeof(tulips), JPEGDraw);
if (rc)
{
lTime = micros();
if (JPEG_decode(&jpg, 0, 0, JPEG_SCALE_QUARTER)) { // 1/4 size
lTime = micros() - lTime;
printf("quarter sized decode in %d us\n", (int)lTime);
}
JPEG_close(&jpg);
}
// Eighth size scaled test
if (argc == 2)
rc = JPEG_openFile(&jpg, argv[1], JPEGDraw);
else
rc = JPEG_openRAM(&jpg, (uint8_t *)tulips, sizeof(tulips), JPEGDraw);
if (rc)
{
lTime = micros();
if (JPEG_decode(&jpg, 0, 0, JPEG_SCALE_EIGHTH)) { // 1/8 size
lTime = micros() - lTime;
printf("eighth sized decode in %d us\n", (int)lTime);
}
JPEG_close(&jpg);
}
return 0; // done
} /* PerfTest() */
int main(int argc, char *argv[])
{
int rc = -1;
printf("JPEG decoder demo\n");
printf("options:\n");
printf("Run without parameters to test in-memory decoding\n");
printf("Pass a single filename to test decoding performance\n");
printf("Pass 2 filenames to convert a JPEG file to a BMP file\n");
printf("e.g. ./jpegdec <infile.jpg> <outfile.bmp>\n\n");
if (argc == 1 || argc == 2) {
rc = PerfTest(argc, argv);
} else if (argc == 3) {
rc = ConvertFileTest(argv, 1); // change the 1 to 2/4/8 for fractional decode
} else {
printf("Invalid number of parameters (re-read the above)\n");
return rc;
}
return rc;
} /* main() */