Update the changelog
[opencv] / otherlibs / VlGrFmts / grfmt_jpeg.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include <assert.h>
43 #include <string.h>
44
45 #include "grfmt_jpeg.h"
46
47 //////////////////////  JPEG-oriented two-level bitstream ////////////////////////
48
49 RMJpegBitStream::RMJpegBitStream()
50 {
51 }
52
53 RMJpegBitStream::~RMJpegBitStream()
54 {
55 }
56
57
58 bool  RMJpegBitStream::Open( const char* filename )
59 {
60     Close();
61     Allocate();
62     
63     m_is_opened = m_low_strm.Open( filename );
64     if( m_is_opened ) SetPos(0);
65     return m_is_opened;
66 }
67
68
69 void  RMJpegBitStream::Close()
70 {
71     m_low_strm.Close();
72     m_is_opened = false;
73 }
74
75
76 void  RMJpegBitStream::ReadBlock()
77 {
78     uchar* end = m_start + m_block_size;
79     uchar* current = m_start;
80
81     try
82     {
83         int sz = m_unGetsize;
84         memmove( current - sz, m_end - sz, sz );
85         while( current < end )
86         {
87             int val = m_low_strm.GetByte();
88             if( val != 0xff )
89             {
90                 *current++ = (uchar)val;
91             }
92             else
93             {
94                 val = m_low_strm.GetByte();
95                 if( val == 0 )
96                     *current++ = 0xFF;
97                 else if( !(0xD0 <= val && val <= 0xD7) )
98                 {
99                     m_low_strm.SetPos( m_low_strm.GetPos() - 2 );
100                     goto fetch_end;
101                 }
102             }
103         }
104 fetch_end: ;
105     }
106     catch( int )
107     {
108         if( current == m_start ) throw;       
109     }
110     m_current = m_start;
111     m_end = m_start + (((current - m_start) + 3) & -4);
112     bs_bswap_block( m_start, m_end );
113 }
114
115
116 void  RMJpegBitStream::Flush()
117 {
118     m_end = m_start + m_block_size;
119     m_current = m_end - 4;
120     m_bit_idx = 0;
121 }
122
123 void  RMJpegBitStream::AlignOnByte()
124 {
125     m_bit_idx &= -8;
126 }
127
128 int  RMJpegBitStream::FindMarker()
129 {
130     int code = m_low_strm.GetWord();
131     while( (code & 0xFF00) != 0xFF00 || (code == 0xFFFF || code == 0xFF00 ))
132     {
133         code = ((code&255) << 8) | m_low_strm.GetByte();
134     }
135     return code;
136 }
137
138
139 /****************************** JPEG (JFIF) reader ***************************/
140
141 // zigzag & IDCT prescaling (AAN algorithm) tables
142 static const uchar zigzag[] =
143 {
144   0,  8,  1,  2,  9, 16, 24, 17, 10,  3,  4, 11, 18, 25, 32, 40,
145  33, 26, 19, 12,  5,  6, 13, 20, 27, 34, 41, 48, 56, 49, 42, 35,
146  28, 21, 14,  7, 15, 22, 29, 36, 43, 50, 57, 58, 51, 44, 37, 30,
147  23, 31, 38, 45, 52, 59, 60, 53, 46, 39, 47, 54, 61, 62, 55, 63,
148  63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63
149 };
150
151 const int idct_prescale[] =
152 {
153   16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
154   22725, 31521, 29692, 26722, 22725, 17855, 12299,  6270,
155   21407, 29692, 27969, 25172, 21407, 16819, 11585,  5906,
156   19266, 26722, 25172, 22654, 19266, 15137, 10426,  5315,
157   16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
158   12873, 17855, 16819, 15137, 12873, 10114,  6967,  3552,
159    8867, 12299, 11585, 10426,  8867,  6967,  4799,  2446,
160    4520,  6270,  5906,  5315,  4520,  3552,  2446,  1247
161 };
162
163 #define fixb       8
164 #define fix(x, n)  (int)((x)*(1 << (n)) + .5)
165
166 #define C1_082  fix( 1.082392200, fixb )
167 #define C1_414  fix( 1.414213562, fixb )
168 #define C1_847  fix( 1.847759065, fixb )
169 #define C2_613  fix( 2.613125930, fixb )
170
171 #define fixc       10
172 #define b_cb       fix( 1.772, fixc )
173 #define g_cb      -fix( 0.34414, fixc )
174 #define g_cr      -fix( 0.71414, fixc )
175 #define r_cr       fix( 1.402, fixc )
176
177 // IDCT without prescaling
178 static void aan_idct8x8( int* src, int *dst, int step )
179 {
180     int   workspace[64], *work = workspace;
181     int   i;
182
183     /* Pass 1: process rows */
184     for( i = 8; i > 0; i--, src += 8, work += 8 )
185     {
186         /* Odd part */
187         int  x0 = src[5], x1 = src[3];
188         int  x2 = src[1], x3 = src[7];
189
190         int  x4 = x0 + x1; x0 -= x1;
191
192         x1 = x2 + x3; x2 -= x3;
193         x3 = x1 + x4; x1 -= x4;
194
195         x4 = (x0 + x2)*C1_847;
196         x0 = descale( x4 - x0*C2_613, fixb);
197         x2 = descale( x2*C1_082 - x4, fixb);
198         x1 = descale( x1*C1_414, fixb);
199
200         x0 -= x3;
201         x1 -= x0;
202         x2 += x1;
203
204         work[7] = x3; work[6] = x0;
205         work[5] = x1; work[4] = x2;
206
207         x2 = src[2]; x3 = src[6];
208         x0 = src[0]; x1 = src[4];
209
210         x4 = x2 + x3;
211         x2 = descale((x2-x3)*C1_414, fixb) - x4;
212
213         x3 = x0 + x1; x0 -= x1;
214         x1 = x3 + x4; x3 -= x4;
215         x4 = x0 + x2; x0 -= x2;
216
217         x2 = work[7];
218         x1 -= x2; x2 = 2*x2 + x1;
219         work[7] = x1; work[0] = x2;
220
221         x2 = work[6];
222         x1 = x4 + x2; x4 -= x2;
223         work[1] = x1; work[6] = x4;
224
225         x1 = work[5]; x2 = work[4];
226         x4 = x0 + x1; x0 -= x1;
227         x1 = x3 + x2; x3 -= x2;
228
229         work[2] = x4; work[5] = x0;
230         work[3] = x3; work[4] = x1;
231     }
232
233     /* Pass 2: process columns */
234     work = workspace;
235     for( i = 8; i > 0; i--, dst+=step, work++ )
236     {
237         /* Odd part */
238         int  x0 = work[8*5], x1 = work[8*3];
239         int  x2 = work[8*1], x3 = work[8*7];
240
241         int  x4 = x0 + x1; x0 -= x1;
242         x1 = x2 + x3; x2 -= x3;
243         x3 = x1 + x4; x1 -= x4;
244
245         x4 = (x0 + x2)*C1_847;
246         x0 = descale( x4 - x0*C2_613, fixb);
247         x2 = descale( x2*C1_082 - x4, fixb);
248         x1 = descale( x1*C1_414, fixb);
249
250         x0 -= x3;
251         x1 -= x0;
252         x2 += x1;
253
254         dst[7] = x3; dst[6] = x0;
255         dst[5] = x1; dst[4] = x2;
256
257         x2 = work[8*2]; x3 = work[8*6];
258         x0 = work[8*0]; x1 = work[8*4];
259
260         x4 = x2 + x3;
261         x2 = descale((x2-x3)*C1_414, fixb) - x4;
262
263         x3 = x0 + x1; x0 -= x1;
264         x1 = x3 + x4; x3 -= x4;
265         x4 = x0 + x2; x0 -= x2;
266
267         x2 = dst[7];
268         x1 -= x2; x2 = 2*x2 + x1;
269         x1 = descale(x1,3);
270         x2 = descale(x2,3);
271
272         dst[7] = x1; dst[0] = x2;
273
274         x2 = dst[6];
275         x1 = descale(x4 + x2,3);
276         x4 = descale(x4 - x2,3);
277         dst[1] = x1; dst[6] = x4;
278
279         x1 = dst[5]; x2 = dst[4];
280
281         x4 = descale(x0 + x1,3);
282         x0 = descale(x0 - x1,3);
283         x1 = descale(x3 + x2,3);
284         x3 = descale(x3 - x2,3);
285        
286         dst[2] = x4; dst[5] = x0;
287         dst[3] = x3; dst[4] = x1;
288     }
289 }
290
291
292 static const int max_dec_htable_size = 1 << 12;
293 static const int first_table_bits = 9;
294
295 GrFmtJpegReader::GrFmtJpegReader()
296 {
297     m_sign_len = 3;
298     m_signature ="\xFF\xD8\xFF";
299     m_description = "JFIF files (*.jpeg;*.jpg;*.jpe)";
300     m_planes= -1;
301     m_offset= -1;
302
303     int i;
304     for( i = 0; i < 4; i++ )
305     {
306         m_td[i] = new short[max_dec_htable_size];
307         m_ta[i] = new short[max_dec_htable_size];
308     }
309 }
310
311
312 GrFmtJpegReader::~GrFmtJpegReader()
313 {
314     for( int i = 0; i < 4; i++ )
315     {
316         delete m_td[i];
317         m_td[i] = 0;
318         delete m_ta[i];
319         m_ta[i] = 0;
320     }
321 }
322
323
324 int  GrFmtJpegReader::GetColor()
325 {
326     return m_planes == 3;
327 }
328
329 void  GrFmtJpegReader::Close()
330 {
331     m_strm.Close();
332 }
333
334 bool GrFmtJpegReader::ReadHeader()
335 {
336     char buffer[16];
337     int  i;
338     bool result = false, is_jfif = false, is_sof = false, 
339          is_qt = false, is_ht = false, is_sos = false;
340     
341     assert( strlen(m_filename) != 0 );
342     if( !m_strm.Open( m_filename )) return false;
343
344     memset( m_is_tq, 0, sizeof(m_is_tq));
345     memset( m_is_td, 0, sizeof(m_is_td));
346     memset( m_is_ta, 0, sizeof(m_is_ta));
347     m_MCUs = 0;
348
349     try
350     {
351         RMByteStream& lstrm = m_strm.m_low_strm;
352         
353         lstrm.Skip( 2 ); // skip SOI marker
354         
355         for(;;)
356         {
357             int marker = m_strm.FindMarker() & 255;
358
359             // check for standalone markers
360             if( marker != 0xD8 /* SOI */ && marker != 0xD9 /* EOI */ &&
361                 marker != 0x01 /* TEM */ && !( 0xD0 <= marker && marker <= 0xD7 ))
362             {
363                 int pos    = lstrm.GetPos();
364                 int length = lstrm.GetWord();
365             
366                 switch( marker )
367                 {
368                 case 0xE0: // APP0
369                     lstrm.GetBytes( buffer, 5 );
370                     if( strcmp(buffer, "JFIF") == 0 ) // JFIF identification
371                     {
372                         m_version = lstrm.GetWord();
373                         is_jfif = true;
374                     }
375                     break;
376
377                 case 0xC0: // SOF0
378                     m_precision = lstrm.GetByte();
379                     m_height = lstrm.GetWord();
380                     m_width = lstrm.GetWord();
381                     m_planes = lstrm.GetByte();
382
383                     if( m_width == 0 || m_height == 0 || // DNL not supported
384                        (m_planes != 1 && m_planes != 3)) goto parsing_end;
385                 
386                     memset( m_ci, -1, sizeof(m_ci));
387
388                     for( i = 0; i < m_planes; i++ )
389                     {
390                         int idx = lstrm.GetByte();
391
392                         if( idx < 1 || idx > m_planes ) // wrong index
393                         {
394                             idx = i+1; // hack
395                         }
396                         cmp_info& ci = m_ci[idx-1];
397                         
398                         if( ci.tq > 0 /* duplicated description */) goto parsing_end;
399
400                         ci.h = (char)lstrm.GetByte();
401                         ci.v = (char)(ci.h & 15);
402                         ci.h >>= 4;
403                         ci.tq = (char)lstrm.GetByte();
404                         if( !((ci.h == 1 || ci.h == 2 || ci.h == 4) &&
405                               (ci.v == 1 || ci.v == 2 || ci.v == 4) &&
406                               ci.tq < 3) ||
407                             // chroma mcu-parts should have equal sizes and
408                             // be non greater then luma sizes
409                             !( i != 2 || (ci.h == m_ci[1].h && ci.v == m_ci[1].v &&
410                                           ci.h <= m_ci[0].h && ci.v <= m_ci[0].v)))
411                             goto parsing_end;
412                     }
413                     is_sof = true;
414                     m_type = marker - 0xC0;
415                     break;
416
417                 case 0xDB: // DQT
418                     if( !load_quant_tables( length )) goto parsing_end;
419                     is_qt = true;
420                     break;
421
422                 case 0xC4: // DHT
423                     if( !load_huffman_tables( length )) goto parsing_end;
424                     is_ht = true;
425                     break;
426
427                 case 0xDA: // SOS
428                     is_sos = true;
429                     m_offset = pos - 2;
430                     goto parsing_end;
431
432                 case 0xDD: // DRI
433                     m_MCUs = lstrm.GetWord();
434                     break;
435                 }
436                 lstrm.SetPos( pos + length );
437             }
438         }
439 parsing_end: ;
440     }
441     catch( int )
442     {
443     }
444
445     result = is_jfif && is_sof && is_qt && is_ht && is_sos;
446     if( !result )
447     {
448         m_width = m_height = -1;
449         m_offset = -1;
450         m_strm.Close();
451     }
452     return result;
453 }
454
455
456 bool GrFmtJpegReader::load_quant_tables( int length )
457 {
458     uchar buffer[128];
459     int  i, tq_size;
460     
461     RMByteStream& lstrm = m_strm.m_low_strm;
462     length -= 2;
463
464     while( length > 0 )
465     {
466         int tq = lstrm.GetByte();
467         int size = tq >> 4;
468         tq &= 15;
469
470         tq_size = (64<<size) + 1; 
471         if( tq > 3 || size > 1 || length < tq_size ) return false;
472         length -= tq_size;
473
474         lstrm.GetBytes( buffer, tq_size - 1 );
475         
476         if( size == 0 ) // 8 bit quant factors
477         {
478             for( i = 0; i < 64; i++ )
479             {
480                 int idx = zigzag[i];
481                 m_tq[tq][idx] = buffer[i] * idct_prescale[idx];
482             }
483         }
484         else // 16 bit quant factors
485         {
486             for( i = 0; i < 64; i++ )
487             {
488                 int idx = zigzag[i];
489                 m_tq[tq][idx] = ((unsigned short*)buffer)[i] * 
490                                 idct_prescale[idx];
491             }
492         }
493         m_is_tq[tq] = true;
494     }
495
496     return true;
497 }
498
499
500 bool GrFmtJpegReader::load_huffman_tables( int length )
501 {
502     const int max_bits = 16;
503     uchar buffer[1024];
504     int  buffer2[1024];
505
506     int  i, ht_size;
507     RMByteStream& lstrm = m_strm.m_low_strm;
508     length -= 2;
509
510     while( length > 0 )
511     {
512         int t = lstrm.GetByte();
513         int hclass = t >> 4;
514         t &= 15;
515
516         if( t > 3 || hclass > 1 || length < 17 ) return false;
517         length -= 17;
518
519         lstrm.GetBytes( buffer, max_bits );
520         for( i = 0, ht_size = 0; i < max_bits; i++ ) ht_size += buffer[i];
521
522         if( length < ht_size ) return false;
523         length -= ht_size;
524
525         lstrm.GetBytes( buffer + max_bits, ht_size );
526         
527         if( !::bs_create_decode_huffman_table( 
528                   ::bs_create_source_huffman_table( 
529                         buffer, buffer2, max_bits, first_table_bits ),
530                         hclass == 0 ? m_td[t] : m_ta[t], 
531                         max_dec_htable_size )) return false;
532         if( hclass == 0 )
533             m_is_td[t] = true;
534         else
535             m_is_ta[t] = true;
536     }
537     return true;
538 }
539
540
541 bool GrFmtJpegReader::ReadData( uchar* data, int step, int color )
542 {
543     if( m_offset < 0 || !m_strm.IsOpened())
544         return false;
545
546     if( m_precision == 8 )
547     {
548         for( int i = 0; i < 4; i++ )
549             if( m_is_tq[i] )
550             {
551                 for( int j = 0; j < 64; j++ )
552                 {
553                     m_tq[i][j] <<= 4;
554                 }
555             }
556     }
557
558     try
559     {
560         RMByteStream& lstrm = m_strm.m_low_strm;
561         lstrm.SetPos( m_offset );
562
563         for(;;)
564         {
565             int marker = m_strm.FindMarker() & 255;
566
567             if( marker == 0xD8 /* SOI */ || marker == 0xD9 /* EOI */ )
568                 goto decoding_end;
569
570             // check for standalone markers
571             if( marker != 0x01 /* TEM */ && !( 0xD0 <= marker && marker <= 0xD7 ))
572             {
573                 int pos    = lstrm.GetPos();
574                 int length = lstrm.GetWord();
575             
576                 switch( marker )
577                 {
578                 case 0xC4: // DHT
579                     if( !load_huffman_tables( length )) goto decoding_end;
580                     break;
581
582                 case 0xDA: // SOS
583                     // read scan header
584                     {
585                         int idx[3] = { -1, -1, -1 };
586                         int i, ns = lstrm.GetByte();
587                         int sum = 0, a; // spectral selection & approximation
588
589                         if( ns != m_planes ) goto decoding_end;
590                         for( i = 0; i < ns; i++ )
591                         {
592                             int td, ta, c = lstrm.GetByte() - 1;
593                             if( c < 0 || m_planes <= c )
594                             {
595                                 c = i; // hack
596                             }
597                             
598                             if( idx[c] != -1 ) goto decoding_end;
599                             idx[i] = c;
600                             td = lstrm.GetByte();
601                             ta = td & 15;
602                             td >>= 4;
603                             if( !(ta <= 3 && m_is_ta[ta] && 
604                                   td <= 3 && m_is_td[td] &&
605                                   m_is_tq[m_ci[c].tq]) )
606                                 goto decoding_end;
607
608                             m_ci[c].td = (char)td;
609                             m_ci[c].ta = (char)ta;
610
611                             sum += m_ci[c].h*m_ci[c].v;
612                         }
613
614                         if( sum > 10 ) goto decoding_end;
615
616                         m_ss = lstrm.GetByte();
617                         m_se = lstrm.GetByte();
618
619                         a = lstrm.GetByte();
620                         m_al = a & 15;
621                         m_ah = a >> 4;
622
623                         ProcessScan( idx, ns, data, step, color );
624                         goto decoding_end; // only single scan case is supported now
625                     }
626
627                     //m_offset = pos - 2;
628                     //break;
629
630                 case 0xDD: // DRI
631                     m_MCUs = lstrm.GetWord();
632                     break;
633                 }
634                 
635                 if( marker != 0xDA ) lstrm.SetPos( pos + length );
636             }
637         }
638 decoding_end: ;
639     }
640     catch( int )
641     {
642     }
643     return true;
644 }
645
646
647 void  GrFmtJpegReader::ResetDecoder()
648 {
649     m_ci[0].dc_pred = m_ci[1].dc_pred = m_ci[2].dc_pred = 0; 
650 }
651
652 void  GrFmtJpegReader::ProcessScan( int* idx, int ns, uchar* data, int step, int color )
653 {
654     int   i, s = 0, mcu, x1 = 0, y1 = 0;
655     int   temp[64];
656     int   blocks[10][64];
657     int   pos[3], h[3], v[3];
658     int   x_shift = 0, y_shift = 0;
659     int   nch = color ? 3 : 1;
660
661     assert( ns == m_planes && m_ss == 0 && m_se == 63 &&
662             m_al == 0 && m_ah == 0 ); // sequental & single scan
663
664     assert( idx[0] == 0 && (ns ==1 || (idx[1] == 1 && idx[2] == 2)));
665
666     for( i = 0; i < ns; i++ )
667     {
668         int c = idx[i];
669         h[c] = m_ci[c].h*8;
670         v[c] = m_ci[c].v*8;
671         pos[c] = s >> 6;
672         s += h[c]*v[c];
673     }
674
675     if( ns == 3 )
676     {
677         x_shift = h[0]/(h[1]*2);
678         y_shift = v[0]/(v[1]*2);
679     }
680
681     m_strm.Flush();
682     ResetDecoder();
683
684     for( mcu = 0;; mcu++ )
685     {
686         int  x2, y2, x, y;
687         int* cmp;
688         uchar* data1;
689         
690         if( mcu == m_MCUs && m_MCUs != 0 )
691         {
692             ResetDecoder();
693             m_strm.AlignOnByte();
694             mcu = 0;
695         }
696
697         // Get mcu
698         for( i = 0; i < ns; i++ )
699         {
700             int  c = idx[i];
701             cmp = blocks[pos[c]];
702             for( y = 0; y < v[c]; y += 8, cmp += h[c]*8 )
703                 for( x = 0; x < h[c]; x += 8 )
704                 {
705                     GetBlock( temp, c );
706                     if( i < (color ? 3 : 1))
707                     {
708                         aan_idct8x8( temp, cmp + x, h[c] );
709                     }
710                 }
711         }
712
713         y2 = v[0];
714         x2 = h[0];
715
716         if( y1 + y2 > m_height ) y2 = m_height - y1;
717         if( x1 + x2 > m_width ) x2 = m_width - x1;
718
719         cmp = blocks[0];
720         data1 = data + x1*nch;
721
722         if( ns == 1 )
723             for( y = 0; y < y2; y++, data1 += step, cmp += h[0] )
724             {
725                 if( color )
726                 {
727                     for( x = 0; x < x2; x++ )
728                     {
729                         int val = descale( cmp[x] + 128*4, 2 );
730                         data1[x*3] = data1[x*3 + 1] = data1[x*3 + 2] = saturate( val );
731                     }
732                 }
733                 else
734                 {
735                     for( x = 0; x < x2; x++ )
736                     {
737                         int val = descale( cmp[x] + 128*4, 2 );
738                         data1[x] = saturate( val );
739                     }
740                 }
741             }
742         else
743         {
744             for( y = 0; y < y2; y++, data1 += step, cmp += h[0] )
745             {
746                 if( color )
747                 {
748                     int  shift = h[1]*(y >> y_shift);
749                     int* cmpCb = blocks[pos[1]] + shift; 
750                     int* cmpCr = blocks[pos[2]] + shift;
751                     for( x = 0; x < x2; x++ )
752                     {
753                         int Y  = (cmp[x] + 128*4) << fixc;
754                         int Cb = cmpCb[x >> x_shift];
755                         int Cr = cmpCr[x >> x_shift];
756                         int t = (Y + Cb*b_cb) >> (fixc + 2);
757                         data1[x*3] = saturate(t);
758                         t = (Y + Cb*g_cb + Cr*g_cr) >> (fixc + 2);
759                         data1[x*3 + 1] = saturate(t);
760                         t = (Y + Cr*r_cr) >> (fixc + 2);
761                         data1[x*3 + 2] = saturate(t);
762                     }
763                 }
764                 else
765                 {
766                     for( x = 0; x < x2; x++ )
767                     {
768                         int val = descale( cmp[x] + 128*4, 2 );
769                         data1[x] = saturate(val);
770                     }
771                 }
772             }
773         }
774
775         x1 += h[0];
776         if( x1 >= m_width )
777         {
778             x1 = 0;
779             y1 += v[0];
780             data += v[0]*step;
781             if( y1 >= m_height ) break;
782         }
783     }
784 }
785
786
787 void  GrFmtJpegReader::GetBlock( int* block, int c )
788 {
789     memset( block, 0, 64*sizeof(block[0]) );
790
791     assert( 0 <= c && c < 3 );
792     const short* td = m_td[m_ci[c].td];
793     const short* ta = m_ta[m_ci[c].ta];
794     const int* tq = m_tq[m_ci[c].tq];
795
796     // Get DC coefficient
797     int i = 0, cat  = m_strm.GetHuff( td );
798     int mask = bs_bits_masks[cat];
799     int val  = m_strm.Get( cat );
800
801     val -= (val*2 <= mask ? mask : 0);
802     m_ci[c].dc_pred = val += m_ci[c].dc_pred;
803     
804     block[0] = (val * tq[0]) >> 16;
805
806     // Get AC coeffs
807     for(;;)
808     {
809         cat = m_strm.GetHuff( ta );
810         if( cat == 0 ) break; // end of block
811
812         i += (cat >> 4) + 1;
813         cat &= 15;
814         mask = bs_bits_masks[cat];
815         val  = m_strm.Get( cat );
816         cat  = zigzag[i];
817         val -= (val*2 <= mask ? mask : 0);
818         block[cat] = (val * tq[cat]) >> 16;
819         assert( i <= 63 );
820         if( i >= 63 ) break;
821     }
822 }