source: gs2-extensions/parallel-building/trunk/src/perllib/cpan/Image/ExifTool/Matroska.pm@ 24626

Last change on this file since 24626 was 24626, checked in by jmt12, 13 years ago

An (almost) complete copy of the perllib directory from a (circa SEP2011) head checkout from Greenstone 2 trunk - in order to try and make merging in this extension a little easier later on (as there have been some major changes to buildcol.pl commited in the main trunk but not in the x64 branch)

  • Property svn:executable set to *
File size: 32.7 KB
RevLine 
[24626]1#------------------------------------------------------------------------------
2# File: Matroska.pm
3#
4# Description: Read meta information from Matroska multimedia files
5#
6# Revisions: 05/26/2010 - P. Harvey Created
7#
8# References: 1) http://www.matroska.org/technical/specs/index.html
9#------------------------------------------------------------------------------
10
11package Image::ExifTool::Matroska;
12
13use strict;
14use vars qw($VERSION);
15use Image::ExifTool qw(:DataAccess :Utils);
16
17$VERSION = '1.04';
18
19my %noYes = ( 0 => 'No', 1 => 'Yes' );
20
21# Matroska tags
22# Note: The tag ID's in the Matroska documentation include the length designation
23# (the upper bits), which is not included in the tag ID's below
24%Image::ExifTool::Matroska::Main = (
25 GROUPS => { 2 => 'Video' },
26 NOTES => q{
27 The following tags are extracted from Matroska multimedia container files.
28 This container format is used by file types such as MKA, MKV, MKS and WEBM.
29 For speed, ExifTool extracts tags only up to the first Cluster unless the
30 Verbose (-v) or Unknown = 2 (-U) option is used. See
31 L<http://www.matroska.org/technical/specs/index.html> for the official
32 Matroska specification.
33 },
34 # supported Format's: signed, unsigned, float, date, string, utf8
35 # (or undef by default)
36#
37# EBML Header
38#
39 0xa45dfa3 => {
40 Name => 'EBMLHeader',
41 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
42 },
43 0x286 => { Name => 'EBMLVersion', Format => 'unsigned' },
44 0x2f7 => { Name => 'EBMLReadVersion', Format => 'unsigned' },
45 0x2f2 => { Name => 'EBMLMaxIDLength', Format => 'unsigned', Unknown => 1 },
46 0x2f3 => { Name => 'EBMLMaxSizeLength', Format => 'unsigned', Unknown => 1 },
47 0x282 => {
48 Name => 'DocType',
49 Format => 'string',
50 # override FileType for "webm" files
51 RawConv => '$self->OverrideFileType("WEBM") if $val eq "webm"; $val',
52 },
53 0x287 => { Name => 'DocTypeVersion', Format => 'unsigned' },
54 0x285 => { Name => 'DocTypeReadVersion',Format => 'unsigned' },
55#
56# General
57#
58 0x3f => { Name => 'CRC-32', Binary => 1, Unknown => 1 },
59 0x6c => { Name => 'Void', NoSave => 1, Unknown => 1 },
60#
61# Signature
62#
63 0xb538667 => {
64 Name => 'SignatureSlot',
65 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
66 },
67 0x3e8a => { Name => 'SignatureAlgo', Format => 'unsigned' },
68 0x3e9a => { Name => 'SignatureHash', Format => 'unsigned' },
69 0x3ea5 => { Name =>'SignaturePublicKey',Binary => 1, Unknown => 1 },
70 0x3eb5 => { Name => 'Signature', Binary => 1, Unknown => 1 },
71 0x3e5b => {
72 Name => 'SignatureElements',
73 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
74 },
75 0x3e7b => {
76 Name => 'SignatureElementList',
77 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
78 },
79 0x2532 => { Name => 'SignedElement', Binary => 1, Unknown => 1 },
80#
81# Segment
82#
83 0x8538067 => {
84 Name => 'SegmentHeader',
85 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
86 },
87 0x14d9b74 => {
88 Name => 'SeekHead',
89 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
90 },
91 0xdbb => {
92 Name => 'Seek',
93 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
94 },
95 0x13ab => { Name => 'SeekID', Binary => 1, Unknown => 1 },
96 0x13ac => { Name => 'SeekPosition', Format => 'unsigned', Unknown => 1 },
97#
98# Segment Info
99#
100 0x549a966 => {
101 Name => 'Info',
102 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
103 },
104 0x33a4 => { Name => 'SegmentUID', Binary => 1, Unknown => 1 },
105 0x3384 => { Name => 'SegmentFileName', Format => 'utf8' },
106 0x1cb923 => { Name => 'PrevUID', Binary => 1, Unknown => 1 },
107 0x1c83ab => { Name => 'PrevFileName', Format => 'utf8' },
108 0x1eb923 => { Name => 'NextUID', Binary => 1, Unknown => 1 },
109 0x1e83bb => { Name => 'NextFileName', Format => 'utf8' },
110 0x0444 => { Name => 'SegmentFamily', Binary => 1, Unknown => 1 },
111 0x2924 => {
112 Name => 'ChapterTranslate',
113 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
114 },
115 0x29fc => { Name => 'ChapterTranslateEditionUID',Format => 'unsigned', Unknown => 1 },
116 0x29bf => {
117 Name => 'ChapterTranslateCodec',
118 Format => 'unsigned',
119 PrintConv => { 0 => 'Matroska Script', 1 => 'DVD Menu' },
120 },
121 0x29a5 => { Name => 'ChapterTranslateID',Binary => 1, Unknown => 1 },
122 0xad7b1 => {
123 Name => 'TimecodeScale',
124 Format => 'unsigned',
125 RawConv => '$$self{TimecodeScale} = $val',
126 ValueConv => '$val / 1e9',
127 PrintConv => '($val * 1000) . " ms"',
128 },
129 0x489 => {
130 Name => 'Duration',
131 Format => 'float',
132 ValueConv => '$$self{TimecodeScale} ? $val * $$self{TimecodeScale} / 1e9 : $val',
133 PrintConv => '$$self{TimecodeScale} ? ConvertDuration($val) : $val',
134 },
135 0x461 => {
136 Name => 'DateTimeOriginal', # called "DateUTC" by the spec
137 Description => 'Date/Time Original',
138 Groups => { 2 => 'Time' },
139 Format => 'date',
140 PrintConv => '$self->ConvertDateTime($val)',
141 },
142 0x3ba9 => { Name => 'Title', Format => 'utf8' },
143 0xd80 => { Name => 'MuxingApp', Format => 'utf8' },
144 0x1741 => { Name => 'WritingApp', Format => 'utf8' },
145#
146# Cluster
147#
148 0xf43b675 => {
149 Name => 'Cluster',
150 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
151 },
152 0x67 => {
153 Name => 'Timecode',
154 Format => 'unsigned',
155 Unknown => 1,
156 ValueConv => '$$self{TimecodeScale} ? $val * $$self{TimecodeScale} / 1e9 : $val',
157 PrintConv => '$$self{TimecodeScale} ? ConvertDuration($val) : $val',
158 },
159 0x1854 => {
160 Name => 'SilentTracks',
161 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
162 },
163 0x18d7 => { Name => 'SilentTrackNumber',Format => 'unsigned' },
164 0x27 => { Name => 'Position', Format => 'unsigned' },
165 0x2b => { Name => 'PrevSize', Format => 'unsigned' },
166 0x23 => { Name => 'SimpleBlock', NoSave => 1, Unknown => 1 },
167 0x20 => {
168 Name => 'BlockGroup',
169 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
170 },
171 0x21 => { Name => 'Block', NoSave => 1, Unknown => 1 },
172 0x22 => { Name => 'BlockVirtual', NoSave => 1, Unknown => 1 },
173 0x35a1 => {
174 Name => 'BlockAdditions',
175 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
176 },
177 0x26 => {
178 Name => 'BlockMore',
179 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
180 },
181 0x6e => { Name => 'BlockAddID', Format => 'unsigned', Unknown => 1 },
182 0x25 => { Name => 'BlockAdditional', NoSave => 1, Unknown => 1 },
183 0x1b => {
184 Name => 'BlockDuration',
185 Format => 'unsigned',
186 Unknown => 1,
187 ValueConv => '$$self{TimecodeScale} ? $val * $$self{TimecodeScale} / 1e9 : $val',
188 PrintConv => '$$self{TimecodeScale} ? "$val s" : $val',
189 },
190 0x7a => { Name => 'ReferencePriority',Format => 'unsigned', Unknown => 1 },
191 0x7b => {
192 Name => 'ReferenceBlock',
193 Format => 'signed',
194 Unknown => 1,
195 ValueConv => '$$self{TimecodeScale} ? $val * $$self{TimecodeScale} / 1e9 : $val',
196 PrintConv => '$$self{TimecodeScale} ? "$val s" : $val',
197 },
198 0x7d => { Name => 'ReferenceVirtual', Format => 'signed', Unknown => 1 },
199 0x24 => { Name => 'CodecState', Binary => 1, Unknown => 1 },
200 0x0e => {
201 Name => 'Slices',
202 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
203 },
204 0x68 => {
205 Name => 'TimeSlice',
206 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
207 },
208 0x4c => { Name => 'LaceNumber', Format => 'unsigned', Unknown => 1 },
209 0x4d => { Name => 'FrameNumber', Format => 'unsigned', Unknown => 1 },
210 0x4b => { Name => 'BlockAdditionalID',Format => 'unsigned', Unknown => 1 },
211 0x4e => { Name => 'Delay', Format => 'unsigned', Unknown => 1 },
212 0x4f => { Name => 'ClusterDuration', Format => 'unsigned', Unknown => 1 },
213 0x2f => { Name => 'EncryptedBlock', NoSave => 1, Unknown => 1 },
214#
215# Tracks
216#
217 0x654ae6b => {
218 Name => 'Tracks',
219 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
220 },
221 0x2e => {
222 Name => 'TrackEntry',
223 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
224 },
225 0x57 => { Name => 'TrackNumber', Format => 'unsigned' },
226 0x33c5 => { Name => 'TrackUID', Format => 'unsigned', Unknown => 1 },
227 0x03 => {
228 Name => 'TrackType',
229 Format => 'unsigned',
230 PrintHex => 1,
231 # remember types of all tracks encountered, as well as the current track type
232 RawConv => '$$self{TrackTypes}{$val} = 1; $$self{TrackType} = $val',
233 PrintConv => {
234 0x01 => 'Video',
235 0x02 => 'Audio',
236 0x03 => 'Complex', # (audio+video)
237 0x10 => 'Logo',
238 0x11 => 'Subtitle',
239 0x12 => 'Buttons',
240 0x20 => 'Control',
241 },
242 },
243 0x39 => { Name => 'TrackUsed', Format => 'unsigned', PrintConv => \%noYes },
244 0x08 => { Name => 'TrackDefault', Format => 'unsigned', PrintConv => \%noYes },
245 0x15aa => { Name => 'TrackForced', Format => 'unsigned', PrintConv => \%noYes },
246 0x1c => {
247 Name => 'TrackLacing',
248 Format => 'unsigned',
249 Unknown => 1,
250 PrintConv => \%noYes,
251 },
252 0x2de7 => { Name => 'MinCache', Format => 'unsigned', Unknown => 1 },
253 0x2df8 => { Name => 'MaxCache', Format => 'unsigned', Unknown => 1 },
254 0x3e383 => [
255 {
256 Name => 'VideoFrameRate',
257 Condition => '$$self{TrackType} and $$self{TrackType} == 0x01',
258 Format => 'unsigned',
259 ValueConv => '$val ? 1e9 / $val : 0',
260 PrintConv => 'int($val * 1000 + 0.5) / 1000',
261 },{
262 Name => 'DefaultDuration',
263 Format => 'unsigned',
264 ValueConv => '$val / 1e9',
265 PrintConv => '($val * 1000) . " ms"',
266 }
267 ],
268 0x3314f => { Name => 'TrackTimecodeScale',Format => 'float' },
269 0x137f => { Name => 'TrackOffset', Format => 'signed', Unknown => 1 },
270 0x15ee => { Name => 'MaxBlockAdditionID',Format => 'unsigned', Unknown => 1 },
271 0x136e => { Name => 'TrackName', Format => 'utf8' },
272 0x2b59c => { Name => 'TrackLanguage', Format => 'string' },
273 0x06 => [
274 {
275 Name => 'VideoCodecID',
276 Condition => '$$self{TrackType} and $$self{TrackType} == 0x01',
277 Format => 'string',
278 },{
279 Name => 'AudioCodecID',
280 Condition => '$$self{TrackType} and $$self{TrackType} == 0x02',
281 Format => 'string',
282 },{
283 Name => 'CodecID',
284 Format => 'string',
285 }
286 ],
287 0x23a2 => { Name => 'CodecPrivate', Binary => 1, Unknown => 1 },
288 0x58688 => [
289 {
290 Name => 'VideoCodecName',
291 Condition => '$$self{TrackType} and $$self{TrackType} == 0x01',
292 Format => 'utf8',
293 },{
294 Name => 'AudioCodecName',
295 Condition => '$$self{TrackType} and $$self{TrackType} == 0x02',
296 Format => 'utf8',
297 },{
298 Name => 'CodecName',
299 Format => 'utf8',
300 }
301 ],
302 0x3446 => { Name => 'TrackAttachmentUID',Format => 'unsigned' },
303 0x1a9697=>{ Name => 'CodecSettings', Format => 'utf8' },
304 0x1b4040=>{ Name => 'CodecInfoURL', Format => 'string' },
305 0x6b240 =>{ Name => 'CodecDownloadURL', Format => 'string' },
306 0x2a => { Name => 'CodecDecodeAll', Format => 'unsigned', PrintConv => \%noYes },
307 0x2fab => { Name => 'TrackOverlay', Format => 'unsigned', Unknown => 1 },
308 0x2624 => {
309 Name => 'TrackTranslate',
310 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
311 },
312 0x26fc => { Name => 'TrackTranslateEditionUID',Format => 'unsigned', Unknown => 1 },
313 0x26bf => {
314 Name => 'TrackTranslateCodec',
315 Format => 'unsigned',
316 PrintConv => { 0 => 'Matroska Script', 1 => 'DVD Menu' },
317 },
318 0x26a5 => { Name => 'TrackTranslateTrackID', Binary => 1, Unknown => 1 },
319#
320# Video
321#
322 0x60 => {
323 Name => 'Video',
324 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
325 },
326 0x1a => {
327 Name => 'VideoScanType',
328 Format => 'unsigned',
329 PrintConv => {
330 0 => 'Progressive',
331 1 => 'Interlaced',
332 },
333 },
334 0x13b8 => {
335 Name => 'Stereo3DMode',
336 Format => 'unsigned',
337 Printconv => {
338 0 => 'Mono',
339 1 => 'Right Eye',
340 2 => 'Left Eye',
341 3 => 'Both Eyes',
342 },
343 },
344 0x30 => { Name => 'ImageWidth', Format => 'unsigned' },
345 0x3a => { Name => 'ImageHeight', Format => 'unsigned' },
346 0x14aa => { Name => 'CropBottom', Format => 'unsigned' },
347 0x14bb => { Name => 'CropTop', Format => 'unsigned' },
348 0x14cc => { Name => 'CropLeft', Format => 'unsigned' },
349 0x14dd => { Name => 'CropRight', Format => 'unsigned' },
350 0x14b0 => { Name => 'DisplayWidth', Format => 'unsigned' },
351 0x14ba => { Name => 'DisplayHeight', Format => 'unsigned' },
352 0x14b2 => {
353 Name => 'DisplayUnit',
354 Format => 'unsigned',
355 PrintConv => {
356 0 => 'Pixels',
357 1 => 'cm',
358 2 => 'inches',
359 },
360 },
361 0x14b3 => {
362 Name => 'AspectRatioType',
363 Format => 'unsigned',
364 PrintConv => {
365 0 => 'Free Resizing',
366 1 => 'Keep Aspect Ratio',
367 2 => 'Fixed',
368 },
369 },
370 0xeb524 => { Name => 'ColorSpace', Binary => 1, Unknown => 1 },
371 0xfb523 => { Name => 'Gamma', Format => 'float' },
372 0x383e3 => { Name => 'FrameRate', Format => 'float' },
373#
374# Audio
375#
376 0x61 => {
377 Name => 'Audio',
378 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
379 },
380 0x35 => { Name => 'AudioSampleRate', Format => 'float', Groups => { 2 => 'Audio' } },
381 0x38b5 => { Name => 'OutputAudioSampleRate',Format => 'float', Groups => { 2 => 'Audio' } },
382 0x1f => { Name => 'AudioChannels', Format => 'unsigned', Groups => { 2 => 'Audio' } },
383 0x3d7b => {
384 Name => 'ChannelPositions',
385 Binary => 1,
386 Unknown => 1,
387 Groups => { 2 => 'Audio' },
388 },
389 0x2264 => { Name => 'AudioBitsPerSample', Format => 'unsigned', Groups => { 2 => 'Audio' } },
390#
391# Content Encoding
392#
393 0x2d80 => {
394 Name => 'ContentEncodings',
395 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
396 },
397 0x2240 => {
398 Name => 'ContentEncoding',
399 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
400 },
401 0x1031 => { Name => 'ContentEncodingOrder', Format => 'unsigned', Unknown => 1 },
402 0x1032 => { Name => 'ContentEncodingScope', Format => 'unsigned', Unknown => 1 },
403 0x1033 => {
404 Name => 'ContentEncodingType',
405 Format => 'unsigned',
406 PrintConv => { 0 => 'Compression', 1 => 'Encryption' },
407 },
408 0x1034 => {
409 Name => 'ContentCompression',
410 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
411 },
412 0x254 => {
413 Name => 'ContentCompressionAlgorithm',
414 Format => 'unsigned',
415 PrintConv => {
416 0 => 'zlib',
417 1 => 'bzlib',
418 2 => 'lzo1x',
419 3 => 'Header Stripping',
420 },
421 },
422 0x255 => { Name => 'ContentCompressionSettings',Binary => 1, Unknown => 1 },
423 0x1035 => {
424 Name => 'ContentEncryption',
425 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
426 },
427 0x7e1 => {
428 Name => 'ContentEncryptionAlgorithm',
429 Format => 'unsigned',
430 PrintConv => {
431 0 => 'Not Encrypted',
432 1 => 'DES',
433 2 => '3DES',
434 3 => 'Twofish',
435 4 => 'Blowfish',
436 5 => 'AES',
437 },
438 },
439 0x7e2 => { Name => 'ContentEncryptionKeyID',Binary => 1, Unknown => 1 },
440 0x7e3 => { Name => 'ContentSignature', Binary => 1, Unknown => 1 },
441 0x7e4 => { Name => 'ContentSignatureKeyID', Binary => 1, Unknown => 1 },
442 0x7e5 => {
443 Name => 'ContentSignatureAlgorithm',
444 Format => 'unsigned',
445 PrintConv => {
446 0 => 'Not Signed',
447 1 => 'RSA',
448 },
449 },
450 0x7e6 => {
451 Name => 'ContentSignatureHashAlgorithm',
452 Format => 'unsigned',
453 PrintConv => {
454 0 => 'Not Signed',
455 1 => 'SHA1-160',
456 2 => 'MD5',
457 },
458 },
459#
460# Cues
461#
462 0xc53bb6b => {
463 Name => 'Cues',
464 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
465 },
466 0x3b => {
467 Name => 'CuePoint',
468 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
469 },
470 0x33 => {
471 Name => 'CueTime',
472 Format => 'unsigned',
473 Unknown => 1,
474 ValueConv => '$$self{TimecodeScale} ? $val * $$self{TimecodeScale} / 1e9 : $val',
475 PrintConv => '$$self{TimecodeScale} ? ConvertDuration($val) : $val',
476 },
477 0x37 => {
478 Name => 'CueTrackPositions',
479 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
480 },
481 0x77 => { Name => 'CueTrack', Format => 'unsigned', Unknown => 1 },
482 0x71 => { Name => 'CueClusterPosition',Format => 'unsigned', Unknown => 1 },
483 0x1378 => { Name => 'CueBlockNumber', Format => 'unsigned', Unknown => 1 },
484 0x6a => { Name => 'CueCodecState', Format => 'unsigned', Unknown => 1 },
485 0x5b => {
486 Name => 'CueReference',
487 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
488 },
489 0x16 => {
490 Name => 'CueRefTime',
491 Format => 'unsigned',
492 Unknown => 1,
493 ValueConv => '$$self{TimecodeScale} ? $val * $$self{TimecodeScale} / 1e9 : $val',
494 PrintConv => '$$self{TimecodeScale} ? ConvertDuration($val) : $val',
495 },
496 0x17 => { Name => 'CueRefCluster', Format => 'unsigned', Unknown => 1 },
497 0x135f=> { Name => 'CueRefNumber', Format => 'unsigned', Unknown => 1 },
498 0x6b => { Name => 'CueRefCodecState', Format => 'unsigned', Unknown => 1 },
499#
500# Attachments
501#
502 0x941a469 => {
503 Name => 'Attachments',
504 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
505 },
506 0x21a7 => {
507 Name => 'AttachedFile',
508 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
509 },
510 0x67e => { Name => 'AttachedFileDescription',Format => 'utf8' },
511 0x66e => { Name => 'AttachedFileName', Format => 'utf8' },
512 0x660 => { Name => 'AttachedFileMIMEType', Format => 'string' },
513 0x65c => { Name => 'AttachedFileData', Binary => 1 },
514 0x6ae => { Name => 'AttachedFileUID', Format => 'unsigned' },
515 0x675 => { Name => 'AttachedFileReferral', Binary => 1, Unknown => 1 },
516#
517# Chapters
518#
519 0x43a770 => {
520 Name => 'Chapters',
521 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
522 },
523 0x5b9 => {
524 Name => 'EditionEntry',
525 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
526 },
527 0x5bc => { Name => 'EditionUID', Format => 'unsigned', Unknown => 1 },
528 0x5bd => { Name => 'EditionFlagHidden', Format => 'unsigned', Unknown => 1 },
529 0x5db => { Name => 'EditionFlagDefault',Format => 'unsigned', Unknown => 1 },
530 0x5dd => { Name => 'EditionFlagOrdered',Format => 'unsigned', Unknown => 1 },
531 0x36 => {
532 Name => 'ChapterAtom',
533 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
534 },
535 0x33c4 => { Name => 'ChapterUID', Format => 'unsigned', Unknown => 1 },
536 0x11 => {
537 Name => 'ChapterTimeStart',
538 Groups => { 1 => 'Chapter#' },
539 Format => 'unsigned',
540 ValueConv => '$val / 1e9',
541 PrintConv => 'ConvertDuration($val)',
542 },
543 0x12 => {
544 Name => 'ChapterTimeEnd',
545 Format => 'unsigned',
546 ValueConv => '$val / 1e9',
547 PrintConv => 'ConvertDuration($val)',
548 },
549 0x18 => { Name => 'ChapterFlagHidden', Format => 'unsigned', Unknown => 1 },
550 0x598 => { Name => 'ChapterFlagEnabled',Format => 'unsigned', Unknown => 1 },
551 0x2e67=> { Name => 'ChapterSegmentUID', Binary => 1, Unknown => 1 },
552 0x2ebc=> { Name => 'ChapterSegmentEditionUID', Binary => 1, Unknown => 1 },
553 0x23c3 => {
554 Name => 'ChapterPhysicalEquivalent',
555 Format => 'unsigned',
556 PrintConv => {
557 10 => 'Index',
558 20 => 'Track',
559 30 => 'Session',
560 40 => 'Layer',
561 50 => 'Side',
562 60 => 'CD / DVD',
563 70 => 'Set / Package',
564 },
565 },
566 0x0f => {
567 Name => 'ChapterTrack',
568 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
569 },
570 0x09 => { Name => 'ChapterTrackNumber', Format => 'unsigned', Unknown => 1 },
571 0x00 => {
572 Name => 'ChapterDisplay',
573 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
574 },
575 0x05 => { Name => 'ChapterString', Format => 'utf8' },
576 0x37c => { Name => 'ChapterLanguage', Format => 'string' },
577 0x37e => { Name => 'ChapterCountry', Format => 'string' },
578 0x2944 => {
579 Name => 'ChapterProcess',
580 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
581 },
582 0x2955 => {
583 Name => 'ChapterProcessCodecID',
584 Format => 'unsigned',
585 Unknown => 1,
586 PrintConv => { 0 => 'Matroska', 1 => 'DVD' },
587 },
588 0x50d => { Name => 'ChapterProcessPrivate', Binary => 1, Unknown => 1 },
589 0x2911 => {
590 Name => 'ChapterProcessCommand',
591 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
592 },
593 0x2922 => {
594 Name => 'ChapterProcessTime',
595 Format => 'unsigned',
596 Unknown => 1,
597 PrintConv => {
598 0 => 'For Duration of Chapter',
599 1 => 'Before Chapter',
600 2 => 'After Chapter',
601 },
602 },
603 0x2933 => { Name => 'ChapterProcessData', Binary => 1, Unknown => 1 },
604#
605# Tags
606#
607 0x254c367 => {
608 Name => 'Tags',
609 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
610 },
611 0x3373 => {
612 Name => 'Tag',
613 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
614 },
615 0x23c0 => {
616 Name => 'Targets',
617 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
618 },
619 0x28ca => { Name => 'TargetTypeValue', Format => 'unsigned' },
620 0x23ca => { Name => 'TargetType', Format => 'string' },
621 0x23c5 => { Name => 'TagTrackUID', Format => 'unsigned', Unknown => 1 },
622 0x23c9 => { Name => 'TagEditionUID', Format => 'unsigned', Unknown => 1 },
623 0x23c4 => { Name => 'TagChapterUID', Format => 'unsigned', Unknown => 1 },
624 0x23c6 => { Name => 'TagAttachmentUID', Format => 'unsigned', Unknown => 1 },
625 0x27c8 => {
626 Name => 'SimpleTag',
627 SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
628 },
629 0x5a3 => { Name => 'TagName', Format => 'utf8' },
630 0x47a => { Name => 'TagLanguage', Format => 'string' },
631 0x484 => { Name => 'TagDefault', Format => 'unsigned', PrintConv => \%noYes },
632 0x487 => { Name => 'TagString', Format => 'utf8' },
633 0x485 => { Name => 'TagBinary', Binary => 1 },
634);
635
636#------------------------------------------------------------------------------
637# Get variable-length Matroska integer
638# Inputs: 0) data buffer, 1) position in data
639# Returns: integer value and updates position, -1 for unknown/reserved value,
640# or undef if no data left
641sub GetVInt($$)
642{
643 return undef if $_[1] >= length $_[0];
644 my $val = ord(substr($_[0], $_[1]++));
645 my $num = 0;
646 unless ($val) {
647 return undef if $_[1] >= length $_[0];
648 $val = ord(substr($_[0], $_[1]++));
649 return undef unless $val; # can't be this large!
650 $num += 7; # 7 more bytes to read (we just read one)
651 }
652 my $mask = 0x7f;
653 while ($val == ($val & $mask)) {
654 $mask >>= 1;
655 ++$num;
656 }
657 $val = ($val & $mask);
658 my $unknown = ($val == $mask);
659 return undef if $_[1] + $num > length $_[0];
660 while ($num) {
661 my $b = ord(substr($_[0], $_[1]++));
662 $unknown = 0 if $b != 0xff;
663 $val = $val * 256 + $b;
664 --$num;
665 }
666 return $unknown ? -1 : $val;
667}
668
669#------------------------------------------------------------------------------
670# Read information from a Matroska multimedia file (MKV, MKA, MKS)
671# Inputs: 0) ExifTool object reference, 1) Directory information reference
672# Returns: 1 on success, 0 if this wasn't a valid Matroska file
673sub ProcessMKV($$)
674{
675 my ($exifTool, $dirInfo) = @_;
676 my $raf = $$dirInfo{RAF};
677 my ($buff, $buf2, @dirEnd, $trackIndent, %trackTypes);
678
679 $raf->Read($buff, 4) == 4 or return 0;
680 return 0 unless $buff =~ /^\x1a\x45\xdf\xa3/;
681
682 # read in 64kB blocks (already read 4 bytes)
683 $raf->Read($buff, 65532) or return 0;
684 my $dataLen = length $buff;
685 my ($pos, $dataPos) = (0, 4);
686
687 # verify header length
688 my $hlen = GetVInt($buff, $pos);
689 return 0 unless $hlen and $hlen > 0;
690 $pos + $hlen > $dataLen and $exifTool->Warn('Truncated Matroska header'), return 1;
691 $exifTool->SetFileType();
692 SetByteOrder('MM');
693 my $tagTablePtr = GetTagTable('Image::ExifTool::Matroska::Main');
694
695 # set flag to process entire file (otherwise we stop at the first Cluster)
696 my $verbose = $exifTool->Options('Verbose');
697 my $processAll = ($verbose or $exifTool->Options('Unknown') > 1);
698 $$exifTool{TrackTypes} = \%trackTypes; # store Track types reference
699 my $oldIndent = $$exifTool{INDENT};
700 my $chapterNum = 0;
701
702 # loop over all Matroska elements
703 for (;;) {
704 while (@dirEnd and $pos + $dataPos >= $dirEnd[-1][0]) {
705 pop @dirEnd;
706 # use INDENT to decide whether or not we are done this Track element
707 delete $$exifTool{SET_GROUP1} if $trackIndent and $trackIndent eq $$exifTool{INDENT};
708 $$exifTool{INDENT} = substr($$exifTool{INDENT}, 0, -2);
709 }
710 # read more if we are getting close to the end of our buffer
711 # (24 more bytes should be enough to read this element header)
712 if ($pos + 24 > $dataLen and $raf->Read($buf2, 65536)) {
713 $buff = substr($buff, $pos) . $buf2;
714 undef $buf2;
715 $dataPos += $pos;
716 $dataLen = length $buff;
717 $pos = 0;
718 }
719 my $tag = GetVInt($buff, $pos);
720 last unless defined $tag and $tag >= 0;
721 my $size = GetVInt($buff, $pos);
722 last unless defined $size;
723 my $unknownSize;
724 $size < 0 and $unknownSize = 1, $size = 1e20;
725 if (@dirEnd and $pos + $dataPos + $size > $dirEnd[-1][0]) {
726 $exifTool->Warn("Invalid or corrupted $dirEnd[-1][1] master element");
727 $pos = $dirEnd[-1][0] - $dataPos;
728 if ($pos < 0 or $pos > $dataLen) {
729 $buff = '';
730 $dataPos += $pos;
731 $dataLen = 0;
732 $pos = 0;
733 $raf->Seek($dataPos, 0) or last;
734 }
735 next;
736 }
737 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
738 # just fall through into the contained EBML elements
739 if ($tagInfo and $$tagInfo{SubDirectory}) {
740 # stop processing at first cluster unless we are in verbose mode
741 last if $$tagInfo{Name} eq 'Cluster' and not $processAll;
742 $$exifTool{INDENT} .= '| ';
743 $exifTool->VerboseDir($$tagTablePtr{$tag}{Name}, undef, $size);
744 push @dirEnd, [ $pos + $dataPos + $size, $$tagInfo{Name} ];
745 if ($$tagInfo{Name} eq 'ChapterAtom') {
746 $$exifTool{SET_GROUP1} = 'Chapter' . (++$chapterNum);
747 $trackIndent = $$exifTool{INDENT};
748 }
749 next;
750 }
751 last if $unknownSize;
752 if ($pos + $size > $dataLen) {
753 # how much more do we need to read?
754 my $more = $pos + $size - $dataLen;
755 # just skip unknown and large data blocks
756 if (not $tagInfo or $more > 10000000) {
757 # don't try to skip very large blocks unless LargeFileSupport is enabled
758 last if $more > 0x80000000 and not $exifTool->Options('LargeFileSupport');
759 $raf->Seek($more, 1) or last;
760 $buff = '';
761 $dataPos += $dataLen + $more;
762 $dataLen = 0;
763 $pos = 0;
764 next;
765 } else {
766 # read data in multiples of 64kB
767 $more = (int($more / 65536) + 1) * 65536;
768 if ($raf->Read($buf2, $more)) {
769 $buff = substr($buff, $pos) . $buf2;
770 undef $buf2;
771 $dataPos += $pos;
772 $dataLen = length $buff;
773 $pos = 0;
774 }
775 last if $pos + $size > $dataLen;
776 }
777 }
778 unless ($tagInfo) {
779 # ignore the element
780 $pos += $size;
781 next;
782 }
783 my $val;
784 if ($$tagInfo{Format}) {
785 my $fmt = $$tagInfo{Format};
786 if ($fmt eq 'string' or $fmt eq 'utf8') {
787 ($val = substr($buff, $pos, $size)) =~ s/\0.*//s;
788 $val = $exifTool->Decode($val, 'UTF8') if $fmt eq 'utf8';
789 } elsif ($fmt eq 'float') {
790 if ($size == 4) {
791 $val = GetFloat(\$buff, $pos);
792 } elsif ($size == 8) {
793 $val = GetDouble(\$buff, $pos);
794 } else {
795 $exifTool->Warn("Illegal float size ($size)");
796 }
797 } else {
798 my @vals = unpack("x${pos}C$size", $buff);
799 $val = 0;
800 if ($fmt eq 'signed' or $fmt eq 'date') {
801 my $over = 1;
802 foreach (@vals) {
803 $val = $val * 256 + $_;
804 $over *= 256;
805 }
806 # interpret negative numbers
807 $val -= $over if $vals[0] & 0x80;
808 # convert dates (nanoseconds since 2001:01:01)
809 if ($fmt eq 'date') {
810 my $t = $val / 1e9;
811 my $f = $t - int($t); # fractional seconds
812 $f =~ s/^\d+//; # remove leading zero
813 # (8 leap days between 1970 and 2001)
814 $t += (((2001-1970)*365+8)*24*3600);
815 $val = Image::ExifTool::ConvertUnixTime($t) . $f . 'Z';
816 }
817 } else { # must be unsigned
818 $val = $val * 256 + $_ foreach @vals;
819 }
820 }
821 # set group1 to Track/Chapter number
822 if ($$tagInfo{Name} eq 'TrackNumber') {
823 $$exifTool{SET_GROUP1} = 'Track' . $val;
824 $trackIndent = $$exifTool{INDENT};
825 }
826 }
827 my %parms = (
828 DataPt => \$buff,
829 DataPos => $dataPos,
830 Start => $pos,
831 Size => $size,
832 );
833 if ($$tagInfo{NoSave}) {
834 $exifTool->VerboseInfo($tag, $tagInfo, Value => $val, %parms) if $verbose;
835 } else {
836 $exifTool->HandleTag($tagTablePtr, $tag, $val, %parms);
837 }
838 $pos += $size; # step to next element
839 }
840 $$exifTool{INDENT} = $oldIndent;
841 delete $$exifTool{SET_GROUP1};
842 # override file type if necessary based on existing track types
843 unless ($trackTypes{0x01} or $trackTypes{0x03}) { # video or complex?
844 if ($trackTypes{0x02}) { # audio?
845 $exifTool->OverrideFileType('MKA');
846 } elsif ($trackTypes{0x11}) { # subtitle?
847 $exifTool->OverrideFileType('MKS');
848 }
849 }
850 return 1;
851}
852
8531; # end
854
855__END__
856
857=head1 NAME
858
859Image::ExifTool::Matroska - Read meta information from Matroska files
860
861=head1 SYNOPSIS
862
863This module is used by Image::ExifTool
864
865=head1 DESCRIPTION
866
867This module contains definitions required by Image::ExifTool to read meta
868information from Matroska multimedia files (MKA, MKV, MKS and WEBM).
869
870=head1 AUTHOR
871
872Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
873
874This library is free software; you can redistribute it and/or modify it
875under the same terms as Perl itself.
876
877=head1 REFERENCES
878
879=over 4
880
881=item L<http://www.matroska.org/technical/specs/index.html>
882
883=back
884
885=head1 SEE ALSO
886
887L<Image::ExifTool::TagNames/Matroska Tags>,
888L<Image::ExifTool(3pm)|Image::ExifTool>
889
890=cut
891
Note: See TracBrowser for help on using the repository browser.