844 lines
19 KiB
C
844 lines
19 KiB
C
|
/*****************************************************************************
|
||
|
*
|
||
|
* This program is free software ; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*
|
||
|
* $Id: mjpeg.c 603 2006-01-19 13:00:33Z picard $
|
||
|
*
|
||
|
* The Core Pocket Media Player
|
||
|
* Copyright (c) 2004-2005 Gabor Kovacs
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include "../common/common.h"
|
||
|
#include "mjpeg.h"
|
||
|
|
||
|
#define WEBMJEG_READSIZE 2048
|
||
|
#define VLC_BITS 9
|
||
|
|
||
|
typedef struct blockindex
|
||
|
{
|
||
|
uint8_t quant;
|
||
|
uint8_t comp;
|
||
|
uint8_t ac;
|
||
|
uint8_t dc;
|
||
|
} blockindex;
|
||
|
|
||
|
typedef struct mjpeg
|
||
|
{
|
||
|
codecidct Codec;
|
||
|
|
||
|
bool_t error;
|
||
|
int sos_no;
|
||
|
int restart_interval;
|
||
|
int restart_count;
|
||
|
idct_block_t* blockptr;
|
||
|
|
||
|
// bitstream
|
||
|
bitstream s;
|
||
|
vlc* v[2][4];
|
||
|
int vsize[2][4];
|
||
|
uint8_t quant[4][64];
|
||
|
|
||
|
int hblock[4];
|
||
|
int vblock[4];
|
||
|
int compid[4];
|
||
|
int quantidx[4];
|
||
|
|
||
|
int Ss;
|
||
|
int Se;
|
||
|
int Al;
|
||
|
int Ah;
|
||
|
|
||
|
int blocks;
|
||
|
int mb_width;
|
||
|
int mb_height;
|
||
|
int last_dc[4];
|
||
|
int comp;
|
||
|
bool_t progressive;
|
||
|
int startstate;
|
||
|
|
||
|
blockindex *indexend;
|
||
|
blockindex index[4*2*2];
|
||
|
uint8_t zigzag[64];
|
||
|
IDCT_BLOCK_DECLARE
|
||
|
|
||
|
} mjpeg;
|
||
|
|
||
|
static const uint8_t zigzag[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
|
||
|
};
|
||
|
|
||
|
static const uint8_t dc_luminance[] =
|
||
|
{
|
||
|
0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
|
||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
|
||
|
};
|
||
|
static const uint8_t dc_chrominance[] =
|
||
|
{
|
||
|
0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
|
||
|
};
|
||
|
static const uint8_t ac_luminance[] =
|
||
|
{
|
||
|
0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125,
|
||
|
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
|
||
|
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
|
||
|
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
|
||
|
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
|
||
|
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
|
||
|
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
|
||
|
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
|
||
|
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
|
||
|
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
|
||
|
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
|
||
|
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
|
||
|
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
|
||
|
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
|
||
|
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||
|
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
|
||
|
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
|
||
|
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
|
||
|
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
|
||
|
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
|
||
|
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
|
||
|
0xf9, 0xfa
|
||
|
};
|
||
|
|
||
|
static const uint8_t ac_chrominance[] =
|
||
|
{
|
||
|
0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119,
|
||
|
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
|
||
|
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
|
||
|
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
|
||
|
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
|
||
|
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
|
||
|
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
|
||
|
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
|
||
|
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
|
||
|
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
||
|
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
||
|
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||
|
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||
|
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
|
||
|
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
|
||
|
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
|
||
|
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
|
||
|
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
|
||
|
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
|
||
|
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
|
||
|
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
|
||
|
0xf9, 0xfa
|
||
|
};
|
||
|
|
||
|
static const uint8_t* const default_dht[4] =
|
||
|
{
|
||
|
dc_luminance,
|
||
|
dc_chrominance,
|
||
|
ac_luminance,
|
||
|
ac_chrominance
|
||
|
};
|
||
|
|
||
|
DECLARE_BITINIT
|
||
|
DECLARE_BITLOAD
|
||
|
|
||
|
#undef bitload_pos
|
||
|
#define bitload_pos(p, bitpos) \
|
||
|
bitpos -= 8; \
|
||
|
if (bitpos >= 0) { \
|
||
|
int bits = (p)->bits; \
|
||
|
const uint8_t* bitptr = (p)->bitptr; \
|
||
|
do { \
|
||
|
bits = (bits << 8) | *bitptr; \
|
||
|
if (*bitptr++ == 0xFF) \
|
||
|
{ \
|
||
|
while (*bitptr==0xFF && bitptr<(p)->bitend) \
|
||
|
bitptr++; \
|
||
|
if (*bitptr==0) \
|
||
|
++bitptr; \
|
||
|
} \
|
||
|
bitpos -= 8; \
|
||
|
} while (bitpos>=0); \
|
||
|
(p)->bits = bits; \
|
||
|
(p)->bitptr = bitptr; \
|
||
|
} \
|
||
|
bitpos += 8;
|
||
|
|
||
|
|
||
|
static NOINLINE int NotSupported(mjpeg* p)
|
||
|
{
|
||
|
if (!p->error)
|
||
|
{
|
||
|
p->error = 1;
|
||
|
ShowError(p->Codec.Node.Class,MJPEG_ID,MJPEG_NOT_SUPPORTED);
|
||
|
}
|
||
|
return ERR_NOT_SUPPORTED;
|
||
|
}
|
||
|
|
||
|
static NOINLINE bool_t VLC(vlc** tab, int* size, const uint8_t *data)
|
||
|
{
|
||
|
uint32_t huffcode[256];
|
||
|
uint16_t huffdata[256];
|
||
|
int i,j,k,n,code;
|
||
|
|
||
|
code = 0;
|
||
|
k = 0;
|
||
|
for (i=1;i<=16;i++)
|
||
|
{
|
||
|
n = data[i];
|
||
|
for (j=0;j<n;j++)
|
||
|
{
|
||
|
huffcode[k] = ((code++)<<5)|i;
|
||
|
huffdata[k] = data[k+17];
|
||
|
++k;
|
||
|
}
|
||
|
code <<= 1;
|
||
|
}
|
||
|
|
||
|
return vlcinit(tab,size,huffcode,4,huffdata,k,0,VLC_BITS);
|
||
|
}
|
||
|
|
||
|
static int DQT(mjpeg* p)
|
||
|
{
|
||
|
int len = bitget(&p->s,16) - 2;
|
||
|
while (len >= 65 && !biteof(&p->s))
|
||
|
{
|
||
|
int comp,i;
|
||
|
|
||
|
bitload(&p->s);
|
||
|
if (bitget(&p->s,4) != 0)
|
||
|
return NotSupported(p); // 16bit prec
|
||
|
|
||
|
comp = bitget(&p->s, 4);
|
||
|
if (comp >= 4)
|
||
|
return ERR_INVALID_DATA;
|
||
|
|
||
|
for (i=0;i<64;i++)
|
||
|
{
|
||
|
bitload(&p->s);
|
||
|
p->quant[comp][i] = (uint8_t)bitget(&p->s,8);
|
||
|
}
|
||
|
|
||
|
len -= 65;
|
||
|
}
|
||
|
|
||
|
return ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static int DHT(mjpeg* p)
|
||
|
{
|
||
|
uint8_t data[17+256];
|
||
|
int len = bitget(&p->s,16)-2;
|
||
|
|
||
|
while (len>=17 && !biteof(&p->s))
|
||
|
{
|
||
|
int n,i;
|
||
|
int comp,idx;
|
||
|
|
||
|
bitload(&p->s);
|
||
|
comp = bitget(&p->s,4);
|
||
|
if (comp >= 2)
|
||
|
break;
|
||
|
|
||
|
idx = bitget(&p->s,4);
|
||
|
if (idx >= 4)
|
||
|
break;
|
||
|
|
||
|
n = 0;
|
||
|
for (i=1;i<=16;i++)
|
||
|
{
|
||
|
bitload(&p->s);
|
||
|
data[i] = (uint8_t) bitget(&p->s,8);
|
||
|
n += data[i];
|
||
|
}
|
||
|
|
||
|
len -= 17+n;
|
||
|
if (len<0 || n>256)
|
||
|
break;
|
||
|
|
||
|
for (i=0;i<n;i++)
|
||
|
{
|
||
|
bitload(&p->s);
|
||
|
data[17+i] = (uint8_t) bitget(&p->s,8);
|
||
|
}
|
||
|
|
||
|
if (!VLC(&p->v[comp][idx],&p->vsize[comp][idx],data))
|
||
|
return ERR_NONE;
|
||
|
}
|
||
|
return ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static int DRI(mjpeg* p)
|
||
|
{
|
||
|
if (bitget(&p->s,16) == 4)
|
||
|
{
|
||
|
bitload(&p->s);
|
||
|
p->restart_interval = bitget(&p->s,16);
|
||
|
}
|
||
|
return ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static int SOF(mjpeg* p,bool_t progressive)
|
||
|
{
|
||
|
int len,i,width,height,mode;
|
||
|
|
||
|
p->progressive = progressive;
|
||
|
|
||
|
len = bitget(&p->s,16);
|
||
|
|
||
|
bitload(&p->s);
|
||
|
if (bitget(&p->s,8) != 8) // 8bit/component
|
||
|
return NotSupported(p);
|
||
|
|
||
|
height = bitget(&p->s,16);
|
||
|
bitload(&p->s);
|
||
|
width = bitget(&p->s,16);
|
||
|
p->comp = bitget(&p->s,8);
|
||
|
|
||
|
if (p->comp != 3 && p->comp != 1) // 3 or 1 components
|
||
|
return NotSupported(p);
|
||
|
|
||
|
if (len != 8+3*p->comp)
|
||
|
return ERR_INVALID_DATA;
|
||
|
|
||
|
p->blocks = 0;
|
||
|
for (i=0;i<p->comp;i++)
|
||
|
{
|
||
|
bitload(&p->s);
|
||
|
|
||
|
p->compid[i] = bitget(&p->s,8);
|
||
|
p->hblock[i] = bitget(&p->s,4);
|
||
|
p->vblock[i] = bitget(&p->s,4);
|
||
|
p->quantidx[i] = bitget(&p->s,8);
|
||
|
if (p->quantidx[i] >= 4)
|
||
|
return ERR_INVALID_DATA;
|
||
|
if (i>0 && (p->hblock[i]!=1 || p->vblock[i]!=1))
|
||
|
return NotSupported(p);
|
||
|
p->blocks += p->hblock[i] * p->vblock[i];
|
||
|
}
|
||
|
|
||
|
p->indexend = p->index + p->blocks;
|
||
|
|
||
|
switch (16*p->vblock[0]+p->hblock[0])
|
||
|
{
|
||
|
case 0x11:
|
||
|
mode = PF_YUV444;
|
||
|
p->mb_width = (width + 7) >> 3;
|
||
|
p->mb_height = (height + 7) >> 3;
|
||
|
break;
|
||
|
case 0x12:
|
||
|
mode = PF_YUV422;
|
||
|
p->mb_width = (width + 15) >> 4;
|
||
|
p->mb_height = (height + 7) >> 3;
|
||
|
break;
|
||
|
case 0x22:
|
||
|
mode = PF_YUV420;
|
||
|
p->mb_width = (width + 15) >> 4;
|
||
|
p->mb_height = (height + 15) >> 4;
|
||
|
break;
|
||
|
default:
|
||
|
return NotSupported(p);
|
||
|
}
|
||
|
|
||
|
return CodecIDCTSetFormat(&p->Codec,mode|PF_YUV_PC,width,height,width,height,p->Codec.In.Format.Format.Video.Aspect);
|
||
|
}
|
||
|
|
||
|
static NOINLINE void scan(mjpeg* p)
|
||
|
{
|
||
|
idct* IDCT = p->Codec.IDCT.Ptr;
|
||
|
int x,y,bitpos;
|
||
|
blockindex* i;
|
||
|
|
||
|
p->restart_count = p->restart_interval;
|
||
|
bitpos = p->s.bitpos;
|
||
|
|
||
|
for (y=0;y<p->mb_height;++y)
|
||
|
for (x=0;x<p->mb_width;++x)
|
||
|
{
|
||
|
IDCT->Process(IDCT,x,y);
|
||
|
|
||
|
for (i=p->index;i!=p->indexend;i++)
|
||
|
{
|
||
|
int len,val,n;
|
||
|
idct_block_t* block = p->blockptr;
|
||
|
uint8_t* quant = p->quant[i->quant];
|
||
|
vlc* tab = p->v[0][i->dc];
|
||
|
|
||
|
if (biteof(&p->s))
|
||
|
break;
|
||
|
|
||
|
ClearBlock(block);
|
||
|
|
||
|
vlcget2_pos(val,tab,&p->s,bitpos,n,255,VLC_BITS);
|
||
|
if (val)
|
||
|
{
|
||
|
bitload_pos(&p->s,bitpos);
|
||
|
bitgetx_pos(&p->s,bitpos,val,n);
|
||
|
}
|
||
|
|
||
|
val = val * quant[0] + p->last_dc[i->comp];
|
||
|
p->last_dc[i->comp] = val;
|
||
|
block[0] = (idct_block_t)val;
|
||
|
|
||
|
tab = p->v[1][i->ac];
|
||
|
len = 1;
|
||
|
for (;;)
|
||
|
{
|
||
|
vlcget2_pos(val,tab,&p->s,bitpos,n,255,VLC_BITS);
|
||
|
if (!val)
|
||
|
break;
|
||
|
if (val == 0xF0)
|
||
|
{
|
||
|
len += 16;
|
||
|
if (len>=64)
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
n = val >> 4;
|
||
|
val &= 15;
|
||
|
len += n;
|
||
|
bitload_pos(&p->s,bitpos);
|
||
|
bitgetx_pos(&p->s,bitpos,val,n);
|
||
|
n = len & 63;
|
||
|
val *= quant[n];
|
||
|
n = p->zigzag[n];
|
||
|
block[n] = (idct_block_t)val;
|
||
|
if (++len>=64)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
IDCT->Intra8x8(IDCT,block,len,IDCTSCAN_ZIGZAG);
|
||
|
}
|
||
|
|
||
|
if (p->comp == 1)
|
||
|
{
|
||
|
idct_block_t* block = p->blockptr;
|
||
|
|
||
|
ClearBlock(block);
|
||
|
block[0] = 1024;
|
||
|
IDCT->Intra8x8(IDCT,block,1,IDCTSCAN_ZIGZAG);
|
||
|
|
||
|
ClearBlock(block);
|
||
|
block[0] = 1024;
|
||
|
IDCT->Intra8x8(IDCT,block,1,IDCTSCAN_ZIGZAG);
|
||
|
}
|
||
|
|
||
|
if (p->restart_interval && !--p->restart_count)
|
||
|
{
|
||
|
p->restart_count = p->restart_interval;
|
||
|
p->last_dc[0] = p->last_dc[1] = p->last_dc[2] = 1024;
|
||
|
|
||
|
bitbytealign_pos(&p->s,bitpos);
|
||
|
bitflush_pos(&p->s,bitpos,16);
|
||
|
bitload_pos(&p->s,bitpos);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p->s.bitpos = bitpos;
|
||
|
}
|
||
|
|
||
|
static int SOS(mjpeg* p)
|
||
|
{
|
||
|
const uint8_t *pos;
|
||
|
int i,j,comp,len,result;
|
||
|
|
||
|
len = bitget(&p->s,16);
|
||
|
comp = bitget(&p->s,8);
|
||
|
if (len != 6+2*comp)
|
||
|
return ERR_INVALID_DATA;
|
||
|
|
||
|
if (p->comp != comp)
|
||
|
return NotSupported(p);
|
||
|
|
||
|
j=0;
|
||
|
for (i=0;i<comp;i++)
|
||
|
{
|
||
|
int n,dc,ac;
|
||
|
bitload(&p->s);
|
||
|
|
||
|
if (p->compid[i] != bitget(&p->s,8))
|
||
|
return NotSupported(p);
|
||
|
|
||
|
dc = bitget(&p->s,4);
|
||
|
ac = bitget(&p->s,4);
|
||
|
|
||
|
if (dc >= 4 || ac >= 4)
|
||
|
return ERR_INVALID_DATA;
|
||
|
|
||
|
for (n=p->hblock[i]*p->vblock[i];n;--n,++j)
|
||
|
{
|
||
|
p->index[j].quant=(uint8_t)p->quantidx[i];
|
||
|
p->index[j].comp=(uint8_t)i;
|
||
|
p->index[j].ac=(uint8_t)ac;
|
||
|
p->index[j].dc=(uint8_t)dc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bitload(&p->s);
|
||
|
p->Ss = bitget(&p->s,8); // Ss
|
||
|
p->Se = bitget(&p->s,8); // Se
|
||
|
|
||
|
bitload(&p->s);
|
||
|
p->Ah = bitget(&p->s,4); // Ah
|
||
|
p->Al = bitget(&p->s,4); // Al
|
||
|
|
||
|
p->last_dc[0] = p->last_dc[1] = p->last_dc[2] = 1024;
|
||
|
|
||
|
if (!p->sos_no)
|
||
|
{
|
||
|
result = p->Codec.IDCT.Ptr->FrameStart(p->Codec.IDCT.Ptr,0,NULL,0,-1,-1,0,0);
|
||
|
if (result != ERR_NONE)
|
||
|
return result;
|
||
|
p->Codec.Show = 0;
|
||
|
}
|
||
|
|
||
|
pos = bitbytepos(&p->s);
|
||
|
bitinit(&p->s,pos,bitendptr(&p->s)-pos);
|
||
|
|
||
|
++p->sos_no;
|
||
|
scan(p);
|
||
|
|
||
|
return ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static int APP(mjpeg* p)
|
||
|
{
|
||
|
int n = bitget(&p->s,16);
|
||
|
if (n>6)
|
||
|
bitflush(&p->s,n*8-16);
|
||
|
return ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static int Frame(mjpeg* p, const uint8_t* ptr, int num)
|
||
|
{
|
||
|
int Result = ERR_NONE;
|
||
|
int code,v;
|
||
|
|
||
|
if (p->Codec.State.DropLevel)
|
||
|
return p->Codec.IDCT.Ptr->Null(p->Codec.IDCT.Ptr,NULL,0);
|
||
|
|
||
|
p->sos_no = 0;
|
||
|
p->progressive = 0;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
for (;;)
|
||
|
{
|
||
|
if (num < 2)
|
||
|
{
|
||
|
code = 0xD9;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
v = *ptr++;
|
||
|
--num;
|
||
|
if ((v == 0xFF) && (*ptr >= 0xC0) && (*ptr <= 0xFE))
|
||
|
{
|
||
|
code = *ptr++;
|
||
|
--num;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (code == 0xD9) // end of image
|
||
|
break;
|
||
|
|
||
|
bitinit(&p->s,ptr,num);
|
||
|
bitload(&p->s);
|
||
|
switch(code)
|
||
|
{
|
||
|
case 0xD8: // start of image
|
||
|
p->restart_interval = 0;
|
||
|
break;
|
||
|
case 0xDD: // define restart interval
|
||
|
Result = DRI(p);
|
||
|
break;
|
||
|
case 0xDB: // define quantization tables
|
||
|
Result = DQT(p);
|
||
|
break;
|
||
|
case 0xC4: // define huffman tables
|
||
|
Result = DHT(p);
|
||
|
break;
|
||
|
case 0xC0: // baseline, huffman
|
||
|
Result = SOF(p,0);
|
||
|
break;
|
||
|
case 0xC2: // progressive, huffman
|
||
|
if (!p->error)
|
||
|
{
|
||
|
p->error = 1;
|
||
|
ShowError(p->Codec.Node.Class,MJPEG_ID,MJPEG_PROGRESSIVE);
|
||
|
}
|
||
|
Result = ERR_NOT_SUPPORTED;
|
||
|
//todo... Result = SOF(p,1);
|
||
|
break;
|
||
|
case 0xDA: // start of scan
|
||
|
if (!p->sos_no || p->progressive)
|
||
|
Result = SOS(p);
|
||
|
continue;
|
||
|
|
||
|
case 0xE0:
|
||
|
case 0xE1:
|
||
|
case 0xE2:
|
||
|
case 0xE3:
|
||
|
case 0xE4:
|
||
|
case 0xE5:
|
||
|
case 0xE6:
|
||
|
case 0xE7:
|
||
|
case 0xE8:
|
||
|
case 0xE9:
|
||
|
case 0xEA:
|
||
|
case 0xEB:
|
||
|
case 0xEC:
|
||
|
case 0xED:
|
||
|
case 0xEE:
|
||
|
case 0xEF:
|
||
|
Result = APP(p);
|
||
|
break;
|
||
|
|
||
|
case 0xC1: // extended sequential, huffman
|
||
|
case 0xC3: // lossless, huffman
|
||
|
case 0xC5: // differential sequential, huffman
|
||
|
case 0xC6: // differential progressive, huffman
|
||
|
case 0xC7: // differential lossless, huffman
|
||
|
case 0xC9: // extended sequential, arithmetic
|
||
|
case 0xCA: // progressive, arithmetic
|
||
|
case 0xCB: // lossless, arithmetic
|
||
|
case 0xCD: // differential sequential, arithmetic
|
||
|
case 0xCE: // differential progressive, arithmetic
|
||
|
case 0xCF: // differential lossless, arithmetic
|
||
|
case 0xC8: // reserved
|
||
|
Result = NotSupported(p);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
v = bitbytepos(&p->s) - ptr;
|
||
|
ptr += v;
|
||
|
num -= v;
|
||
|
}
|
||
|
while (Result == ERR_NONE);
|
||
|
|
||
|
if (p->sos_no)
|
||
|
p->Codec.IDCT.Ptr->FrameEnd(p->Codec.IDCT.Ptr);
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
static int Flush(mjpeg* p)
|
||
|
{
|
||
|
p->startstate = 0;
|
||
|
return ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static bool_t FindNext(mjpeg* p)
|
||
|
{
|
||
|
const uint8_t* Ptr = p->Codec.Buffer.Data;
|
||
|
int Len = p->Codec.Buffer.WritePos;
|
||
|
int Pos = p->Codec.FrameEnd;
|
||
|
|
||
|
for (;Pos<Len;++Pos)
|
||
|
{
|
||
|
uint8_t ch = Ptr[Pos];
|
||
|
bool_t Valid;
|
||
|
|
||
|
switch (p->startstate)
|
||
|
{
|
||
|
case -1:
|
||
|
Valid = 0;
|
||
|
break;
|
||
|
case 1:
|
||
|
Valid = ch == 0xD8;
|
||
|
break;
|
||
|
case 3:
|
||
|
Valid = (ch >= 0xC0) && (ch <= 0xFE);
|
||
|
break;
|
||
|
default:
|
||
|
Valid = ch == 0xFF;
|
||
|
break;
|
||
|
}
|
||
|
if (!Valid)
|
||
|
p->startstate = 0;
|
||
|
else
|
||
|
if (++p->startstate == 4)
|
||
|
{
|
||
|
p->Codec.FrameEnd = Pos-3;
|
||
|
p->startstate = -1;
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p->Codec.FrameEnd = Pos;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int UpdateInput(mjpeg* p)
|
||
|
{
|
||
|
int i,j;
|
||
|
int Result = ERR_NONE;
|
||
|
|
||
|
p->error = 0;
|
||
|
IDCT_BLOCK_PREPARE(p,p->blockptr);
|
||
|
memcpy(p->zigzag,zigzag,sizeof(zigzag));
|
||
|
|
||
|
for (i=0;i<2;++i)
|
||
|
for (j=0;j<4;++j)
|
||
|
vlcdone(&p->v[i][j],&p->vsize[i][j]);
|
||
|
|
||
|
if (p->Codec.In.Format.Type == PACKET_VIDEO)
|
||
|
{
|
||
|
Result = CodecIDCTSetFormat(&p->Codec,PF_YUV422|PF_YUV_PC,p->Codec.In.Format.Format.Video.Width,p->Codec.In.Format.Format.Video.Height,
|
||
|
p->Codec.In.Format.Format.Video.Width,p->Codec.In.Format.Format.Video.Height,
|
||
|
p->Codec.In.Format.Format.Video.Aspect);
|
||
|
if (Result == ERR_NONE)
|
||
|
{
|
||
|
for (i=0;i<2;++i)
|
||
|
for (j=0;j<2;++j)
|
||
|
if (!VLC(&p->v[i][j],&p->vsize[i][j],default_dht[i*2+j]))
|
||
|
Result = ERR_OUT_OF_MEMORY;
|
||
|
|
||
|
if (p->Codec.In.Format.PacketRate.Num>0)
|
||
|
p->Codec.FrameTime = Scale(TICKSPERSEC,p->Codec.In.Format.PacketRate.Den,p->Codec.In.Format.PacketRate.Num);
|
||
|
else
|
||
|
p->Codec.FrameTime = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
static int Create(mjpeg* p)
|
||
|
{
|
||
|
p->Codec.MinCount = 1;
|
||
|
p->Codec.Frame = (codecidctframe)Frame;
|
||
|
p->Codec.UpdateInput = (nodefunc)UpdateInput;
|
||
|
p->Codec.FindNext = (codecidctnext)FindNext;
|
||
|
p->Codec.Flush = (nodefunc)Flush;
|
||
|
return ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static const nodedef MJPEG =
|
||
|
{
|
||
|
sizeof(mjpeg),
|
||
|
MJPEG_ID,
|
||
|
CODECIDCT_CLASS,
|
||
|
PRI_DEFAULT,
|
||
|
(nodecreate)Create,
|
||
|
NULL,
|
||
|
};
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------
|
||
|
|
||
|
static const nodedef JPEG =
|
||
|
{
|
||
|
0, // parent size
|
||
|
JPEG_ID,
|
||
|
RAWIMAGE_CLASS,
|
||
|
PRI_DEFAULT,
|
||
|
};
|
||
|
|
||
|
//---------------------------------------------------------------------------------------------
|
||
|
|
||
|
typedef struct webmjpeg
|
||
|
{
|
||
|
format_base Format;
|
||
|
|
||
|
} webmjpeg;
|
||
|
|
||
|
static int WEBMJPEGInit(rawaudio* p)
|
||
|
{
|
||
|
format_stream* s = Format_AddStream(&p->Format,sizeof(format_stream));
|
||
|
if (s)
|
||
|
{
|
||
|
PacketFormatClear(&s->Format);
|
||
|
s->Format.Type = PACKET_VIDEO;
|
||
|
s->Format.Format.Video.Pixel.Flags = PF_FOURCC|PF_FRAGMENTED;
|
||
|
s->Format.Format.Video.Pixel.FourCC = FOURCC('J','P','E','G');
|
||
|
s->PacketBurst = 1;
|
||
|
s->Fragmented = 1;
|
||
|
s->DisableDrop = 1;
|
||
|
Format_PrepairStream(&p->Format,s);
|
||
|
}
|
||
|
p->Format.HeaderLoaded = 1;
|
||
|
p->Format.ProcessMinBuffer = 0;
|
||
|
p->Format.ReadSize = WEBMJEG_READSIZE;
|
||
|
return ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static int WEBMJPEGPacket(rawaudio* p, format_reader* Reader, format_packet* Packet)
|
||
|
{
|
||
|
format_stream* Stream = p->Format.Streams[0];
|
||
|
|
||
|
if (Reader->FilePos<=0)
|
||
|
Packet->RefTime = 0;
|
||
|
else
|
||
|
Packet->RefTime = TIME_UNKNOWN;
|
||
|
Packet->Data = Reader->ReadAsRef(Reader,-WEBMJEG_READSIZE);
|
||
|
Packet->Stream = Stream;
|
||
|
|
||
|
if (Stream->LastTime < TIME_UNKNOWN)
|
||
|
Stream->LastTime = TIME_UNKNOWN;
|
||
|
|
||
|
return ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static int WEBMJPEGSeek(rawaudio* p, tick_t Time, filepos_t FilePos,bool_t PrevKey)
|
||
|
{
|
||
|
if (Time==0 || FilePos==0)
|
||
|
p->Format.Reader->Seek(p->Format.Reader,0,SEEK_SET);
|
||
|
return ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static int WEBMJPEGCreate(rawaudio* p)
|
||
|
{
|
||
|
p->Format.Init = (fmtfunc)WEBMJPEGInit;
|
||
|
p->Format.Seek = (fmtseek)WEBMJPEGSeek;
|
||
|
p->Format.ReadPacket = (fmtreadpacket)WEBMJPEGPacket;
|
||
|
return ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static const nodedef WEBMJPEG =
|
||
|
{
|
||
|
sizeof(webmjpeg),
|
||
|
WEB_MJPEG_ID,
|
||
|
FORMATBASE_CLASS,
|
||
|
PRI_DEFAULT,
|
||
|
(nodecreate)WEBMJPEGCreate,
|
||
|
NULL,
|
||
|
};
|
||
|
|
||
|
//---------------------------------------------------------------------------------------------
|
||
|
|
||
|
void MJPEG_Init()
|
||
|
{
|
||
|
NodeRegisterClass(&MJPEG);
|
||
|
NodeRegisterClass(&JPEG);
|
||
|
NodeRegisterClass(&WEBMJPEG);
|
||
|
}
|
||
|
|
||
|
void MJPEG_Done()
|
||
|
{
|
||
|
NodeUnRegisterClass(MJPEG_ID);
|
||
|
NodeUnRegisterClass(JPEG_ID);
|
||
|
NodeUnRegisterClass(WEB_MJPEG_ID);
|
||
|
}
|