source: gsdl/trunk/perllib/cpan/Image/ExifTool/RIFF.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: 19.5 KB
Line 
1#------------------------------------------------------------------------------
2# File: RIFF.pm
3#
4# Description: Read RIFF/WAV/AVI meta information
5#
6# Revisions: 09/14/2005 - P. Harvey Created
7#
8# References: 1) http://www.exif.org/Exif2-2.PDF
9# 2) http://www.vlsi.fi/datasheets/vs1011.pdf
10# 3) http://www.music-center.com.br/spec_rif.htm
11# 4) http://www.codeproject.com/audio/wavefiles.asp
12# 5) http://msdn.microsoft.com/archive/en-us/directx9_c/directx/htm/avirifffilereference.asp
13# 6) http://research.microsoft.com/invisible/tests/riff.h.htm
14# 7) http://www.onicos.com/staff/iz/formats/wav.html
15# 8) http://graphics.cs.uni-sb.de/NMM/dist-0.9.1/Docs/Doxygen/html/mmreg_8h-source.html
16# 9) http://developers.videolan.org/vlc/vlc/doc/doxygen/html/codecs_8h-source.html
17#------------------------------------------------------------------------------
18
19package Image::ExifTool::RIFF;
20
21use strict;
22use vars qw($VERSION);
23use Image::ExifTool qw(:DataAccess :Utils);
24
25$VERSION = '1.10';
26
27# type of current stream
28$Image::ExifTool::RIFF::streamType = '';
29
30my %riffEncoding = ( #2
31 0x01 => 'Microsoft PCM',
32 0x02 => 'Microsoft ADPCM',
33 0x03 => 'Microsoft IEEE float',
34 0x04 => 'Compaq VSELP', #4
35 0x05 => 'IBM CVSD', #4
36 0x06 => 'Microsoft a-Law',
37 0x07 => 'Microsoft u-Law',
38 0x08 => 'Microsoft DTS', #4
39 0x09 => 'DRM', #4
40 0x0a => 'WMA 9 Speech', #9
41 0x10 => 'OKI-ADPCM',
42 0x11 => 'Intel IMA/DVI-ADPCM',
43 0x12 => 'Videologic Mediaspace ADPCM', #4
44 0x13 => 'Sierra ADPCM', #4
45 0x14 => 'Antex G.723 ADPCM', #4
46 0x15 => 'DSP Solutions DIGISTD',
47 0x16 => 'DSP Solutions DIGIFIX',
48 0x17 => 'Dialoic OKI ADPCM', #6
49 0x18 => 'Media Vision ADPCM', #6
50 0x19 => 'HP CU', #7
51 0x20 => 'Yamaha ADPCM', #6
52 0x21 => 'SONARC Speech Compression', #6
53 0x22 => 'DSP Group True Speech', #6
54 0x23 => 'Echo Speech Corp.', #6
55 0x24 => 'Virtual Music Audiofile AF36', #6
56 0x25 => 'Audio Processing Tech.', #6
57 0x26 => 'Virtual Music Audiofile AF10', #6
58 0x27 => 'Aculab Prosody 1612', #7
59 0x28 => 'Merging Tech. LRC', #7
60 0x30 => 'Dolby AC2',
61 0x31 => 'Microsoft GSM610',
62 0x32 => 'MSN Audio', #6
63 0x33 => 'Antex ADPCME', #6
64 0x34 => 'Control Resources VQLPC', #6
65 0x35 => 'DSP Solutions DIGIREAL', #6
66 0x36 => 'DSP Solutions DIGIADPCM', #6
67 0x37 => 'Control Resources CR10', #6
68 0x38 => 'Natural MicroSystems VBX ADPCM', #6
69 0x39 => 'Crystal Semiconductor IMA ADPCM', #6
70 0x3a => 'Echo Speech ECHOSC3', #6
71 0x3b => 'Rockwell ADPCM',
72 0x3c => 'Rockwell DIGITALK',
73 0x3d => 'Xebec Multimedia', #6
74 0x40 => 'Antex G.721 ADPCM',
75 0x41 => 'Antex G.728 CELP',
76 0x42 => 'Microsoft MSG723', #7
77 0x45 => 'ITU-T G.726', #9
78 0x50 => 'Microsoft MPEG',
79 0x51 => 'RT23 or PAC', #7
80 0x52 => 'InSoft RT24', #4
81 0x53 => 'InSoft PAC', #4
82 0x55 => 'MP3',
83 0x59 => 'Cirrus', #7
84 0x60 => 'Cirrus Logic', #6
85 0x61 => 'ESS Tech. PCM', #6
86 0x62 => 'Voxware Inc.', #6
87 0x63 => 'Canopus ATRAC', #6
88 0x64 => 'APICOM G.726 ADPCM',
89 0x65 => 'APICOM G.722 ADPCM',
90 0x66 => 'Microsoft DSAT', #6
91 0x67 => 'Micorsoft DSAT DISPLAY', #6
92 0x69 => 'Voxware Byte Aligned', #7
93 0x70 => 'Voxware AC8', #7
94 0x71 => 'Voxware AC10', #7
95 0x72 => 'Voxware AC16', #7
96 0x73 => 'Voxware AC20', #7
97 0x74 => 'Voxware MetaVoice', #7
98 0x75 => 'Voxware MetaSound', #7
99 0x76 => 'Voxware RT29HW', #7
100 0x77 => 'Voxware VR12', #7
101 0x78 => 'Voxware VR18', #7
102 0x79 => 'Voxware TQ40', #7
103 0x80 => 'Soundsoft', #6
104 0x81 => 'Voxware TQ60', #7
105 0x82 => 'Microsoft MSRT24', #7
106 0x83 => 'AT&T G.729A', #7
107 0x84 => 'Motion Pixels MVI MV12', #7
108 0x85 => 'DataFusion G.726', #7
109 0x86 => 'DataFusion GSM610', #7
110 0x88 => 'Iterated Systems Audio', #7
111 0x89 => 'Onlive', #7
112 0x91 => 'Siemens SBC24', #7
113 0x92 => 'Sonic Foundry Dolby AC3 APDIF', #7
114 0x93 => 'MediaSonic G.723', #8
115 0x94 => 'Aculab Prosody 8kbps', #8
116 0x97 => 'ZyXEL ADPCM', #7,
117 0x98 => 'Philips LPCBB', #7
118 0x99 => 'Studer Professional Audio Packed', #7
119 0xa0 => 'Malden PhonyTalk', #8
120 0x100 => 'Rhetorex ADPCM', #6
121 0x101 => 'IBM u-Law', #3
122 0x102 => 'IBM a-Law', #3
123 0x103 => 'IBM ADPCM', #3
124 0x111 => 'Vivo G.723', #7
125 0x112 => 'Vivo Siren', #7
126 0x123 => 'Digital G.723', #7
127 0x125 => 'Sanyo LD ADPCM', #8
128 0x130 => 'Sipro Lab ACEPLNET', #8
129 0x131 => 'Sipro Lab ACELP4800', #8
130 0x132 => 'Sipro Lab ACELP8V3', #8
131 0x133 => 'Sipro Lab G.729', #8
132 0x134 => 'Sipro Lab G.729A', #8
133 0x135 => 'Sipro Lab Kelvin', #8
134 0x140 => 'Dictaphone G.726 ADPCM', #8
135 0x150 => 'Qualcomm PureVoice', #8
136 0x151 => 'Qualcomm HalfRate', #8
137 0x155 => 'Ring Zero Systems TUBGSM', #8
138 0x160 => 'Microsoft Audio1', #8
139 0x200 => 'Creative Labs ADPCM', #6
140 0x202 => 'Creative Labs FASTSPEECH8', #6
141 0x203 => 'Creative Labs FASTSPEECH10', #6
142 0x210 => 'UHER ADPCM', #8
143 0x220 => 'Quarterdeck Corp.', #6
144 0x230 => 'I-Link VC', #8
145 0x240 => 'Aureal Semiconductor Raw Sport', #8
146 0x250 => 'Interactive Products HSX', #8
147 0x251 => 'Interactive Products RPELP', #8
148 0x260 => 'Consistent CS2', #8
149 0x270 => 'Sony SCX', #8
150 0x300 => 'Fujitsu FM TOWNS SND', #6
151 0x400 => 'Brooktree Digital', #6
152 0x450 => 'QDesign Music', #8
153 0x680 => 'AT&T VME VMPCM', #7
154 0x681 => 'AT&T TCP', #8
155 0x1000 => 'Olivetti GSM', #6
156 0x1001 => 'Olivetti ADPCM', #6
157 0x1002 => 'Olivetti CELP', #6
158 0x1003 => 'Olivetti SBC', #6
159 0x1004 => 'Olivetti OPR', #6
160 0x1100 => 'Lernout & Hauspie', #6
161 0x1400 => 'Norris Comm. Inc.', #6
162 0x1401 => 'ISIAudio', #7
163 0x1500 => 'AT&T Soundspace Music Compression', #7
164 0x2000 => 'FAST Multimedia DVM', #7
165 0xfffe => 'Extensible', #7
166 0xffff => 'Development', #4
167);
168
169# RIFF info
170%Image::ExifTool::RIFF::Main = (
171 PROCESS_PROC => \&Image::ExifTool::RIFF::ProcessChunks,
172 NOTES => q{
173 Windows WAV and AVI files are RIFF format files. Meta information embedded
174 in two types of RIFF C<LIST> chunks: C<INFO> and C<exif>. As well, some
175 information about the audio content is extracted from the C<fmt > chunk.
176 },
177 'fmt ' => {
178 Name => 'AudioFormat',
179 SubDirectory => { TagTable => 'Image::ExifTool::RIFF::AudioFormat' },
180 },
181 LIST_INFO => {
182 Name => 'Info',
183 SubDirectory => { TagTable => 'Image::ExifTool::RIFF::Info' },
184 },
185 LIST_exif => {
186 Name => 'Exif',
187 SubDirectory => { TagTable => 'Image::ExifTool::RIFF::Exif' },
188 },
189 LIST_hdrl => { # AVI header LIST chunk
190 Name => 'Hdrl',
191 SubDirectory => { TagTable => 'Image::ExifTool::RIFF::Hdrl' },
192 },
193);
194
195# Format and Audio Stream Format chunk data
196%Image::ExifTool::RIFF::AudioFormat = (
197 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
198 GROUPS => { 2 => 'Audio' },
199 FORMAT => 'int16u',
200 0 => {
201 Name => 'Encoding',
202 PrintHex => 1,
203 PrintConv => \%riffEncoding,
204 },
205 1 => 'NumChannels',
206 2 => {
207 Name => 'SampleRate',
208 Format => 'int32u',
209 },
210 4 => {
211 Name => 'AvgBytesPerSec',
212 Format => 'int32u',
213 },
214 # uninteresting
215 # 6 => 'BlockAlignment',
216 7 => 'BitsPerSample',
217);
218
219# Sub chunks of INFO LIST chunk
220%Image::ExifTool::RIFF::Info = (
221 PROCESS_PROC => \&Image::ExifTool::RIFF::ProcessChunks,
222 GROUPS => { 2 => 'Audio' },
223 IARL => 'ArchivalLocation',
224 IART => { Name => 'Artist', Groups => { 2 => 'Author' } },
225 ICMS => 'Commissioned',
226 ICMT => 'Comment',
227 ICOP => { Name => 'Copyright', Groups => { 2 => 'Author' } },
228 ICRD => {
229 Name => 'DateCreated',
230 Groups => { 2 => 'Time' },
231 ValueConv => '$_=$val; s/-/:/g; s/\0.*//s; $_',
232 },
233 ICRP => 'Cropped',
234 IDIM => 'Dimensions',
235 IDPI => 'DotsPerInch',
236 IENG => 'Engineer',
237 IGNR => 'Genre',
238 IKEY => 'Keywords',
239 ILGT => 'Lightness',
240 IMED => 'Medium',
241 INAM => 'Title',
242 IPLT => 'NumColors',
243 IPRD => 'Product',
244 ISBJ => 'Subject',
245 ISFT => 'Software',
246 ISHP => 'Sharpness',
247 ISRC => 'Source',
248 ISRF => 'SourceForm',
249 ITCH => 'Technician',
250);
251
252# Sub chunks of EXIF LIST chunk
253%Image::ExifTool::RIFF::Exif = (
254 PROCESS_PROC => \&Image::ExifTool::RIFF::ProcessChunks,
255 GROUPS => { 2 => 'Audio' },
256 ever => 'ExifVersion',
257 erel => 'RelatedImageFile',
258 etim => { Name => 'TimeCreated', Groups => { 2 => 'Time' } },
259 ecor => { Name => 'Make', Groups => { 2 => 'Camera' } },
260 emdl => { Name => 'Model', Groups => { 2 => 'Camera' } },
261 emnt => { Name => 'MakerNotes', Binary => 1 },
262 eucm => {
263 Name => 'UserComment',
264 PrintConv => 'Image::ExifTool::Exif::ConvertExifText($self,$val)',
265 },
266);
267
268# Sub chunks of hdrl LIST chunk
269%Image::ExifTool::RIFF::Hdrl = (
270 PROCESS_PROC => \&Image::ExifTool::RIFF::ProcessChunks,
271 GROUPS => { 2 => 'Image' },
272 avih => {
273 Name => 'AVIHeader',
274 SubDirectory => { TagTable => 'Image::ExifTool::RIFF::AVIHeader' },
275 },
276 IDIT => {
277 Name => 'DateTimeOriginal',
278 Description => 'Date/Time Original',
279 Groups => { 2 => 'Time' },
280 ValueConv => 'Image::ExifTool::RIFF::ConvertRIFFDate($val)',
281 PrintConv => '$self->ConvertDateTime($val)',
282 },
283 ISMP => 'TimeCode',
284 LIST_strl => {
285 Name => 'Stream',
286 SubDirectory => { TagTable => 'Image::ExifTool::RIFF::Stream' },
287 },
288);
289
290%Image::ExifTool::RIFF::AVIHeader = (
291 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
292 GROUPS => { 2 => 'Video' },
293 FORMAT => 'int32u',
294 FIRST_ENTRY => 0,
295 0 => {
296 Name => 'FrameRate',
297 ValueConv => '$val ? 1e6 / $val : undef',
298 PrintConv => 'int($val * 1000 + 0.5) / 1000',
299 },
300 1 => {
301 Name => 'MaxDataRate',
302 PrintConv => 'sprintf("%.4g kB/s",$val / 1024)',
303 },
304 # 2 => 'PaddingGranularity',
305 # 3 => 'Flags',
306 4 => 'FrameCount',
307 # 5 => 'InitialFrames',
308 6 => 'StreamCount',
309 # 7 => 'SuggestedBufferSize',
310 8 => 'ImageWidth',
311 9 => 'ImageHeight',
312);
313
314%Image::ExifTool::RIFF::Stream = (
315 PROCESS_PROC => \&Image::ExifTool::RIFF::ProcessChunks,
316 GROUPS => { 2 => 'Image' },
317 strh => {
318 Name => 'StreamHeader',
319 SubDirectory => { TagTable => 'Image::ExifTool::RIFF::StreamHeader' },
320 },
321 strn => 'StreamName',
322 strd => { #PH
323 Name => 'StreamData',
324 SubDirectory => { TagTable => 'Image::ExifTool::RIFF::StreamData' },
325 },
326 strf => [
327 {
328 Name => 'AudioFormat',
329 Condition => '$Image::ExifTool::RIFF::streamType eq "auds"',
330 SubDirectory => { TagTable => 'Image::ExifTool::RIFF::AudioFormat' },
331 },
332 {
333 Name => 'VideoFormat',
334 Condition => '$Image::ExifTool::RIFF::streamType eq "vids"',
335 SubDirectory => { TagTable => 'Image::ExifTool::BMP::Main' },
336 },
337 ],
338);
339
340%Image::ExifTool::RIFF::StreamHeader = (
341 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
342 GROUPS => { 2 => 'Video' },
343 FORMAT => 'int32u',
344 FIRST_ENTRY => 0,
345 0 => {
346 Name => 'StreamType',
347 Format => 'string[4]',
348 RawConv => '$Image::ExifTool::RIFF::streamType = $val',
349 PrintConv => {
350 auds => 'Audio',
351 mids => 'MIDI',
352 txts => 'Text',
353 vids => 'Video',
354 },
355 },
356 1 => {
357 Name => 'Codec',
358 Format => 'string[4]',
359 },
360 # 2 => 'StreamFlags',
361 # 3 => 'StreamPriority',
362 # 3.5 => 'Language',
363 # 4 => 'InitialFrames',
364 # 5 => 'Scale',
365 # 6 => 'Rate',
366 # 7 => 'Start',
367 # 8 => 'Length',
368 # 9 => 'SuggestedBufferSize',
369 10 => 'Quality',
370 11 => {
371 Name => 'SampleSize',
372 PrintConv => '$val ? "$val byte" . ($val==1 ? "" : "s") : "Variable"',
373 },
374 # 12 => { Name => 'Frame', Format => 'int16u[4]' },
375);
376
377%Image::ExifTool::RIFF::StreamData = ( #PH
378 PROCESS_PROC => \&Image::ExifTool::RIFF::ProcessStreamData,
379 GROUPS => { 2 => 'Video' },
380 NOTES => 'This chunk contains EXIF information in FujiFilm F30 AVI files.',
381 AVIF => {
382 Name => 'AVIF',
383 SubDirectory => {
384 TagTable => 'Image::ExifTool::Exif::Main',
385 DirName => 'IFD0',
386 Start => 8,
387 ByteOrder => 'II',
388 },
389 },
390);
391
392# RIFF composite tags
393%Image::ExifTool::RIFF::Composite = (
394 Duration => {
395 Require => {
396 0 => 'FrameRate',
397 1 => 'FrameCount',
398 },
399 ValueConv => '$val[0] ? $val[1] / $val[0] : undef',
400 PrintConv => 'sprintf("%.2fs",$val)',
401 },
402);
403
404# add our composite tags
405Image::ExifTool::AddCompositeTags('Image::ExifTool::RIFF');
406
407
408#------------------------------------------------------------------------------
409# Convert RIFF date to EXIF format
410my %monthNum = (
411 Jan=>1, Feb=>2, Mar=>3, Apr=>4, May=>5, Jun=>6,
412 Jul=>7, Aug=>8, Sep=>9, Oct=>10,Nov=>11,Dec=>12
413);
414sub ConvertRIFFDate($)
415{
416 my $val = shift;
417 my @part = split ' ', $val;
418 my $mon;
419 if (@part >= 5 and $mon = $monthNum{ucfirst(lc($part[1]))}) {
420 # the standard AVI date format (ie. "Mon Mar 10 15:04:43 2003")
421 $val = sprintf("%.4d:%.2d:%.2d %s", $part[4],
422 $mon, $part[2], $part[3]);
423 } elsif ($val =~ m{(\d{4})/\s*(\d+)/\s*(\d+)/?\s+(\d+):\s*(\d+)\s*(P?)}) {
424 # but the Casio QV-3EX writes dates like "2001/ 1/27 1:42PM",
425 # and the Casio EX-Z30 writes "2005/11/28/ 09:19"... doh!
426 $val = sprintf("%.4d:%.2d:%.2d %.2d:%.2d:00",$1,$2,$3,$4+($6?12:0),$5);
427 }
428 return $val;
429}
430
431#------------------------------------------------------------------------------
432# Process stream data
433# Inputs: 0) ExifTool object ref, 1) dirInfo reference, 2) tag table ref
434# Returns: 1 on success
435sub ProcessStreamData($$$)
436{
437 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
438 my $dataPt = $$dirInfo{DataPt};
439 my $start = $$dirInfo{DirStart};
440 my $size = $$dirInfo{DirLen};
441 return 0 if $size < 4;
442 if ($exifTool->Options('Verbose')) {
443 $exifTool->VerboseDir($$dirInfo{DirName}, 0, $size);
444 }
445 my $tag = substr($$dataPt, $start, 4);
446 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
447 my $subdir = $$tagInfo{SubDirectory};
448 if ($subdir) {
449 my $offset = $$subdir{Start} || 0;
450 my $baseShift = $$dirInfo{DataPos} + $$dirInfo{DirStart} + $offset;
451 my %subdirInfo = (
452 DataPt => $dataPt,
453 DataPos => $$dirInfo{DataPos} - $baseShift,
454 Base => ($$dirInfo{Base} || 0) + $baseShift,
455 DataLen => $$dirInfo{DataLen},
456 DirStart=> $$dirInfo{DirStart} + $offset,
457 DirLen => $$dirInfo{DirLen} - $offset,
458 DirName => $$subdir{DirName},
459 Parent => $$dirInfo{DirName},
460 );
461 # (we could set FIRST_EXIF_POS to $subdirInfo{Base} here to make
462 # htmlDump offsets relative to EXIF base if we wanted...)
463 my $subTable = GetTagTable($$subdir{TagTable});
464 $exifTool->ProcessDirectory(\%subdirInfo, $subTable);
465 }
466 return 1;
467}
468
469#------------------------------------------------------------------------------
470# Process RIFF chunks
471# Inputs: 0) ExifTool object reference, 1) directory information reference
472# 2) tag table reference
473# Returns: 1 on success
474sub ProcessChunks($$$)
475{
476 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
477 my $dataPt = $$dirInfo{DataPt};
478 my $start = $$dirInfo{DirStart};
479 my $size = $$dirInfo{DirLen};
480 my $end = $start + $size;
481
482 if ($exifTool->Options('Verbose')) {
483 $exifTool->VerboseDir($$dirInfo{DirName}, 0, $size);
484 }
485 while ($start + 8 < $end) {
486 my $tag = substr($$dataPt, $start, 4);
487 my $len = Get32u($dataPt, $start + 4);
488 $start += 8;
489 if ($start + $len > $end) {
490 $exifTool->Warn("Bad $tag chunk");
491 return 0;
492 }
493 if ($tag eq 'LIST' and $len >= 4) {
494 $tag .= '_' . substr($$dataPt, $start, 4);
495 $len -= 4;
496 $start += 4;
497 }
498 $exifTool->HandleTag($tagTablePtr, $tag, undef,
499 DataPt => $dataPt,
500 DataPos => $$dirInfo{DataPos},
501 Start => $start,
502 Size => $len,
503 );
504 ++$len if $len & 0x01; # must account for padding if odd number of bytes
505 $start += $len;
506 }
507 return 1;
508}
509
510#------------------------------------------------------------------------------
511# Extract information from a RIFF file
512# Inputs: 0) ExifTool object reference, 1) DirInfo reference
513# Returns: 1 on success, 0 if this wasn't a valid RIFF file
514sub ProcessRIFF($$)
515{
516 my ($exifTool, $dirInfo) = @_;
517 my $raf = $$dirInfo{RAF};
518 my ($buff, $err);
519 my %types = ( 'WAVE' => 'WAV', 'AVI ' => 'AVI' );
520
521 # verify this is a valid RIFF file
522 return 0 unless $raf->Read($buff, 12) == 12;
523 return 0 unless $buff =~ /^RIFF....(.{4})/s;
524 $exifTool->SetFileType($types{$1}); # set type to 'WAV', 'AVI' or 'RIFF'
525 $Image::ExifTool::RIFF::streamType = ''; # initialize stream type
526 SetByteOrder('II');
527 my $tagTablePtr = GetTagTable('Image::ExifTool::RIFF::Main');
528 my $pos = 12;
529#
530# Read chunks in RIFF image until we get to the 'data' chunk
531#
532 for (;;) {
533 $raf->Read($buff, 8) == 8 or $err=1, last;
534 $pos += 8;
535 my ($tag, $len) = unpack('a4V', $buff);
536 # special case: construct new tag name from specific LIST type
537 if ($tag eq 'LIST') {
538 $raf->Read($buff, 4) == 4 or $err=1, last;
539 $pos += 4;
540 $tag .= "_$buff";
541 $len -= 4; # already read 4 bytes (the LIST type)
542 }
543 $exifTool->VPrint(0, "RIFF '$tag' chunk ($len bytes of data):\n");
544 # stop when we hit the audio data or AVI index or AVI movie data
545 if ($tag eq 'data' or $tag eq 'idx1' or $tag eq 'LIST_movi') {
546 $exifTool->VPrint(0, "(end of parsing)\n");
547 last;
548 }
549 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
550 # RIFF chunks are padded to an even number of bytes
551 my $len2 = $len + ($len & 0x01);
552 if ($tagInfo and $$tagInfo{SubDirectory}) {
553 $raf->Read($buff, $len2) == $len2 or $err=1, last;
554 my %dirInfo = (
555 DataPt => \$buff,
556 DataPos => $pos,
557 DirStart => 0,
558 DirLen => $len,
559 );
560 my $tagTablePtr = GetTagTable($tagInfo->{SubDirectory}->{TagTable});
561 $exifTool->ProcessDirectory(\%dirInfo, $tagTablePtr);
562 } else {
563 $raf->Seek($len2, 1) or $err=1, last;
564 }
565 $pos += $len2;
566 }
567 $err and $exifTool->Warn('Error reading RIFF file (corrupted?)');
568 return 1;
569}
570
5711; # end
572
573__END__
574
575=head1 NAME
576
577Image::ExifTool::RIFF - Read RIFF/WAV/AVI meta information
578
579=head1 SYNOPSIS
580
581This module is used by Image::ExifTool
582
583=head1 DESCRIPTION
584
585This module contains routines required by Image::ExifTool to extract
586information from RIFF-based (Resource Interchange File Format) files,
587including Windows WAV audio and AVI video files.
588
589=head1 AUTHOR
590
591Copyright 2003-2007, Phil Harvey (phil at owl.phy.queensu.ca)
592
593This library is free software; you can redistribute it and/or modify it
594under the same terms as Perl itself.
595
596=head1 REFERENCES
597
598=over 4
599
600=item L<http://www.exif.org/Exif2-2.PDF>
601
602=item L<http://www.vlsi.fi/datasheets/vs1011.pdf>
603
604=item L<http://www.music-center.com.br/spec_rif.htm>
605
606=item L<http://www.codeproject.com/audio/wavefiles.asp>
607
608=item L<http://msdn.microsoft.com/archive/en-us/directx9_c/directx/htm/avirifffilereference.asp>
609
610=back
611
612=head1 SEE ALSO
613
614L<Image::ExifTool::TagNames/RIFF Tags>,
615L<Image::ExifTool(3pm)|Image::ExifTool>
616
617=cut
618
Note: See TracBrowser for help on using the repository browser.