Support unrar64.dll
[xy_vsfilter.git] / src / apps / mplayerc / jpeg.cpp
blob0ea2172e595725aa1e2236b0d1c2ef8c607e7727
1 /*
2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
20 * - a simple baseline encoder
21 * - created exactly after the specs
22 * - no optimization or anything like that :)
27 #include "stdafx.h"
28 #include <math.h>
29 #include "jpeg.h"
30 #include "jpeg_tables.h"
32 bool CJpegEncoder::PutBit(int b, int n)
34 if(n > 24 || n <= 0) return(false);
36 m_bbuff <<= n;
37 m_bbuff |= b & ((1 << n) - 1);
38 m_bwidth += n;
40 while(m_bwidth >= 8)
42 BYTE c = (BYTE)(m_bbuff >> (m_bwidth - 8));
43 PutByte(c);
44 if(c == 0xff) PutByte(0);
45 m_bwidth -= 8;
48 return(true);
51 void CJpegEncoder::Flush()
53 if(m_bwidth > 0)
55 BYTE c = m_bbuff << (8 - m_bwidth);
56 PutByte(c);
57 if(c == 0xff) PutByte(0);
60 m_bbuff = m_bwidth = 0;
63 ///////
65 int CJpegEncoder::GetBitWidth(short q)
67 if(q == 0) return(0);
68 if(q < 0) q = -q;
70 int width = 15;
71 for(; !(q&0x4000); q <<= 1, width--);
72 return(width);
75 ///////
77 void CJpegEncoder::WriteSOI()
79 PutByte(0xff);
80 PutByte(0xd8);
83 void CJpegEncoder::WriteDQT()
85 PutByte(0xff);
86 PutByte(0xdb);
88 WORD size = 2 + 2*(65 + 64*0);
89 PutByte(size>>8);
90 PutByte(size&0xff);
92 for(int c = 0; c < 2; c++)
94 PutByte(c);
95 PutBytes(quanttbl[c], 64);
99 void CJpegEncoder::WriteSOF0()
101 PutByte(0xff);
102 PutByte(0xc0);
104 WORD size = 8 + 3*ColorComponents;
105 PutByte(size>>8);
106 PutByte(size&0xff);
108 PutByte(8); // precision
110 PutByte(m_h>>8);
111 PutByte(m_h&0xff);
112 PutByte(m_w>>8);
113 PutByte(m_w&0xff);
115 PutByte(ColorComponents); // color components
117 PutByte(1); // component id
118 PutByte(0x11); // hor | ver sampling factor
119 PutByte(0); // quant. tbl. id
121 PutByte(2); // component id
122 PutByte(0x11); // hor | ver sampling factor
123 PutByte(1); // quant. tbl. id
125 PutByte(3); // component id
126 PutByte(0x11); // hor | ver sampling factor
127 PutByte(1); // quant. tbl. id
130 void CJpegEncoder::WriteDHT()
132 PutByte(0xff);
133 PutByte(0xc4);
135 WORD size = 0x01A2; // 2 + n*(17+mi);
136 PutByte(size>>8);
137 PutByte(size&0xff);
139 PutByte(0x00); // tbl class (DC) | tbl id
140 PutBytes(DCVLC_NumByLength[0], 16);
141 for(int i = 0; i < 12; i++) PutByte(i);
143 PutByte(0x01); // tbl class (DC) | tbl id
144 PutBytes(DCVLC_NumByLength[1], 16);
145 for(int i = 0; i < 12; i++) PutByte(i);
147 PutByte(0x10); // tbl class (AC) | tbl id
148 PutBytes(ACVLC_NumByLength[0], 16);
149 PutBytes(ACVLC_Data[0], sizeof(ACVLC_Data[0]));
151 PutByte(0x11); // tbl class (AC) | tbl id
152 PutBytes(ACVLC_NumByLength[1], 16);
153 PutBytes(ACVLC_Data[1], sizeof(ACVLC_Data[1]));
156 // float(1.0 / sqrt(2.0))
157 #define invsq2 0.70710678118654f
158 #define PI 3.14159265358979
160 void CJpegEncoder::WriteSOS()
162 PutByte(0xff);
163 PutByte(0xda);
165 WORD size = 6 + 2*ColorComponents;
166 PutByte(size>>8);
167 PutByte(size&0xff);
169 PutByte(ColorComponents); // color components: 3
171 PutByte(1); // component id
172 PutByte(0x00); // DC | AC huff tbl
174 PutByte(2); // component id
175 PutByte(0x11); // DC | AC huff tbl
177 PutByte(3); // component id
178 PutByte(0x11); // DC | AC huff tbl
180 PutByte(0); // ss, first AC
181 PutByte(63); // se, last AC
183 PutByte(0); // ah | al
185 static float cosuv[8][8][8][8];
187 // oh yeah, we don't need no fast dct :)
188 for(int v = 0; v < 8; v++)
189 for(int u = 0; u < 8; u++)
190 for(int j = 0; j < 8; j++)
191 for(int i = 0; i < 8; i++)
192 cosuv[v][u][j][i] = (float)(cos((2*i+1)*u*PI/16) * cos((2*j+1)*v*PI/16));
194 int prevDC[3] = {0, 0, 0};
196 for(int y = 0; y < m_h; y += 8)
198 int jj = min(m_h - y, 8);
200 for(int x = 0; x < m_w; x += 8)
202 int ii = min(m_w - x, 8);
204 for(int c = 0; c < ColorComponents; c++)
206 int cc = !!c;
208 int ACs = 0;
210 static short block[64];
212 for(int zigzag = 0; zigzag < 64; zigzag++)
214 BYTE u = zigzagU[zigzag];
215 BYTE v = zigzagV[zigzag];
217 float F = 0;
219 for(int j = 0; j < jj; j++)
220 for(int i = 0; i < ii; i++)
221 F += (signed char)m_p[((y+j)*m_w + (x+i))*4 + c] * cosuv[v][u][j][i];
223 for(int j = 0; j < jj; j++)
225 signed char* p = (signed char*)&m_p[((y+j)*m_w + x)*4 + c];
226 for(int i = 0; i < ii; i++, p += 4)
227 F += *p * cosuv[v][u][j][i];
230 float cu = !u ? invsq2 : 1.0f;
231 float cv = !v ? invsq2 : 1.0f;
233 block[zigzag] = short(2.0 / 8.0 * cu * cv * F) / quanttbl[cc][zigzag];
236 short DC = block[0] - prevDC[c];
237 prevDC[c] = block[0];
239 int size = GetBitWidth(DC);
240 PutBit(DCVLC[cc][size], DCVLC_Size[cc][size]);
242 if(DC < 0) DC = DC - 1;
243 PutBit(DC, size);
245 int j;
246 for(j = 64; j > 1 && !block[j-1]; j--);
248 for(int i = 1; i < j; i++)
250 short AC = block[i];
252 if(AC == 0)
254 if(++ACs == 16)
256 PutBit(ACVLC[cc][15][0], ACVLC_Size[cc][15][0]);
257 ACs = 0;
260 else
262 int size = GetBitWidth(AC);
263 PutBit(ACVLC[cc][ACs][size], ACVLC_Size[cc][ACs][size]);
265 if(AC < 0) AC--;
266 PutBit(AC, size);
268 ACs = 0;
272 if(j < 64) PutBit(ACVLC[cc][0][0], ACVLC_Size[cc][0][0]);
277 Flush();
280 void CJpegEncoder::WriteEOI()
282 PutByte(0xff);
283 PutByte(0xd9);
288 CJpegEncoder::CJpegEncoder()
292 bool CJpegEncoder::Encode(const BYTE* dib)
294 m_bbuff = m_bwidth = 0;
296 BITMAPINFO* bi = (BITMAPINFO*)dib;
298 int bpp = bi->bmiHeader.biBitCount;
300 if(bpp != 16 && bpp != 24 && bpp != 32) // 16 & 24 not tested!!! there may be some alignment problems when the row size is not 4*something in bytes
301 return false;
303 m_w = bi->bmiHeader.biWidth;
304 m_h = abs(bi->bmiHeader.biHeight);
305 m_p = new BYTE[m_w*m_h*4];
307 const BYTE* src = dib + sizeof(bi->bmiHeader);
308 if(bi->bmiHeader.biBitCount <= 8)
310 if(bi->bmiHeader.biClrUsed) src += bi->bmiHeader.biClrUsed * sizeof(bi->bmiColors[0]);
311 else src += (1 << bi->bmiHeader.biBitCount) * sizeof(bi->bmiColors[0]);
314 int srcpitch = m_w*(bpp>>3);
315 int dstpitch = m_w*4;
317 BitBltFromRGBToRGB(
318 m_w, m_h,
319 m_p, dstpitch, 32,
320 (BYTE*)src + srcpitch*(m_h-1), -srcpitch, bpp);
322 BYTE* p = m_p;
323 for(BYTE* e = p + m_h*dstpitch; p < e; p += 4)
325 int r = p[2], g = p[1], b = p[0];
327 p[0] = (BYTE)min(max(0.2990*r+0.5870*g+0.1140*b, 0), 255) - 128;
328 p[1] = (BYTE)min(max(-0.1687*r-0.3313*g+0.5000*b + 128, 0), 255) - 128;
329 p[2] = (BYTE)min(max(0.5000*r-0.4187*g-0.0813*b + 128, 0), 255) - 128;
332 if(quanttbl[0][0] == 16)
334 for(int i = 0; i < countof(quanttbl); i++)
335 for(int j = 0; j < countof(quanttbl[0]); j++)
336 quanttbl[i][j] >>= 2; // the default quantization table contains a little too large values
339 WriteSOI();
340 WriteDQT();
341 WriteSOF0();
342 WriteDHT();
343 WriteSOS();
344 WriteEOI();
346 delete [] m_p;
348 return true;
351 //////////
353 CJpegEncoderFile::CJpegEncoderFile(LPCTSTR fn)
355 m_fn = fn;
356 m_file = NULL;
359 bool CJpegEncoderFile::PutByte(BYTE b)
361 return fputc(b, m_file) != EOF;
364 bool CJpegEncoderFile::PutBytes(const void* pData, int len)
366 return fwrite(pData, 1, len, m_file) == len;
369 bool CJpegEncoderFile::Encode(const BYTE* dib)
371 if(!(m_file = _tfopen(m_fn, _T("wb")))) return false;
372 bool ret = __super::Encode(dib);
373 fclose(m_file);
374 m_file = NULL;
375 return ret;
378 //////////
380 CJpegEncoderMem::CJpegEncoderMem()
384 bool CJpegEncoderMem::PutByte(BYTE b)
386 m_pdata->Add(b); // yeah... a bit unbuffered, for now
387 return true;
390 bool CJpegEncoderMem::PutBytes(const void* pData, int len)
392 CAtlArray<BYTE> moredata;
393 moredata.SetCount(len);
394 memcpy(moredata.GetData(), pData, len);
395 m_pdata->Append(moredata);
396 return true;
399 bool CJpegEncoderMem::Encode(const BYTE* dib, CAtlArray<BYTE>& data)
401 m_pdata = &data;
402 return __super::Encode(dib);