source: main/trunk/greenstone2/perllib/cpan/Image/ExifTool/ASF.pm@ 24107

Last change on this file since 24107 was 24107, checked in by sjm84, 13 years ago

Updating the ExifTool perl modules

File size: 29.2 KB
Line 
1#------------------------------------------------------------------------------
2# File: ASF.pm
3#
4# Description: Read ASF/WMA/WMV meta information
5#
6# Revisions: 12/23/2005 - P. Harvey Created
7#
8# References: 1) http://www.microsoft.com/windows/windowsmedia/format/asfspec.aspx
9# 2) http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart3.pdf (Oct 2008)
10#------------------------------------------------------------------------------
11
12package Image::ExifTool::ASF;
13
14use strict;
15use vars qw($VERSION);
16use Image::ExifTool qw(:DataAccess :Utils);
17use Image::ExifTool::Exif;
18use Image::ExifTool::RIFF;
19
20$VERSION = '1.17';
21
22sub ProcessMetadata($$$);
23sub ProcessContentDescription($$$);
24sub ProcessPicture($$$);
25sub ProcessCodecList($$$);
26
27# GUID definitions
28my %errorCorrection = (
29 '20FB5700-5B55-11CF-A8FD-00805F5C442B' => 'No Error Correction',
30 'BFC3CD50-618F-11CF-8BB2-00AA00B4E220' => 'Audio Spread',
31);
32
33my %streamType = (
34 'F8699E40-5B4D-11CF-A8FD-00805F5C442B' => 'Audio',
35 'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B' => 'Video',
36 '59DACFC0-59E6-11D0-A3AC-00A0C90348F6' => 'Command',
37 'B61BE100-5B4E-11CF-A8FD-00805F5C442B' => 'JFIF',
38 '35907DE0-E415-11CF-A917-00805F5C442B' => 'Degradable JPEG',
39 '91BD222C-F21C-497A-8B6D-5AA86BFC0185' => 'File Transfer',
40 '3AFB65E2-47EF-40F2-AC2C-70A90D71D343' => 'Binary',
41);
42
43my %mutex = (
44 'D6E22A00-35DA-11D1-9034-00A0C90349BE' => 'MutexLanguage',
45 'D6E22A01-35DA-11D1-9034-00A0C90349BE' => 'MutexBitrate',
46 'D6E22A02-35DA-11D1-9034-00A0C90349BE' => 'MutexUnknown',
47);
48
49my %bandwidthSharing = (
50 'AF6060AA-5197-11D2-B6AF-00C04FD908E9' => 'SharingExclusive',
51 'AF6060AB-5197-11D2-B6AF-00C04FD908E9' => 'SharingPartial',
52);
53
54my %typeSpecific = (
55 '776257D4-C627-41CB-8F81-7AC7FF1C40CC' => 'WebStreamMediaSubtype',
56 'DA1E6B13-8359-4050-B398-388E965BF00C' => 'WebStreamFormat',
57);
58
59my %advancedContentEncryption = (
60 '7A079BB6-DAA4-4e12-A5CA-91D38DC11A8D' => 'DRMNetworkDevices',
61);
62
63# ASF top level objects
64%Image::ExifTool::ASF::Main = (
65 PROCESS_PROC => \&Image::ExifTool::ASF::ProcessASF,
66 NOTES => q{
67 The ASF format is used by Windows WMA and WMV files, and DIVX videos. Tag
68 ID's aren't listed because they are huge 128-bit GUID's that would ruin the
69 formatting of this table.
70 },
71 '75B22630-668E-11CF-A6D9-00AA0062CE6C' => {
72 Name => 'Header',
73 SubDirectory => { TagTable => 'Image::ExifTool::ASF::Header', Size => 6 },
74 },
75 '75B22636-668E-11CF-A6D9-00AA0062CE6C' => 'Data',
76 '33000890-E5B1-11CF-89F4-00A0C90349CB' => 'SimpleIndex',
77 'D6E229D3-35DA-11D1-9034-00A0C90349BE' => 'Index',
78 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C' => 'MediaIndex',
79 '3CB73FD0-0C4A-4803-953D-EDF7B6228F0C' => 'TimecodeIndex',
80 'BE7ACFCB-97A9-42E8-9C71-999491E3AFAC' => { #2
81 Name => 'XMP',
82 SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
83 },
84);
85
86# ASF header objects
87%Image::ExifTool::ASF::Header = (
88 PROCESS_PROC => \&Image::ExifTool::ASF::ProcessASF,
89 '8CABDCA1-A947-11CF-8EE4-00C00C205365' => {
90 Name => 'FileProperties',
91 SubDirectory => { TagTable => 'Image::ExifTool::ASF::FileProperties' },
92 },
93 'B7DC0791-A9B7-11CF-8EE6-00C00C205365' => {
94 Name => 'StreamProperties',
95 SubDirectory => { TagTable => 'Image::ExifTool::ASF::StreamProperties' },
96 },
97 '5FBF03B5-A92E-11CF-8EE3-00C00C205365' => {
98 Name => 'HeaderExtension',
99 SubDirectory => { TagTable => 'Image::ExifTool::ASF::HeaderExtension', Size => 22 },
100 },
101 '86D15240-311D-11D0-A3A4-00A0C90348F6' => {
102 Name => 'CodecList',
103 SubDirectory => { TagTable => 'Image::ExifTool::ASF::CodecList' },
104 },
105 '1EFB1A30-0B62-11D0-A39B-00A0C90348F6' => 'ScriptCommand',
106 'F487CD01-A951-11CF-8EE6-00C00C205365' => 'Marker',
107 'D6E229DC-35DA-11D1-9034-00A0C90349BE' => 'BitrateMutualExclusion',
108 '75B22635-668E-11CF-A6D9-00AA0062CE6C' => 'ErrorCorrection',
109 '75B22633-668E-11CF-A6D9-00AA0062CE6C' => {
110 Name => 'ContentDescription',
111 SubDirectory => { TagTable => 'Image::ExifTool::ASF::ContentDescr' },
112 },
113 '2211B3FA-BD23-11D2-B4B7-00A0C955FC6E' => {
114 Name => 'ContentBranding',
115 SubDirectory => { TagTable => 'Image::ExifTool::ASF::ContentBranding' },
116 },
117 'D2D0A440-E307-11D2-97F0-00A0C95EA850' => {
118 Name => 'ExtendedContentDescr',
119 SubDirectory => { TagTable => 'Image::ExifTool::ASF::ExtendedDescr' },
120 },
121 '7BF875CE-468D-11D1-8D82-006097C9A2B2' => 'StreamBitrateProps',
122 '2211B3FB-BD23-11D2-B4B7-00A0C955FC6E' => 'ContentEncryption',
123 '298AE614-2622-4C17-B935-DAE07EE9289C' => 'ExtendedContentEncryption',
124 '2211B3FC-BD23-11D2-B4B7-00A0C955FC6E' => 'DigitalSignature',
125 '1806D474-CADF-4509-A4BA-9AABCB96AAE8' => 'Padding',
126);
127
128%Image::ExifTool::ASF::ContentDescr = (
129 PROCESS_PROC => \&ProcessContentDescription,
130 GROUPS => { 2 => 'Video' },
131 0 => 'Title',
132 1 => { Name => 'Author', Groups => { 2 => 'Author' } },
133 2 => { Name => 'Copyright', Groups => { 2 => 'Author' } },
134 3 => 'Description',
135 4 => 'Rating',
136);
137
138%Image::ExifTool::ASF::ContentBranding = (
139 PROCESS_PROC => \&ProcessContentBranding,
140 GROUPS => { 2 => 'Author' },
141 0 => {
142 Name => 'BannerImageType',
143 PrintConv => {
144 0 => 'None',
145 1 => 'Bitmap',
146 2 => 'JPEG',
147 3 => 'GIF',
148 },
149 },
150 1 => { Name => 'BannerImage', Binary => 1 },
151 2 => 'BannerImageURL',
152 3 => 'CopyrightURL',
153);
154
155%Image::ExifTool::ASF::ExtendedDescr = (
156 PROCESS_PROC => \&ProcessExtendedContentDescription,
157 GROUPS => { 2 => 'Video' },
158 ASFLeakyBucketPairs => { Binary => 1 },
159 AspectRatioX => {},
160 AspectRatioY => {},
161 Author => { Groups => { 2 => 'Author' } },
162 AverageLevel => {},
163 BannerImageData => {},
164 BannerImageType => {},
165 BannerImageURL => {},
166 Bitrate => { PrintConv => 'ConvertBitrate($val)' },
167 Broadcast => {},
168 BufferAverage => {},
169 Can_Skip_Backward => {},
170 Can_Skip_Forward => {},
171 Copyright => { Groups => { 2 => 'Author' } },
172 CopyrightURL => { Groups => { 2 => 'Author' } },
173 CurrentBitrate => { PrintConv => 'ConvertBitrate($val)' },
174 Description => {},
175 DRM_ContentID => {},
176 DRM_DRMHeader_ContentDistributor => {},
177 DRM_DRMHeader_ContentID => {},
178 DRM_DRMHeader_IndividualizedVersion => {},
179 DRM_DRMHeader_KeyID => {},
180 DRM_DRMHeader_LicenseAcqURL => {},
181 DRM_DRMHeader_SubscriptionContentID => {},
182 DRM_DRMHeader => {},
183 DRM_IndividualizedVersion => {},
184 DRM_KeyID => {},
185 DRM_LASignatureCert => {},
186 DRM_LASignatureLicSrvCert => {},
187 DRM_LASignaturePrivKey => {},
188 DRM_LASignatureRootCert => {},
189 DRM_LicenseAcqURL => {},
190 DRM_V1LicenseAcqURL => {},
191 Duration => { PrintConv => 'ConvertDuration($val)' },
192 FileSize => {},
193 HasArbitraryDataStream => {},
194 HasAttachedImages => {},
195 HasAudio => {},
196 HasFileTransferStream => {},
197 HasImage => {},
198 HasScript => {},
199 HasVideo => {},
200 Is_Protected => {},
201 Is_Trusted => {},
202 IsVBR => {},
203 NSC_Address => {},
204 NSC_Description => {},
205 NSC_Email => {},
206 NSC_Name => {},
207 NSC_Phone => {},
208 NumberOfFrames => {},
209 OptimalBitrate => { PrintConv => 'ConvertBitrate($val)' },
210 PeakValue => {},
211 Rating => {},
212 Seekable => {},
213 Signature_Name => {},
214 Stridable => {},
215 Title => {},
216 VBRPeak => {},
217 # "WM/" tags...
218 AlbumArtist => {},
219 AlbumCoverURL => {},
220 AlbumTitle => {},
221 ASFPacketCount => {},
222 ASFSecurityObjectsSize => {},
223 AudioFileURL => {},
224 AudioSourceURL => {},
225 AuthorURL => { Groups => { 2 => 'Author' } },
226 BeatsPerMinute => {},
227 Category => {},
228 Codec => {},
229 Composer => {},
230 Conductor => {},
231 ContainerFormat => {},
232 ContentDistributor => {},
233 ContentGroupDescription => {},
234 Director => {},
235 DRM => {},
236 DVDID => {},
237 EncodedBy => {},
238 EncodingSettings => {},
239 EncodingTime => { Groups => { 2 => 'Time' } },
240 Genre => {},
241 GenreID => {},
242 InitialKey => {},
243 ISRC => {},
244 Language => {},
245 Lyrics => {},
246 Lyrics_Synchronised => {},
247 MCDI => {},
248 MediaClassPrimaryID => {},
249 MediaClassSecondaryID => {},
250 MediaCredits => {},
251 MediaIsDelay => {},
252 MediaIsFinale => {},
253 MediaIsLive => {},
254 MediaIsPremiere => {},
255 MediaIsRepeat => {},
256 MediaIsSAP => {},
257 MediaIsStereo => {},
258 MediaIsSubtitled => {},
259 MediaIsTape => {},
260 MediaNetworkAffiliation => {},
261 MediaOriginalBroadcastDateTime => { Groups => { 2 => 'Time' } },
262 MediaOriginalChannel => {},
263 MediaStationCallSign => {},
264 MediaStationName => {},
265 ModifiedBy => {},
266 Mood => {},
267 OriginalAlbumTitle => {},
268 OriginalArtist => {},
269 OriginalFilename => {},
270 OriginalLyricist => {},
271 OriginalReleaseTime => { Groups => { 2 => 'Time' } },
272 OriginalReleaseYear => { Groups => { 2 => 'Time' } },
273 ParentalRating => {},
274 ParentalRatingReason => {},
275 PartOfSet => {},
276 PeakBitrate => { PrintConv => 'ConvertBitrate($val)' },
277 Period => {},
278 Picture => {
279 SubDirectory => {
280 TagTable => 'Image::ExifTool::ASF::Picture',
281 },
282 },
283 PlaylistDelay => {},
284 Producer => {},
285 PromotionURL => {},
286 ProtectionType => {},
287 Provider => {},
288 ProviderCopyright => {},
289 ProviderRating => {},
290 ProviderStyle => {},
291 Publisher => {},
292 RadioStationName => {},
293 RadioStationOwner => {},
294 SharedUserRating => {},
295 StreamTypeInfo => {},
296 SubscriptionContentID => {},
297 SubTitle => {},
298 SubTitleDescription => {},
299 Text => {},
300 ToolName => {},
301 ToolVersion => {},
302 Track => {},
303 TrackNumber => {},
304 UniqueFileIdentifier => {},
305 UserWebURL => {},
306 VideoClosedCaptioning => {},
307 VideoFrameRate => {},
308 VideoHeight => {},
309 VideoWidth => {},
310 WMADRCAverageReference => {},
311 WMADRCAverageTarget => {},
312 WMADRCPeakReference => {},
313 WMADRCPeakTarget => {},
314 WMCollectionGroupID => {},
315 WMCollectionID => {},
316 WMContentID => {},
317 Writer => { Groups => { 2 => 'Author' } },
318 Year => { Groups => { 2 => 'Time' } },
319);
320
321%Image::ExifTool::ASF::Picture = (
322 PROCESS_PROC => \&ProcessPicture,
323 GROUPS => { 2 => 'Image' },
324 0 => {
325 Name => 'PictureType',
326 PrintConv => { # (Note: Duplicated in ID3, ASF and FLAC modules!)
327 0 => 'Other',
328 1 => '32x32 PNG Icon',
329 2 => 'Other Icon',
330 3 => 'Front Cover',
331 4 => 'Back Cover',
332 5 => 'Leaflet',
333 6 => 'Media',
334 7 => 'Lead Artist',
335 8 => 'Artist',
336 9 => 'Conductor',
337 10 => 'Band',
338 11 => 'Composer',
339 12 => 'Lyricist',
340 13 => 'Recording Studio or Location',
341 14 => 'Recording Session',
342 15 => 'Performance',
343 16 => 'Capture from Movie or Video',
344 17 => 'Bright(ly) Colored Fish',
345 18 => 'Illustration',
346 19 => 'Band Logo',
347 20 => 'Publisher Logo',
348 },
349 },
350 1 => 'PictureMimeType',
351 2 => 'PictureDescription',
352 3 => {
353 Name => 'Picture',
354 Binary => 1,
355 },
356);
357
358%Image::ExifTool::ASF::FileProperties = (
359 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
360 GROUPS => { 2 => 'Video' },
361 0 => {
362 Name => 'FileID',
363 Format => 'binary[16]',
364 ValueConv => 'Image::ExifTool::ASF::GetGUID($val)',
365 },
366 16 => { Name => 'FileLength', Format => 'int64u' },
367 24 => {
368 Name => 'CreationDate',
369 Format => 'int64u',
370 Groups => { 2 => 'Time' },
371 # time is in 100 ns intervals since 0:00 UTC Jan 1, 1601
372 ValueConv => q{ # (89 leap years between 1601 and 1970)
373 my $t = $val / 1e7 - (((1970-1601)*365+89)*24*3600);
374 return Image::ExifTool::ConvertUnixTime($t) . 'Z';
375 }
376 },
377 32 => { Name => 'DataPackets', Format => 'int64u' },
378 40 => {
379 Name => 'PlayDuration',
380 Format => 'int64u',
381 ValueConv => '$val / 1e7',
382 PrintConv => 'ConvertDuration($val)',
383 },
384 48 => {
385 Name => 'SendDuration',
386 Format => 'int64u',
387 ValueConv => '$val / 1e7',
388 PrintConv => 'ConvertDuration($val)',
389 },
390 56 => { Name => 'Preroll', Format => 'int64u' },
391 64 => { Name => 'Flags', Format => 'int32u' },
392 68 => { Name => 'MinPacketSize',Format => 'int32u' },
393 72 => { Name => 'MaxPacketSize',Format => 'int32u' },
394 76 => { Name => 'MaxBitrate', Format => 'int32u', PrintConv => 'ConvertBitrate($val)' },
395);
396
397%Image::ExifTool::ASF::StreamProperties = (
398 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
399 GROUPS => { 2 => 'Video' },
400 NOTES => 'Tags with index 54 and greater are conditional based on the StreamType.',
401 0 => {
402 Name => 'StreamType',
403 Format => 'binary[16]',
404 RawConv => sub { # set ASF_STREAM_TYPE for use in conditional tags
405 my ($val, $exifTool) = @_;
406 $exifTool->{ASF_STREAM_TYPE} = $streamType{GetGUID($val)} || '';
407 return $val;
408 },
409 ValueConv => 'Image::ExifTool::ASF::GetGUID($val)',
410 PrintConv => \%streamType,
411 },
412 16 => {
413 Name => 'ErrorCorrectionType',
414 Format => 'binary[16]',
415 ValueConv => 'Image::ExifTool::ASF::GetGUID($val)',
416 PrintConv => \%errorCorrection,
417 },
418 32 => {
419 Name => 'TimeOffset',
420 Format => 'int64u',
421 ValueConv => '$val / 1e7',
422 PrintConv => '"$val s"',
423 },
424 48 => {
425 Name => 'StreamNumber',
426 Format => 'int16u',
427 PrintConv => '($val & 0x7f) . ($val & 0x8000 ? " (encrypted)" : "")',
428 },
429 54 => [
430 {
431 Condition => '$self->{ASF_STREAM_TYPE} eq "Audio"',
432 Name => 'AudioCodecID',
433 Format => 'int16u',
434 PrintHex => 1,
435 SeparateTable => 'RIFF AudioEncoding',
436 PrintConv => \%Image::ExifTool::RIFF::audioEncoding,
437 },
438 {
439 Condition => '$self->{ASF_STREAM_TYPE} =~ /^(Video|JFIF|Degradable JPEG)$/',
440 Name => 'ImageWidth',
441 Format => 'int32u',
442 },
443 ],
444 56 => {
445 Condition => '$self->{ASF_STREAM_TYPE} eq "Audio"',
446 Name => 'AudioChannels',
447 Format => 'int16u',
448 },
449 58 => [
450 {
451 Condition => '$self->{ASF_STREAM_TYPE} eq "Audio"',
452 Name => 'AudioSampleRate',
453 Format => 'int32u',
454 },
455 {
456 Condition => '$self->{ASF_STREAM_TYPE} =~ /^(Video|JFIF|Degradable JPEG)$/',
457 Name => 'ImageHeight',
458 Format => 'int32u',
459 },
460 ],
461);
462
463%Image::ExifTool::ASF::HeaderExtension = (
464 PROCESS_PROC => \&Image::ExifTool::ASF::ProcessASF,
465 '14E6A5CB-C672-4332-8399-A96952065B5A' => 'ExtendedStreamProps',
466 'A08649CF-4775-4670-8A16-6E35357566CD' => 'AdvancedMutualExcl',
467 'D1465A40-5A79-4338-B71B-E36B8FD6C249' => 'GroupMutualExclusion',
468 'D4FED15B-88D3-454F-81F0-ED5C45999E24' => 'StreamPrioritization',
469 'A69609E6-517B-11D2-B6AF-00C04FD908E9' => 'BandwidthSharing',
470 '7C4346A9-EFE0-4BFC-B229-393EDE415C85' => 'LanguageList',
471 'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA' => {
472 Name => 'Metadata',
473 SubDirectory => { TagTable => 'Image::ExifTool::ASF::Metadata' },
474 },
475 '44231C94-9498-49D1-A141-1D134E457054' => {
476 Name => 'MetadataLibrary',
477 SubDirectory => { TagTable => 'Image::ExifTool::ASF::Metadata' },
478 },
479 'D6E229DF-35DA-11D1-9034-00A0C90349BE' => 'IndexParameters',
480 '6B203BAD-3F11-48E4-ACA8-D7613DE2CFA7' => 'TimecodeIndexParms',
481 '75B22630-668E-11CF-A6D9-00AA0062CE6C' => 'Compatibility',
482 '43058533-6981-49E6-9B74-AD12CB86D58C' => 'AdvancedContentEncryption',
483 'ABD3D211-A9BA-11cf-8EE6-00C00C205365' => 'Reserved1',
484);
485
486%Image::ExifTool::ASF::Metadata = (
487 PROCESS_PROC => \&Image::ExifTool::ASF::ProcessMetadata,
488);
489
490%Image::ExifTool::ASF::CodecList = (
491 PROCESS_PROC => \&ProcessCodecList,
492 VideoCodecName => {},
493 VideoCodecDescription => {},
494 AudioCodecName => {},
495 AudioCodecDescription => {},
496 OtherCodecName => {},
497 OtherCodecDescription => {},
498);
499
500#------------------------------------------------------------------------------
501# Generate GUID from 16 bytes of binary data
502# Inputs: 0) data
503# Returns: GUID
504sub GetGUID($)
505{
506 # must do some byte swapping
507 my $buff = unpack('H*',pack('NnnNN',unpack('VvvNN',$_[0])));
508 $buff =~ s/(.{8})(.{4})(.{4})(.{4})/$1-$2-$3-$4-/;
509 return uc($buff);
510}
511
512#------------------------------------------------------------------------------
513# Process ASF content description
514# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table reference
515# Returns: 1 on success
516sub ProcessContentDescription($$$)
517{
518 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
519 my $dataPt = $$dirInfo{DataPt};
520 my $dirLen = $$dirInfo{DirLen};
521 return 0 if $dirLen < 10;
522 my @len = unpack('v5', $$dataPt);
523 my $pos = 10;
524 my $tag;
525 foreach $tag (0..4) {
526 my $len = shift @len;
527 next unless $len;
528 return 0 if $pos + $len > $dirLen;
529 my $val = $exifTool->Decode(substr($$dataPt,$pos,$len),'UCS2','II');
530 $exifTool->HandleTag($tagTablePtr, $tag, $val);
531 $pos += $len;
532 }
533 return 1;
534}
535
536#------------------------------------------------------------------------------
537# Process ASF content branding
538# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table reference
539# Returns: 1 on success
540sub ProcessContentBranding($$$)
541{
542 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
543 my $dataPt = $$dirInfo{DataPt};
544 my $dirLen = $$dirInfo{DirLen};
545 return 0 if $dirLen < 40;
546 # decode banner image type
547 $exifTool->HandleTag($tagTablePtr, 0, unpack('V', $$dataPt));
548 # decode banner image, banner URL and copyright URL
549 my $pos = 4;
550 my $tag;
551 foreach $tag (1..3) {
552 return 0 if $pos + 4 > $dirLen;
553 my $size = unpack("x${pos}V", $$dataPt);
554 $pos += 4;
555 next unless $size;
556 return 0 if $pos + $size > $dirLen;
557 my $val = substr($$dataPt, $pos, $size);
558 $exifTool->HandleTag($tagTablePtr, $tag, $val);
559 $pos += $size;
560 }
561 return 1;
562}
563
564#------------------------------------------------------------------------------
565# Read ASF value
566# Inputs: 0) ExifTool object ref, 1) data reference, 2) value offset,
567# 3) format number, 4) size
568# Returns: converted value
569sub ReadASF($$$$$)
570{
571 my ($exifTool, $dataPt, $pos, $format, $size) = @_;
572 my @vals;
573 if ($format == 0) { # unicode string
574 $vals[0] = $exifTool->Decode(substr($$dataPt,$pos,$size),'UCS2','II');
575 } elsif ($format == 2) { # 4-byte boolean
576 @vals = ReadValue($dataPt, $pos, 'int32u', undef, $size);
577 foreach (@vals) {
578 $_ = $_ ? 'True' : 'False';
579 }
580 } elsif ($format == 3) { # int32u
581 @vals = ReadValue($dataPt, $pos, 'int32u', undef, $size);
582 } elsif ($format == 4) { # int64u
583 @vals = ReadValue($dataPt, $pos, 'int64u', undef, $size);
584 } elsif ($format == 5) { # int16u
585 @vals = ReadValue($dataPt, $pos, 'int16u', undef, $size);
586 } else { # any other format (including 1, byte array): return raw data
587 $vals[0] = substr($$dataPt,$pos,$size);
588 }
589 return join ' ', @vals;
590}
591
592#------------------------------------------------------------------------------
593# Process extended content description
594# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table reference
595# Returns: 1 on success
596sub ProcessExtendedContentDescription($$$)
597{
598 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
599 my $dataPt = $$dirInfo{DataPt};
600 my $dirLen = $$dirInfo{DirLen};
601 return 0 if $dirLen < 2;
602 my $count = Get16u($dataPt, 0);
603 $exifTool->VerboseDir($dirInfo, $count);
604 my $pos = 2;
605 my $i;
606 for ($i=0; $i<$count; ++$i) {
607 return 0 if $pos + 6 > $dirLen;
608 my $nameLen = unpack("x${pos}v", $$dataPt);
609 $pos += 2;
610 return 0 if $pos + $nameLen + 4 > $dirLen;
611 my $tag = Image::ExifTool::Decode(undef,substr($$dataPt,$pos,$nameLen),'UCS2','II','Latin');
612 $tag =~ s/^WM\///; # remove leading "WM/"
613 $pos += $nameLen;
614 my ($dType, $dLen) = unpack("x${pos}v2", $$dataPt);
615 my $val = ReadASF($exifTool,$dataPt,$pos+4,$dType,$dLen);
616 $exifTool->HandleTag($tagTablePtr, $tag, $val,
617 DataPt => $dataPt,
618 Start => $pos + 4,
619 Size => $dLen,
620 );
621 $pos += 4 + $dLen;
622 }
623 return 1;
624}
625
626#------------------------------------------------------------------------------
627# Process WM/Picture preview
628# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table reference
629# Returns: 1 on success
630sub ProcessPicture($$$)
631{
632 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
633 my $dataPt = $$dirInfo{DataPt};
634 my $dirStart = $$dirInfo{DirStart};
635 my $dirLen = $$dirInfo{DirLen};
636 return 0 unless $dirLen > 9;
637 # extract picture type and length
638 my ($type, $picLen) = unpack("x${dirStart}CV", $$dataPt);
639 $exifTool->HandleTag($tagTablePtr, 0, $type);
640 # extract mime type and description strings (null-terminated unicode strings)
641 my $n = $dirLen - 5 - $picLen;
642 return 0 if $n & 0x01 or $n < 4;
643 my $str = substr($$dataPt, $dirStart+5, $n);
644 if ($str =~ /^((?:..)*?)\0\0((?:..)*?)\0\0/) {
645 my ($mime, $desc) = ($1, $2);
646 $exifTool->HandleTag($tagTablePtr, 1, $exifTool->Decode($mime,'UCS2','II'));
647 $exifTool->HandleTag($tagTablePtr, 2, $exifTool->Decode($desc,'UCS2','II')) if length $desc;
648 }
649 $exifTool->HandleTag($tagTablePtr, 3, substr($$dataPt, $dirStart+5+$n, $picLen));
650 return 1;
651}
652
653#------------------------------------------------------------------------------
654# Process codec list
655# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table reference
656# Returns: 1 on success
657sub ProcessCodecList($$$)
658{
659 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
660 my $dataPt = $$dirInfo{DataPt};
661 my $dirLen = $$dirInfo{DirLen};
662 return 0 if $dirLen < 20;
663 my $count = Get32u($dataPt, 16);
664 $exifTool->VerboseDir($dirInfo, $count);
665 my $pos = 20;
666 my $i;
667 my %codecType = ( 1 => 'Video', 2 => 'Audio' );
668 for ($i=0; $i<$count; ++$i) {
669 return 0 if $pos + 8 > $dirLen;
670 my $type = ($codecType{Get16u($dataPt, $pos)} || 'Other') . 'Codec';
671 # stupid Windows programmers: these lengths are in characters (others are in bytes)
672 my $nameLen = Get16u($dataPt, $pos + 2) * 2;
673 $pos += 4;
674 return 0 if $pos + $nameLen + 2 > $dirLen;
675 my $name = $exifTool->Decode(substr($$dataPt,$pos,$nameLen),'UCS2','II');
676 $exifTool->HandleTag($tagTablePtr, "${type}Name", $name);
677 my $descLen = Get16u($dataPt, $pos + $nameLen) * 2;
678 $pos += $nameLen + 2;
679 return 0 if $pos + $descLen + 2 > $dirLen;
680 my $desc = $exifTool->Decode(substr($$dataPt,$pos,$descLen),'UCS2','II');
681 $exifTool->HandleTag($tagTablePtr, "${type}Description", $desc);
682 my $infoLen = Get16u($dataPt, $pos + $descLen);
683 $pos += $descLen + 2 + $infoLen;
684 }
685 return 1;
686}
687
688#------------------------------------------------------------------------------
689# Process ASF metadata library
690# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table reference
691# Returns: 1 on success
692sub ProcessMetadata($$$)
693{
694 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
695 my $dataPt = $$dirInfo{DataPt};
696 my $dirLen = $$dirInfo{DirLen};
697 return 0 if $dirLen < 2;
698 my $count = Get16u($dataPt, 0);
699 $exifTool->VerboseDir($dirInfo, $count);
700 my $pos = 2;
701 my $i;
702 for ($i=0; $i<$count; ++$i) {
703 return 0 if $pos + 12 > $dirLen;
704 my ($index, $stream, $nameLen, $dType, $dLen) = unpack("x${pos}v4V", $$dataPt);
705 $pos += 12;
706 return 0 if $pos + $nameLen + $dLen > $dirLen;
707 my $tag = Image::ExifTool::Decode(undef,substr($$dataPt,$pos,$nameLen),'UCS2','II','Latin');
708 my $val = ReadASF($exifTool,$dataPt,$pos+$nameLen,$dType,$dLen);
709 $exifTool->HandleTag($tagTablePtr, $tag, $val,
710 DataPt => $dataPt,
711 Start => $pos,
712 Size => $dLen,
713 );
714 $pos += $nameLen + $dLen;
715 }
716 return 1;
717}
718
719#------------------------------------------------------------------------------
720# Extract information from a ASF file
721# Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) tag table ref
722# Returns: 1 on success, 0 if this wasn't a valid ASF file
723sub ProcessASF($$;$)
724{
725 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
726 my $raf = $$dirInfo{RAF};
727 my $verbose = $exifTool->Options('Verbose');
728 my $rtnVal = 0;
729 my $pos = 0;
730 my ($buff, $err, @parentTable, @childEnd);
731
732 for (;;) {
733 last unless $raf->Read($buff, 24) == 24;
734 $pos += 24;
735 my $tag = GetGUID($buff);
736 unless ($tagTablePtr) {
737 # verify this is a valid ASF file
738 last unless $tag eq '75B22630-668E-11CF-A6D9-00AA0062CE6C';
739 my $fileType = $exifTool->{FILE_EXT};
740 $fileType = 'ASF' unless $fileType and $fileType =~ /^(ASF|WMV|WMA|DIVX)$/;
741 $exifTool->SetFileType($fileType);
742 SetByteOrder('II');
743 $tagTablePtr = GetTagTable('Image::ExifTool::ASF::Main');
744 $rtnVal = 1;
745 }
746 my $size = Image::ExifTool::Get64u(\$buff, 16) - 24;
747 if ($size < 0) {
748 $err = 'Invalid ASF object size';
749 last;
750 }
751 if ($size > 0x7fffffff) {
752 if ($size > 0x7fffffff * 4294967296) {
753 $err = 'Invalid ASF object size';
754 } elsif ($exifTool->Options('LargeFileSupport')) {
755 if ($raf->Seek($size, 1)) {
756 $exifTool->VPrint(0, " Skipped large ASF object ($size bytes)\n");
757 $pos += $size;
758 next;
759 }
760 $err = 'Error seeking past large ASF object';
761 } else {
762 $err = 'Large ASF objects not supported (LargeFileSupport not set)';
763 }
764 last;
765 }
766 # go back to parent tag table if done with previous children
767 if (@childEnd and $pos >= $childEnd[-1]) {
768 pop @childEnd;
769 $tagTablePtr = pop @parentTable;
770 $exifTool->{INDENT} = substr($exifTool->{INDENT},0,-2);
771 }
772 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
773 $verbose and $exifTool->VerboseInfo($tag, $tagInfo);
774 if ($tagInfo) {
775 my $subdir = $$tagInfo{SubDirectory};
776 if ($subdir) {
777 my $subTable = GetTagTable($$subdir{TagTable});
778 if ($$subTable{PROCESS_PROC} eq \&ProcessASF) {
779 if (defined $$subdir{Size}) {
780 my $s = $$subdir{Size};
781 if ($verbose > 2) {
782 $raf->Read($buff, $s) == $s or $err = 'Truncated file', last;
783 $exifTool->VerboseDump(\$buff);
784 } elsif (not $raf->Seek($s, 1)) {
785 $err = 'Seek error';
786 last;
787 }
788 # continue processing linearly using subTable
789 push @parentTable, $tagTablePtr;
790 push @childEnd, $pos + $size;
791 $tagTablePtr = $subTable;
792 $pos += $$subdir{Size};
793 if ($verbose) {
794 $exifTool->{INDENT} .= '| ';
795 $exifTool->VerboseDir($$tagInfo{Name});
796 }
797 next;
798 }
799 } elsif ($raf->Read($buff, $size) == $size) {
800 my %subdirInfo = (
801 DataPt => \$buff,
802 DirStart => 0,
803 DirLen => $size,
804 DirName => $$tagInfo{Name},
805 );
806 $exifTool->VerboseDump(\$buff) if $verbose > 2;
807 unless ($exifTool->ProcessDirectory(\%subdirInfo, $subTable)) {
808 $exifTool->Warn("Error processing $$tagInfo{Name} directory");
809 }
810 $pos += $size;
811 next;
812 } else {
813 $err = 'Unexpected end of file';
814 last;
815 }
816 }
817 }
818 if ($verbose > 2) {
819 $raf->Read($buff, $size) == $size or $err = 'Truncated file', last;
820 $exifTool->VerboseDump(\$buff);
821 } elsif (not $raf->Seek($size, 1)) { # skip the block
822 $err = 'Seek error';
823 last;
824 }
825 $pos += $size;
826 }
827 $err and $exifTool->Warn($err);
828 return $rtnVal;
829}
830
8311; # end
832
833__END__
834
835=head1 NAME
836
837Image::ExifTool::ASF - Read ASF/WMA/WMV meta information
838
839=head1 SYNOPSIS
840
841This module is used by Image::ExifTool
842
843=head1 DESCRIPTION
844
845This module contains routines required by Image::ExifTool to extract
846information from Microsoft Advanced Systems Format (ASF) files, including
847Windows Media Audio (WMA) and Windows Media Video (WMV) files.
848
849=head1 AUTHOR
850
851Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
852
853This library is free software; you can redistribute it and/or modify it
854under the same terms as Perl itself.
855
856=head1 REFERENCES
857
858=over 4
859
860=item L<http://www.microsoft.com/windows/windowsmedia/format/asfspec.aspx>
861
862=back
863
864=head1 SEE ALSO
865
866L<Image::ExifTool::TagNames/ASF Tags>,
867L<Image::ExifTool(3pm)|Image::ExifTool>
868
869=cut
870
Note: See TracBrowser for help on using the repository browser.