5 Star 14 Fork 2

火星大王/SCNSLibrary

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
ScnsTjpgdec.c 37.21 KB
一键复制 编辑 原始数据 按行查看 历史
火星大王 提交于 2024-02-22 01:08 . scnsLikely,scnsUnlikely
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
#include "ScnsTjpgdec.h"
#if defined(SCNS_TJPGDEC_ENABLE)&&SCNS_TJPGDEC_ENABLE==1
#include "ScnsColor.h"
#include "ScnsMath.h"
#include "ScnsMalloc.h"
#include "ScnsMem.h"
#define INTERNAL_TEXT(x) __attribute__((section(".text.__scnsTjpgdec_" #x))) static
#define INTERNAL_BSS(x) __attribute__((section(".bss.__scnsTjpgdec_" #x))) static
#define INTERNAL_RODATA(x) __attribute__((section(".rodata.__scnsTjpgdec_" #x))) static const
#define INTERNAL_TEXT_RODATA(x,y) __attribute__((section(".rodata.__scnsTjpgdec_" #x "_" #y))) static const
#define JD_SZBUF 256 /* Specifies size of stream input buffer */
/*----------------------------------------------------------------------------/
/ TJpgDec - Tiny JPEG Decompressor R0.03 (C)ChaN, 2021
/-----------------------------------------------------------------------------/
/ The TJpgDec is a generic JPEG decompressor module for tiny embedded systems.
/ This is a free software that opened for education, research and commercial
/ developments under license policy of following terms.
/
/ Copyright (C) 2021, ChaN, all right reserved.
/
/ * The TJpgDec module is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/-----------------------------------------------------------------------------/
/ Oct 04, 2011 R0.01 First release.
/ Feb 19, 2012 R0.01a Fixed decompression fails when scan starts with an escape seq.
/ Sep 03, 2012 R0.01b Added JD_TBLCLIP option.
/ Mar 16, 2019 R0.01c Supprted stdint.h.
/ Jul 01, 2020 R0.01d Fixed wrong integer type usage.
/ May 08, 2021 R0.02 Supprted grayscale image. Separated configuration options.
/ Jun 11, 2021 R0.02a Some performance improvement.
/ Jul 01, 2021 R0.03 Added JD_FASTDECODE option.
/ Some performance improvement.
/----------------------------------------------------------------------------*/
INTERNAL_RODATA(Zig) uint8 Zig[64]={ /* Zigzag-order to raster-order conversion table */
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
};
INTERNAL_RODATA(Ipsf) uint16 Ipsf[64]={ /* See also aa_idct.png */
(uint16)(1.00000*8192),(uint16)(1.38704*8192),(uint16)(1.30656*8192),(uint16)(1.17588*8192),(uint16)(1.00000*8192),(uint16)(0.78570*8192),(uint16)(0.54120*8192),(uint16)(0.27590*8192),
(uint16)(1.38704*8192),(uint16)(1.92388*8192),(uint16)(1.81226*8192),(uint16)(1.63099*8192),(uint16)(1.38704*8192),(uint16)(1.08979*8192),(uint16)(0.75066*8192),(uint16)(0.38268*8192),
(uint16)(1.30656*8192),(uint16)(1.81226*8192),(uint16)(1.70711*8192),(uint16)(1.53636*8192),(uint16)(1.30656*8192),(uint16)(1.02656*8192),(uint16)(0.70711*8192),(uint16)(0.36048*8192),
(uint16)(1.17588*8192),(uint16)(1.63099*8192),(uint16)(1.53636*8192),(uint16)(1.38268*8192),(uint16)(1.17588*8192),(uint16)(0.92388*8192),(uint16)(0.63638*8192),(uint16)(0.32442*8192),
(uint16)(1.00000*8192),(uint16)(1.38704*8192),(uint16)(1.30656*8192),(uint16)(1.17588*8192),(uint16)(1.00000*8192),(uint16)(0.78570*8192),(uint16)(0.54120*8192),(uint16)(0.27590*8192),
(uint16)(0.78570*8192),(uint16)(1.08979*8192),(uint16)(1.02656*8192),(uint16)(0.92388*8192),(uint16)(0.78570*8192),(uint16)(0.61732*8192),(uint16)(0.42522*8192),(uint16)(0.21677*8192),
(uint16)(0.54120*8192),(uint16)(0.75066*8192),(uint16)(0.70711*8192),(uint16)(0.63638*8192),(uint16)(0.54120*8192),(uint16)(0.42522*8192),(uint16)(0.29290*8192),(uint16)(0.14932*8192),
(uint16)(0.27590*8192),(uint16)(0.38268*8192),(uint16)(0.36048*8192),(uint16)(0.32442*8192),(uint16)(0.27590*8192),(uint16)(0.21678*8192),(uint16)(0.14932*8192),(uint16)(0.07612*8192)
};
/**
* Create de-quantization and prescaling tables with a DQT segment
* @param jd Pointer to the decompressor object
* @param data Pointer to the quantizer tables
* @param ndata Size of input data
* @return 0:OK, !0:Failed
*/
INTERNAL_TEXT(create_qt_tbl) ScnsStatus create_qt_tbl(ScnsTjpgdec*jd,const uint8*data,ScnsSize ndata)
{
unsigned int i,zi;
uint8 d;
int32*pb;
while(ndata)
{ /* Process all tables in the segment */
if(ndata<65){return SCNS_STATUS_TJPGD_FMT1;} /* Err: table size is unaligned */
ndata-=65;
d=*data++; /* Get table property */
if(d&0xF0){return SCNS_STATUS_TJPGD_FMT1;} /* Err: not 8-bit resolution */
i=d&3; /* Get table ID */
pb=scnsMalloc(64*sizeof(int32)); /* Allocate a memory block for the table */
if(!pb){return SCNS_STATUS_MALLOC_FAILED;} /* Err: not enough memory */
jd->qttbl[i]=pb; /* Register the table */
for(i=0;i<64;i++)
{ /* Load the table */
zi=Zig[i]; /* Zigzag-order to raster-order conversion */
pb[zi]=(int32)((uint32)*data++*Ipsf[zi]); /* Apply scale factor of Arai algorithm to the de-quantizers */
}
}
return SCNS_STATUS_OK;
}
/**
* Create huffman code tables with a DHT segment
* @param jd Pointer to the decompressor object
* @param data Pointer to the packed huffman tables
* @param ndata Size of input data
* @return 0:OK, !0:Failed
*/
INTERNAL_TEXT(create_huffman_tbl) ScnsStatus create_huffman_tbl(ScnsTjpgdec*jd,const uint8*data,ScnsSize ndata)
{
unsigned int i,j,b,cls,num;
ScnsSize np;
uint8 d,*pb,*pd;
uint16 hc,*ph;
while(ndata) /* Process all tables in the segment */
{
if(ndata<17){return SCNS_STATUS_TJPGD_FMT1;} /* Err: wrong data size */
ndata-=17;
d=*data++; /* Get table number and class */
if(d&0xEE){return SCNS_STATUS_TJPGD_FMT1;} /* Err: invalid class/number */
cls=d>>4;
num=d&0x0F; /* class = dc(0)/ac(1), table number = 0/1 */
pb=scnsMalloc(16); /* Allocate a memory block for the bit distribution table */
if(!pb){return SCNS_STATUS_MALLOC_FAILED;} /* Err: not enough memory */
jd->huffbits[num][cls]=pb;
for(np=i=0;i<16;i++)
{ /* Load number of patterns for 1 to 16-bit code */
np+=(pb[i]=*data++); /* Get sum of code words for each code */
}
ph=scnsMalloc(np*sizeof(uint16)); /* Allocate a memory block for the code word table */
if(!ph){return SCNS_STATUS_MALLOC_FAILED;} /* Err: not enough memory */
jd->huffcode[num][cls]=ph;
hc=0;
for(j=i=0;i<16;i++) /* Re-build huffman code word table */
{
b=pb[i];
while(b--){ph[j++]=hc++;}
hc<<=1;
}
if(ndata<np){return SCNS_STATUS_TJPGD_FMT1;} /* Err: wrong data size */
ndata-=np;
pd=scnsMalloc(np); /* Allocate a memory block for the decoded data */
if(!pd){return SCNS_STATUS_MALLOC_FAILED;} /* Err: not enough memory */
jd->huffdata[num][cls]=pd;
for(i=0;i<np;i++) /* Load decoded data corresponds to each code word */
{
d=*data++;
if(!cls&&d>11){return SCNS_STATUS_TJPGD_FMT1;}
pd[i]=d;
}
}
return SCNS_STATUS_OK;
}
/**
* Extract a huffman decoded data from input stream
* @param jd Pointer to the decompressor object
* @param id Table ID (0:Y, 1:C)
* @param cls Table class (0:DC, 1:AC)
* @return >=0: decoded data, <0: error code
*/
INTERNAL_TEXT(huffext) int huffext(ScnsTjpgdec*jd,unsigned int id,unsigned int cls)
{
ScnsSize dc=jd->dctr;
uint8*dp=jd->dptr;
unsigned int d,flg=0;
const uint8*hb,*hd;
const uint16*hc;
unsigned int nc,bl,wbit=jd->dbit%32;
uint32 w=jd->wreg&((1UL<<wbit)-1);
while(wbit<16) /* Prepare 16 bits into the working register */
{
if(jd->marker)
{
d=0xFF; /* Input stream has stalled for a marker. Generate stuff bits */
}
else
{
if(!dc)
{ /* Buffer empty, re-fill input buffer */
dp=jd->inbuf; /* Top of input buffer */
dc=jd->infunc(jd,dp,JD_SZBUF);
if(!dc){return 0-(int)SCNS_STATUS_TJPGD_INP;} /* Err: read error or wrong stream termination */
}
d=*dp++;
dc--;
if(flg)
{ /* In flag sequence? */
flg=0; /* Exit flag sequence */
if(d!=0){jd->marker=d;} /* Not an escape of 0xFF but a marker */
d=0xFF;
}
else
{
if(d==0xFF)
{ /* Is start of flag sequence? */
flg=1;
continue; /* Enter flag sequence, get trailing byte */
}
}
}
w=w<<8|d; /* Shift 8 bits in the working register */
wbit+=8;
}
jd->dctr=dc;
jd->dptr=dp;
jd->wreg=w;
/* Incremental serch for all codes */
hb=jd->huffbits[id][cls]; /* Bit distribution table */
hc=jd->huffcode[id][cls]; /* Code word table */
hd=jd->huffdata[id][cls]; /* Data table */
bl=1;
for(;bl<=16;bl++) /* Incremental search */
{
nc=*hb++;
if(nc)
{
d=w>>(wbit-bl);
do
{ /* Search the code word in this bit length */
if(d==*hc++) /* Matched? */
{
jd->dbit=wbit-bl; /* Snip the huffman code */
return *hd; /* Return the decoded data */
}
hd++;
}while(--nc);
}
}
return 0-(int)SCNS_STATUS_TJPGD_FMT1; /* Err: code not found (may be collapted data) */
}
/**
* Extract N bits from input stream
* @param jd Pointer to the decompressor object
* @param nbit Number of bits to extract (1 to 16)
* @return >=0: extracted data, <0: error code
*/
INTERNAL_TEXT(bitext) int bitext(ScnsTjpgdec*jd,unsigned int nbit)
{
ScnsSize dc=jd->dctr;
uint8*dp=jd->dptr;
unsigned int d,flg=0;
unsigned int wbit=jd->dbit%32;
uint32 w=jd->wreg&((1UL<<wbit)-1);
while(wbit<nbit)
{ /* Prepare nbit bits into the working register */
if(jd->marker)
{
d=0xFF; /* Input stream stalled, generate stuff bits */
}
else
{
if(!dc)
{ /* Buffer empty, re-fill input buffer */
dp=jd->inbuf; /* Top of input buffer */
dc=jd->infunc(jd,dp,JD_SZBUF);
if(!dc){return 0-(int)SCNS_STATUS_TJPGD_INP;} /* Err: read error or wrong stream termination */
}
d=*dp++;
dc--;
if(flg)
{ /* In flag sequence? */
flg=0; /* Exit flag sequence */
if(d!=0){jd->marker=d;} /* Not an escape of 0xFF but a marker */
d=0xFF;
}
else
{
if(d==0xFF)
{ /* Is start of flag sequence? */
flg=1;
continue; /* Enter flag sequence, get trailing byte */
}
}
}
w=w<<8|d; /* Get 8 bits into the working register */
wbit+=8;
}
jd->wreg=w;
jd->dbit=wbit-nbit;
jd->dctr=dc;
jd->dptr=dp;
return (int)(w>>((wbit-nbit)%32));
}
/**
* Process restart interval
* @param jd Pointer to the decompressor object
* @param rstn Expected restert sequense number
* @return status
*/
INTERNAL_TEXT(restart) ScnsStatus restart(ScnsTjpgdec*jd,uint16 rstn)
{
unsigned int i;
uint8*dp=jd->dptr;
ScnsSize dc=jd->dctr;
uint16 marker;
if(jd->marker)
{ /* Generate a maker if it has been detected */
marker=0xFF00|jd->marker;
jd->marker=0;
}
else
{
marker=0;
for(i=0;i<2;i++)
{ /* Get a restart marker */
if(!dc)
{ /* No input data is available, re-fill input buffer */
dp=jd->inbuf;
dc=jd->infunc(jd,dp,JD_SZBUF);
if(!dc){return SCNS_STATUS_TJPGD_INP;}
}
marker=(marker<<8)|*dp++; /* Get a byte */
dc--;
}
jd->dptr=dp;
jd->dctr=dc;
}
/* Check the marker */
if((marker&0xFFD8)!=0xFFD0||(marker&7)!=(rstn&7))
{
return SCNS_STATUS_TJPGD_FMT1; /* Err: expected RSTn marker was not detected (may be collapted data) */
}
jd->dbit=0; /* Discard stuff bits */
jd->dcv[2]=jd->dcv[1]=jd->dcv[0]=0; /* Reset DC offset */
return SCNS_STATUS_OK;
}
/**
* Apply Inverse-DCT in Arai Algorithm (see also aa_idct.png)
* @param src Input block data (de-quantized and pre-scaled for Arai Algorithm)
* @param dst Pointer to the destination to store the block as byte array
*/
INTERNAL_TEXT(block_idct) void block_idct(int32*src,int16*dst)
{
const int32 M13=(int32)(1.41421*4096),M2=(int32)(1.08239*4096),M4=(int32)(2.61313*4096),M5=(int32)(1.84776*4096);
int32 v0,v1,v2,v3,v4,v5,v6,v7;
int32 t10,t11,t12,t13;
int i;
/* Process columns */
for(i=0;i<8;i++)
{
v0=src[8*0]; /* Get even elements */
v1=src[8*2];
v2=src[8*4];
v3=src[8*6];
t10=v0+v2; /* Process the even elements */
t12=v0-v2;
t11=(v1-v3)*M13>>12;
v3+=v1;
t11-=v3;
v0=t10+v3;
v3=t10-v3;
v1=t11+t12;
v2=t12-t11;
v4=src[8*7]; /* Get odd elements */
v5=src[8*1];
v6=src[8*5];
v7=src[8*3];
t10=v5-v4; /* Process the odd elements */
t11=v5+v4;
t12=v6-v7;
v7+=v6;
v5=(t11-v7)*M13>>12;
v7+=t11;
t13=(t10+t12)*M5>>12;
v4=t13-(t10*M2>>12);
v6=t13-(t12*M4>>12)-v7;
v5-=v6;
v4-=v5;
src[8*0]=v0+v7; /* Write-back transformed values */
src[8*7]=v0-v7;
src[8*1]=v1+v6;
src[8*6]=v1-v6;
src[8*2]=v2+v5;
src[8*5]=v2-v5;
src[8*3]=v3+v4;
src[8*4]=v3-v4;
src++; /* Next column */
}
/* Process rows */
src-=8;
for(i=0;i<8;i++)
{
v0=src[0]+(128L<<8); /* Get even elements (remove DC offset (-128) here) */
v1=src[2];
v2=src[4];
v3=src[6];
t10=v0+v2; /* Process the even elements */
t12=v0-v2;
t11=(v1-v3)*M13>>12;
v3+=v1;
t11-=v3;
v0=t10+v3;
v3=t10-v3;
v1=t11+t12;
v2=t12-t11;
v4=src[7]; /* Get odd elements */
v5=src[1];
v6=src[5];
v7=src[3];
t10=v5-v4; /* Process the odd elements */
t11=v5+v4;
t12=v6-v7;
v7+=v6;
v5=(t11-v7)*M13>>12;
v7+=t11;
t13=(t10+t12)*M5>>12;
v4=t13-(t10*M2>>12);
v6=t13-(t12*M4>>12)-v7;
v5-=v6;
v4-=v5;
/* Descale the transformed values 8 bits and output a row */
dst[0]=(int16)((v0+v7)>>8);
dst[7]=(int16)((v0-v7)>>8);
dst[1]=(int16)((v1+v6)>>8);
dst[6]=(int16)((v1-v6)>>8);
dst[2]=(int16)((v2+v5)>>8);
dst[5]=(int16)((v2-v5)>>8);
dst[3]=(int16)((v3+v4)>>8);
dst[4]=(int16)((v3-v4)>>8);
dst+=8;
src+=8; /* Next row */
}
}
/**
* Load all blocks in an MCU into working buffer
* @param jd Pointer to the decompressor object
* @return status
*/
INTERNAL_TEXT(mcu_load) ScnsStatus mcu_load(ScnsTjpgdec*jd)
{
int32*tmp=(int32*)jd->workbuf; /* Block working buffer for de-quantize and IDCT */
int d,e;
unsigned int blk,nby,i,bc,z,id,cmp;
int16*bp;
const int32*dqf;
nby=jd->msx*jd->msy; /* Number of Y blocks (1, 2 or 4) */
bp=jd->mcubuf; /* Pointer to the first block of MCU */
for(blk=0;blk<nby+2;blk++)
{ /* Get nby Y blocks and two C blocks */
cmp=(blk<nby)?0:blk-nby+1; /* Component number 0:Y, 1:Cb, 2:Cr */
if(cmp&&jd->ncomp!=3)
{ /* Clear C blocks if not exist (monochrome image) */
for(i=0;i<64;bp[i++]=128){}
}
else
{ /* Load Y/C blocks from input stream */
id=cmp?1:0; /* Huffman table ID of this component */
/* Extract a DC element from input stream */
d=huffext(jd,id,0); /* Extract a huffman coded data (bit length) */
if(d<0){return (ScnsStatus)(0-d);} /* Err: invalid code or input */
bc=(unsigned int)d;
d=jd->dcv[cmp]; /* DC value of previous block */
if(bc)
{ /* If there is any difference from previous block */
e=bitext(jd,bc); /* Extract data bits */
if(e<0){return (ScnsStatus)(0-e);} /* Err: input */
bc=1<<(bc-1); /* MSB position */
if(!(e&bc)){e-=(bc<<1)-1;} /* Restore negative value if needed */
d+=e; /* Get current value */
jd->dcv[cmp]=(int16)d; /* Save current DC value for next block */
}
dqf=jd->qttbl[jd->qtid[cmp]]; /* De-quantizer table ID for this component */
tmp[0]=d*dqf[0]>>8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */
/* Extract following 63 AC elements from input stream */
scnsMemset(&tmp[1],0,63*sizeof(int32)); /* Initialize all AC elements */
z=1; /* Top of the AC elements (in zigzag-order) */
do
{
d=huffext(jd,id,1); /* Extract a huffman coded value (zero runs and bit length) */
if(d==0){break;} /* EOB? */
if(d<0){return (ScnsStatus)(0-d);} /* Err: invalid code or input error */
bc=(unsigned int)d;
z+=bc>>4; /* Skip leading zero run */
if(z>=64){return SCNS_STATUS_TJPGD_FMT1;} /* Too long zero run */
if(bc&=0x0F)
{ /* Bit length? */
d=bitext(jd,bc); /* Extract data bits */
if(d<0){return (ScnsStatus)(0-d);} /* Err: input device */
bc=1<<(bc-1); /* MSB position */
if(!(d&bc)){d-=(bc<<1)-1;} /* Restore negative value if needed */
i=Zig[z]; /* Get raster-order index */
tmp[i]=d*dqf[i]>>8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */
}
}while(++z<64); /* Next AC element */
/* C components may not be processed if in grayscale output */
if(z==1)
{ /* If no AC element or scale ratio is 1/8, IDCT can be ommited and the block is filled with DC value */
d=(int16)((*tmp/256)+128);
for(i=0;i<64;bp[i++]=d){}
}
else
{
block_idct(tmp,bp); /* Apply IDCT and store the block to the MCU buffer */
}
}
bp+=64; /* Next block */
}
return SCNS_STATUS_OK; /* All blocks have been loaded successfully */
}
#define LDB_WORD(ptr) (uint16)(((uint16)*((uint8*)(ptr))<<8)|(uint16)*(uint8*)((ptr)+1))
/**
* Analyze the JPEG image and Initialize decompressor object
* @param jd Blank decompressor object
* @param infunc JPEG strem input function
* @param dev I/O device identifier for the session
* @return status
*/
ScnsStatus scnsTjpgdecPrepare(ScnsTjpgdec*jd,ScnsSize (*infunc)(ScnsTjpgdec*,uint8*,ScnsSize),void*dev)
{
SCNS_ASSERT_ON_RUN(jd);
SCNS_ASSERT_ON_RUN(infunc);
SCNS_ASSERT_ON_RUN(dev);
uint8*seg,b;
uint16 marker;
unsigned int n,i,ofs;
ScnsSize len;
ScnsStatus rc;
scnsMemset(jd,0,sizeof(ScnsTjpgdec)); /* Clear decompression object (this might be a problem if machine's null pointer is not all bits zero) */
jd->infunc=infunc; /* Stream input function */
jd->device=dev; /* I/O device identifier */
jd->inbuf=seg=scnsMalloc(JD_SZBUF); /* Allocate stream input buffer */
if(!seg){return SCNS_STATUS_MALLOC_FAILED;}
ofs=marker=0; /* Find SOI marker */
do
{
if(jd->infunc(jd,seg,1)!=1){return SCNS_STATUS_TJPGD_INP;} /* Err: SOI was not detected */
ofs++;
marker=marker<<8|seg[0];
}while(marker!=0xFFD8);
for(;;)
{
/* Parse JPEG segments */
/* Get a JPEG marker */
if(jd->infunc(jd,seg,4)!=4){return SCNS_STATUS_TJPGD_INP;}
marker=LDB_WORD(seg); /* Marker */
len=LDB_WORD(seg+2); /* Length field */
if(len<=2||(marker>>8)!=0xFF){return SCNS_STATUS_TJPGD_FMT1;}
len-=2; /* Segent content size */
ofs+=4+len; /* Number of bytes loaded */
switch(marker&0xFF)
{
case 0xC0:
{
/* SOF0 (baseline JPEG) */
if(len>JD_SZBUF){return SCNS_STATUS_TJPGD_MEM2;}
if(jd->infunc(jd,seg,len)!=len){return SCNS_STATUS_TJPGD_INP;} /* Load segment data */
jd->width=LDB_WORD(&seg[3]); /* Image width in unit of pixel */
jd->height=LDB_WORD(&seg[1]); /* Image height in unit of pixel */
jd->ncomp=seg[5]; /* Number of color components */
if(jd->ncomp!=3&&jd->ncomp!=1){return SCNS_STATUS_TJPGD_FMT3;} /* Err: Supports only Grayscale and Y/Cb/Cr */
/* Check each image component */
for(i=0;i<jd->ncomp;i++)
{
b=seg[7+3*i]; /* Get sampling factor */
if(i==0)
{ /* Y component */
if(b!=0x11&&b!=0x22&&b!=0x21)
{ /* Check sampling factor */
return SCNS_STATUS_TJPGD_FMT3; /* Err: Supports only 4:4:4, 4:2:0 or 4:2:2 */
}
jd->msx=b>>4;
jd->msy=b&15; /* Size of MCU [blocks] */
}
else
{ /* Cb/Cr component */
if(b!=0x11){return SCNS_STATUS_TJPGD_FMT3;} /* Err: Sampling factor of Cb/Cr must be 1 */
}
jd->qtid[i]=seg[8+3*i]; /* Get dequantizer table ID for this component */
if(jd->qtid[i]>3){return SCNS_STATUS_TJPGD_FMT3;} /* Err: Invalid ID */
}
break;
}
case 0xDD:
{
/* DRI - Define Restart Interval */
if(len>JD_SZBUF){return SCNS_STATUS_TJPGD_MEM2;}
if(jd->infunc(jd,seg,len)!=len){return SCNS_STATUS_TJPGD_INP;} /* Load segment data */
jd->nrst=LDB_WORD(seg); /* Get restart interval (MCUs) */
break;
}
case 0xC4:
{
/* DHT - Define Huffman Tables */
if(len>JD_SZBUF){return SCNS_STATUS_TJPGD_MEM2;}
if(jd->infunc(jd,seg,len)!=len){return SCNS_STATUS_TJPGD_INP;} /* Load segment data */
rc=create_huffman_tbl(jd,seg,len); /* Create huffman tables */
if(rc){return rc;}
break;
}
case 0xDB:
{
/* DQT - Define Quaitizer Tables */
if(len>JD_SZBUF){return SCNS_STATUS_TJPGD_MEM2;}
if(jd->infunc(jd,seg,len)!=len){return SCNS_STATUS_TJPGD_INP;} /* Load segment data */
rc=create_qt_tbl(jd,seg,len); /* Create de-quantizer tables */
if(rc){return rc;}
break;
}
case 0xDA:
{
/* SOS - Start of Scan */
if(len>JD_SZBUF){return SCNS_STATUS_TJPGD_MEM2;}
if(jd->infunc(jd,seg,len)!=len){return SCNS_STATUS_TJPGD_INP;} /* Load segment data */
if(!jd->width||!jd->height){return SCNS_STATUS_TJPGD_FMT1;} /* Err: Invalid image size */
if(seg[0]!=jd->ncomp){return SCNS_STATUS_TJPGD_FMT3;} /* Err: Wrong color components */
/* Check if all tables corresponding to each components have been loaded */
for(i=0;i<jd->ncomp;i++)
{
b=seg[2+2*i]; /* Get huffman table ID */
if(b!=0x00&&b!=0x11){return SCNS_STATUS_TJPGD_FMT3;} /* Err: Different table number for DC/AC element */
n=i?1:0; /* Component class */
if(!jd->huffbits[n][0]||!jd->huffbits[n][1]) /* Check huffman table for this component */
{
return SCNS_STATUS_TJPGD_FMT1; /* Err: Nnot loaded */
}
if(!jd->qttbl[jd->qtid[i]]) /* Check dequantizer table for this component */
{
return SCNS_STATUS_TJPGD_FMT1; /* Err: Not loaded */
}
}
/* Allocate working buffer for MCU and pixel output */
n=jd->msy*jd->msx; /* Number of Y blocks in the MCU */
if(!n){return SCNS_STATUS_TJPGD_FMT1;} /* Err: SOF0 has not been loaded */
len=n*64*3+64; /* Allocate buffer for IDCT and RGB output */
if(len<1024){len=1024;} /* but at least 256 byte is required for IDCT */
jd->workbuf=scnsMalloc(len); /* and it may occupy a part of following MCU working buffer for RGB output */
if(!jd->workbuf){return SCNS_STATUS_MALLOC_FAILED;} /* Err: not enough memory */
jd->mcubuf=scnsMalloc((n+2)*64*sizeof(int16)); /* Allocate MCU working buffer */
if(!jd->mcubuf){return SCNS_STATUS_MALLOC_FAILED;} /* Err: not enough memory */
/* Align stream read offset to JD_SZBUF */
if(ofs%=JD_SZBUF)
{
jd->dctr=jd->infunc(jd,seg+ofs,(ScnsSize)(JD_SZBUF-ofs));
}
jd->dptr=seg+ofs-0;
return SCNS_STATUS_OK; /* Initialization succeeded. Ready to decompress the JPEG image. */
}
case 0xC1: /* SOF1 */
case 0xC2: /* SOF2 */
case 0xC3: /* SOF3 */
case 0xC5: /* SOF5 */
case 0xC6: /* SOF6 */
case 0xC7: /* SOF7 */
case 0xC9: /* SOF9 */
case 0xCA: /* SOF10 */
case 0xCB: /* SOF11 */
case 0xCD: /* SOF13 */
case 0xCE: /* SOF14 */
case 0xCF: /* SOF15 */
case 0xD9: /* EOI */
{
return SCNS_STATUS_TJPGD_FMT3; /* Unsuppoted JPEG standard (may be progressive JPEG) */
}
default:
{
/* Unknown segment (comment, exif or etc..) */
/* Skip segment data (null pointer specifies to remove data from the stream) */
if(jd->infunc(jd,0,len)!=len){return SCNS_STATUS_TJPGD_INP;}
}
}
}
}
/**
* Output an MCU: Convert YCrCb to RGB and output it in RGB form
* @param jd Pointer to the decompressor object
* @param outfunc RGB output function
* @param x MCU location in the image
* @param y MCU location in the image
* @return status
*/
INTERNAL_TEXT(mcu_output) ScnsStatus mcu_output(ScnsTjpgdec*jd,ScnsStatus (*outfunc)(ScnsTjpgdec*,ScnsColorArgb8888*,Point plu,uint16 w,uint16 h),unsigned int x,unsigned int y)
{
const unsigned int mx=jd->msx*8;
const unsigned int my=jd->msy*8; /* MCU size (pixel) */
const unsigned int rx=(x+mx<=jd->width)?mx:jd->width-x; /* Output rectangular size (it may be clipped at right/bottom end of image) */
const unsigned int ry=(y+my<=jd->height)?my:jd->height-y;
ScnsColorArgb8888*pic=(ScnsColorArgb8888*)jd->workbuf;
for(unsigned int iy=0;iy<my;iy++)
{
int16*py=jd->mcubuf,*pc=jd->mcubuf;
if(my==16) /* Double block height? */
{
pc+=64*4+(iy>>1)*8;
if(iy>=8){py+=64;}
}
else /* Single block height */
{
pc+=mx*8+iy*8;
}
py+=iy*8;
for(unsigned int ix=0;ix<mx;ix++)
{
const int cb=pc[0]-128; /* Get Cb/Cr component and remove offset */
const int cr=pc[64]-128;
if(mx==16)
{ /* Double block width? */
if(ix==8){py+=64-8;} /* Jump to next block if double block heigt */
pc+=ix&1; /* Step forward chroma pointer every two pixels */
}
else
{ /* Single block width */
pc++; /* Step forward chroma pointer every pixel */
}
const int yy=*py++; /* Get Y component */
const int CVACC=1024;
*pic++=scnsColorARGBToRgb888(
0XFF,
scnsLimit2((yy+((int)(1.402f*CVACC)*cr)/CVACC),0,255),
scnsLimit2((yy-((int)(0.344f*CVACC)*cb+(int)(0.714f*CVACC)*cr)/CVACC),0,255),
scnsLimit2((yy+((int)(1.772f*CVACC)*cb)/CVACC),0,255)
);
}
}
return outfunc(jd,jd->workbuf,(Point){.x=x,.y=y},rx,ry);
}
/**
* Start to decompress the JPEG picture
* @param jd Initialized decompression object
* @param outfunc RGB output function
* @return
*/
INTERNAL_TEXT(innerDecomp) ScnsStatus innerDecomp(ScnsTjpgdec*jd,ScnsStatus mcu_output(ScnsTjpgdec*jd,ScnsStatus (*outfunc)(ScnsTjpgdec*,ScnsColorArgb8888*,Point plu,uint16 w,uint16 h),unsigned int x,unsigned int y),ScnsStatus (*outfunc)(ScnsTjpgdec*,ScnsColorArgb8888*,Point plu,uint16 w,uint16 h))
{
unsigned int x,y,mx,my;
uint16 rst,rsc;
ScnsStatus rc;
mx=jd->msx*8;
my=jd->msy*8; /* Size of the MCU (pixel) */
jd->dcv[2]=jd->dcv[1]=jd->dcv[0]=0; /* Initialize DC values */
rst=rsc=0;
rc=SCNS_STATUS_OK;
for(y=0;y<jd->height;y+=my) /* Vertical loop of MCUs */
{
for(x=0;x<jd->width;x+=mx) /* Horizontal loop of MCUs */
{
if(jd->nrst&&rst++==jd->nrst) /* Process restart interval if enabled */
{
rc=restart(jd,rsc++);
if(rc!=SCNS_STATUS_OK){return rc;}
rst=1;
}
rc=mcu_load(jd); /* Load an MCU (decompress huffman coded stream, dequantize and apply IDCT) */
if(rc!=SCNS_STATUS_OK){return rc;}
rc=mcu_output(jd,outfunc,x,y); /* Output the MCU (YCbCr to RGB, scaling and output) */
if(rc!=SCNS_STATUS_OK){return rc;}
}
}
return rc;
}
ScnsStatus scnsTjpgdecDecomp(ScnsTjpgdec*jd,ScnsStatus (*outfunc)(ScnsTjpgdec*,ScnsColorArgb8888*,Point plu,uint16 w,uint16 h))
{
SCNS_ASSERT_ON_RUN(jd);
SCNS_ASSERT_ON_RUN(outfunc);
return innerDecomp(jd,mcu_output,outfunc);
}
void scnsTjpgdecFree(ScnsTjpgdec*jd)
{
SCNS_ASSERT_ON_RUN(jd);
scnsFree(jd->inbuf);
scnsFree(jd->workbuf);
scnsFree(jd->mcubuf);
for(uint8 i=0;i<sizeof(jd->qttbl)/sizeof(jd->qttbl[0]);++i){scnsFree(jd->qttbl[i]);}
for(uint8 i=0;i<sizeof(jd->huffbits)/sizeof(jd->huffbits[0]);++i){for(uint8 j=0;j<sizeof(jd->huffbits[0])/sizeof(jd->huffbits[0][0]);++j){scnsFree(jd->huffbits[i][j]);}}
for(uint8 i=0;i<sizeof(jd->huffcode)/sizeof(jd->huffcode[0]);++i){for(uint8 j=0;j<sizeof(jd->huffcode[0])/sizeof(jd->huffcode[0][0]);++j){scnsFree(jd->huffcode[i][j]);}}
for(uint8 i=0;i<sizeof(jd->huffdata)/sizeof(jd->huffdata[0]);++i){for(uint8 j=0;j<sizeof(jd->huffdata[0])/sizeof(jd->huffdata[0][0]);++j){scnsFree(jd->huffdata[i][j]);}}
scnsMemset(jd,0,sizeof(ScnsTjpgdec));
}
#if defined(SCNS_LCD_ENABLE)&&SCNS_LCD_ENABLE==1
#include "ScnsLcd.h"
typedef struct
{
const uint8*inPtr;
uint32 inI;
uint32 inSize;
Point plu;
ScnsLcdLayer layN;
}LcdConfig;
INTERNAL_TEXT(lcd_output) ScnsStatus lcd_output(ScnsTjpgdec*jd,ScnsStatus (*outfunc)(ScnsTjpgdec*,ScnsColorArgb8888*,Point plu,uint16 w,uint16 h),unsigned int x,unsigned int y)
{
const unsigned int mx=jd->msx*8;
const unsigned int my=jd->msy*8; /* MCU size (pixel) */
const unsigned int rx=(x+mx<=jd->width)?mx:jd->width-x; /* Output rectangular size (it may be clipped at right/bottom end of image) */
const unsigned int ry=(y+my<=jd->height)?my:jd->height-y;
ScnsLcdColor*pic=(ScnsLcdColor*)jd->workbuf;
for(unsigned int iy=0;iy<my;iy++)
{
int16*py=jd->mcubuf,*pc=jd->mcubuf;
if(my==16) /* Double block height? */
{
pc+=64*4+(iy>>1)*8;
if(iy>=8){py+=64;}
}
else /* Single block height */
{
pc+=mx*8+iy*8;
}
py+=iy*8;
for(unsigned int ix=0;ix<mx;ix++)
{
const int cb=pc[0]-128; /* Get Cb/Cr component and remove offset */
const int cr=pc[64]-128;
if(mx==16)
{ /* Double block width? */
if(ix==8){py+=64-8;} /* Jump to next block if double block heigt */
pc+=ix&1; /* Step forward chroma pointer every two pixels */
}
else
{ /* Single block width */
pc++; /* Step forward chroma pointer every pixel */
}
const int yy=*py++; /* Get Y component */
const int CVACC=1024;
*pic++=scnsLcdColorARGBToScreen(
0XFF,
scnsLimit2((yy+((int)(1.402f*CVACC)*cr)/CVACC),0,255),
scnsLimit2((yy-((int)(0.344f*CVACC)*cb+(int)(0.714f*CVACC)*cr)/CVACC),0,255),
scnsLimit2((yy+((int)(1.772f*CVACC)*cb)/CVACC),0,255)
);
}
}
LcdConfig*conf=(LcdConfig*)jd->device;
scnsLcdDisplayArrayImage(conf->layN,(Point){.x=x+conf->plu.x,.y=y+conf->plu.y},jd->workbuf,SCNS_LCD_COLOR_FORMAT,NULL,rx,ry,rx,ry,0);
return SCNS_STATUS_OK;
}
INTERNAL_TEXT(lcdInFunc) ScnsSize lcdInFunc(ScnsTjpgdec*jd,uint8_t*buff,ScnsSize ndata)
{
LcdConfig*conf=(LcdConfig*)jd->device;
if(buff)
{
int sizz=scnsMin(ndata,conf->inSize-conf->inI);
scnsMemcpy(buff,conf->inPtr+conf->inI,sizz);
conf->inI+=sizz;
return sizz;
}
else
{
conf->inI+=ndata;
return ndata;
}
}
/**
* 在LCD上画一个JPG图
* @param layN 显示层
* @param plu 图的左上角坐标
* @param p 图的首地址
* @param pSize 图的大小
* @param disW 图的显示宽度
* @param disH 图的显示高度
* @param merge 是否混合填充
*/
void scnsLcdDisplayJpgImage(ScnsLcdLayer layN,Point plu,const void*p,uint32 pSize,int16 disW,int16 disH,uint8 merge)
{
//TODO 实现disH disW
if(!p)
{
scnsLcdFill(layN,plu,disW,disH,SCNS_LCD_COLOR_BACKGROUND,0);
return;
}
ScnsTjpgdec jd;
LcdConfig config={
.inPtr=p,
.inSize=pSize,
.inI=0,
.plu=plu,
};
if(scnsUnlikely(scnsTjpgdecPrepare(&jd,lcdInFunc,&config)!=SCNS_STATUS_OK)){return;}
scnsLcdLayerAutoBegin();
config.layN=layN;
innerDecomp(&jd,lcd_output,NULL);
scnsTjpgdecFree(&jd);
scnsLcdLayerAutoEnd();
}
#endif
#endif
//@scnsReference:http://elm-chan.org/fsw/tjpgd/00index.html
//@scnsName:Tiny JPEG Decompressor
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/huoxingdawang/scns.git
git@gitee.com:huoxingdawang/scns.git
huoxingdawang
scns
SCNSLibrary
master

搜索帮助