1 /* Copyright (c) MediaArea.net SARL. All Rights Reserved.
2 *
3 * Use of this source code is governed by a BSD-style license that can
4 * be found in the License.html file in the root of the source tree.
5 */
6
7 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 //
9 // Links:
10 //
11 // http://www.fileformat.info/format/jpeg/
12 // http://park2.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
13 // http://www.w3.org/Graphics/JPEG/jfif3.pdf
14 // http://www.sentex.net/~mwandel/jhead/
15 //
16 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
17
18 //---------------------------------------------------------------------------
19 // Pre-compilation
20 #include "MediaInfo/PreComp.h"
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24 //---------------------------------------------------------------------------
25
26 //---------------------------------------------------------------------------
27 #include "MediaInfo/Setup.h"
28 //---------------------------------------------------------------------------
29
30 //---------------------------------------------------------------------------
31 #if defined(MEDIAINFO_JPEG_YES)
32 //---------------------------------------------------------------------------
33
34 //---------------------------------------------------------------------------
35 #include "MediaInfo/Image/File_Jpeg.h"
36 #include "MediaInfo/MediaInfo_Config_MediaInfo.h"
37 #include "ZenLib/Utils.h"
38 #include <vector>
39 using namespace ZenLib;
40 using namespace std;
41 //---------------------------------------------------------------------------
42
43 namespace MediaInfoLib
44 {
45
46 //***************************************************************************
47 // Constants
48 //***************************************************************************
49
50 //---------------------------------------------------------------------------
51 namespace Elements
52 {
53 const int16u TEM =0xFF01;
54 const int16u SOC =0xFF4F; //JPEG 2000
55 const int16u SIZ =0xFF51; //JPEG 2000
56 const int16u COD =0xFF52; //JPEG 2000
57 const int16u COC =0xFF53; //JPEG 2000
58 const int16u TLM =0xFF55; //JPEG 2000
59 const int16u PLM =0xFF57; //JPEG 2000
60 const int16u PLT =0xFF58; //JPEG 2000
61 const int16u QCD =0xFF5C; //JPEG 2000
62 const int16u QCC =0xFF5D; //JPEG 2000
63 const int16u RGN =0xFF5E; //JPEG 2000
64 const int16u POC =0xFF5F; //JPEG 2000
65 const int16u PPM =0xFF60; //JPEG 2000
66 const int16u PPT =0xFF61; //JPEG 2000
67 const int16u CME =0xFF64; //JPEG 2000
68 const int16u SOT =0xFF90; //JPEG 2000
69 const int16u SOP =0xFF91; //JPEG 2000
70 const int16u EPH =0xFF92; //JPEG 2000
71 const int16u SOD =0xFF93; //JPEG 2000
72 const int16u SOF0=0xFFC0;
73 const int16u SOF1=0xFFC1;
74 const int16u SOF2=0xFFC2;
75 const int16u SOF3=0xFFC3;
76 const int16u DHT =0xFFC4;
77 const int16u SOF5=0xFFC5;
78 const int16u SOF6=0xFFC6;
79 const int16u SOF7=0xFFC7;
80 const int16u JPG =0xFFC8;
81 const int16u SOF9=0xFFC9;
82 const int16u SOFA=0xFFCA;
83 const int16u SOFB=0xFFCB;
84 const int16u DAC =0xFFCC;
85 const int16u SOFD=0xFFCD;
86 const int16u SOFE=0xFFCE;
87 const int16u SOFF=0xFFCF;
88 const int16u RST0=0xFFD0;
89 const int16u RST1=0xFFD1;
90 const int16u RST2=0xFFD2;
91 const int16u RST3=0xFFD3;
92 const int16u RST4=0xFFD4;
93 const int16u RST5=0xFFD5;
94 const int16u RST6=0xFFD6;
95 const int16u RST7=0xFFD7;
96 const int16u SOI =0xFFD8;
97 const int16u EOI =0xFFD9; //EOC in JPEG 2000
98 const int16u SOS =0xFFDA;
99 const int16u DQT =0xFFDB;
100 const int16u DNL =0xFFDC;
101 const int16u DRI =0xFFDD;
102 const int16u DHP =0xFFDE;
103 const int16u EXP =0xFFDF;
104 const int16u APP0=0xFFE0;
105 const int16u APP1=0xFFE1;
106 const int16u APP2=0xFFE2;
107 const int16u APP3=0xFFE3;
108 const int16u APP4=0xFFE4;
109 const int16u APP5=0xFFE5;
110 const int16u APP6=0xFFE6;
111 const int16u APP7=0xFFE7;
112 const int16u APP8=0xFFE8;
113 const int16u APP9=0xFFE9;
114 const int16u APPA=0xFFEA;
115 const int16u APPB=0xFFEB;
116 const int16u APPC=0xFFEC;
117 const int16u APPD=0xFFED;
118 const int16u APPE=0xFFEE;
119 const int16u APPF=0xFFEF;
120 const int16u JPG0=0xFFF0;
121 const int16u JPG1=0xFFF1;
122 const int16u JPG2=0xFFF2;
123 const int16u JPG3=0xFFF3;
124 const int16u JPG4=0xFFF4;
125 const int16u JPG5=0xFFF5;
126 const int16u JPG6=0xFFF6;
127 const int16u JPG7=0xFFF7;
128 const int16u JPG8=0xFFF8;
129 const int16u JPG9=0xFFF9;
130 const int16u JPGA=0xFFFA;
131 const int16u JPGB=0xFFFB;
132 const int16u JPGC=0xFFFC;
133 const int16u JPGD=0xFFFD;
134 const int16u COM =0xFFFE;
135 }
136
137 //---------------------------------------------------------------------------
138 // Borland C++ does not accept local template
139 struct Jpeg_samplingfactor
140 {
141 int8u Ci;
142 int8u Hi;
143 int8u Vi;
144 };
145
146 //---------------------------------------------------------------------------
Jpeg_AddDec(string & Current,int8u Value)147 void Jpeg_AddDec(string& Current, int8u Value)
148 {
149 if (Value < 10)
150 Current += '0' + Value;
151 else
152 {
153 Current += '1';
154 Current += '0' - 10 + Value;
155 }
156 }
157
158 //---------------------------------------------------------------------------
Jpeg_WithLevel(string Profile,int8u Level,bool HasSubLevel=false)159 string Jpeg_WithLevel(string Profile, int8u Level, bool HasSubLevel=false)
160 {
161 Profile += '@';
162 if (HasSubLevel)
163 Profile += 'M'; // Has Mainlevel
164 Profile += 'L';
165 Jpeg_AddDec(Profile, Level & 0xF);
166 if (HasSubLevel)
167 {
168 Profile += 'S'; // Has Sublevel
169 Profile += 'L';
170 Jpeg_AddDec(Profile, Level >> 4);
171 }
172 return Profile;
173 }
174
Jpeg2000_Rsiz(int16u Rsiz)175 string Jpeg2000_Rsiz(int16u Rsiz)
176 {
177 switch (Rsiz)
178 {
179 case 0x0000: return "No restrictions";
180 case 0x0001: return "Profile-0";
181 case 0x0002: return "Profile-1";
182 case 0x0003: return "D-Cinema 2k";
183 case 0x0004: return "D-Cinema 4k";
184 case 0x0005: return "D-Cinema 2k Scalable";
185 case 0x0006: return "D-Cinema 4k Scalable";
186 case 0x0007: return "Long-term storage";
187 case 0x0306: return "BCMR@L6"; //Broadcast Contribution Multi-tile Reversible
188 case 0x0307: return "BCMR@L7"; //Broadcast Contribution Multi-tile Reversible
189 default:
190 switch ((Rsiz & 0xFFF0))
191 {
192 case 0x0100: return Jpeg_WithLevel("BCS", (int8u)Rsiz); //Broadcast Contribution Single-tile
193 case 0x0200: return Jpeg_WithLevel("BCM", (int8u)Rsiz); //Broadcast Contribution Multi-tile
194 default:;
195 }
196 switch ((Rsiz & 0xFF00))
197 {
198 case 0x0400: return Jpeg_WithLevel("IMFS2k", (int8u)Rsiz, true); // IMF Single-tile 2k
199 case 0x0500: return Jpeg_WithLevel("IMFS4k", (int8u)Rsiz, true); // IMF Single-tile 4k
200 case 0x0600: return Jpeg_WithLevel("IMFS8k", (int8u)Rsiz, true); // IMF Single-tile 8k
201 case 0x0700: return Jpeg_WithLevel("IMFMR2k", (int8u)Rsiz, true); // IMF Single/Multi-tile 2k
202 case 0x0800: return Jpeg_WithLevel("IMFMR4k", (int8u)Rsiz, true); // IMF Single/Multi-tile 4k
203 case 0x0900: return Jpeg_WithLevel("IMFMR8k", (int8u)Rsiz, true); // IMF Single/Multi-tile 8k
204 default:;
205 }
206 return Ztring::ToZtring(Rsiz, 16).To_UTF8();
207 }
208 }
209
ICC_Tag(int32u Signature)210 string ICC_Tag(int32u Signature)
211 {
212 switch (Signature)
213 {
214 case 0x63707274: return "Copyright";
215 case 0x64657363: return "Profile description";
216 case 0x77747074: return "White point";
217 case 0x626B7074: return "Black point";
218 case 0x72545243: return "Reproduction curve, red";
219 case 0x67545243: return "Reproduction curve, green";
220 case 0x62545243: return "Reproduction curve, blue";
221 case 0x7258595A: return "Matrix, red";
222 case 0x6758595A: return "Matrix, green";
223 case 0x6258595A: return "Matrix, blue";
224 default : return Ztring().From_CC4(Signature).To_UTF8();
225 }
226 }
227
ICC_ColorSpace(int32u ColorSpace)228 string ICC_ColorSpace(int32u ColorSpace)
229 {
230 switch (ColorSpace)
231 {
232 case 0x434D5920: return "CMY";
233 case 0x434D594B: return "CMYK";
234 case 0x47524159: return "Y";
235 case 0x484C5320: return "HLS";
236 case 0x48535620: return "HSV";
237 case 0x4C616220: return "Lab";
238 case 0x4C757620: return "Luv";
239 case 0x52474220: return "RGB";
240 case 0x58595A20: return "XYZ";
241 case 0x59436272: return "YCbCr";
242 case 0x59787920: return "xyY";
243 default : return Ztring().From_CC4(ColorSpace).To_UTF8();
244 }
245 }
246
247 //***************************************************************************
248 // Constructor/Destructor
249 //***************************************************************************
250
251 //---------------------------------------------------------------------------
File_Jpeg()252 File_Jpeg::File_Jpeg()
253 {
254 //Config
255 #if MEDIAINFO_EVENTS
256 ParserIDs[0]=MediaInfo_Parser_Jpeg;
257 StreamIDs_Width[0]=0;
258 #endif //MEDIAINFO_EVENTS
259 #if MEDIAINFO_TRACE
260 Trace_Layers_Update(8); //Stream
261 #endif //MEDIAINFO_TRACE
262 MustSynchronize=true;
263 StreamSource=IsStream;
264
265 //In
266 StreamKind=Stream_Image;
267 Interlaced=false;
268 #if MEDIAINFO_DEMUX
269 FrameRate=0;
270 #endif //MEDIAINFO_DEMUX
271 }
272
273 //***************************************************************************
274 // Streams management
275 //***************************************************************************
276
277 //---------------------------------------------------------------------------
Streams_Accept()278 void File_Jpeg::Streams_Accept()
279 {
280 if (!IsSub)
281 {
282 TestContinuousFileNames();
283
284 Stream_Prepare(Config->File_Names.size()>1?Stream_Video:StreamKind);
285 if (File_Size!=(int64u)-1)
286 Fill(StreamKind_Last, StreamPos_Last, Fill_Parameter(StreamKind_Last, Generic_StreamSize), File_Size);
287 if (StreamKind_Last==Stream_Video)
288 Fill(Stream_Video, StreamPos_Last, Video_FrameCount, Config->File_Names.size());
289 }
290 else
291 Stream_Prepare(StreamKind);
292
293 //Configuration
294 Buffer_MaximumSize=64*1024*1024; //Some big frames are possible (e.g YUV 4:2:2 10 bits 1080p)
295 }
296
297 //---------------------------------------------------------------------------
Streams_Finish()298 void File_Jpeg::Streams_Finish()
299 {
300 if (StreamKind_Last==Stream_Video && Config->ParseSpeed>=1.0)
301 Fill (Stream_Video, 0, Video_StreamSize, Buffer_TotalBytes, 10, true);
302 }
303
304 //***************************************************************************
305 // Static stuff
306 //***************************************************************************
307
308 //---------------------------------------------------------------------------
FileHeader_Begin()309 bool File_Jpeg::FileHeader_Begin()
310 {
311 //Element_Size
312 if (Buffer_Size<3)
313 return false; //Must wait for more data
314
315 if (Buffer[2]!=0xFF
316 || (CC2(Buffer)!=Elements::SOI
317 && CC2(Buffer)!=Elements::SOC))
318 {
319 Reject("JPEG");
320 return false;
321 }
322
323 //All should be OK...
324 return true;
325 }
326
327 //***************************************************************************
328 // Buffer - Synchro
329 //***************************************************************************
330
331 //---------------------------------------------------------------------------
Synchronize()332 bool File_Jpeg::Synchronize()
333 {
334 //Synchronizing
335 while(Buffer_Offset+2<=Buffer_Size && (Buffer[Buffer_Offset ]!=0xFF
336 || Buffer[Buffer_Offset+1]==0x00))
337 Buffer_Offset++;
338
339 if (Buffer_Offset+1==Buffer_Size && Buffer[Buffer_Offset ]!=0xFF)
340 Buffer_Offset++;
341
342 if (Buffer_Offset+2>Buffer_Size)
343 return false;
344
345 //Synched is OK
346 Synched=true;
347 return true;
348 }
349
350 //---------------------------------------------------------------------------
Synched_Test()351 bool File_Jpeg::Synched_Test()
352 {
353 if (SOS_SOD_Parsed)
354 return true; ///No sync after SOD
355
356 //Must have enough buffer for having header
357 if (Buffer_Offset+2>Buffer_Size)
358 return false;
359
360 //Quick test of synchro
361 if (Buffer[Buffer_Offset]!=0xFF)
362 {
363 Synched=false;
364 return true;
365 }
366
367 //We continue
368 return true;
369 }
370
371 //---------------------------------------------------------------------------
Synched_Init()372 void File_Jpeg::Synched_Init()
373 {
374 APP0_JFIF_Parsed=false;
375 SOS_SOD_Parsed=false;
376 APPE_Adobe0_transform=(int8u)-1;
377 }
378
379 //***************************************************************************
380 // Buffer - Demux
381 //***************************************************************************
382
383 //---------------------------------------------------------------------------
384 #if MEDIAINFO_DEMUX
Demux_UnpacketizeContainer_Test()385 bool File_Jpeg::Demux_UnpacketizeContainer_Test()
386 {
387 if (!IsSub)
388 {
389 if (!Status[IsAccepted])
390 {
391 Accept();
392 if (Config->Demux_EventWasSent)
393 return false;
394 }
395 if (Config->File_Names.size()>1)
396 return Demux_UnpacketizeContainer_Test_OneFramePerFile();
397 }
398
399 if (Interlaced && Buffer_Offset==0)
400 {
401 bool StartIsFound=false;
402 while (Demux_Offset+2<=Buffer_Size)
403 {
404 int16u code=BigEndian2int16u(Buffer+Demux_Offset);
405 Demux_Offset+=2;
406 switch (code)
407 {
408 case Elements::SOD : //JPEG-2000 start
409 StartIsFound=true;
410 case Elements::TEM :
411 case Elements::RST0 :
412 case Elements::RST1 :
413 case Elements::RST2 :
414 case Elements::RST3 :
415 case Elements::RST4 :
416 case Elements::RST5 :
417 case Elements::RST6 :
418 case Elements::RST7 :
419 case Elements::SOC :
420 case Elements::SOI :
421 case Elements::EOI :
422 break;
423 default :
424 if (Demux_Offset+2>Buffer_Size)
425 break;
426 {
427 int16u size=BigEndian2int16u(Buffer+Demux_Offset);
428 if (Demux_Offset+2+size>Buffer_Size)
429 break;
430 Demux_Offset+=size;
431 if (code==Elements::SOS) //JPEG start
432 StartIsFound=true;
433 }
434 }
435 if (StartIsFound)
436 break;
437 }
438
439 while (Demux_Offset+2<=Buffer_Size)
440 {
441 while (Demux_Offset<Buffer_Size && Buffer[Demux_Offset]!=0xFF)
442 Demux_Offset++;
443 if (Demux_Offset+2<=Buffer_Size && Buffer[Demux_Offset+1]==0xD9) //EOI (JPEG 2000)
444 break;
445 Demux_Offset++;
446 }
447 if (Demux_Offset+2<=Buffer_Size)
448 Demux_Offset+=2;
449 }
450 else
451 Demux_Offset=Buffer_Size;
452
453 if (Interlaced)
454 {
455 if (Field_Count==0 && FrameRate && Demux_Offset!=Buffer_Size)
456 FrameRate*=2; //Now field rate
457 if (FrameRate)
458 FrameInfo.DUR=float64_int64s(1000000000/FrameRate); //Actually, field or frame rate
459 }
460
461 Demux_UnpacketizeContainer_Demux();
462
463 if (Interlaced)
464 {
465 if (FrameInfo.DTS!=(int64u)-1 && FrameInfo.DUR!=(int64u)-1)
466 FrameInfo.DTS+=FrameInfo.DUR;
467 }
468
469 return true;
470 }
471 #endif //MEDIAINFO_DEMUX
472
473 //***************************************************************************
474 // Buffer - Global
475 //***************************************************************************
476
477 //---------------------------------------------------------------------------
Read_Buffer_Unsynched()478 void File_Jpeg::Read_Buffer_Unsynched()
479 {
480 SOS_SOD_Parsed=false;
481
482 Read_Buffer_Unsynched_OneFramePerFile();
483 }
484
485 //---------------------------------------------------------------------------
Read_Buffer_Continue()486 void File_Jpeg::Read_Buffer_Continue()
487 {
488 if (Config->ParseSpeed>=1.0 && IsSub && Status[IsFilled])
489 {
490 #if MEDIAINFO_DEMUX
491 if (Buffer_TotalBytes<Demux_TotalBytes)
492 {
493 Skip_XX(Demux_TotalBytes-Buffer_TotalBytes, "Data"); //We currently don't want to parse data during demux
494 Param_Info1(Frame_Count);
495 if (Interlaced)
496 {
497 Field_Count++;
498 Field_Count_InThisBlock++;
499 }
500 if (!Interlaced || Field_Count%2==0)
501 {
502 Frame_Count++;
503 if (Frame_Count_NotParsedIncluded!=(int64u)-1)
504 Frame_Count_NotParsedIncluded++;
505 }
506 return;
507 }
508 #endif //MEDIAINFO_DEMUX
509
510 #if MEDIAINFO_DEMUX
511 if (!Demux_UnpacketizeContainer)
512 #endif //MEDIAINFO_DEMUX
513 {
514 Skip_XX(Buffer_Size, "Data"); //We currently don't want to parse data during demux
515 Param_Info1(Frame_Count);
516 if (Interlaced)
517 Field_Count+=2;
518 Frame_Count++;
519 if (Frame_Count_NotParsedIncluded!=(int64u)-1)
520 Frame_Count_NotParsedIncluded++;
521 }
522 }
523 }
524
525 //***************************************************************************
526 // Buffer - Per element
527 //***************************************************************************
528
529 //---------------------------------------------------------------------------
Header_Parse()530 void File_Jpeg::Header_Parse()
531 {
532 if (SOS_SOD_Parsed)
533 {
534 Header_Fill_Code(0, "Data");
535 if (!Header_Parser_Fill_Size())
536 {
537 Element_WaitForMoreData();
538 return;
539 }
540 return;
541 }
542
543 //Parsing
544 int16u code, size;
545 Get_B2 (code, "Marker");
546 switch (code)
547 {
548 case Elements::TEM :
549 case Elements::RST0 :
550 case Elements::RST1 :
551 case Elements::RST2 :
552 case Elements::RST3 :
553 case Elements::RST4 :
554 case Elements::RST5 :
555 case Elements::RST6 :
556 case Elements::RST7 :
557 case Elements::SOC :
558 case Elements::SOD :
559 case Elements::SOI :
560 case Elements::EOI :
561 size=0; break;
562 default : Get_B2 (size, "Fl - Frame header length");
563 }
564
565 //Filling
566 Header_Fill_Code(code, Ztring().From_CC2(code));
567 Header_Fill_Size(2+size);
568 }
569
570 //---------------------------------------------------------------------------
Header_Parser_Fill_Size()571 bool File_Jpeg::Header_Parser_Fill_Size()
572 {
573 //Look for next Sync word
574 if (Buffer_Offset_Temp==0) //Buffer_Offset_Temp is not 0 if Header_Parse_Fill_Size() has already parsed first frames
575 Buffer_Offset_Temp=Buffer_Offset;
576
577 #if MEDIAINFO_DEMUX
578 if (Buffer_TotalBytes+2<Demux_TotalBytes)
579 Buffer_Offset_Temp=(size_t)(Demux_TotalBytes-(Buffer_TotalBytes+2));
580 #endif //MEDIAINFO_DEMUX
581
582 while (Buffer_Offset_Temp+2<=Buffer_Size)
583 {
584 while (Buffer_Offset_Temp<Buffer_Size && Buffer[Buffer_Offset_Temp]!=0xFF)
585 Buffer_Offset_Temp++;
586 if (Buffer_Offset_Temp+2<=Buffer_Size && Buffer[Buffer_Offset_Temp+1]==0xD9) //EOI
587 break;
588 Buffer_Offset_Temp++;
589 }
590
591 //Must wait more data?
592 if (Buffer_Offset_Temp+2>Buffer_Size)
593 {
594 if (/*FrameIsAlwaysComplete ||*/ File_Offset+Buffer_Size>=File_Size)
595 Buffer_Offset_Temp=Buffer_Size; //We are sure that the next bytes are a start
596 else
597 return false;
598 }
599
600 //OK, we continue
601 Header_Fill_Size(Buffer_Offset_Temp-Buffer_Offset);
602 Buffer_Offset_Temp=0;
603 return true;
604 }
605
606 //---------------------------------------------------------------------------
Data_Parse()607 void File_Jpeg::Data_Parse()
608 {
609 #define CASE_INFO(_NAME, _DETAIL) \
610 case Elements::_NAME : Element_Info1(#_NAME); Element_Info1(_DETAIL); _NAME(); break;
611
612 //Parsing
613 if (SOS_SOD_Parsed)
614 {
615 Skip_XX(Element_Size, "Data");
616 SOS_SOD_Parsed=false;
617 return;
618 }
619 switch (Element_Code)
620 {
621 CASE_INFO(TEM , "TEM");
622 CASE_INFO(SOC , "Start of codestream"); //JPEG 2000
623 CASE_INFO(SIZ , "Image and tile size"); //JPEG 2000
624 CASE_INFO(COD , "Coding style default"); //JPEG 2000
625 CASE_INFO(COC , "Coding style component"); //JPEG 2000
626 CASE_INFO(TLM , "Tile-part lengths, main header"); //JPEG 2000
627 CASE_INFO(PLM , "Packet length, main header"); //JPEG 2000
628 CASE_INFO(PLT , "Packet length, tile-part header"); //JPEG 2000
629 CASE_INFO(QCD , "Quantization default"); //JPEG 2000
630 CASE_INFO(QCC , "Quantization component "); //JPEG 2000
631 CASE_INFO(RGN , "Region-of-interest"); //JPEG 2000
632 CASE_INFO(POC , "Progression order change"); //JPEG 2000
633 CASE_INFO(PPM , "Packed packet headers, main header"); //JPEG 2000
634 CASE_INFO(PPT , "Packed packet headers, tile-part header"); //JPEG 2000
635 CASE_INFO(CME , "Comment and extension"); //JPEG 2000
636 CASE_INFO(SOT , "Start of tile-part"); //JPEG 2000
637 CASE_INFO(SOP , "Start of packet"); //JPEG 2000
638 CASE_INFO(EPH , "End of packet header"); //JPEG 2000
639 CASE_INFO(SOD , "Start of data"); //JPEG 2000
640 CASE_INFO(SOF0, "Baseline DCT (Huffman)");
641 CASE_INFO(SOF1, "Extended sequential DCT (Huffman)");
642 CASE_INFO(SOF2, "Progressive DCT (Huffman)");
643 CASE_INFO(SOF3, "Lossless (sequential) (Huffman)");
644 CASE_INFO(DHT , "Define Huffman Tables");
645 CASE_INFO(SOF5, "Differential sequential DCT (Huffman)");
646 CASE_INFO(SOF6, "Differential progressive DCT (Huffman)");
647 CASE_INFO(SOF7, "Differential lossless (sequential) (Huffman)");
648 CASE_INFO(JPG , "Reserved for JPEG extensions");
649 CASE_INFO(SOF9, "Extended sequential DCT (Arithmetic)");
650 CASE_INFO(SOFA, "Progressive DCT (Arithmetic)");
651 CASE_INFO(SOFB, "Lossless (sequential) (Arithmetic)");
652 CASE_INFO(DAC , "Define Arithmetic Coding");
653 CASE_INFO(SOFD, "Differential sequential DCT (Arithmetic)");
654 CASE_INFO(SOFE, "Differential progressive DCT (Arithmetic)");
655 CASE_INFO(SOFF, "Differential lossless (sequential) (Arithmetic)");
656 CASE_INFO(RST0, "Restart Interval Termination 0");
657 CASE_INFO(RST1, "Restart Interval Termination 1");
658 CASE_INFO(RST2, "Restart Interval Termination 2");
659 CASE_INFO(RST3, "Restart Interval Termination 3");
660 CASE_INFO(RST4, "Restart Interval Termination 4");
661 CASE_INFO(RST5, "Restart Interval Termination 5");
662 CASE_INFO(RST6, "Restart Interval Termination 6");
663 CASE_INFO(RST7, "Restart Interval Termination 7");
664 CASE_INFO(SOI , "Start Of Image");
665 CASE_INFO(EOI , "End Of Image"); //Is EOC (End of codestream) in JPEG 2000
666 CASE_INFO(SOS , "Start Of Scan");
667 CASE_INFO(DQT , "Define Quantization Tables");
668 CASE_INFO(DNL , "Define Number of Lines");
669 CASE_INFO(DRI , "Define Restart Interval");
670 CASE_INFO(DHP , "Define Hierarchical Progression");
671 CASE_INFO(EXP , "Expand Reference Components");
672 CASE_INFO(APP0, "Application-specific marker 0");
673 CASE_INFO(APP1, "Application-specific marker 1");
674 CASE_INFO(APP2, "Application-specific marker 2");
675 CASE_INFO(APP3, "Application-specific marker 3");
676 CASE_INFO(APP4, "Application-specific marker 4");
677 CASE_INFO(APP5, "Application-specific marker 5");
678 CASE_INFO(APP6, "Application-specific marker 6");
679 CASE_INFO(APP7, "Application-specific marker 7");
680 CASE_INFO(APP8, "Application-specific marker 8");
681 CASE_INFO(APP9, "Application-specific marker 9");
682 CASE_INFO(APPA, "Application-specific marker 10");
683 CASE_INFO(APPB, "Application-specific marker 11");
684 CASE_INFO(APPC, "Application-specific marker 12");
685 CASE_INFO(APPD, "Application-specific marker 13");
686 CASE_INFO(APPE, "Application-specific marker 14");
687 CASE_INFO(APPF, "Application-specific marker 15");
688 CASE_INFO(JPG0, "JPG");
689 CASE_INFO(JPG1, "JPG");
690 CASE_INFO(JPG2, "JPG");
691 CASE_INFO(JPG3, "JPG");
692 CASE_INFO(JPG4, "JPG");
693 CASE_INFO(JPG5, "JPG");
694 CASE_INFO(JPG6, "JPG");
695 CASE_INFO(JPG7, "JPG");
696 CASE_INFO(JPG8, "JPG");
697 CASE_INFO(JPG9, "JPG");
698 CASE_INFO(JPGA, "JPG");
699 CASE_INFO(JPGB, "JPG");
700 CASE_INFO(JPGC, "JPG");
701 CASE_INFO(JPGD, "JPG");
702 CASE_INFO(COM , "Comment");
703 default : Element_Info1("Reserved");
704 Skip_XX(Element_Size, "Data");
705 }
706 }
707
708 //***************************************************************************
709 // Elements
710 //***************************************************************************
711
712 //---------------------------------------------------------------------------
SIZ()713 void File_Jpeg::SIZ()
714 {
715 //Parsing
716 vector<float> SamplingFactors;
717 vector<int8u> BitDepths;
718 int8u SamplingFactors_Max=0;
719 int32u Xsiz, Ysiz;
720 int16u Rsiz, Count;
721 Get_B2 (Rsiz, "Rsiz - Capability of the codestream");
722 Get_B4 (Xsiz, "Xsiz - Image size X");
723 Get_B4 (Ysiz, "Ysiz - Image size Y");
724 Skip_B4( "XOsiz - Image offset X");
725 Skip_B4( "YOsiz - Image offset Y");
726 Skip_B4( "tileW - Size of tile W");
727 Skip_B4( "tileH - Size of tile H");
728 Skip_B4( "XTOsiz - Upper-left tile offset X");
729 Skip_B4( "YTOsiz - Upper-left tile offset Y");
730 Get_B2 (Count, "Components and initialize related arrays");
731 for (int16u Pos=0; Pos<Count; Pos++)
732 {
733 Element_Begin1("Initialize related array");
734 int8u BitDepth, compSubsX, compSubsY;
735 BS_Begin();
736 Skip_SB( "Signed");
737 Get_S1 (7, BitDepth, "BitDepth"); Param_Info1(1+BitDepth); Element_Info1(1+BitDepth);
738 BS_End();
739 Get_B1 ( compSubsX, "compSubsX"); Element_Info1(compSubsX);
740 Get_B1 ( compSubsY, "compSubsY"); Element_Info1(compSubsY);
741 Element_End0();
742
743 //Filling list of HiVi
744 if (compSubsX)
745 {
746 SamplingFactors.push_back(((float)compSubsY)/compSubsX);
747 if (((float)compSubsY)/compSubsX>SamplingFactors_Max)
748 SamplingFactors_Max=(int8u)((float)compSubsY)/compSubsX;
749 }
750
751 if (BitDepths.empty() || BitDepth!=BitDepths[0])
752 BitDepths.push_back(BitDepth);
753 }
754
755 FILLING_BEGIN_PRECISE();
756 if (Frame_Count==0 && Field_Count==0)
757 {
758 Accept("JPEG 2000");
759 Fill("JPEG 2000");
760
761 if (Count_Get(StreamKind_Last)==0)
762 Stream_Prepare(StreamKind_Last);
763 Fill(StreamKind_Last, 0, Fill_Parameter(StreamKind_Last, Generic_Format), "JPEG 2000");
764 Fill(StreamKind_Last, 0, Fill_Parameter(StreamKind_Last, Generic_Codec), "JPEG 2000");
765 Fill(StreamKind_Last, 0, "Format_Profile", Jpeg2000_Rsiz(Rsiz));
766 if (StreamKind_Last==Stream_Image)
767 Fill(Stream_Image, 0, Image_Codec_String, "JPEG 2000", Unlimited, true, true); //To Avoid automatic filling
768 Fill(StreamKind_Last, 0, StreamKind_Last==Stream_Image?(size_t)Image_Width:(size_t)Video_Width, Xsiz);
769 Fill(StreamKind_Last, 0, StreamKind_Last==Stream_Image?(size_t)Image_Height:(size_t)Video_Height, Ysiz*(Interlaced?2:1)); //If image is from interlaced content, must multiply height by 2
770
771 if (BitDepths.size()==1)
772 Fill(StreamKind_Last, 0, Fill_Parameter(StreamKind_Last, Generic_BitDepth), 1+BitDepths[0]);
773
774 //Chroma subsampling
775 if (SamplingFactors_Max)
776 while (SamplingFactors_Max<4)
777 {
778 for (size_t Pos=0; Pos<SamplingFactors.size(); Pos++)
779 SamplingFactors[Pos]*=2;
780 SamplingFactors_Max*=2;
781 }
782 while (SamplingFactors.size()<3)
783 SamplingFactors.push_back(0);
784 Ztring ChromaSubsampling;
785 for (size_t Pos=0; Pos<SamplingFactors.size(); Pos++)
786 ChromaSubsampling+=Ztring::ToZtring(SamplingFactors[Pos], 0)+__T(':');
787 if (!ChromaSubsampling.empty())
788 {
789 ChromaSubsampling.resize(ChromaSubsampling.size()-1);
790 Fill(StreamKind_Last, 0, "ChromaSubsampling", ChromaSubsampling);
791
792 //Not for sure
793 if (ChromaSubsampling==__T("4:4:4") && (Retrieve(StreamKind_Last, 0, "Format_Profile")==__T("D-Cinema 2k") || Retrieve(StreamKind_Last, 0, "Format_Profile")==__T("D-Cinema 4k")))
794 Fill(StreamKind_Last, 0, "ColorSpace", "XYZ");
795 else if (!IsSub)
796 {
797 if (ChromaSubsampling==__T("4:2:0") || ChromaSubsampling==__T("4:2:2"))
798 Fill(StreamKind_Last, 0, "ColorSpace", "YUV");
799 else if (ChromaSubsampling==__T("4:4:4"))
800 Fill(StreamKind_Last, 0, "ColorSpace", "RGB");
801 }
802 }
803 }
804 FILLING_END();
805 }
806
807 //---------------------------------------------------------------------------
COD()808 void File_Jpeg::COD()
809 {
810 //Parsing
811 int8u Style, Style2, Levels, MultipleComponentTransform;
812 bool PrecinctUsed;
813 Get_B1 (Style, "Scod - Style");
814 Get_Flags (Style, 0, PrecinctUsed, "Precinct used");
815 Skip_Flags(Style, 1, "Use SOP (start of packet)");
816 Skip_Flags(Style, 2, "Use EPH (end of packet header)");
817 Get_B1 (Levels, "Number of decomposition levels");
818 Skip_B1( "Progression order");
819 Skip_B2( "Number of layers");
820 Info_B1(DimX, "Code-blocks dimensions X (2^(n+2))"); Param_Info2(1<<(DimX+2), " pixels");
821 Info_B1(DimY, "Code-blocks dimensions Y (2^(n+2))"); Param_Info2(1<<(DimY+2), " pixels");
822 Get_B1 (Style2, "Style of the code-block coding passes");
823 Skip_Flags(Style2, 0, "Selective arithmetic coding bypass");
824 Skip_Flags(Style2, 1, "MQ states for all contexts");
825 Skip_Flags(Style2, 2, "Regular termination");
826 Skip_Flags(Style2, 3, "Vertically stripe-causal context formation");
827 Skip_Flags(Style2, 4, "Error resilience info is embedded on MQ termination");
828 Skip_Flags(Style2, 5, "Segmentation marker is to be inserted at the end of each normalization coding pass");
829 Skip_B1( "Transform");
830 Get_B1(MultipleComponentTransform, "Multiple component transform");
831 if (PrecinctUsed)
832 {
833 BS_Begin();
834 Skip_S1(4, "LL sub-band width");
835 Skip_S1(4, "LL sub-band height");
836 BS_End();
837 for (int16u Pos=0; Pos<Levels; Pos++)
838 {
839 Element_Begin1("Decomposition level");
840 BS_Begin();
841 Skip_S1(4, "decomposition level width");
842 Skip_S1(4, "decomposition level height");
843 BS_End();
844 Element_End0();
845 }
846 }
847
848 FILLING_BEGIN();
849 if (Frame_Count==0 && Field_Count==0)
850 {
851 switch (MultipleComponentTransform)
852 {
853 case 0x01 : Fill(StreamKind_Last, 0, "Compression_Mode", "Lossless"); break;
854 case 0x02 : Fill(StreamKind_Last, 0, "Compression_Mode", "Lossy"); break;
855 default : ;
856 }
857 }
858 FILLING_END();
859 }
860
861 //---------------------------------------------------------------------------
QCD()862 void File_Jpeg::QCD()
863 {
864 //Parsing
865 Skip_B1( "Sqcd - Style");
866 Skip_XX(Element_Size-Element_Offset, "QCD data");
867 }
868
869 //---------------------------------------------------------------------------
SOD()870 void File_Jpeg::SOD()
871 {
872 SOS_SOD_Parsed=true;
873 if (Interlaced)
874 {
875 Field_Count++;
876 Field_Count_InThisBlock++;
877 }
878 if (!Interlaced || Field_Count%2==0)
879 {
880 Frame_Count++;
881 Frame_Count_InThisBlock++;
882 if (Frame_Count_NotParsedIncluded!=(int64u)-1)
883 Frame_Count_NotParsedIncluded++;
884 if (Status[IsFilled])
885 Fill();
886 if (Config->ParseSpeed<1.0)
887 Finish("JPEG 2000"); //No need of more
888 }
889 }
890
891 //---------------------------------------------------------------------------
SOF_()892 void File_Jpeg::SOF_()
893 {
894 //Parsing
895 vector<Jpeg_samplingfactor> SamplingFactors;
896 int16u Height, Width;
897 int8u Resolution, Count;
898 Get_B1 (Resolution, "P - Sample precision");
899 Get_B2 (Height, "Y - Number of lines");
900 Get_B2 (Width, "X - Number of samples per line");
901 Get_B1 (Count, "Nf - Number of image components in frame");
902 for (int8u Pos=0; Pos<Count; Pos++)
903 {
904 Jpeg_samplingfactor SamplingFactor;
905 Element_Begin1("Component");
906 Get_B1 ( SamplingFactor.Ci, "Ci - Component identifier"); if (SamplingFactor.Ci>Count) Element_Info1(Ztring().append(1, (Char)SamplingFactor.Ci)); else Element_Info1(SamplingFactor.Ci);
907 BS_Begin();
908 Get_S1 (4, SamplingFactor.Hi, "Hi - Horizontal sampling factor"); Element_Info1(SamplingFactor.Hi);
909 Get_S1 (4, SamplingFactor.Vi, "Vi - Vertical sampling factor"); Element_Info1(SamplingFactor.Vi);
910 BS_End();
911 Skip_B1( "Tqi - Quantization table destination selector");
912 Element_End0();
913
914 //Filling list of HiVi
915 SamplingFactors.push_back(SamplingFactor);
916 }
917
918 FILLING_BEGIN_PRECISE();
919 if (Frame_Count==0 && Field_Count==0)
920 {
921 Accept("JPEG");
922 Fill("JPEG");
923
924 if (Count_Get(StreamKind_Last)==0)
925 Stream_Prepare(StreamKind_Last);
926 Fill(StreamKind_Last, 0, Fill_Parameter(StreamKind_Last, Generic_Format), "JPEG");
927 Fill(StreamKind_Last, 0, Fill_Parameter(StreamKind_Last, Generic_Codec), "JPEG");
928 if (StreamKind_Last==Stream_Image)
929 Fill(Stream_Image, 0, Image_Codec_String, "JPEG", Unlimited, true, true); //To Avoid automatic filling
930 if (StreamKind_Last==Stream_Video)
931 Fill(Stream_Video, 0, Video_InternetMediaType, "video/JPEG", Unlimited, true, true);
932 Fill(StreamKind_Last, 0, Fill_Parameter(StreamKind_Last, Generic_BitDepth), Resolution);
933 Fill(StreamKind_Last, 0, "Height", Height*(Interlaced?2:1));
934 Fill(StreamKind_Last, 0, "Width", Width);
935
936 //ColorSpace from http://docs.oracle.com/javase/1.4.2/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html
937 //TODO: if APPE_Adobe0_transform is present, indicate that K is inverted, see http://halicery.com/Image/jpeg/JPEGCMYK.html
938 switch (APPE_Adobe0_transform)
939 {
940 case 0x01 :
941 if (Count==3)
942 Fill(StreamKind_Last, 0, "ColorSpace", "YUV");
943 break;
944 case 0x02 :
945 if (Count==4)
946 Fill(StreamKind_Last, 0, "ColorSpace", "YUVK");
947 break;
948 default :
949 {
950 int8u Ci[256];
951 memset(Ci, 0, 256);
952 for (int8u Pos=0; Pos<Count; Pos++)
953 Ci[SamplingFactors[Pos].Ci]++;
954
955 switch (Count)
956 {
957 case 1 : Fill(StreamKind_Last, 0, "ColorSpace", "Y"); break;
958 case 2 : Fill(StreamKind_Last, 0, "ColorSpace", "YA"); break;
959 case 3 :
960 if (!APP0_JFIF_Parsed && Ci['R']==1 && Ci['G']==1 && Ci['B']==1) //RGB
961 Fill(StreamKind_Last, 0, "ColorSpace", "RGB");
962 else if ((Ci['Y']==1 && ((Ci['C']==1 && Ci['c']==1) //YCc
963 || Ci['C']==2)) //YCC
964 || APP0_JFIF_Parsed //APP0 JFIF header present so YCC
965 || APPE_Adobe0_transform==0 //transform set to YCC
966 || (SamplingFactors[0].Ci==0 && SamplingFactors[1].Ci==1 && SamplingFactors[2].Ci==2) //012
967 || (SamplingFactors[0].Ci==1 && SamplingFactors[1].Ci==2 && SamplingFactors[2].Ci==3)) //123
968 Fill(StreamKind_Last, 0, "ColorSpace", "YUV");
969 else if (APPE_Adobe0_transform==0 || APPE_Adobe0_transform==(int8u)-1) //transform set to RGB (it is a guess)
970 Fill(StreamKind_Last, 0, "ColorSpace", "RGB");
971 break;
972 case 4 :
973 if (!APP0_JFIF_Parsed && Ci['R']==1 && Ci['G']==1 && Ci['B']==1 && Ci['A']==1) //RGBA
974 Fill(StreamKind_Last, 0, "ColorSpace", "RGBA");
975 else if ((Ci['Y']==1 && Ci['A']==1 && ((Ci['C']==1 && Ci['c']==1) //YCcA
976 || Ci['C']==2)) //YCCA
977 || APP0_JFIF_Parsed //APP0 JFIF header present so YCCA
978 || (SamplingFactors[0].Ci==0 && SamplingFactors[1].Ci==1 && SamplingFactors[2].Ci==2 && SamplingFactors[3].Ci==3) //0123
979 || (SamplingFactors[0].Ci==1 && SamplingFactors[1].Ci==2 && SamplingFactors[2].Ci==3 && SamplingFactors[3].Ci==4)) //1234
980 Fill(StreamKind_Last, 0, "ColorSpace", "YUVA");
981 else if (Ci['C']==1 && Ci['M']==1 && Ci['Y']==1 && Ci['K']==1) //CMYK
982 Fill(StreamKind_Last, 0, "ColorSpace", "CMYK");
983 else if (APPE_Adobe0_transform==0 || APPE_Adobe0_transform==(int8u)-1) //transform set to CMYK (it is a guess)
984 Fill(StreamKind_Last, 0, "ColorSpace", "CMYK");
985 break;
986 default: ;
987 }
988 }
989 }
990
991 //Chroma subsampling
992 if ((SamplingFactors.size()==3 || SamplingFactors.size()==4) && SamplingFactors[1].Hi==1 && SamplingFactors[2].Hi==1 && SamplingFactors[1].Vi==1 && SamplingFactors[2].Vi==1)
993 {
994 string ChromaSubsampling;
995 switch (SamplingFactors[0].Hi)
996 {
997 case 1 :
998 switch (SamplingFactors[0].Vi)
999 {
1000 case 1 : if (Retrieve(StreamKind_Last, 0, "ColorSpace").find(__T("YUV"))==0) ChromaSubsampling="4:4:4"; break;
1001 default: ;
1002 }
1003 break;
1004 case 2 :
1005 switch (SamplingFactors[0].Vi)
1006 {
1007 case 1 : ChromaSubsampling="4:2:2"; break;
1008 case 2 : ChromaSubsampling="4:2:0"; break;
1009 default: ;
1010 }
1011 break;
1012 case 4 :
1013 switch (SamplingFactors[0].Vi)
1014 {
1015 case 1 : ChromaSubsampling="4:1:1"; break;
1016 case 2 : ChromaSubsampling="4:1:0"; break;
1017 default: ;
1018 }
1019 break;
1020 default: ;
1021 }
1022 if (!ChromaSubsampling.empty())
1023 {
1024 if (SamplingFactors.size()>3 && (SamplingFactors[3].Hi!=SamplingFactors[0].Hi || SamplingFactors[3].Vi!=SamplingFactors[0].Vi))
1025 ChromaSubsampling+=":?";
1026 Fill(StreamKind_Last, 0, "ChromaSubsampling", ChromaSubsampling);
1027 }
1028 }
1029 }
1030 FILLING_END();
1031 }
1032
1033 //---------------------------------------------------------------------------
SOS()1034 void File_Jpeg::SOS()
1035 {
1036 //Parsing
1037 int8u Count;
1038 Get_B1 (Count, "Number of image components in scan");
1039 for (int8u Pos=0; Pos<Count; Pos++)
1040 {
1041 Skip_B1( "Scan component selector");
1042 Skip_B1( "Entropy coding table destination selector");
1043 }
1044 Skip_B1( "Start of spectral or predictor selection");
1045 Skip_B1( "End of spectral selection");
1046 Skip_B1( "Successive approximation bit position");
1047
1048 FILLING_BEGIN_PRECISE();
1049 SOS_SOD_Parsed=true;
1050 if (Interlaced)
1051 {
1052 Field_Count++;
1053 Field_Count_InThisBlock++;
1054 }
1055 if (!Interlaced || Field_Count%2==0)
1056 {
1057 Frame_Count++;
1058 Frame_Count_InThisBlock++;
1059 if (Frame_Count_NotParsedIncluded!=(int64u)-1)
1060 Frame_Count_NotParsedIncluded++;
1061 }
1062 if (Status[IsFilled])
1063 Fill();
1064 if (Config->ParseSpeed<1.0)
1065 Finish("JPEG"); //No need of more
1066 FILLING_END();
1067 }
1068
1069 //---------------------------------------------------------------------------
APP0()1070 void File_Jpeg::APP0()
1071 {
1072 //Parsing
1073 int32u Name;
1074 Get_C4(Name, "Name");
1075 switch (Name)
1076 {
1077 case 0x41564931 : APP0_AVI1(); break; //"AVI1"
1078 case 0x4A464946 : APP0_JFIF(); break; //"JFIF"
1079 case 0x4A464646 : APP0_JFFF(); break; //"JFFF"
1080 default : Skip_XX(Element_Size-Element_Offset, "Unknown");
1081 }
1082 }
1083
1084 //---------------------------------------------------------------------------
1085 // From OpenDML AVI File Format Extensions
APP0_AVI1()1086 void File_Jpeg::APP0_AVI1()
1087 {
1088 Element_Info1("AVI1");
1089
1090 //Parsing
1091 bool UnknownInterlacement_IsDetected=false;
1092 int8u FieldOrder=(int8u)-1;
1093 Get_B1 (FieldOrder, "Polarity");
1094 if (Element_Size>=14)
1095 {
1096 int32u FieldSize, FieldSizeLessPadding;
1097 Skip_B1( "Reserved");
1098 Get_B4 (FieldSize, "FieldSize");
1099 Get_B4 (FieldSizeLessPadding, "FieldSizeLessPadding");
1100
1101 //Coherency
1102 if (FieldOrder==0 && IsSub && FieldSize && FieldSize!=Buffer_Size)
1103 {
1104 if (FieldSizeLessPadding>1 && FieldSizeLessPadding<=Buffer_Size && Buffer[FieldSizeLessPadding-2]==0xFF && Buffer[FieldSizeLessPadding-1]==0xD9 //EOI
1105 && FieldSize+1 < Buffer_Size && Buffer[FieldSize] ==0xFF && Buffer[FieldSize+1] ==0xD8) //SOI
1106 UnknownInterlacement_IsDetected=true;
1107 }
1108 }
1109 Skip_XX(Element_Size-Element_Offset, "Unknown");
1110
1111 FILLING_BEGIN();
1112 if (Frame_Count==0 && Field_Count==0)
1113 {
1114 Accept();
1115
1116 if (UnknownInterlacement_IsDetected)
1117 {
1118 Fill(Stream_Video, 0, Video_ScanType, "Interlaced");
1119 Interlaced=true;
1120 }
1121 else
1122 {
1123 switch (FieldOrder)
1124 {
1125 case 0x00 : Fill(Stream_Video, 0, Video_Interlacement, "PPF"); Fill(Stream_Video, 0, Video_ScanType, "Progressive"); break;
1126 case 0x01 : Fill(Stream_Video, 0, Video_Interlacement, "TFF"); Fill(Stream_Video, 0, Video_ScanType, "Interlaced"); Fill(Stream_Video, 0, Video_ScanOrder, "TFF"); Interlaced=true; break;
1127 case 0x02 : Fill(Stream_Video, 0, Video_Interlacement, "BFF"); Fill(Stream_Video, 0, Video_ScanType, "Interlaced"); Fill(Stream_Video, 0, Video_ScanOrder, "BFF"); Interlaced=true; break;
1128 default : ;
1129 }
1130 }
1131 }
1132 FILLING_END();
1133 }
1134
1135 //---------------------------------------------------------------------------
APP0_JFIF()1136 void File_Jpeg::APP0_JFIF()
1137 {
1138 Element_Info1("JFIF");
1139
1140 //Parsing
1141 Skip_B1( "Zero");
1142 int16u Width, Height;
1143 int8u Unit, ThumbailX, ThumbailY;
1144 Skip_B2( "Version");
1145 Get_B1 (Unit, "Unit"); //0=Pixels, 1=dpi, 2=dpcm
1146 Get_B2 (Width, "Xdensity");
1147 Get_B2 (Height, "Ydensity");
1148 Get_B1 (ThumbailX, "Xthumbail");
1149 Get_B1 (ThumbailY, "Ythumbail");
1150 Skip_XX(3*ThumbailX*ThumbailY, "RGB Thumbail");
1151
1152 APP0_JFIF_Parsed=true;
1153 }
1154
1155 //---------------------------------------------------------------------------
APP0_JFFF()1156 void File_Jpeg::APP0_JFFF()
1157 {
1158 Element_Info1("JFFF");
1159
1160 Skip_B1( "Zero");
1161 Skip_B1( "extension_code"); //0x10 Thumbnail coded using JPEG, 0x11 Thumbnail stored using 1 byte/pixel, 0x13 Thumbnail stored using 3 bytes/pixel
1162 if (Element_Size>Element_Offset)
1163 Skip_XX(Element_Size-Element_Offset, "extension_data");
1164 }
1165
1166 //---------------------------------------------------------------------------
APP0_JFFF_JPEG()1167 void File_Jpeg::APP0_JFFF_JPEG()
1168 {
1169 //Parsing
1170 Element_Begin1("Thumbail JPEG");
1171 if (Element_Size>Element_Offset)
1172 Skip_XX(Element_Size-Element_Offset, "Data");
1173 Element_End0();
1174 }
1175
1176 //---------------------------------------------------------------------------
APP0_JFFF_1B()1177 void File_Jpeg::APP0_JFFF_1B()
1178 {
1179 //Parsing
1180 Element_Begin1("Thumbail 1 byte per pixel");
1181 int8u ThumbailX, ThumbailY;
1182 Get_B1 (ThumbailX, "Xthumbail");
1183 Get_B1 (ThumbailY, "Ythumbail");
1184 Skip_XX(768, "Palette");
1185 Skip_XX(ThumbailX*ThumbailY, "Thumbail");
1186 Element_End0();
1187 }
1188
1189 //---------------------------------------------------------------------------
APP0_JFFF_3B()1190 void File_Jpeg::APP0_JFFF_3B()
1191 {
1192 //Parsing
1193 Element_Begin1("Thumbail 3 bytes per pixel");
1194 int8u ThumbailX, ThumbailY;
1195 Get_B1 (ThumbailX, "Xthumbail");
1196 Get_B1 (ThumbailY, "Ythumbail");
1197 Skip_XX(3*ThumbailX*ThumbailY, "RGB Thumbail");
1198 Element_End0();
1199 }
1200
1201 //---------------------------------------------------------------------------
APP1()1202 void File_Jpeg::APP1()
1203 {
1204 //Parsing
1205 int64u Name;
1206 Get_C6(Name, "Name");
1207
1208 switch (Name)
1209 {
1210 case 0x457869660000LL : APP1_EXIF(); break; //"Exif\0\0"
1211 default : Skip_XX(Element_Size-Element_Offset, "Data");
1212 }
1213 }
1214
1215 //---------------------------------------------------------------------------
APP1_EXIF()1216 void File_Jpeg::APP1_EXIF()
1217 {
1218 Element_Info1("Exif");
1219
1220 //Parsing
1221 int32u Alignment;
1222 Get_C4(Alignment, "Alignment");
1223 if (Alignment==0x49492A00)
1224 Skip_B4( "First_IFD");
1225 if (Alignment==0x4D4D2A00)
1226 Skip_L4( "First_IFD");
1227 }
1228
1229 //---------------------------------------------------------------------------
APP2()1230 void File_Jpeg::APP2()
1231 {
1232 //Parsing
1233 if (Element_Size>=12 && Buffer[Buffer_Offset+11]==0 && string((const char*)Buffer+Buffer_Offset)=="ICC_PROFILE")
1234 {
1235 Element_Info1("ICC profile");
1236 int8u Pos;
1237 Skip_Local(12, "Signature");
1238 Get_B1 (Pos, "Chunk position?"); //1-based?
1239 Skip_B1( "Chunk Max?"); //1-based?
1240 if (Pos<=1) //Multi-chunk ICC is not supported so we test it is order to skip the extra ICC blocks
1241 APP2_ICC_PROFILE();
1242 else
1243 Skip_XX(Element_Size-Element_Offset, "(Multi-chunk ICC is not supported)");
1244 }
1245 else
1246 Skip_XX(Element_Size, "Data");
1247 }
1248
1249 //---------------------------------------------------------------------------
1250 struct icctagtable
1251 {
1252 int32u Signature;
1253 int32u Offset;
1254 int32u Size;
1255 };
APP2_ICC_PROFILE()1256 void File_Jpeg::APP2_ICC_PROFILE()
1257 {
1258 Element_Begin1("ICC profile");
1259
1260 //Parsing
1261 int64u Element_Start=Element_Offset; // Needed for tags position
1262 int32u ColorSpace;
1263 Element_Begin1("Profile header");
1264 Skip_B4( "Profile size");
1265 Skip_C4( "Preferred CMM type");
1266 Element_Begin1("Profile version number");
1267 int8u M;
1268 Get_B1(M, "Major");
1269 if (M>4)
1270 {
1271 Element_End0();
1272 Element_End0();
1273 Element_End0();
1274 return;
1275 }
1276 BS_Begin();
1277 Info_S1(4, m, "Minor");
1278 Info_S1(4, f, "Fix");
1279 BS_End();
1280 Skip_B2( "Reserved");
1281 Element_Info1(Ztring().From_Number(M)+__T('.')+Ztring().From_Number(m)+__T('.')+Ztring().From_Number(f));
1282 Element_End0();
1283 Skip_C4( "Profile/Device class");
1284 Get_C4 (ColorSpace, "Colour space of data");
1285 Skip_C4( "PCS");
1286 Element_Begin1("Date/Time");
1287 Info_B2(YY, "Year");
1288 Info_B2(MM, "Month");
1289 Info_B2(DD, "Day");
1290 Info_B2(hh, "Hour");
1291 Info_B2(mm, "Minute");
1292 Info_B2(ss, "Second");
1293 #if MEDIAINFO_TRACE
1294 string DateTime;
1295 DateTime+='0'+YY/1000;
1296 DateTime+='0'+(YY%1000)/100;
1297 DateTime+='0'+(YY%100)/10;
1298 DateTime+='0'+(YY%1000);
1299 DateTime+='-';
1300 DateTime+='0'+MM/10;
1301 DateTime+='0'+(MM%10);
1302 DateTime+='-';
1303 DateTime+='0'+DD/10;
1304 DateTime+='0'+(DD%10);
1305 DateTime+=' ';
1306 DateTime+='0'+hh/10;
1307 DateTime+='0'+(hh%10);
1308 DateTime+=':';
1309 DateTime+='0'+mm/10;
1310 DateTime+='0'+(mm%10);
1311 DateTime+=':';
1312 DateTime+='0'+ss/10;
1313 DateTime+='0'+(ss%10);
1314 Element_Info1(DateTime.c_str());
1315 #endif //MEDIAINFO_TRACE
1316 Element_End0();
1317 Skip_C4( "'acsp' profile file signature ");
1318 Skip_C4( "Primary platform signature");
1319 Skip_B4( "Profile flags");
1320 Skip_C4( "Device manufacturer");
1321 Skip_B4( "Device model");
1322 Skip_B4( "Device attributes TODO 1");
1323 Skip_B4( "Device attributes TODO 2");
1324 Skip_B4( "Rendering Intent");
1325 Element_Begin1("Illuminant of the PCS");
1326 APP2_ICC_PROFILE_XYZNumber();
1327 Element_End0();
1328 Skip_C4( "Profile creator signature");
1329 Skip_XX(16, "Profile ID");
1330 Skip_XX(28, "Reserved");
1331 Element_End0();
1332
1333 int32u Count;
1334 vector<icctagtable> TagTables;
1335 Element_Begin1("Tag table");
1336 Get_B4(Count, "Count");
1337 if (Count*12>Element_Size-Element_Offset)
1338 Count=(Element_Size-Element_Offset)/12;
1339 for (int32u i=0; i<Count; i++)
1340 {
1341 icctagtable TagTable;
1342 Get_C4(TagTable.Signature, "Signature"); Param_Info1(ICC_Tag(TagTable.Signature).c_str());
1343 Get_B4(TagTable.Offset, "Offset");
1344 Get_B4(TagTable.Size, "Size");
1345 if (((int64u)TagTable.Offset)+TagTable.Size<=Element_Size-Element_Start)
1346 TagTables.push_back(TagTable);
1347 }
1348 Element_End0();
1349
1350 Element_Begin1("Tagged element data");
1351 Count=(int32u)TagTables.size();
1352 for (int32u i=0; i<Count; i++)
1353 {
1354 icctagtable& TagTable=TagTables[i];
1355 Ztring Name;
1356
1357 Element_Begin1(ICC_Tag(TagTable.Signature).c_str());
1358 Element_Offset=Element_Start+TagTable.Offset;
1359 int32u Type;
1360 Get_C4(Type, "Type");
1361 switch (Type)
1362 {
1363 case 0x63757276: //curv
1364 if (TagTable.Size<12)
1365 Skip_XX(TagTable.Size-4, "Unknown");
1366 else
1367 {
1368 int32u Count;
1369 Skip_B4( "Reserved");
1370 Get_B4(Count, "Count");
1371 if (12+4*((Count+1)/2)!=TagTable.Size)
1372 Skip_XX(TagTable.Size-12, "Unknown");
1373 else
1374 {
1375 for (int32u i=0; i<Count; i++)
1376 Skip_B2( "Value");
1377 if (Count%2)
1378 Skip_B2( "Padding");
1379 }
1380 }
1381 break;
1382 case 0x64657363: //desc
1383 if (TagTable.Size<12)
1384 Skip_XX(TagTable.Size-4, "Unknown");
1385 else
1386 {
1387 Skip_B7( "?");
1388 Skip_B1( "String size");
1389 Skip_Local(TagTable.Size-12, "Value"); //TODO: beter handling of this complex type
1390 }
1391 break;
1392 case 0x74657874: //text
1393 if (TagTable.Size<8)
1394 Skip_XX(TagTable.Size-4, "Unknown");
1395 else
1396 {
1397 Skip_B4( "Reserved");
1398 Skip_Local(TagTable.Size-8, "Value");
1399 }
1400 break;
1401 case 0x58595A20: //XYZ
1402 if (TagTable.Size!=20)
1403 Skip_XX(TagTable.Size-4, "Unknown");
1404 else
1405 {
1406 Skip_B4( "Reserved");
1407 APP2_ICC_PROFILE_XYZNumber();
1408 }
1409 break;
1410 default: Skip_XX(TagTable.Size-4, "Unknown");
1411 }
1412 Element_End0();
1413 }
1414 Element_End0();
1415 Element_End0();
1416
1417 FILLING_BEGIN()
1418 Fill(StreamKind, 0, "ColorSpace_ICC", ICC_ColorSpace(ColorSpace));
1419 FILLING_END()
1420 }
1421
APP2_ICC_PROFILE_XYZNumber()1422 void File_Jpeg::APP2_ICC_PROFILE_XYZNumber()
1423 {
1424 #if MEDIAINFO_TRACE
1425 APP2_ICC_PROFILE_s15Fixed16Number("X");
1426 APP2_ICC_PROFILE_s15Fixed16Number("Y");
1427 APP2_ICC_PROFILE_s15Fixed16Number("Z");
1428 #else //MEDIAINFO_TRACE
1429 Element_Offset+=12;
1430 #endif //MEDIAINFO_TRACE
1431 }
1432
APP2_ICC_PROFILE_s15Fixed16Number(const char * Name)1433 void File_Jpeg::APP2_ICC_PROFILE_s15Fixed16Number(const char* Name)
1434 {
1435 Info_B4(Value, Name); Param_Info1(Ztring().From_Number(((float64)Value)/0x10000, 6));
1436 }
1437
1438 //---------------------------------------------------------------------------
APPE()1439 void File_Jpeg::APPE()
1440 {
1441 //Parsing
1442 int64u Name;
1443 Get_C6(Name, "Name");
1444 switch (Name)
1445 {
1446 case 0x41646F626500LL : APPE_Adobe0(); break; //"AVI1"
1447 default : Skip_XX(Element_Size-Element_Offset, "Unknown");
1448 }
1449 }
1450
1451 //---------------------------------------------------------------------------
APPE_Adobe0()1452 void File_Jpeg::APPE_Adobe0()
1453 {
1454 Element_Info1("Adobe");
1455
1456 //Parsing
1457 int8u Version;
1458 Get_B1(Version, "Version");
1459 if (Version==100)
1460 {
1461 int8u transform;
1462 Skip_B2( "flags0");
1463 Skip_B2( "flags1");
1464 Get_B1 (transform, "transform");
1465
1466 FILLING_BEGIN();
1467 APPE_Adobe0_transform=transform;
1468 FILLING_END();
1469 }
1470 else
1471 Skip_XX(Element_Size-Element_Offset, "unknown");
1472 }
1473
1474 } //NameSpace
1475
1476 #endif
1477