source: gsdl/trunk/perllib/cpan/Image/ExifTool/QuickTime.pm@ 16842

Last change on this file since 16842 was 16842, checked in by davidb, 16 years ago

ExifTool added to cpan area to support metadata extraction from files such as JPEG. Primarily targetted as Image files (hence the Image folder name decided upon by the ExifTool author) it also can handle video such as flash and audio such as Wav

File size: 23.3 KB
Line 
1#------------------------------------------------------------------------------
2# File: QuickTime.pm
3#
4# Description: Read QuickTime, MP4 and M4A meta information
5#
6# Revisions: 10/04/2005 - P. Harvey Created
7# 12/19/2005 - P. Harvey Added MP4 support
8# 09/22/2006 - P. Harvey Added M4A support
9#
10# References: 1) http://developer.apple.com/documentation/QuickTime/
11# 2) http://search.cpan.org/dist/MP4-Info-1.04/
12# 3) http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
13# 4) http://wiki.multimedia.cx/index.php?title=Apple_QuickTime
14#------------------------------------------------------------------------------
15
16package Image::ExifTool::QuickTime;
17
18use strict;
19use vars qw($VERSION);
20use Image::ExifTool qw(:DataAccess :Utils);
21use Image::ExifTool::Exif;
22
23$VERSION = '1.12';
24
25sub FixWrongFormat($);
26sub ProcessMOV($$;$);
27
28# information for time/date-based tags (time zero is Jan 1, 1904)
29my %timeInfo = (
30 Groups => { 2 => 'Time' },
31 # Note: This value will be in UTC if generated by a system that is aware of the time zone
32 ValueConv => 'ConvertUnixTime($val - ((66 * 365 + 17) * 24 * 3600))',
33 PrintConv => '$self->ConvertDateTime($val)',
34);
35# information for duration tags
36my %durationInfo = (
37 ValueConv => '$self->{TimeScale} ? $val / $self->{TimeScale} : $val',
38 PrintConv => '$self->{TimeScale} ? sprintf("%.2fs", $val) : $val',
39);
40
41# QuickTime atoms
42%Image::ExifTool::QuickTime::Main = (
43 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMOV,
44 GROUPS => { 2 => 'Video' },
45 NOTES => q{
46 These tags are used in QuickTime MOV and MP4 videos, and QTIF images. Tags
47 with a question mark after their name are not extracted unless the Unknown
48 option is set.
49 },
50 free => { Unknown => 1, Binary => 1 },
51 skip => { Unknown => 1, Binary => 1 },
52 wide => { Unknown => 1, Binary => 1 },
53 ftyp => { #MP4
54 Name => 'FrameType',
55 Unknown => 1,
56 Notes => 'MP4 only',
57 Binary => 1,
58 },
59 pnot => {
60 Name => 'Preview',
61 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Preview' },
62 },
63 PICT => {
64 Name => 'PreviewPICT',
65 Binary => 1,
66 },
67 moov => {
68 Name => 'Movie',
69 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Movie' },
70 },
71 mdat => { Unknown => 1, Binary => 1 },
72);
73
74# atoms used in QTIF files
75%Image::ExifTool::QuickTime::ImageFile = (
76 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMOV,
77 GROUPS => { 2 => 'Image' },
78 NOTES => 'Tags used in QTIF QuickTime Image Files.',
79 idsc => {
80 Name => 'ImageDescription',
81 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ImageDesc' },
82 },
83 idat => {
84 Name => 'ImageData',
85 Binary => 1,
86 },
87 iicc => {
88 Name => 'ICC_Profile',
89 SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' },
90 },
91);
92
93# image description data block
94%Image::ExifTool::QuickTime::ImageDesc = (
95 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
96 GROUPS => { 2 => 'Image' },
97 4 => { Name => 'CompressorID', Format => 'string[4]' },
98 20 => { Name => 'VendorID', Format => 'string[4]' },
99 28 => { Name => 'Quality', Format => 'int32u' },
100 32 => { Name => 'ImageWidth', Format => 'int16u' },
101 34 => { Name => 'ImageHeight', Format => 'int16u' },
102 36 => { Name => 'XResolution', Format => 'int32u' },
103 40 => { Name => 'YResolution', Format => 'int32u' },
104 48 => { Name => 'FrameCount', Format => 'int16u' },
105 50 => { Name => 'NameLength', Format => 'int8u' },
106 51 => { Name => 'Compressor', Format => 'string[$val{46}]' },
107 82 => { Name => 'BitDepth', Format => 'int16u' },
108);
109
110# preview data block
111%Image::ExifTool::QuickTime::Preview = (
112 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
113 GROUPS => { 2 => 'Image' },
114 FORMAT => 'int16u',
115 0 => {
116 Name => 'PreviewDate',
117 Format => 'int32u',
118 %timeInfo,
119 },
120 2 => 'PreviewVersion',
121 3 => {
122 Name => 'PreviewAtomType',
123 Format => 'string[4]',
124 },
125 5 => 'PreviewAtomIndex',
126);
127
128# movie atoms
129%Image::ExifTool::QuickTime::Movie = (
130 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMOV,
131 GROUPS => { 2 => 'Video' },
132 mvhd => {
133 Name => 'MovieHeader',
134 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieHdr' },
135 },
136 trak => {
137 Name => 'Track',
138 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' },
139 },
140 udta => {
141 Name => 'UserData',
142 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::UserData' },
143 },
144);
145
146# movie header data block
147%Image::ExifTool::QuickTime::MovieHdr = (
148 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
149 GROUPS => { 2 => 'Video' },
150 FORMAT => 'int32u',
151 0 => { Name => 'Version', Format => 'int8u' },
152 1 => {
153 Name => 'CreateDate',
154 %timeInfo,
155 },
156 2 => {
157 Name => 'ModifyDate',
158 %timeInfo,
159 },
160 3 => {
161 Name => 'TimeScale',
162 RawConv => '$self->{TimeScale} = $val',
163 },
164 4 => { Name => 'Duration', %durationInfo },
165 5 => {
166 Name => 'PreferredRate',
167 ValueConv => '$val / 0x10000',
168 },
169 6 => {
170 Name => 'PreferredVolume',
171 Format => 'int16u',
172 ValueConv => '$val / 256',
173 PrintConv => 'sprintf("%.2f%%", $val * 100)',
174 },
175 18 => { Name => 'PreviewTime', %durationInfo },
176 19 => { Name => 'PreviewDuration', %durationInfo },
177 20 => { Name => 'PosterTime', %durationInfo },
178 21 => { Name => 'SelectionTime', %durationInfo },
179 22 => { Name => 'SelectionDuration',%durationInfo },
180 23 => { Name => 'CurrentTime', %durationInfo },
181 24 => 'NextTrackID',
182);
183
184# track atoms
185%Image::ExifTool::QuickTime::Track = (
186 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMOV,
187 GROUPS => { 2 => 'Video' },
188 tkhd => {
189 Name => 'TrackHeader',
190 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackHdr' },
191 },
192 udta => {
193 Name => 'UserData',
194 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::UserData' },
195 },
196 mdia => { #MP4
197 Name => 'Media',
198 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Media' },
199 },
200);
201
202# track header data block
203%Image::ExifTool::QuickTime::TrackHdr = (
204 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
205 GROUPS => { 1 => 'Track#', 2 => 'Video' },
206 FORMAT => 'int32u',
207 0 => {
208 Name => 'TrackVersion',
209 Format => 'int8u',
210 Priority => 0,
211 },
212 1 => {
213 Name => 'TrackCreateDate',
214 Priority => 0,
215 %timeInfo,
216 },
217 2 => {
218 Name => 'TrackModifyDate',
219 Priority => 0,
220 %timeInfo,
221 },
222 3 => {
223 Name => 'TrackID',
224 Priority => 0,
225 },
226 5 => {
227 Name => 'TrackDuration',
228 Priority => 0,
229 %durationInfo,
230 },
231 8 => {
232 Name => 'TrackLayer',
233 Format => 'int16u',
234 Priority => 0,
235 },
236 9 => {
237 Name => 'TrackVolume',
238 Format => 'int16u',
239 Priority => 0,
240 ValueConv => '$val / 256',
241 PrintConv => 'sprintf("%.2f%%", $val * 100)',
242 },
243 19 => {
244 Name => 'ImageWidth',
245 Priority => 0,
246 RawConv => \&FixWrongFormat,
247 },
248 20 => {
249 Name => 'ImageHeight',
250 Priority => 0,
251 RawConv => \&FixWrongFormat,
252 },
253);
254
255# user data atoms
256%Image::ExifTool::QuickTime::UserData = (
257 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMOV,
258 GROUPS => { 2 => 'Video' },
259 NOTES => q{
260 Tag ID's beginning with the copyright symbol (hex 0xa9) are multi-language
261 text, but ExifTool only extracts the text from the first language in the
262 record. ExifTool will extract any multi-language user data tags found, even
263 if they don't exist in this table.
264 },
265 "\xa9cpy" => 'Copyright',
266 "\xa9day" => 'CreateDate',
267 "\xa9dir" => 'Director',
268 "\xa9ed1" => 'Edit1',
269 "\xa9ed2" => 'Edit2',
270 "\xa9ed3" => 'Edit3',
271 "\xa9ed4" => 'Edit4',
272 "\xa9ed5" => 'Edit5',
273 "\xa9ed6" => 'Edit6',
274 "\xa9ed7" => 'Edit7',
275 "\xa9ed8" => 'Edit8',
276 "\xa9ed9" => 'Edit9',
277 "\xa9fmt" => 'Format',
278 "\xa9inf" => 'Information',
279 "\xa9prd" => 'Producer',
280 "\xa9prf" => 'Performers',
281 "\xa9req" => 'Requirements',
282 "\xa9src" => 'Source',
283 "\xa9wrt" => 'Writer',
284 name => 'Name',
285 WLOC => {
286 Name => 'WindowLocation',
287 Format => 'int16u',
288 },
289 LOOP => {
290 Name => 'LoopStyle',
291 Format => 'int32u',
292 PrintConv => {
293 1 => 'Normal',
294 2 => 'Palindromic',
295 },
296 },
297 SelO => {
298 Name => 'PlaySelection',
299 Format => 'int8u',
300 },
301 AllF => {
302 Name => 'PlayAllFrames',
303 Format => 'int8u',
304 },
305 meta => {
306 Name => 'Meta',
307 SubDirectory => {
308 TagTable => 'Image::ExifTool::QuickTime::Meta',
309 HasVersion => 1, # must skip 4-byte version number header
310 },
311 },
312 'ptv '=> {
313 Name => 'PrintToVideo',
314 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Video' },
315 },
316 # hnti => 'HintInfo',
317 # hinf => 'HintTrackInfo',
318 TAGS => [
319 {
320 # these tags were initially discovered in a Pentax movie, but
321 # seem very similar to those used by Nikon
322 Name => 'PentaxTags',
323 Condition => '$$valPt =~ /^PENTAX DIGITAL CAMERA\0/',
324 SubDirectory => {
325 TagTable => 'Image::ExifTool::Pentax::MOV',
326 ByteOrder => 'LittleEndian',
327 },
328 },
329 {
330 Name => 'NikonTags',
331 Condition => '$$valPt =~ /^NIKON DIGITAL CAMERA\0/',
332 SubDirectory => {
333 TagTable => 'Image::ExifTool::Nikon::MOV',
334 ByteOrder => 'LittleEndian',
335 },
336 },
337 {
338 Name => 'SanyoMOV',
339 Condition => q{
340 $$valPt =~ /^SANYO DIGITAL CAMERA\0/ and
341 $self->{VALUE}->{FileType} eq "MOV"
342 },
343 SubDirectory => {
344 TagTable => 'Image::ExifTool::Sanyo::MOV',
345 ByteOrder => 'LittleEndian',
346 },
347 },
348 {
349 Name => 'SanyoMP4',
350 Condition => q{
351 $$valPt =~ /^SANYO DIGITAL CAMERA\0/ and
352 $self->{VALUE}->{FileType} eq "MP4"
353 },
354 SubDirectory => {
355 TagTable => 'Image::ExifTool::Sanyo::MP4',
356 ByteOrder => 'LittleEndian',
357 },
358 },
359 {
360 Name => 'UnknownTags',
361 Unknown => 1,
362 Binary => 1
363 },
364 ],
365);
366
367# meta atoms
368%Image::ExifTool::QuickTime::Meta = (
369 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMOV,
370 GROUPS => { 2 => 'Video' },
371 ilst => {
372 Name => 'InfoList',
373 SubDirectory => {
374 TagTable => 'Image::ExifTool::QuickTime::InfoList',
375 HasData => 1, # process atoms as containers with 'data' elements
376 },
377 },
378);
379
380# info list atoms
381# -> these atoms are unique, and contain one or more 'data' atoms
382%Image::ExifTool::QuickTime::InfoList = (
383 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMOV,
384 GROUPS => { 2 => 'Audio' },
385 "\xa9ART" => 'Artist',
386 "\xa9alb" => 'Album',
387 "\xa9cmt" => 'Comment',
388 "\xa9com" => 'Composer',
389 "\xa9day" => 'Year',
390 "\xa9des" => 'Description', #4
391 "\xa9gen" => 'Genre',
392 "\xa9grp" => 'Grouping',
393 "\xa9lyr" => 'Lyrics',
394 "\xa9nam" => 'Title',
395 "\xa9too" => 'Encoder',
396 "\xa9trk" => 'Track',
397 "\xa9wrt" => 'Composer',
398 '----' => {
399 Name => 'iTunesInfo',
400 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::iTunesInfo' },
401 },
402 aART => 'AlbumArtist',
403 apid => 'AppleStoreID',
404 auth => 'Author',
405 covr => 'CoverArt',
406 cpil => {
407 Name => 'Compilation',
408 PrintConv => { 0 => 'No', 1 => 'Yes' },
409 },
410 cprt => 'Copyright',
411 disk => {
412 Name => 'DiskNumber',
413 ValueConv => 'length($val) >= 6 ? join(" of ",unpack("x2nn",$val)) : \$val',
414 },
415 dscp => 'Description',
416 gnre => 'Genre',
417 perf => 'Performer',
418 pgap => {
419 Name => 'PlayGap',
420 PrintConv => {
421 0 => 'Insert Gap',
422 1 => 'No Gap',
423 },
424 },
425 rtng => 'Rating', # int
426 titl => 'Title',
427 tmpo => 'BeatsPerMinute', # int
428 trkn => {
429 Name => 'TrackNumber',
430 ValueConv => 'length($val) >= 6 ? join(" of ",unpack("x2nn",$val)) : \$val',
431 },
432);
433
434# info list atoms
435%Image::ExifTool::QuickTime::iTunesInfo = (
436 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMOV,
437 GROUPS => { 2 => 'Audio' },
438);
439
440# print to video data block
441%Image::ExifTool::QuickTime::Video = (
442 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
443 GROUPS => { 2 => 'Video' },
444 0 => {
445 Name => 'DisplaySize',
446 PrintConv => {
447 0 => 'Normal',
448 1 => 'Double Size',
449 2 => 'Half Size',
450 3 => 'Full Screen',
451 4 => 'Current Size',
452 },
453 },
454 6 => {
455 Name => 'SlideShow',
456 PrintConv => {
457 0 => 'No',
458 1 => 'Yes',
459 },
460 },
461);
462
463# MP4 media
464%Image::ExifTool::QuickTime::Media = (
465 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMOV,
466 GROUPS => { 2 => 'Video' },
467 NOTES => 'MP4 only (most tags unknown because ISO charges for the specification).',
468 minf => {
469 Name => 'Minf',
470 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Minf' },
471 },
472);
473
474%Image::ExifTool::QuickTime::Minf = (
475 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMOV,
476 GROUPS => { 2 => 'Video' },
477 NOTES => 'MP4 only (most tags unknown because ISO charges for the specification).',
478 dinf => {
479 Name => 'Dinf',
480 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Dinf' },
481 },
482 stbl => {
483 Name => 'Stbl',
484 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Stbl' },
485 },
486);
487
488%Image::ExifTool::QuickTime::Stbl = (
489 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMOV,
490 GROUPS => { 2 => 'Video' },
491 NOTES => 'MP4 only (most tags unknown because ISO charges for the specification).',
492);
493
494%Image::ExifTool::QuickTime::Dinf = (
495 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMOV,
496 GROUPS => { 2 => 'Video' },
497 NOTES => 'MP4 only (most tags unknown because ISO charges for the specification).',
498);
499
500#------------------------------------------------------------------------------
501# Fix incorrect format for ImageWidth/Height as written by Pentax
502sub FixWrongFormat($)
503{
504 my $val = shift;
505 return undef unless $val;
506 if ($val & 0xffff0000) {
507 $val = unpack('n',pack('N',$val));
508 }
509 return $val;
510}
511
512#------------------------------------------------------------------------------
513# Process a QuickTime atom
514# Inputs: 0) ExifTool object reference, 1) directory information reference
515# 2) optional tag table reference
516# Returns: 1 on success
517sub ProcessMOV($$;$)
518{
519 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
520 my $raf = $$dirInfo{RAF};
521 my $dataPt = $$dirInfo{DataPt};
522 my $verbose = $exifTool->Options('Verbose');
523 my $dataPos = $$dirInfo{Base} || 0;
524 my ($buff, $tag, $size, $track);
525
526 # more convenient to package data as a RandomAccess file
527 $raf or $raf = new File::RandomAccess($dataPt);
528 # skip leading 4-byte version number if necessary
529 ($raf->Read($buff,4) == 4 and $dataPos += 4) or return 0 if $$dirInfo{HasVersion};
530 # read size/tag name atom header
531 $raf->Read($buff,8) == 8 or return 0;
532 $dataPos += 8;
533 $tagTablePtr or $tagTablePtr = GetTagTable('Image::ExifTool::QuickTime::Main');
534 ($size, $tag) = unpack('Na4', $buff);
535 if ($dataPt) {
536 $verbose and $exifTool->VerboseDir($$dirInfo{DirName});
537 } else {
538 # check on file type if called with a RAF
539 $$tagTablePtr{$tag} or return 0;
540 if ($tag eq 'ftyp') {
541 # read ahead 4 bytes to see if this is an M4A file
542 my $ftyp = 'MP4';
543 if ($raf->Read($buff, 4) == 4) {
544 $raf->Seek(-4, 1);
545 $ftyp = 'M4A' if $buff eq 'M4A ';
546 }
547 $exifTool->SetFileType($ftyp); # MP4 or M4A
548 } else {
549 $exifTool->SetFileType(); # MOV
550 }
551 SetByteOrder('MM');
552 }
553 for (;;) {
554 if ($size < 8) {
555 last if $size == 0;
556 $size == 1 or $exifTool->Warn('Invalid atom size'), last;
557 $raf->Read($buff, 8) == 8 or last;
558 $dataPos += 8;
559 my ($hi, $lo) = unpack('NN', $buff);
560 if ($hi or $lo > 0x7fffffff) {
561 $exifTool->Warn('End of processing at large atom');
562 last;
563 }
564 $size = $lo;
565 }
566 $size -= 8;
567 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
568 # generate tagInfo if Unknown option set
569 if (not defined $tagInfo and ($exifTool->{OPTIONS}->{Unknown} or
570 $tag =~ /^\xa9/))
571 {
572 my $name = $tag;
573 $name =~ s/([\x00-\x1f\x7f-\xff])/'x'.unpack('H*',$1)/eg;
574 if ($name =~ /^xa9(.*)/) {
575 $tagInfo = {
576 Name => "UserData_$1",
577 Description => "User Data $1",
578 };
579 } else {
580 $tagInfo = {
581 Name => "Unknown_$name",
582 Description => "Unknown $name",
583 Unknown => 1,
584 Binary => 1,
585 };
586 }
587 Image::ExifTool::AddTagToTable($tagTablePtr, $tag, $tagInfo);
588 }
589 # load values only if associated with a tag (or verbose) and < 16MB long
590 if ((defined $tagInfo or $verbose) and $size < 0x1000000) {
591 my $val;
592 unless ($raf->Read($val, $size) == $size) {
593 $exifTool->Warn("Truncated '$tag' data");
594 last;
595 }
596 # use value to get tag info if necessary
597 $tagInfo or $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag, \$val);
598 my $hasData = ($$dirInfo{HasData} and $val =~ /^\0...data\0/s);
599 if ($verbose and not $hasData) {
600 $exifTool->VerboseInfo($tag, $tagInfo,
601 Value => $val,
602 DataPt => \$val,
603 DataPos => $dataPos,
604 );
605 }
606 if ($tagInfo) {
607 my $subdir = $$tagInfo{SubDirectory};
608 if ($subdir) {
609 my %dirInfo = (
610 DataPt => \$val,
611 DirStart => 0,
612 DirLen => $size,
613 DirName => $$tagInfo{Name},
614 HasData => $$subdir{HasData},
615 HasVersion => $$subdir{HasVersion},
616 # Base needed for IsOffset tags in binary data
617 Base => $dataPos,
618 );
619 if ($$subdir{ByteOrder} and $$subdir{ByteOrder} =~ /^Little/) {
620 SetByteOrder('II');
621 }
622 if ($$tagInfo{Name} eq 'Track') {
623 $track or $track = 0;
624 $exifTool->{SET_GROUP1} = 'Track' . (++$track);
625 }
626 my $subTable = GetTagTable($$subdir{TagTable});
627 $exifTool->ProcessDirectory(\%dirInfo, $subTable);
628 delete $exifTool->{SET_GROUP1};
629 SetByteOrder('MM');
630 } elsif ($hasData) {
631 # handle atoms containing 'data' tags
632 my $pos = 0;
633 for (;;) {
634 last if $pos + 16 > $size;
635 my ($len, $type, $flags) = unpack("x${pos}Na4N", $val);
636 last if $pos + $len > $size;
637 my $value;
638 if ($type eq 'data' and $len >= 16) {
639 $pos += 16;
640 $len -= 16;
641 $value = substr($val, $pos, $len);
642 # format flags: 0x0=binary, 0x1=text, 0xd=image, 0x15=boolean
643 if ($flags == 0x0015) {
644 $value = $len ? ReadValue(\$value, $len-1, 'int8u', 1, 1) : '';
645 } elsif ($flags != 0x01 and not $$tagInfo{ValueConv}) {
646 # make binary data a scalar reference unless a ValueConv exists
647 my $buf = $value;
648 $value = \$buf;
649 }
650 }
651 $exifTool->VerboseInfo($tag, $tagInfo,
652 Value => ref $value ? $$value : $value,
653 DataPt => \$val,
654 DataPos => $dataPos,
655 Start => $pos,
656 Size => $len,
657 Extra => sprintf(", Type='$type', Flags=0x%x",$flags)
658 ) if $verbose;
659 $exifTool->FoundTag($tagInfo, $value) if defined $value;
660 $pos += $len;
661 }
662 } else {
663 if ($tag =~ /^\xa9/) {
664 # parse international text to extract first string
665 my $len = unpack('n', $val);
666 # $len should include 4 bytes for length and type words,
667 # but Pentax forgets to add these in, so allow for this
668 $len += 4 if $len == $size - 4;
669 $val = substr($val, 4, $len - 4) if $len <= $size;
670 } elsif ($$tagInfo{Format}) {
671 $val = ReadValue(\$val, 0, $$tagInfo{Format}, $$tagInfo{Count}, length($val));
672 }
673 $exifTool->FoundTag($tagInfo, $val);
674 }
675 }
676 } else {
677 $raf->Seek($size, 1) or $exifTool->Warn("Truncated '$tag' data"), last;
678 }
679 $raf->Read($buff, 8) == 8 or last;
680 $dataPos += $size + 8;
681 ($size, $tag) = unpack('Na4', $buff);
682 }
683 return 1;
684}
685
686#------------------------------------------------------------------------------
687# Process a QuickTime Image File
688# Inputs: 0) ExifTool object reference, 1) directory information reference
689# Returns: 1 on success
690sub ProcessQTIF($$)
691{
692 my $table = GetTagTable('Image::ExifTool::QuickTime::ImageFile');
693 return ProcessMOV($_[0], $_[1], $table);
694}
695
6961; # end
697
698__END__
699
700=head1 NAME
701
702Image::ExifTool::QuickTime - Read QuickTime and MP4 meta information
703
704=head1 SYNOPSIS
705
706This module is used by Image::ExifTool
707
708=head1 DESCRIPTION
709
710This module contains routines required by Image::ExifTool to extract
711information from QuickTime and MP4 video, and M4A audio files.
712
713=head1 BUGS
714
715The MP4 support is rather pathetic since the specification documentation is
716not freely available (yes, ISO sucks).
717
718=head1 AUTHOR
719
720Copyright 2003-2007, Phil Harvey (phil at owl.phy.queensu.ca)
721
722This library is free software; you can redistribute it and/or modify it
723under the same terms as Perl itself.
724
725=head1 REFERENCES
726
727=over 4
728
729=item L<http://developer.apple.com/documentation/QuickTime/>
730
731=back
732
733=head1 SEE ALSO
734
735L<Image::ExifTool::TagNames/QuickTime Tags>,
736L<Image::ExifTool(3pm)|Image::ExifTool>
737
738=cut
739
Note: See TracBrowser for help on using the repository browser.