- Timestamp:
- 2021-02-26T19:39:51+13:00 (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/greenstone2/perllib/cpan/Image/ExifTool/QuickTime.pm
r24107 r34921 2 2 # File: QuickTime.pm 3 3 # 4 # Description: Read QuickTime , MP4 and M4Ameta information4 # Description: Read QuickTime and MP4 meta information 5 5 # 6 6 # Revisions: 10/04/2005 - P. Harvey Created … … 9 9 # 07/27/2010 - P. Harvey Updated to 2010-05-03 QuickTime spec 10 10 # 11 # References: 1) http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html 12 # 2) http://search.cpan.org/dist/MP4-Info-1.04/ 13 # 3) http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt 14 # 4) http://wiki.multimedia.cx/index.php?title=Apple_QuickTime 15 # 5) ISO 14496-12 (http://neuron2.net/library/avc/c041828_ISO_IEC_14496-12_2005(E).pdf) 16 # 6) ISO 14496-16 (http://www.iec-normen.de/previewpdf/info_isoiec14496-16%7Bed2.0%7Den.pdf) 17 # 7) http://atomicparsley.sourceforge.net/mpeg-4files.html 18 # 8) http://wiki.multimedia.cx/index.php?title=QuickTime_container 19 # 9) http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart3.pdf (Oct 2008) 20 # 10) http://code.google.com/p/mp4v2/wiki/iTunesMetadata 21 # 11) http://www.canieti.com.mx/assets/files/1011/IEC_100_1384_DC.pdf 22 # 12) QuickTime file format specification 2010-05-03 23 # 13) http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v10.pdf 24 # 14) http://standards.iso.org/ittf/PubliclyAvailableStandards/c051533_ISO_IEC_14496-12_2008.zip 11 # References: 12 # 13 # 1) http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html 14 # 2) http://search.cpan.org/dist/MP4-Info-1.04/ 15 # 3) http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt 16 # 4) http://wiki.multimedia.cx/index.php?title=Apple_QuickTime 17 # 5) ISO 14496-12 (http://read.pudn.com/downloads64/ebook/226547/ISO_base_media_file_format.pdf) 18 # 6) ISO 14496-16 (http://www.iec-normen.de/previewpdf/info_isoiec14496-16%7Bed2.0%7Den.pdf) 19 # 7) http://atomicparsley.sourceforge.net/mpeg-4files.html 20 # 8) http://wiki.multimedia.cx/index.php?title=QuickTime_container 21 # 9) http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart3.pdf (Oct 2008) 22 # 10) http://code.google.com/p/mp4v2/wiki/iTunesMetadata 23 # 11) http://www.canieti.com.mx/assets/files/1011/IEC_100_1384_DC.pdf 24 # 12) QuickTime file format specification 2010-05-03 25 # 13) http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v10.pdf 26 # 14) http://standards.iso.org/ittf/PubliclyAvailableStandards/c051533_ISO_IEC_14496-12_2008.zip 27 # 15) http://getid3.sourceforge.net/source/module.audio-video.quicktime.phps 28 # 16) http://qtra.apple.com/atoms.html 29 # 17) http://www.etsi.org/deliver/etsi_ts/126200_126299/126244/10.01.00_60/ts_126244v100100p.pdf 30 # 18) https://github.com/appsec-labs/iNalyzer/blob/master/scinfo.m 31 # 19) http://nah6.com/~itsme/cvs-xdadevtools/iphone/tools/decodesinf.pl 32 # 20) https://developer.apple.com/legacy/library/documentation/quicktime/reference/QT7-1_Update_Reference/QT7-1_Update_Reference.pdf 33 # 21) Francois Bonzon private communication 34 # 22) https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html 35 # 23) http://atomicparsley.sourceforge.net/mpeg-4files.html 36 # 24) https://github.com/sergiomb2/libmp4v2/wiki/iTunesMetadata 37 # 25) https://cconcolato.github.io/mp4ra/atoms.html 38 # 26) https://github.com/SamsungVR/android_upload_sdk/blob/master/SDKLib/src/main/java/com/samsung/msca/samsungvr/sdk/UserVideo.java 39 # 27) https://exiftool.org/forum/index.php?topic=11517.0 25 40 #------------------------------------------------------------------------------ 26 41 … … 28 43 29 44 use strict; 30 use vars qw($VERSION );45 use vars qw($VERSION $AUTOLOAD %stringEncoding); 31 46 use Image::ExifTool qw(:DataAccess :Utils); 32 47 use Image::ExifTool::Exif; 33 34 $VERSION = '1.48'; 35 36 sub FixWrongFormat($); 48 use Image::ExifTool::GPS; 49 50 $VERSION = '2.59'; 51 37 52 sub ProcessMOV($$;$); 38 53 sub ProcessKeys($$$); 54 sub ProcessMetaKeys($$$); 39 55 sub ProcessMetaData($$$); 56 sub ProcessEncodingParams($$$); 57 sub ProcessSampleDesc($$$); 58 sub ProcessHybrid($$$); 59 sub ProcessRights($$$); 60 # ++vvvvvvvvvvvv++ (in QuickTimeStream.pl) 61 sub Process_mebx($$$); 62 sub Process_3gf($$$); 63 sub Process_gps0($$$); 64 sub Process_gsen($$$); 65 sub ProcessRIFFTrailer($$$); 66 sub ProcessTTAD($$$); 67 sub ProcessNMEA($$$); 68 sub SaveMetaKeys($$$); 69 # ++^^^^^^^^^^^^++ 70 sub ParseItemLocation($$); 71 sub ParseContentDescribes($$); 72 sub ParseItemInfoEntry($$); 73 sub ParseItemPropAssoc($$); 74 sub FixWrongFormat($); 75 sub GetMatrixStructure($$); 40 76 sub ConvertISO6709($); 77 sub ConvInvISO6709($); 78 sub ConvertChapterList($); 79 sub PrintChapter($); 41 80 sub PrintGPSCoordinates($); 42 43 # information for time/date-based tags (time zero is Jan 1, 1904) 44 my %timeInfo = ( 45 # Note: This value will be in UTC if generated by a system that is aware of the time zone 46 ValueConv => 'ConvertUnixTime($val - ((66 * 365 + 17) * 24 * 3600))', 47 PrintConv => '$self->ConvertDateTime($val)', 48 # (can't put Groups here because they aren't constant!) 49 ); 50 # information for duration tags 51 my %durationInfo = ( 52 ValueConv => '$$self{TimeScale} ? $val / $$self{TimeScale} : $val', 53 PrintConv => '$$self{TimeScale} ? ConvertDuration($val) : $val', 54 ); 55 56 # 4-character Vendor ID codes (ref PH) 57 my %vendorID = ( 58 appl => 'Apple', 59 fe20 => 'Olympus (fe20)', # (FE200) 60 FFMP => 'FFmpeg', 61 'GIC '=> 'General Imaging Co.', 62 kdak => 'Kodak', 63 KMPI => 'Konica-Minolta', 64 mino => 'Minolta', 65 niko => 'Nikon', 66 NIKO => 'Nikon', 67 olym => 'Olympus', 68 pana => 'Panasonic', 69 pent => 'Pentax', 70 pr01 => 'Olympus (pr01)', # (FE100,FE110,FE115) 71 sany => 'Sanyo', 72 'SMI '=> 'Sorenson Media Inc.', 73 ZORA => 'Zoran Corporation', 74 ); 75 76 # QuickTime data atom encodings for string types (ref 12) 77 my %stringEncoding = ( 78 1 => 'UTF8', 79 2 => 'UTF16', 80 3 => 'ShiftJIS', 81 4 => 'UTF8', 82 5 => 'UTF16', 83 ); 81 sub PrintInvGPSCoordinates($); 82 sub UnpackLang($;$); 83 sub WriteKeys($$$); 84 sub WriteQuickTime($$$); 85 sub WriteMOV($$); 86 sub GetLangInfo($$); 87 sub CheckQTValue($$$); 84 88 85 89 # MIME types for all entries in the ftypLookup with file extensions … … 88 92 '3G2' => 'video/3gpp2', 89 93 '3GP' => 'video/3gpp', 94 AAX => 'audio/vnd.audible.aax', 90 95 DVB => 'video/vnd.dvb.file', 91 96 F4A => 'audio/mp4', … … 100 105 MOV => 'video/quicktime', 101 106 MQV => 'video/quicktime', 102 ); 103 104 my %graphicsMode = ( 105 # (ref http://homepage.mac.com/vanhoek/MovieGuts%20docs/64.html) 106 0x00 => 'srcCopy', 107 0x01 => 'srcOr', 108 0x02 => 'srcXor', 109 0x03 => 'srcBic', 110 0x04 => 'notSrcCopy', 111 0x05 => 'notSrcOr', 112 0x06 => 'notSrcXor', 113 0x07 => 'notSrcBic', 114 0x08 => 'patCopy', 115 0x09 => 'patOr', 116 0x0a => 'patXor', 117 0x0b => 'patBic', 118 0x0c => 'notPatCopy', 119 0x0d => 'notPatOr', 120 0x0e => 'notPatXor', 121 0x0f => 'notPatBic', 122 0x20 => 'blend', 123 0x21 => 'addPin', 124 0x22 => 'addOver', 125 0x23 => 'subPin', 126 0x24 => 'transparent', 127 0x25 => 'addMax', 128 0x26 => 'subOver', 129 0x27 => 'addMin', 130 0x31 => 'grayishTextOr', 131 0x32 => 'hilite', 132 0x40 => 'ditherCopy', 133 # the following ref ISO/IEC 15444-3 134 0x100 => 'Alpha', 135 0x101 => 'White Alpha', 136 0x102 => 'Pre-multiplied Black Alpha', 137 0x110 => 'Component Alpha', 107 HEIC => 'image/heic', 108 HEVC => 'image/heic-sequence', 109 HEICS=> 'image/heic-sequence', 110 HEIF => 'image/heif', 111 HEIFS=> 'image/heif-sequence', 112 AVIF => 'image/avif', #PH (NC) 113 CRX => 'video/x-canon-crx', # (will get overridden) 138 114 ); 139 115 … … 156 132 '3gp6' => '3GPP Media (.3GP) Release 6 Streaming Servers', # video/3gpp 157 133 '3gs7' => '3GPP Media (.3GP) Release 7 Streaming Servers', # video/3gpp 134 'aax ' => 'Audible Enhanced Audiobook (.AAX)', #PH 158 135 'avc1' => 'MP4 Base w/ AVC ext [ISO 14496-12:2005]', # video/mp4 159 136 'CAEP' => 'Canon Digital Camera', … … 191 168 'jpx ' => 'JPEG 2000 with extensions (.JPX) [ISO 15444-2]', # image/jpx 192 169 'KDDI' => '3GPP2 EZmovie for KDDI 3G cellphones', # video/3gpp2 170 #LCAG => (found in CompatibleBrands of Leica MOV videos) 193 171 'M4A ' => 'Apple iTunes AAC-LC (.M4A) Audio', # audio/x-m4a 194 172 'M4B ' => 'Apple iTunes AAC-LC (.M4B) Audio Book', # audio/mp4 … … 227 205 'ssc1' => 'Samsung stereoscopic, single stream', 228 206 'ssc2' => 'Samsung stereoscopic, dual stream', 207 'XAVC' => 'Sony XAVC', #PH 208 'heic' => 'High Efficiency Image Format HEVC still image (.HEIC)', # image/heic 209 'hevc' => 'High Efficiency Image Format HEVC sequence (.HEICS)', # image/heic-sequence 210 'mif1' => 'High Efficiency Image Format still image (.HEIF)', # image/heif 211 'msf1' => 'High Efficiency Image Format sequence (.HEIFS)', # image/heif-sequence 212 'heix' => 'High Efficiency Image Format still image (.HEIF)', # image/heif (ref PH, Canon 1DXmkIII) 213 'avif' => 'AV1 Image File Format (.AVIF)', # image/avif 214 'crx ' => 'Canon Raw (.CRX)', #PH (CR3 or CRM; use Canon CompressorVersion to decide) 215 ); 216 217 # information for int32u date/time tags (time zero is Jan 1, 1904) 218 my %timeInfo = ( 219 Notes => 'converted from UTC to local time if the QuickTimeUTC option is set', 220 Shift => 'Time', 221 Writable => 1, 222 Permanent => 1, 223 DelValue => 0, 224 # It is not uncommon for brain-dead software to use the wrong time zero, 225 # so assume a time zero of Jan 1, 1970 if the date is before this 226 # Note: This value will be in UTC if generated by a system that is aware of the time zone 227 RawConv => q{ 228 my $offset = (66 * 365 + 17) * 24 * 3600; 229 return $val - $offset if $val >= $offset or $$self{OPTIONS}{QuickTimeUTC}; 230 if ($val and not $$self{IsWriting}) { 231 $self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1); 232 } 233 return $val; 234 }, 235 RawConvInv => q{ 236 if ($$self{FileType} eq 'CR3' and not $self->Options('QuickTimeUTC')) { 237 # convert to UTC 238 my $offset = (66 * 365 + 17) * 24 * 3600; 239 $val = ConvertUnixTime($val - $offset); 240 $val = GetUnixTime($val, 1) + $offset; 241 } 242 return $val; 243 }, 244 # (all CR3 files store UTC times - PH) 245 ValueConv => 'ConvertUnixTime($val, $self->Options("QuickTimeUTC") || $$self{FileType} eq "CR3")', 246 ValueConvInv => 'GetUnixTime($val, $self->Options("QuickTimeUTC")) + (66 * 365 + 17) * 24 * 3600', 247 PrintConv => '$self->ConvertDateTime($val)', 248 PrintConvInv => '$self->InverseDateTime($val)', 249 # (can't put Groups here because they aren't constant!) 250 ); 251 # information for duration tags 252 my %durationInfo = ( 253 ValueConv => '$$self{TimeScale} ? $val / $$self{TimeScale} : $val', 254 PrintConv => '$$self{TimeScale} ? ConvertDuration($val) : $val', 255 ); 256 # handle unknown tags 257 my %unknownInfo = ( 258 Unknown => 1, 259 ValueConv => '$val =~ /^([\x20-\x7e]*)\0*$/ ? $1 : \$val', 260 ); 261 262 # multi-language text with 6-byte header 263 my %langText = ( IText => 6 ); 264 265 # parsing for most of the 3gp udta language text boxes 266 my %langText3gp = ( 267 Notes => 'used in 3gp videos', 268 Avoid => 1, 269 IText => 6, 270 ); 271 272 # 4-character Vendor ID codes (ref PH) 273 my %vendorID = ( 274 appl => 'Apple', 275 fe20 => 'Olympus (fe20)', # (FE200) 276 FFMP => 'FFmpeg', 277 'GIC '=> 'General Imaging Co.', 278 kdak => 'Kodak', 279 KMPI => 'Konica-Minolta', 280 leic => 'Leica', 281 mino => 'Minolta', 282 niko => 'Nikon', 283 NIKO => 'Nikon', 284 olym => 'Olympus', 285 pana => 'Panasonic', 286 pent => 'Pentax', 287 pr01 => 'Olympus (pr01)', # (FE100,FE110,FE115) 288 sany => 'Sanyo', 289 'SMI '=> 'Sorenson Media Inc.', 290 ZORA => 'Zoran Corporation', 291 'AR.D'=> 'Parrot AR.Drone', 292 ' KD '=> 'Kodak', # (FZ201) 293 ); 294 295 # QuickTime data atom encodings for string types (ref 12) 296 %stringEncoding = ( 297 1 => 'UTF8', 298 2 => 'UTF16', 299 3 => 'ShiftJIS', 300 4 => 'UTF8', 301 5 => 'UTF16', 302 ); 303 304 my %graphicsMode = ( 305 # (ref http://homepage.mac.com/vanhoek/MovieGuts%20docs/64.html) 306 0x00 => 'srcCopy', 307 0x01 => 'srcOr', 308 0x02 => 'srcXor', 309 0x03 => 'srcBic', 310 0x04 => 'notSrcCopy', 311 0x05 => 'notSrcOr', 312 0x06 => 'notSrcXor', 313 0x07 => 'notSrcBic', 314 0x08 => 'patCopy', 315 0x09 => 'patOr', 316 0x0a => 'patXor', 317 0x0b => 'patBic', 318 0x0c => 'notPatCopy', 319 0x0d => 'notPatOr', 320 0x0e => 'notPatXor', 321 0x0f => 'notPatBic', 322 0x20 => 'blend', 323 0x21 => 'addPin', 324 0x22 => 'addOver', 325 0x23 => 'subPin', 326 0x24 => 'transparent', 327 0x25 => 'addMax', 328 0x26 => 'subOver', 329 0x27 => 'addMin', 330 0x31 => 'grayishTextOr', 331 0x32 => 'hilite', 332 0x40 => 'ditherCopy', 333 # the following ref ISO/IEC 15444-3 334 0x100 => 'Alpha', 335 0x101 => 'White Alpha', 336 0x102 => 'Pre-multiplied Black Alpha', 337 0x110 => 'Component Alpha', 338 ); 339 340 my %channelLabel = ( 341 0xFFFFFFFF => 'Unknown', 342 0 => 'Unused', 343 100 => 'UseCoordinates', 344 1 => 'Left', 345 2 => 'Right', 346 3 => 'Center', 347 4 => 'LFEScreen', 348 5 => 'LeftSurround', 349 6 => 'RightSurround', 350 7 => 'LeftCenter', 351 8 => 'RightCenter', 352 9 => 'CenterSurround', 353 10 => 'LeftSurroundDirect', 354 11 => 'RightSurroundDirect', 355 12 => 'TopCenterSurround', 356 13 => 'VerticalHeightLeft', 357 14 => 'VerticalHeightCenter', 358 15 => 'VerticalHeightRight', 359 16 => 'TopBackLeft', 360 17 => 'TopBackCenter', 361 18 => 'TopBackRight', 362 33 => 'RearSurroundLeft', 363 34 => 'RearSurroundRight', 364 35 => 'LeftWide', 365 36 => 'RightWide', 366 37 => 'LFE2', 367 38 => 'LeftTotal', 368 39 => 'RightTotal', 369 40 => 'HearingImpaired', 370 41 => 'Narration', 371 42 => 'Mono', 372 43 => 'DialogCentricMix', 373 44 => 'CenterSurroundDirect', 374 45 => 'Haptic', 375 200 => 'Ambisonic_W', 376 201 => 'Ambisonic_X', 377 202 => 'Ambisonic_Y', 378 203 => 'Ambisonic_Z', 379 204 => 'MS_Mid', 380 205 => 'MS_Side', 381 206 => 'XY_X', 382 207 => 'XY_Y', 383 301 => 'HeadphonesLeft', 384 302 => 'HeadphonesRight', 385 304 => 'ClickTrack', 386 305 => 'ForeignLanguage', 387 400 => 'Discrete', 388 0x10000 => 'Discrete_0', 389 0x10001 => 'Discrete_1', 390 0x10002 => 'Discrete_2', 391 0x10003 => 'Discrete_3', 392 0x10004 => 'Discrete_4', 393 0x10005 => 'Discrete_5', 394 0x10006 => 'Discrete_6', 395 0x10007 => 'Discrete_7', 396 0x10008 => 'Discrete_8', 397 0x10009 => 'Discrete_9', 398 0x1000a => 'Discrete_10', 399 0x1000b => 'Discrete_11', 400 0x1000c => 'Discrete_12', 401 0x1000d => 'Discrete_13', 402 0x1000e => 'Discrete_14', 403 0x1000f => 'Discrete_15', 404 0x1ffff => 'Discrete_65535', 405 ); 406 407 # properties which don't get inherited from the parent 408 my %dontInherit = ( 409 ispe => 1, # size of parent may be different 410 hvcC => 1, # (likely redundant) 411 ); 412 413 # tags that may be duplicated and directories that may contain duplicate tags 414 # (used only to avoid warnings when Validate-ing) 415 my %dupTagOK = ( mdat => 1, trak => 1, free => 1, infe => 1, sgpd => 1, dimg => 1, CCDT => 1, 416 sbgp => 1, csgm => 1, uuid => 1, cdsc => 1, maxr => 1, '----' => 1 ); 417 my %dupDirOK = ( ipco => 1, '----' => 1 ); 418 419 # the usual atoms required to decode timed metadata with the ExtractEmbedded option 420 my %eeStd = ( stco => 'stbl', co64 => 'stbl', stsz => 'stbl', stz2 => 'stbl', 421 stsc => 'stbl', stts => 'stbl' ); 422 423 # boxes and their containers for the various handler types that we want to save 424 # when the ExtractEmbedded is enabled (currently only the 'gps ' container name is 425 # used, but others have been checked against all available sample files and may be 426 # useful in the future if the names are used for different boxes on other locations) 427 my %eeBox = ( 428 # (note: vide is only processed if specific atoms exist in the VideoSampleDesc) 429 vide => { %eeStd, 430 JPEG => 'stsd', 431 }, 432 text => { %eeStd }, 433 meta => { %eeStd }, 434 sbtl => { %eeStd }, 435 data => { %eeStd }, 436 camm => { %eeStd }, # (Insta360) 437 ctbx => { %eeStd }, # (GM cars) 438 '' => { 'gps ' => 'moov', 'GPS ' => 'main' }, # (no handler -- in top level 'moov' box, and main) 439 ); 440 # boxes to save when ExtractEmbedded is set to 2 or higher 441 my %eeBox2 = ( 442 vide => { avcC => 'stsd' }, # (parses H264 video stream) 229 443 ); 230 444 … … 232 446 %Image::ExifTool::QuickTime::Main = ( 233 447 PROCESS_PROC => \&ProcessMOV, 448 WRITE_PROC => \&WriteQuickTime, # (only needs to be defined for directories to process when writing) 234 449 GROUPS => { 2 => 'Video' }, 235 NOTES => q{ 236 The QuickTime format is used for many different types of audio, video and 237 image files. Exiftool extracts meta information from the UserData atom 238 (including some proprietary manufacturer-specific information), as well as 239 extracting various audio, video and image parameters. Tags with a question 240 mark after their name are not extracted unless the Unknown option is set. 241 }, 242 free => { Unknown => 1, Binary => 1 }, 243 skip => { Unknown => 1, Binary => 1 }, 450 meta => { # 'meta' is found here in my Sony ILCE-7S MP4 sample - PH 451 Name => 'Meta', 452 SubDirectory => { 453 TagTable => 'Image::ExifTool::QuickTime::Meta', 454 Start => 4, # skip 4-byte version number header 455 }, 456 }, 457 meco => { #ISO14496-12:2015 458 Name => 'OtherMeta', 459 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' }, 460 }, 461 free => [ 462 { 463 Name => 'KodakFree', 464 # (found in Kodak M5370 MP4 videos) 465 Condition => '$$valPt =~ /^\0\0\0.Seri/s', 466 SubDirectory => { TagTable => 'Image::ExifTool::Kodak::Free' }, 467 },{ 468 Name => 'Pittasoft', 469 # (Pittasoft Blackview dashcam MP4 videos) 470 Condition => '$$valPt =~ /^\0\0..(cprt|sttm|ptnm|ptrh|thum|gps |3gf )/s', 471 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' }, 472 },{ 473 Unknown => 1, 474 Binary => 1, 475 }, 476 # (also Samsung WB750 uncompressed thumbnail data starting with "SDIC\0") 477 ], 478 # fre1 - 4 bytes: "june" (Kodak PixPro SP360) 479 frea => { 480 Name => 'Kodak_frea', 481 SubDirectory => { TagTable => 'Image::ExifTool::Kodak::frea' }, 482 }, 483 skip => [ 484 { 485 Name => 'CanonSkip', 486 Condition => '$$valPt =~ /^\0.{3}(CNDB|CNCV|CNMN|CNFV|CNTH|CNDM)/s', 487 SubDirectory => { TagTable => 'Image::ExifTool::Canon::Skip' }, 488 }, 489 { 490 Name => 'PreviewImage', # (found in DuDuBell M1 dashcam MOV files) 491 Groups => { 2 => 'Preview' }, 492 Condition => '$$valPt =~ /^.{12}\xff\xd8\xff/', 493 Binary => 1, 494 RawConv => q{ 495 my $len = Get32u(\$val, 8); 496 return undef unless length($val) >= $len + 12; 497 return substr($val, 12, $len); 498 }, 499 }, 500 { Name => 'Skip', Unknown => 1, Binary => 1 }, 501 ], 244 502 wide => { Unknown => 1, Binary => 1 }, 245 503 ftyp => { #MP4 … … 253 511 PICT => { 254 512 Name => 'PreviewPICT', 513 Groups => { 2 => 'Preview' }, 255 514 Binary => 1, 256 515 }, 257 516 pict => { #8 258 517 Name => 'PreviewPICT', 518 Groups => { 2 => 'Preview' }, 259 519 Binary => 1, 260 520 }, 521 # (note that moov is present for an HEIF sequence) 261 522 moov => { 262 523 Name => 'Movie', 263 524 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Movie' }, 264 525 }, 265 mdat => { Name => 'MovieData', Unknown => 1, Binary => 1 }, 526 moof => { 527 Name => 'MovieFragment', 528 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieFragment' }, 529 }, 530 # mfra - movie fragment random access: contains tfra (track fragment random access), and 531 # mfro (movie fragment random access offset) (ref 5) 532 mdat => { Name => 'MediaData', Unknown => 1, Binary => 1 }, 266 533 'mdat-size' => { 267 Name => 'M ovieDataSize',534 Name => 'MediaDataSize', 268 535 Notes => q{ 269 536 not a real tag ID, this tag represents the size of the 'mdat' data in bytes … … 271 538 }, 272 539 }, 540 'mdat-offset' => 'MediaDataOffset', 273 541 junk => { Unknown => 1, Binary => 1 }, #8 274 542 uuid => [ 275 543 { #9 (MP4 files) 276 Name => 'UUID-XMP', 544 Name => 'XMP', 545 # *** this is where ExifTool writes XMP in MP4 videos (as per XMP spec) *** 277 546 Condition => '$$valPt=~/^\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac/', 547 WriteGroup => 'XMP', # (write main XMP tags here) 278 548 SubDirectory => { 279 549 TagTable => 'Image::ExifTool::XMP::Main', … … 291 561 { #PH (Flip MP4 files) 292 562 Name => 'UUID-Flip', 293 Condition => '$$valPt=~/ \x4a\xb0\x3b\x0f\x61\x8d\x40\x75\x82\xb2\xd9\xfa\xce\xd3\x5f\xf5/',563 Condition => '$$valPt=~/^\x4a\xb0\x3b\x0f\x61\x8d\x40\x75\x82\xb2\xd9\xfa\xce\xd3\x5f\xf5/', 294 564 SubDirectory => { 295 565 TagTable => 'Image::ExifTool::QuickTime::Flip', … … 298 568 }, 299 569 # "\x98\x7f\xa3\xdf\x2a\x85\x43\xc0\x8f\x8f\xd9\x7c\x47\x1e\x8e\xea" - unknown data in Flip videos 570 { #PH (Canon CR3) 571 Name => 'UUID-Canon2', 572 WriteLast => 1, # MUST come after mdat or DPP will drop mdat when writing! 573 Condition => '$$valPt=~/^\x21\x0f\x16\x87\x91\x49\x11\xe4\x81\x11\x00\x24\x21\x31\xfc\xe4/', 574 SubDirectory => { 575 TagTable => 'Image::ExifTool::Canon::uuid2', 576 Start => 16, 577 }, 578 }, 579 { # (ref https://github.com/JamesHeinrich/getID3/blob/master/getid3/module.audio-video.quicktime.php) 580 Name => 'SensorData', # sensor data for the 360Fly 581 Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/ and $$self{OPTIONS}{ExtractEmbedded}', 582 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Tags360Fly' }, 583 }, 584 { 585 Name => 'SensorData', 586 Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/', 587 Notes => 'raw 360Fly sensor data without ExtractEmbedded option', 588 RawConv => q{ 589 $self->WarnOnce('Use the ExtractEmbedded option to decode timed SensorData',3); 590 return \$val; 591 }, 592 }, 593 { #PH (Canon CR3) 594 Name => 'PreviewImage', 595 Condition => '$$valPt=~/^\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16/', 596 Groups => { 2 => 'Preview' }, 597 # 0x00 - undef[16]: UUID 598 # 0x10 - int32u[2]: "0 1" (version and/or item count?) 599 # 0x18 - int32u: PRVW atom size 600 # 0x20 - int32u: 'PRVW' 601 # 0x30 - int32u: 0 602 # 0x34 - int16u: 1 603 # 0x36 - int16u: image width 604 # 0x38 - int16u: image height 605 # 0x3a - int16u: 1 606 # 0x3c - int32u: preview length 607 RawConv => '$val = substr($val, 0x30); $self->ValidateImage(\$val, $tag)', 608 }, 300 609 { #8 301 610 Name => 'UUID-Unknown', 302 Unknown => 1, 303 Binary => 1, 611 %unknownInfo, 304 612 }, 305 613 ], 614 _htc => { 615 Name => 'HTCInfo', 616 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HTCInfo' }, 617 }, 618 udta => { 619 Name => 'UserData', 620 SubDirectory => { TagTable => 'Image::ExifTool::FLIR::UserData' }, 621 }, 622 thum => { #PH 623 Name => 'ThumbnailImage', 624 Groups => { 2 => 'Preview' }, 625 Binary => 1, 626 }, 627 'thm ' => { #PH (70mai A800) 628 Name => 'ThumbnailImage', 629 Groups => { 2 => 'Preview' }, 630 Binary => 1, 631 }, 632 ardt => { #PH 633 Name => 'ARDroneFile', 634 ValueConv => 'length($val) > 4 ? substr($val,4) : $val', # remove length 635 }, 636 prrt => { #PH 637 Name => 'ARDroneTelemetry', 638 Notes => q{ 639 telemetry information for each video frame: status1, status2, time, pitch, 640 roll, yaw, speed, altitude 641 }, 642 ValueConv => q{ 643 my $size = length $val; 644 return \$val if $size < 12 or not $$self{OPTIONS}{Binary}; 645 my $len = Get16u(\$val, 2); 646 my $str = ''; 647 SetByteOrder('II'); 648 my $pos = 12; 649 while ($pos + $len <= $size) { 650 my $s1 = Get16u(\$val, $pos); 651 # s2: 7=take-off?, 3=moving, 4=hovering, 9=landing?, 2=landed 652 my $s2 = Get16u(\$val, $pos + 2); 653 $str .= "$s1 $s2"; 654 my $num = int(($len-4)/4); 655 my ($i, $v); 656 for ($i=0; $i<$num; ++$i) { 657 my $pt = $pos + 4 + $i * 4; 658 if ($i > 0 && $i < 4) { 659 $v = GetFloat(\$val, $pt); # pitch/roll/yaw 660 } else { 661 $v = Get32u(\$val, $pt); 662 # convert time to sec, and speed(NC)/altitude to metres 663 $v /= 1000 if $i <= 5; 664 } 665 $str .= " $v"; 666 } 667 $str .= "\n"; 668 $pos += $len; 669 } 670 SetByteOrder('MM'); 671 return \$str; 672 }, 673 }, 674 udat => { #PH (GPS NMEA-format log written by Datakam Player software) 675 Name => 'GPSLog', 676 Binary => 1, # (actually ASCII, but very lengthy) 677 }, 678 # meta - proprietary XML information written by some Flip cameras - PH 679 # beam - 16 bytes found in an iPhone video 680 IDIT => { #PH (written by DuDuBell M1, VSYS M6L dashcams) 681 Name => 'DateTimeOriginal', 682 Description => 'Date/Time Original', 683 Groups => { 2 => 'Time' }, 684 Format => 'string', # (removes trailing "\0") 685 Shift => 'Time', 686 Writable => 1, 687 Permanent => 1, 688 DelValue => '0000-00-00T00:00:00+0000', 689 ValueConv => '$val=~tr/-/:/; $val', 690 ValueConvInv => '$val=~s/(\d+):(\d+):/$1-$2-/; $val', 691 PrintConv => '$self->ConvertDateTime($val)', 692 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 693 }, 694 gps0 => { #PH (DuDuBell M1, VSYS M6L) 695 Name => 'GPSTrack', 696 SubDirectory => { 697 TagTable => 'Image::ExifTool::QuickTime::Stream', 698 ProcessProc => \&Process_gps0, 699 }, 700 }, 701 gsen => { #PH (DuDuBell M1, VSYS M6L) 702 Name => 'GSensor', 703 SubDirectory => { 704 TagTable => 'Image::ExifTool::QuickTime::Stream', 705 ProcessProc => \&Process_gsen, 706 }, 707 }, 708 # gpsa - seen hex "01 20 00 00" (DuDuBell M1, VSYS M6L) 709 # gsea - 20 bytes hex "05 00's..." (DuDuBell M1) "05 08 02 01 ..." (VSYS M6L) 710 'GPS ' => { # GPS data written by 70mai dashcam (parsed in QuickTimeStream.pl) 711 Name => 'GPSDataList2', 712 Unknown => 1, 713 Binary => 1, 714 }, 306 715 ); 307 716 … … 326 735 Format => 'undef[$size-8]', 327 736 # ignore any entry with a null, and return others as a list 328 ValueConv => 'my @a=($val=~/.{4}/sg); @a=grep(!/\0/,@a); \@a', 737 ValueConv => 'my @a=($val=~/.{4}/sg); @a=grep(!/\0/,@a); \@a', 738 }, 739 ); 740 741 # proprietary HTC atom (HTC One MP4 video) 742 %Image::ExifTool::QuickTime::HTCInfo = ( 743 PROCESS_PROC => \&ProcessMOV, 744 GROUPS => { 2 => 'Video' }, 745 NOTES => 'Tags written by some HTC camera phones.', 746 slmt => { 747 Name => 'Unknown_slmt', 748 Unknown => 1, 749 Format => 'int32u', # (observed values: 4) 329 750 }, 330 751 ); … … 351 772 # image description data block 352 773 %Image::ExifTool::QuickTime::ImageDesc = ( 353 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 774 PROCESS_PROC => \&ProcessHybrid, 775 VARS => { ID_LABEL => 'ID/Index' }, 354 776 GROUPS => { 2 => 'Image' }, 355 777 FORMAT => 'int16u', … … 385 807 # v410 => "Uncompressed Y'CbCr, 10-bit 4:4:4", 386 808 # v210 => "Uncompressed Y'CbCr, 10-bit 4:2:2", 809 # hvc1 => 'HEVC', #PH 387 810 # }, 388 811 }, … … 410 833 }, 411 834 41 => 'BitDepth', 835 # 836 # Observed offsets for child atoms of various CompressorID types: 837 # 838 # CompressorID Offset Child atoms 839 # ----------- ------ ---------------- 840 # avc1 86 avcC, btrt, colr, pasp, fiel, clap, svcC 841 # mp4v 86 esds, pasp 842 # s263 86 d263 843 # 844 btrt => { 845 Name => 'BitrateInfo', 846 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Bitrate' }, 847 }, 848 # Reference for fiel, colr, pasp, clap: 849 # https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9 850 fiel => { 851 Name => 'VideoFieldOrder', 852 ValueConv => 'join(" ", unpack("C*",$val))', 853 PrintConv => [{ 854 1 => 'Progressive', 855 2 => '2:1 Interlaced', 856 }], 857 }, 858 colr => { 859 Name => 'ColorRepresentation', 860 ValueConv => 'join(" ", substr($val,0,4), unpack("x4n*",$val))', 861 }, 862 pasp => { 863 Name => 'PixelAspectRatio', 864 ValueConv => 'join(":", unpack("N*",$val))', 865 }, 866 clap => { 867 Name => 'CleanAperture', 868 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::CleanAperture' }, 869 }, 870 avcC => { 871 # (see http://thompsonng.blogspot.ca/2010/11/mp4-file-format-part-2.html) 872 Name => 'AVCConfiguration', 873 Unknown => 1, 874 Binary => 1, 875 }, 876 JPEG => { # (found in CR3 images; used as a flag to identify JpgFromRaw 'vide' stream) 877 Name => 'JPEGInfo', 878 # (4 bytes all zero) 879 Unknown => 1, 880 Binary => 1, 881 }, 882 # hvcC - HEVC configuration 883 # svcC - 7 bytes: 00 00 00 00 ff e0 00 884 # esds - elementary stream descriptor 885 # d263 886 gama => { Name => 'Gamma', Format => 'fixed32u' }, 887 # mjqt - default quantization table for MJPEG 888 # mjht - default Huffman table for MJPEG 889 # csgm ? (seen in hevc video) 890 CMP1 => { # Canon CR3 891 Name => 'CMP1', 892 SubDirectory => { TagTable => 'Image::ExifTool::Canon::CMP1' }, 893 }, 894 CDI1 => { # Canon CR3 895 Name => 'CDI1', 896 SubDirectory => { 897 TagTable => 'Image::ExifTool::Canon::CDI1', 898 Start => 4, 899 }, 900 }, 901 # JPEG - 4 bytes all 0 (Canon CR3) 902 # free - (Canon CR3) 903 # 904 # spherical video v2 stuff (untested) 905 # 906 st3d => { 907 Name => 'Stereoscopic3D', 908 Format => 'int8u', 909 ValueConv => '$val =~ s/.* //; $val', # (remove leading version/flags bytes?) 910 PrintConv => { 911 0 => 'Monoscopic', 912 1 => 'Stereoscopic Top-Bottom', 913 2 => 'Stereoscopic Left-Right', 914 3 => 'Stereoscopic Stereo-Custom', # (provisional in spec as of 2017-10-10) 915 }, 916 }, 917 sv3d => { 918 Name => 'SphericalVideo', 919 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::sv3d' }, 920 }, 921 ); 922 923 # 'sv3d' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 924 %Image::ExifTool::QuickTime::sv3d = ( 925 PROCESS_PROC => \&ProcessMOV, 926 GROUPS => { 2 => 'Video' }, 927 NOTES => q{ 928 Tags defined by the Spherical Video V2 specification. See 929 L<https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md> 930 for the specification. 931 }, 932 svhd => { 933 Name => 'MetadataSource', 934 Format => 'undef', 935 ValueConv => '$val=~tr/\0//d; $val', # (remove version/flags? and terminator?) 936 }, 937 proj => { 938 Name => 'Projection', 939 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::proj' }, 940 }, 941 ); 942 943 # 'proj' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 944 %Image::ExifTool::QuickTime::proj = ( 945 PROCESS_PROC => \&ProcessMOV, 946 GROUPS => { 2 => 'Video' }, 947 prhd => { 948 Name => 'ProjectionHeader', 949 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::prhd' }, 950 }, 951 cbmp => { 952 Name => 'CubemapProj', 953 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::cbmp' }, 954 }, 955 equi => { 956 Name => 'EquirectangularProj', 957 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::equi' }, 958 }, 959 # mshp - MeshProjection (P.I.T.A. to decode, for not much reward, see ref) 960 ); 961 962 # 'prhd' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 963 %Image::ExifTool::QuickTime::prhd = ( 964 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 965 GROUPS => { 2 => 'Video' }, 966 FORMAT => 'fixed32s', 967 # 0 - version (high 8 bits) / flags (low 24 bits) 968 1 => 'PoseYawDegrees', 969 2 => 'PosePitchDegrees', 970 3 => 'PoseRollDegrees', 971 ); 972 973 # 'cbmp' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 974 %Image::ExifTool::QuickTime::cbmp = ( 975 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 976 GROUPS => { 2 => 'Video' }, 977 FORMAT => 'int32u', 978 # 0 - version (high 8 bits) / flags (low 24 bits) 979 1 => 'Layout', 980 2 => 'Padding', 981 ); 982 983 # 'equi' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 984 %Image::ExifTool::QuickTime::equi = ( 985 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 986 GROUPS => { 2 => 'Video' }, 987 FORMAT => 'int32u', # (actually 0.32 fixed point) 988 # 0 - version (high 8 bits) / flags (low 24 bits) 989 1 => { Name => 'ProjectionBoundsTop', ValueConv => '$val / 4294967296' }, 990 2 => { Name => 'ProjectionBoundsBottom',ValueConv => '$val / 4294967296' }, 991 3 => { Name => 'ProjectionBoundsLeft', ValueConv => '$val / 4294967296' }, 992 4 => { Name => 'ProjectionBoundsRight', ValueConv => '$val / 4294967296' }, 993 ); 994 995 # 'btrt' atom information (ref http://lists.freedesktop.org/archives/gstreamer-commits/2011-October/054459.html) 996 %Image::ExifTool::QuickTime::Bitrate = ( 997 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 998 GROUPS => { 2 => 'Video' }, 999 FORMAT => 'int32u', 1000 PRIORITY => 0, # often filled with zeros 1001 0 => 'BufferSize', 1002 1 => 'MaxBitrate', 1003 2 => 'AverageBitrate', 1004 ); 1005 1006 # 'clap' atom information (ref https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9) 1007 %Image::ExifTool::QuickTime::CleanAperture = ( 1008 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1009 GROUPS => { 2 => 'Video' }, 1010 FORMAT => 'rational64s', 1011 0 => 'CleanApertureWidth', 1012 1 => 'CleanApertureHeight', 1013 2 => 'CleanApertureOffsetX', 1014 3 => 'CleanApertureOffsetY', 412 1015 ); 413 1016 … … 415 1018 %Image::ExifTool::QuickTime::Preview = ( 416 1019 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1020 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1021 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 417 1022 GROUPS => { 2 => 'Image' }, 418 1023 FORMAT => 'int16u', … … 434 1039 %Image::ExifTool::QuickTime::Movie = ( 435 1040 PROCESS_PROC => \&ProcessMOV, 1041 WRITE_PROC => \&WriteQuickTime, 436 1042 GROUPS => { 2 => 'Video' }, 437 1043 mvhd => { … … 441 1047 trak => { 442 1048 Name => 'Track', 1049 CanCreate => 0, # don't create this atom 443 1050 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' }, 444 1051 }, … … 464 1071 }, 465 1072 }, 1073 { #PH (Canon SX280) 1074 Name => 'UUID-Canon', 1075 Condition => '$$valPt=~/^\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48/', 1076 SubDirectory => { 1077 TagTable => 'Image::ExifTool::Canon::uuid', 1078 Start => 16, 1079 }, 1080 }, 466 1081 { 467 1082 Name => 'UUID-Unknown', 468 Unknown => 1, 469 Binary => 1, 1083 %unknownInfo, 470 1084 }, 471 1085 ], 1086 cmov => { 1087 Name => 'CompressedMovie', 1088 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::CMovie' }, 1089 }, 1090 htka => { # (written by HTC One M8 in slow-motion 1280x720 video - PH) 1091 Name => 'HTCTrack', 1092 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' }, 1093 }, 1094 'gps ' => { # GPS data written by Novatek cameras (parsed in QuickTimeStream.pl) 1095 Name => 'GPSDataList', 1096 Unknown => 1, 1097 Binary => 1, 1098 }, 1099 meco => { #ISO14496-12:2015 1100 Name => 'OtherMeta', 1101 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' }, 1102 }, 472 1103 # prfl - Profile (ref 12) 473 1104 # clip - clipping --> contains crgn (clip region) (ref 12) 474 1105 # mvex - movie extends --> contains mehd (movie extends header), trex (track extends) (ref 14) 1106 # ICAT - 4 bytes: "6350" (Nikon CoolPix S6900), "6500" (Panasonic FT7) 1107 ); 1108 1109 # (ref CFFMediaFormat-2_1.pdf) 1110 %Image::ExifTool::QuickTime::MovieFragment = ( 1111 PROCESS_PROC => \&ProcessMOV, 1112 WRITE_PROC => \&WriteQuickTime, 1113 GROUPS => { 2 => 'Video' }, 1114 mfhd => { 1115 Name => 'MovieFragmentHeader', 1116 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieFragHdr' }, 1117 }, 1118 traf => { 1119 Name => 'TrackFragment', 1120 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackFragment' }, 1121 }, 1122 meta => { #ISO14496-12:2015 1123 Name => 'Meta', 1124 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 1125 }, 1126 ); 1127 1128 # (ref CFFMediaFormat-2_1.pdf) 1129 %Image::ExifTool::QuickTime::MovieFragHdr = ( 1130 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1131 GROUPS => { 2 => 'Video' }, 1132 FORMAT => 'int32u', 1133 1 => 'MovieFragmentSequence', 1134 ); 1135 1136 # (ref CFFMediaFormat-2_1.pdf) 1137 %Image::ExifTool::QuickTime::TrackFragment = ( 1138 PROCESS_PROC => \&ProcessMOV, 1139 WRITE_PROC => \&WriteQuickTime, 1140 GROUPS => { 2 => 'Video' }, 1141 meta => { #ISO14496-12:2015 1142 Name => 'Meta', 1143 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 1144 }, 1145 # tfhd - track fragment header 1146 # edts - edits --> contains elst (edit list) (ref PH) 1147 # tfdt - track fragment base media decode time 1148 # trik - trick play box 1149 # trun - track fragment run box 1150 # avcn - AVC NAL unit storage box 1151 # secn - sample encryption box 1152 # saio - sample auxiliary information offsets box 1153 # sbgp - sample to group box 1154 # sgpd - sample group description box 1155 # sdtp - independent and disposable samples (ref 5) 1156 # subs - sub-sample information (ref 5) 475 1157 ); 476 1158 … … 478 1160 %Image::ExifTool::QuickTime::MovieHeader = ( 479 1161 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1162 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1163 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 480 1164 GROUPS => { 2 => 'Video' }, 481 1165 FORMAT => 'int32u', 1166 DATAMEMBER => [ 0, 1, 2, 3, 4 ], 482 1167 0 => { 483 1168 Name => 'MovieHeaderVersion', … … 541 1226 %Image::ExifTool::QuickTime::Track = ( 542 1227 PROCESS_PROC => \&ProcessMOV, 543 GROUPS => { 2 => 'Video' }, 1228 WRITE_PROC => \&WriteQuickTime, 1229 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 544 1230 tkhd => { 545 1231 Name => 'TrackHeader', … … 561 1247 Name => 'TrackRef', 562 1248 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackRef' }, 1249 }, 1250 tapt => { 1251 Name => 'TrackAperture', 1252 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackAperture' }, 563 1253 }, 564 1254 uuid => [ … … 571 1261 }, 572 1262 }, 1263 { #https://github.com/google/spatial-media/blob/master/docs/spherical-video-rfc.md 1264 Name => 'SphericalVideoXML', 1265 Condition => '$$valPt=~/^\xff\xcc\x82\x63\xf8\x55\x4a\x93\x88\x14\x58\x7a\x02\x52\x1f\xdd/', 1266 WriteGroup => 'GSpherical', # write only GSpherical XMP tags here 1267 HandlerType => 'vide', # only write in video tracks 1268 SubDirectory => { 1269 TagTable => 'Image::ExifTool::XMP::Main', 1270 Start => 16, 1271 WriteProc => 'Image::ExifTool::XMP::WriteGSpherical', 1272 }, 1273 }, 573 1274 { 574 1275 Name => 'UUID-Unknown', 575 Unknown => 1, 576 Binary => 1, 1276 %unknownInfo, 577 1277 }, 578 1278 ], 1279 meco => { #ISO14492-12:2015 pg 83 1280 Name => 'OtherMeta', 1281 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' }, 1282 }, 579 1283 # edts - edits --> contains elst (edit list) 580 # tapt - TrackApertureModeDimensionsAID --> contains clef (TrackCleanApertureDimensionsAID),581 # prof (TrackProductionApertureDimensionsAID), enof (TrackEncodedPixelsDimensionsAID)582 1284 # clip - clipping --> contains crgn (clip region) 583 1285 # matt - track matt --> contains kmat (compressed matt) … … 590 1292 %Image::ExifTool::QuickTime::TrackHeader = ( 591 1293 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1294 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1295 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 592 1296 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 593 1297 FORMAT => 'int32u', 1298 DATAMEMBER => [ 0, 1, 2, 5, 7 ], 594 1299 0 => { 595 1300 Name => 'TrackHeaderVersion', … … 625 1330 Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4', 626 1331 }, 1332 7 => { # (used only for writing MatrixStructure) 1333 Name => 'ImageSizeLookahead', 1334 Hidden => 1, 1335 Format => 'int32u[14]', 1336 RawConv => '$$self{ImageSizeLookahead} = $val; undef', 1337 }, 627 1338 8 => { 628 1339 Name => 'TrackLayer', … … 640 1351 Name => 'MatrixStructure', 641 1352 Format => 'fixed32s[9]', 1353 Notes => 'writable for the video track via the Composite Rotation tag', 1354 Writable => 1, 1355 Protected => 1, 1356 Permanent => 1, 1357 # only set rotation if image size is non-zero 1358 RawConvInv => \&GetMatrixStructure, 642 1359 # (the right column is fixed 2.30 instead of 16.16) 643 1360 ValueConv => q{ … … 646 1363 return "@a"; 647 1364 }, 1365 ValueConvInv => q{ 1366 my @a = split ' ',$val; 1367 $_ *= 0x4000 foreach @a[2,5,8]; 1368 return "@a"; 1369 }, 648 1370 }, 649 1371 19 => { … … 662 1384 %Image::ExifTool::QuickTime::UserData = ( 663 1385 PROCESS_PROC => \&ProcessMOV, 664 GROUPS => { 2 => 'Video' }, 1386 WRITE_PROC => \&WriteQuickTime, 1387 CHECK_PROC => \&CheckQTValue, 1388 GROUPS => { 1 => 'UserData', 2 => 'Video' }, 1389 WRITABLE => 1, 1390 PREFERRED => 1, # (preferred over Keys tags when writing) 1391 FORMAT => 'string', 1392 WRITE_GROUP => 'UserData', 1393 LANG_INFO => \&GetLangInfo, 665 1394 NOTES => q{ 666 1395 Tag ID's beginning with the copyright symbol (hex 0xa9) are multi-language 667 text. Alternate language tags are accessed by adding a dash followed by the 668 language/country code to the tag name. ExifTool will extract any 669 multi-language user data tags found, even if they don't exist in this table. 1396 text. Alternate language tags are accessed by adding a dash followed by a 1397 3-character ISO 639-2 language code to the tag name. ExifTool will extract 1398 any multi-language user data tags found, even if they aren't in this table. 1399 Note when creating new tags, 1400 L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags are 1401 preferred over these, so to create the tag when a same-named ItemList tag 1402 exists, either "UserData" must be specified (eg. C<-UserData:Artist=Monet> 1403 on the command line), or the PREFERRED level must be changed via 1404 L<the config file|../config.html#PREF>. 670 1405 }, 671 1406 "\xa9cpy" => { Name => 'Copyright', Groups => { 2 => 'Author' } }, 672 1407 "\xa9day" => { 673 Name => 'C reateDate',1408 Name => 'ContentCreateDate', 674 1409 Groups => { 2 => 'Time' }, 1410 Shift => 'Time', 675 1411 # handle values in the form "2010-02-12T13:27:14-0800" (written by Apple iPhone) 676 1412 ValueConv => q{ … … 680 1416 return $val; 681 1417 }, 1418 ValueConvInv => q{ 1419 require Image::ExifTool::XMP; 1420 my $tmp = Image::ExifTool::XMP::FormatXMPDate($val); 1421 ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon 1422 return $val; 1423 }, 682 1424 PrintConv => '$self->ConvertDateTime($val)', 1425 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 683 1426 }, 684 1427 "\xa9ART" => 'Artist', #PH (iTunes 8.0.2) … … 717 1460 "\xa9prk" => 'PerformerKeywords', #12 718 1461 "\xa9prl" => 'PerformerURL', 719 "\xa9dir" => 'Director', #12720 1462 "\xa9req" => 'Requirements', 721 1463 "\xa9snk" => 'SubtitleKeywords', #12 … … 727 1469 "\xa9too" => 'Encoder', #PH (NC) 728 1470 "\xa9trk" => 'Track', #PH (NC) 729 "\xa9wrt" => 'Composer',1471 "\xa9wrt" => { Name => 'Composer', Avoid => 1 }, # ("\xa9com" is preferred in UserData) 730 1472 "\xa9xyz" => { #PH (iPhone 3GS) 731 1473 Name => 'GPSCoordinates', 732 1474 Groups => { 2 => 'Location' }, 733 1475 ValueConv => \&ConvertISO6709, 1476 ValueConvInv => \&ConvInvISO6709, 734 1477 PrintConv => \&PrintGPSCoordinates, 735 }, 1478 PrintConvInv => \&PrintInvGPSCoordinates, 1479 }, 1480 # \xa9 tags written by DJI Phantom 3: (ref PH) 1481 "\xa9xsp" => 'SpeedX', #PH (guess) 1482 "\xa9ysp" => 'SpeedY', #PH (guess) 1483 "\xa9zsp" => 'SpeedZ', #PH (guess) 1484 "\xa9fpt" => 'Pitch', #PH 1485 "\xa9fyw" => 'Yaw', #PH 1486 "\xa9frl" => 'Roll', #PH 1487 "\xa9gpt" => 'CameraPitch', #PH 1488 "\xa9gyw" => 'CameraYaw', #PH 1489 "\xa9grl" => 'CameraRoll', #PH 1490 "\xa9enc" => 'EncoderID', #PH (forum9271) 1491 # and the following entries don't have the proper 4-byte header for \xa9 tags: 1492 "\xa9dji" => { Name => 'UserData_dji', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 }, 1493 "\xa9res" => { Name => 'UserData_res', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 }, 1494 "\xa9uid" => { Name => 'UserData_uid', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 }, 1495 "\xa9mdl" => { 1496 Name => 'Model', 1497 Notes => 'non-standard-format DJI tag', 1498 Format => 'string', 1499 Avoid => 1, 1500 }, 1501 # end DJI tags 736 1502 name => 'Name', 737 1503 WLOC => { … … 762 1528 }, 763 1529 }, 764 DcMD => {765 Name => 'DcMD',766 SubDirectory => {767 TagTable => 'Image::ExifTool::QuickTime::DcMD',768 },769 },770 1530 'ptv '=> { 771 1531 Name => 'PrintToVideo', 772 1532 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Video' }, 773 1533 }, 774 'hnti'=> {1534 hnti => { 775 1535 Name => 'HintInfo', 776 1536 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintInfo' }, 777 1537 }, 778 'hinf'=> {1538 hinf => { 779 1539 Name => 'HintTrackInfo', 780 1540 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintTrackInfo' }, 781 1541 }, 1542 hinv => 'HintVersion', #PH (guess) 1543 XMP_ => { #PH (Adobe CS3 Bridge) 1544 Name => 'XMP', 1545 WriteGroup => 'XMP', # (write main tags here) 1546 # *** this is where ExifTool writes XMP in MOV videos (as per XMP spec) *** 1547 SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' }, 1548 }, 1549 # the following are 3gp tags, references: 1550 # http://atomicparsley.sourceforge.net 1551 # http://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/TSGS4_25/Docs/ 1552 # (note that all %langText3gp tags are Avoid => 1) 1553 cprt => { Name => 'Copyright', %langText3gp, Groups => { 2 => 'Author' } }, 1554 auth => { Name => 'Author', %langText3gp, Groups => { 2 => 'Author' } }, 1555 titl => { Name => 'Title', %langText3gp }, 1556 dscp => { Name => 'Description',%langText3gp }, 1557 perf => { Name => 'Performer', %langText3gp }, 1558 gnre => { Name => 'Genre', %langText3gp }, 1559 albm => { Name => 'Album', %langText3gp }, 1560 coll => { Name => 'CollectionName', %langText3gp }, #17 1561 rtng => { 1562 Name => 'Rating', 1563 # (4-byte flags, 4-char entity, 4-char criteria, 2-byte lang, string) 1564 RawConv => q{ 1565 return '<err>' unless length $val >= 14; 1566 my $str = 'Entity=' . substr($val,4,4) . ' Criteria=' . substr($val,8,4); 1567 $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters 1568 my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 12)); 1569 $lang = $lang ? "($lang) " : ''; 1570 $val = substr($val, 14); 1571 $val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/; 1572 return $lang . $str . ' ' . $val; 1573 }, 1574 }, 1575 clsf => { 1576 Name => 'Classification', 1577 # (4-byte flags, 4-char entity, 2-byte index, 2-byte lang, string) 1578 RawConv => q{ 1579 return '<err>' unless length $val >= 12; 1580 my $str = 'Entity=' . substr($val,4,4) . ' Index=' . Get16u(\$val,8); 1581 $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters 1582 my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 10)); 1583 $lang = $lang ? "($lang) " : ''; 1584 $val = substr($val, 12); 1585 $val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/; 1586 return $lang . $str . ' ' . $val; 1587 }, 1588 }, 1589 kywd => { 1590 Name => 'Keywords', 1591 # (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings, ref 17) 1592 # (but I have also seen a simple string written by iPhone) 1593 RawConv => q{ 1594 my $sep = $self->Options('ListSep'); 1595 return join($sep, split /\0+/, $val) unless $val =~ /^\0/; # (iPhone) 1596 return '<err>' unless length $val >= 7; 1597 my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4)); 1598 $lang = $lang ? "($lang) " : ''; 1599 my $num = Get8u(\$val, 6); 1600 my ($i, @vals); 1601 my $pos = 7; 1602 for ($i=0; $i<$num; ++$i) { 1603 last if $pos >= length $val; 1604 my $len = Get8u(\$val, $pos++); 1605 last if $pos + $len > length $val; 1606 my $v = substr($val, $pos, $len); 1607 $v = $self->Decode($v, 'UCS2') if $v =~ /^\xfe\xff/; 1608 push @vals, $v; 1609 $pos += $len; 1610 } 1611 return $lang . join($sep, @vals); 1612 }, 1613 }, 1614 loci => { 1615 Name => 'LocationInformation', 1616 Groups => { 2 => 'Location' }, 1617 # (4-byte flags, 2-byte lang, location string, 1-byte role, 4-byte fixed longitude, 1618 # 4-byte fixed latitude, 4-byte fixed altitude, body string, notes string) 1619 RawConv => q{ 1620 return '<err>' unless length $val >= 6; 1621 my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4)); 1622 $lang = $lang ? "($lang) " : ''; 1623 $val = substr($val, 6); 1624 my $str; 1625 if ($val =~ /^\xfe\xff/) { 1626 $val =~ s/^(\xfe\xff(.{2})*?)\0\0//s or return '<err>'; 1627 $str = $self->Decode($1, 'UCS2'); 1628 } else { 1629 $val =~ s/^(.*?)\0//s or return '<err>'; 1630 $str = $1; 1631 } 1632 $str = '(none)' unless length $str; 1633 return '<err>' if length $val < 13; 1634 my $role = Get8u(\$val, 0); 1635 my $lon = GetFixed32s(\$val, 1); 1636 my $lat = GetFixed32s(\$val, 5); 1637 my $alt = GetFixed32s(\$val, 9); 1638 my $roleStr = {0=>'shooting',1=>'real',2=>'fictional',3=>'reserved'}->{$role}; 1639 $str .= ' Role=' . ($roleStr || "unknown($role)"); 1640 $str .= sprintf(' Lat=%.5f Lon=%.5f Alt=%.2f', $lat, $lon, $alt); 1641 $val = substr($val, 13); 1642 if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) { 1643 $str .= ' Body=' . $self->Decode($1, 'UCS2'); 1644 } elsif ($val =~ s/^(.*?)\0//s) { 1645 $str .= " Body=$1"; 1646 } 1647 if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) { 1648 $str .= ' Notes=' . $self->Decode($1, 'UCS2'); 1649 } elsif ($val =~ s/^(.*?)\0//s) { 1650 $str .= " Notes=$1"; 1651 } 1652 return $lang . $str; 1653 }, 1654 }, 1655 yrrc => { 1656 Name => 'Year', 1657 Groups => { 2 => 'Time' }, 1658 RawConv => 'length($val) >= 6 ? Get16u(\$val,4) : "<err>"', 1659 }, 1660 urat => { #17 1661 Name => 'UserRating', 1662 RawConv => q{ 1663 return '<err>' unless length $val >= 8; 1664 return Get8u(\$val, 7); 1665 }, 1666 }, 1667 # tsel - TrackSelection (ref 17) 1668 # Apple tags (ref 16[dead] -- see ref 25 instead) 1669 angl => { Name => 'CameraAngle', Format => 'string' }, # (NC) 1670 clfn => { Name => 'ClipFileName', Format => 'string' }, # (NC) 1671 clid => { Name => 'ClipID', Format => 'string' }, # (NC) 1672 cmid => { Name => 'CameraID', Format => 'string' }, # (NC) 1673 cmnm => { # (NC) 1674 Name => 'Model', 1675 Description => 'Camera Model Name', 1676 Avoid => 1, 1677 Format => 'string', # (necessary to remove the trailing NULL) 1678 }, 1679 date => { 1680 Name => 'DateTimeOriginal', 1681 Description => 'Date/Time Original', 1682 Groups => { 2 => 'Time' }, 1683 Notes => q{ 1684 Apple Photos has been reported to show a crazy date/time for some MP4 files 1685 containing this tag, but perhaps only if it is missing a time zone 1686 }, #forum10690/11125 1687 Shift => 'Time', 1688 ValueConv => q{ 1689 require Image::ExifTool::XMP; 1690 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 1691 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 1692 return $val; 1693 }, 1694 ValueConvInv => q{ 1695 require Image::ExifTool::XMP; 1696 $val = Image::ExifTool::XMP::FormatXMPDate($val); 1697 $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon 1698 return $val; 1699 }, 1700 PrintConv => '$self->ConvertDateTime($val)', 1701 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 1702 }, 1703 manu => { # (SX280) 1704 Name => 'Make', 1705 Avoid => 1, 1706 # (with Canon there are 6 unknown bytes before the model: "\0\0\0\0\x15\xc7") 1707 RawConv => '$val=~s/^\0{4}..//s; $val=~s/\0.*//; $val', 1708 }, 1709 modl => { # (Samsung GT-S8530, Canon SX280) 1710 Name => 'Model', 1711 Description => 'Camera Model Name', 1712 Avoid => 1, 1713 # (with Canon there are 6 unknown bytes before the model: "\0\0\0\0\x15\xc7") 1714 RawConv => '$val=~s/^\0{4}..//s; $val=~s/\0.*//; $val', 1715 }, 1716 reel => { Name => 'ReelName', Format => 'string' }, # (NC) 1717 scen => { Name => 'Scene', Format => 'string' }, # (NC) 1718 shot => { Name => 'ShotName', Format => 'string' }, # (NC) 1719 slno => { Name => 'SerialNumber', Format => 'string' }, # (NC) 1720 apmd => { Name => 'ApertureMode', Format => 'undef' }, #20 1721 kgtt => { #http://lists.ffmpeg.org/pipermail/ffmpeg-devel-irc/2012-June/000707.html 1722 # 'TrackType' will expand to 'Track#Type' when found inside a track 1723 Name => 'TrackType', 1724 # set flag to process this as international text 1725 # even though the tag ID doesn't start with 0xa9 1726 IText => 4, # IText with 4-byte header 1727 }, 1728 chpl => { # (Nero chapter list) 1729 Name => 'ChapterList', 1730 ValueConv => \&ConvertChapterList, 1731 PrintConv => \&PrintChapter, 1732 }, 1733 # ndrm - 7 bytes (0 0 0 1 0 0 0) Nero Digital Rights Management? (PH) 1734 # other non-Apple tags (ref 16) 1735 # hpix - HipixRichPicture (ref 16, HIPIX) 1736 # strk - sub-track information (ref 16, ISO) 1737 # 1738 # Manufacturer-specific metadata 1739 # 782 1740 TAGS => [ #PH 783 1741 # these tags were initially discovered in a Pentax movie, 784 1742 # but similar information is found in videos from other manufacturers 1743 { 1744 Name => 'FujiFilmTags', 1745 Condition => '$$valPt =~ /^FUJIFILM DIGITAL CAMERA\0/', 1746 SubDirectory => { 1747 TagTable => 'Image::ExifTool::FujiFilm::MOV', 1748 ByteOrder => 'LittleEndian', 1749 }, 1750 }, 785 1751 { 786 1752 Name => 'KodakTags', … … 837 1803 TagTable => 'Image::ExifTool::Olympus::MP4', 838 1804 ByteOrder => 'LittleEndian', 1805 }, 1806 }, 1807 { 1808 Name => 'OlympusTags4', 1809 Condition => '$$valPt =~ /^.{16}OLYM\0/s', 1810 SubDirectory => { 1811 TagTable => 'Image::ExifTool::Olympus::MOV3', 1812 Start => 12, 839 1813 }, 840 1814 }, … … 883 1857 }, 884 1858 ], 885 NCDT => { #PH 886 Name => 'NikonNCDT', 887 SubDirectory => { 888 TagTable => 'Image::ExifTool::Nikon::NCDT', 889 ProcessProc => \&ProcessMOV, 890 }, 891 }, 1859 # ---- Canon ---- 1860 CNCV => { Name => 'CompressorVersion', Format => 'string' }, #PH (5D Mark II) 1861 CNMN => { 1862 Name => 'Model', #PH (EOS 550D) 1863 Description => 'Camera Model Name', 1864 Avoid => 1, 1865 Format => 'string', # (necessary to remove the trailing NULL) 1866 }, 1867 CNFV => { Name => 'FirmwareVersion', Format => 'string' }, #PH (EOS 550D) 1868 CNTH => { #PH (PowerShot S95) 1869 Name => 'CanonCNTH', 1870 SubDirectory => { TagTable => 'Image::ExifTool::Canon::CNTH' }, 1871 }, 1872 CNOP => { #PH (7DmkII) 1873 Name => 'CanonCNOP', 1874 SubDirectory => { TagTable => 'Image::ExifTool::Canon::CNOP' }, 1875 }, 1876 # CNDB - 2112 bytes (550D) 1877 # CNDM - 4 bytes - 0xff,0xd8,0xff,0xd9 (S95) 1878 # CNDG - 10232 bytes, mostly zeros (N100) 1879 # ---- Casio ---- 892 1880 QVMI => { #PH 893 1881 Name => 'CasioQVMI', 894 # Casio stores standard EXIF-format information in MOV videos ( ie. EX-S880)1882 # Casio stores standard EXIF-format information in MOV videos (eg. EX-S880) 895 1883 SubDirectory => { 896 1884 TagTable => 'Image::ExifTool::Exif::Main', 1885 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 897 1886 DirName => 'IFD0', 898 1887 Multi => 0, # (no NextIFD pointer) … … 901 1890 }, 902 1891 }, 903 MMA0 => { #PH (DiMage 7Hi) 904 Name => 'MinoltaMMA0', 905 SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' }, 906 }, 907 MMA1 => { #PH (Dimage A2) 908 Name => 'MinoltaMMA1', 909 SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' }, 910 }, 911 XMP_ => { #PH (Adobe CS3 Bridge) 912 Name => 'XMP', 913 SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' }, 914 }, 915 vndr => 'Vendor', #PH (Samsung PL70) 916 SDLN => 'PlayMode', #PH (NC, Samsung ST80 "SEQ_PLAY") 917 # Canon tags 918 CNCV => 'CompressorVersion', #PH (5D Mark II) 919 CNMN => 'Model', #PH (EOS 550D) 920 CNFV => 'FirmwareVersion', #PH (EOS 550D) 921 CNTH => { #PH (PowerShot S95) 922 Name => 'CanonCNTH', 923 SubDirectory => { 924 TagTable => 'Image::ExifTool::Canon::CNTH', 925 ProcessProc => \&ProcessMOV, 926 }, 927 }, 928 # CNDB - 2112 bytes (550D) 929 # CNDM - 4 bytes - 0xff,0xd8,0xff,0xd9 (S95) 930 INFO => { 931 Name => 'SamsungINFO', 932 SubDirectory => { TagTable => 'Image::ExifTool::Samsung::INFO' }, 933 }, 1892 # ---- FujiFilm ---- 934 1893 FFMV => { #PH (FinePix HS20EXR) 935 1894 Name => 'FujiFilmFFMV', … … 940 1899 SubDirectory => { 941 1900 TagTable => 'Image::ExifTool::Exif::Main', 1901 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 942 1902 DirName => 'IFD0', 943 1903 Start => 16, … … 946 1906 }, 947 1907 }, 1908 # ---- Garmin ---- (ref PH) 1909 uuid => [{ 1910 Name => 'GarminSoftware', # (NC) 1911 Condition => '$$valPt =~ /^VIRBactioncamera/', 1912 RawConv => 'substr($val, 16)', 1913 RawConvInv => '"VIRBactioncamera$val"', 1914 },{ 1915 # have seen "28 f3 11 e2 b7 91 4f 6f 94 e2 4f 5d ea cb 3c 01" for RicohThetaZ1 accelerometer RADT data (not yet decoded) 1916 Name => 'UUID-Unknown', 1917 Writable => 0, 1918 %unknownInfo, 1919 }], 1920 pmcc => { 1921 Name => 'GarminSettings', 1922 ValueConv => 'substr($val, 4)', 1923 ValueConvInv => '"\0\0\0\x01$val"', 1924 }, 1925 # hmtp - "\0\0\0\x01" followed by 408 bytes of zero 1926 # vrin - "\0\0\0\x01" followed by 8 bytes of zero 1927 # ---- GoPro ---- (ref PH) 1928 GoPr => 'GoProType', # (Hero3+) 1929 FIRM => { Name => 'FirmwareVersion', Avoid => 1 }, # (Hero4) 1930 LENS => 'LensSerialNumber', # (Hero4) 1931 CAME => { # (Hero4) 1932 Name => 'SerialNumberHash', 1933 Description => 'Camera Serial Number Hash', 1934 ValueConv => 'unpack("H*",$val)', 1935 ValueConvInv => 'pack("H*",$val)', 1936 }, 1937 # SETT? 12 bytes (Hero4) 1938 # MUID? 32 bytes (Hero4, starts with serial number hash) 1939 # HMMT? 404 bytes (Hero4, all zero) 1940 # BCID? 26 bytes (Hero5, all zero), 36 bytes GoPro Max 1941 # GUMI? 16 bytes (Hero5) 1942 "FOV\0" => 'FieldOfView', #forum8938 (Hero2) seen: "Wide" 1943 GPMF => { 1944 Name => 'GoProGPMF', 1945 SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' }, 1946 }, 1947 # free (all zero) 1948 "\xa9TSC" => 'StartTimeScale', # (Hero6) 1949 "\xa9TSZ" => 'StartTimeSampleSize', # (Hero6) 1950 "\xa9TIM" => 'StartTimecode', #PH (NC) 1951 # --- HTC ---- 1952 htcb => { 1953 Name => 'HTCBinary', 1954 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HTCBinary' }, 1955 }, 1956 # ---- Kodak ---- 1957 DcMD => { 1958 Name => 'KodakDcMD', 1959 SubDirectory => { TagTable => 'Image::ExifTool::Kodak::DcMD' }, 1960 }, 1961 SNum => { Name => 'SerialNumber', Avoid => 1, Groups => { 2 => 'Camera' } }, 1962 ptch => { Name => 'Pitch', Format => 'rational64s', Avoid => 1 }, # Units?? 1963 _yaw => { Name => 'Yaw', Format => 'rational64s', Avoid => 1 }, # Units?? 1964 roll => { Name => 'Roll', Format => 'rational64s', Avoid => 1 }, # Units?? 1965 _cx_ => { Name => 'CX', Format => 'rational64s', Unknown => 1 }, 1966 _cy_ => { Name => 'CY', Format => 'rational64s', Unknown => 1 }, 1967 rads => { Name => 'Rads', Format => 'rational64s', Unknown => 1 }, 1968 lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess) 1969 Lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess) 1970 pose => { Name => 'pose', SubDirectory => { TagTable => 'Image::ExifTool::Kodak::pose' } }, 1971 # AMBA => Ambarella AVC atom (unknown data written by Kodak Playsport video cam) 1972 # tmlp - 1 byte: 0 (PixPro SP360/4KVR360) 1973 # pivi - 72 bytes (PixPro SP360) 1974 # pive - 12 bytes (PixPro SP360) 1975 # loop - 4 bytes: 0 0 0 0 (PixPro 4KVR360) 1976 # m cm - 2 bytes: 0 0 (PixPro 4KVR360) 1977 # m ev - 2 bytes: 0 0 (PixPro SP360/4KVR360) (exposure comp?) 1978 # m vr - 2 bytes: 0 1 (PixPro 4KVR360) (virtual reality?) 1979 # m wb - 4 bytes: 0 0 0 0 (PixPro SP360/4KVR360) (white balance?) 1980 # mclr - 4 bytes: 0 0 0 0 (PixPro SP360/4KVR360) 1981 # mmtr - 4 bytes: 0,6 0 0 0 (PixPro SP360/4KVR360) 1982 # mflr - 4 bytes: 0 0 0 0 (PixPro SP360) 1983 # lvlm - 24 bytes (PixPro SP360) 1984 # Lvlm - 24 bytes (PixPro 4KVR360) 1985 # ufdm - 4 bytes: 0 0 0 1 (PixPro SP360) 1986 # mtdt - 1 byte: 0 (PixPro SP360/4KVR360) 1987 # gdta - 75240 bytes (PixPro SP360) 1988 # EIS1 - 4 bytes: 03 07 00 00 (PixPro 4KVR360) 1989 # EIS2 - 4 bytes: 04 97 00 00 (PixPro 4KVR360) 1990 # ---- LG ---- 1991 adzc => { Name => 'Unknown_adzc', Unknown => 1, Hidden => 1, %langText }, # "false\0/","true\0/" 1992 adze => { Name => 'Unknown_adze', Unknown => 1, Hidden => 1, %langText }, # "false\0/" 1993 adzm => { Name => 'Unknown_adzm', Unknown => 1, Hidden => 1, %langText }, # "\x0e\x04/","\x10\x06" 1994 # ---- Microsoft ---- 1995 Xtra => { #PH (microsoft) 1996 Name => 'MicrosoftXtra', 1997 SubDirectory => { TagTable => 'Image::ExifTool::Microsoft::Xtra' }, 1998 }, 1999 # ---- Minolta ---- 2000 MMA0 => { #PH (DiMage 7Hi) 2001 Name => 'MinoltaMMA0', 2002 SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' }, 2003 }, 2004 MMA1 => { #PH (Dimage A2) 2005 Name => 'MinoltaMMA1', 2006 SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' }, 2007 }, 2008 # ---- Nikon ---- 2009 NCDT => { #PH 2010 Name => 'NikonNCDT', 2011 SubDirectory => { TagTable => 'Image::ExifTool::Nikon::NCDT' }, 2012 }, 2013 # ---- Olympus ---- 2014 scrn => { #PH (TG-810) 2015 Name => 'OlympusPreview', 2016 Condition => '$$valPt =~ /^.{4}\xff\xd8\xff\xdb/s', 2017 SubDirectory => { TagTable => 'Image::ExifTool::Olympus::scrn' }, 2018 }, 2019 # ---- Panasonic/Leica ---- 2020 PANA => { #PH 2021 Name => 'PanasonicPANA', 2022 SubDirectory => { TagTable => 'Image::ExifTool::Panasonic::PANA' }, 2023 }, 2024 LEIC => { #PH 2025 Name => 'LeicaLEIC', 2026 SubDirectory => { TagTable => 'Image::ExifTool::Panasonic::PANA' }, 2027 }, 2028 # ---- Pentax ---- 2029 thmb => [ # (apparently defined by 3gpp, ref 16) 2030 { #PH (Pentax Q) 2031 Name => 'MakerNotePentax5a', 2032 Condition => '$$valPt =~ /^PENTAX \0II/', 2033 SubDirectory => { 2034 TagTable => 'Image::ExifTool::Pentax::Main', 2035 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 2036 Start => 10, 2037 Base => '$start - 10', 2038 ByteOrder => 'LittleEndian', 2039 }, 2040 },{ #PH (TG-810) 2041 Name => 'OlympusThumbnail', 2042 Condition => '$$valPt =~ /^.{4}\xff\xd8\xff\xdb/s', 2043 SubDirectory => { TagTable => 'Image::ExifTool::Olympus::thmb' }, 2044 },{ #17 (format is in bytes 3-7) 2045 Name => 'ThumbnailImage', 2046 Condition => '$$valPt =~ /^.{8}\xff\xd8\xff[\xdb\xe0]/s', 2047 Groups => { 2 => 'Preview' }, 2048 RawConv => 'substr($val, 8)', 2049 Binary => 1, 2050 },{ #17 (format is in bytes 3-7) 2051 Name => 'ThumbnailPNG', 2052 Condition => '$$valPt =~ /^.{8}\x89PNG\r\n\x1a\n/s', 2053 Groups => { 2 => 'Preview' }, 2054 RawConv => 'substr($val, 8)', 2055 Binary => 1, 2056 },{ 2057 Name => 'UnknownThumbnail', 2058 Groups => { 2 => 'Preview' }, 2059 Binary => 1, 2060 }, 2061 ], 2062 PENT => { #PH 2063 Name => 'PentaxPENT', 2064 SubDirectory => { 2065 TagTable => 'Image::ExifTool::Pentax::PENT', 2066 ByteOrder => 'LittleEndian', 2067 }, 2068 }, 2069 PXTH => { #PH (Pentax K-01) 2070 Name => 'PentaxPreview', 2071 SubDirectory => { TagTable => 'Image::ExifTool::Pentax::PXTH' }, 2072 }, 2073 PXMN => [{ #PH (Pentax K-01) 2074 Name => 'MakerNotePentax5b', 2075 Condition => '$$valPt =~ /^PENTAX \0MM/', 2076 SubDirectory => { 2077 TagTable => 'Image::ExifTool::Pentax::Main', 2078 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 2079 Start => 10, 2080 Base => '$start - 10', 2081 ByteOrder => 'BigEndian', 2082 }, 2083 },{ #PH (Pentax 645Z) 2084 Name => 'MakerNotePentax5c', 2085 Condition => '$$valPt =~ /^PENTAX \0II/', 2086 SubDirectory => { 2087 TagTable => 'Image::ExifTool::Pentax::Main', 2088 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 2089 Start => 10, 2090 Base => '$start - 10', 2091 ByteOrder => 'LittleEndian', 2092 }, 2093 },{ 2094 Name => 'MakerNotePentaxUnknown', 2095 Binary => 1, 2096 }], 2097 # ---- Ricoh ---- 2098 RTHU => { #PH (GR) 2099 Name => 'PreviewImage', 2100 Groups => { 2 => 'Preview' }, 2101 RawConv => '$self->ValidateImage(\$val, $tag)', 2102 }, 2103 RMKN => { #PH (GR) 2104 Name => 'RicohRMKN', 2105 SubDirectory => { 2106 TagTable => 'Image::ExifTool::Exif::Main', 2107 ProcessProc => \&Image::ExifTool::ProcessTIFF, # (because ProcessMOV is default) 2108 }, 2109 }, 2110 '@mak' => { Name => 'Make', Avoid => 1 }, 2111 '@mod' => { Name => 'Model', Avoid => 1 }, 2112 '@swr' => { Name => 'SoftwareVersion', Avoid => 1 }, 2113 '@day' => { 2114 Name => 'ContentCreateDate', 2115 Notes => q{ 2116 some stupid Ricoh programmer used the '@' symbol instead of the copyright 2117 symbol in these tag ID's for the Ricoh Theta Z1 and maybe other models 2118 }, 2119 Groups => { 2 => 'Time' }, 2120 Shift => 'Time', 2121 Avoid => 1, 2122 # handle values in the form "2010-02-12T13:27:14-0800" 2123 ValueConv => q{ 2124 require Image::ExifTool::XMP; 2125 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 2126 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 2127 return $val; 2128 }, 2129 ValueConvInv => q{ 2130 require Image::ExifTool::XMP; 2131 my $tmp = Image::ExifTool::XMP::FormatXMPDate($val); 2132 ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon 2133 return $val; 2134 }, 2135 PrintConv => '$self->ConvertDateTime($val)', 2136 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 2137 }, 2138 '@xyz' => { #PH (iPhone 3GS) 2139 Name => 'GPSCoordinates', 2140 Groups => { 2 => 'Location' }, 2141 Avoid => 1, 2142 ValueConv => \&ConvertISO6709, 2143 ValueConvInv => \&ConvInvISO6709, 2144 PrintConv => \&PrintGPSCoordinates, 2145 PrintConvInv => \&PrintInvGPSCoordinates, 2146 }, 2147 # RDT1 - pairs of int32u_BE, starting at byte 8: "458275 471846" 2148 # RDT2 - pairs of int32u_BE, starting at byte 8: "472276 468526" 2149 # RDT3 - pairs of int32u_BE, starting at byte 8: "876603 482191" 2150 # RDT4 - pairs of int32u_BE, starting at byte 8: "1955 484612" 2151 # RDT6 - empty 2152 # RDT7 - empty 2153 # RDT8 - empty 2154 # RDT9 - only 16-byte header? 2155 # the boxes below all have a similar header (little-endian): 2156 # 0 int32u - number of records 2157 # 4 ? - "1e 00" 2158 # 6 int16u - record length in bytes 2159 # 8 ? - "23 01 00 00 00 00 00 00" 2160 # 16 - start of records (each record ends in an int64u timestamp in ns) 2161 # RDTA - float[4],ts: "-0.31289672 -0.2245330 11.303817 0 775.780" 2162 # RDTB - float[4],ts: "-0.04841613 -0.2166595 0.0724792 0 775.780" 2163 # RDTC - float[4],ts: "27.60925 -27.10037 -13.27285 0 775.829" 2164 # RDTD - int16s[3],ts: "353 -914 16354 0 775.829" 2165 # RDTG - ts: "775.825" 2166 # RDTI - float[4],ts: "0.00165951 0.005770059 0.06838259 0.1744695 775.862" 2167 # ---- Samsung ---- 2168 vndr => 'Vendor', #PH (Samsung PL70) 2169 SDLN => 'PlayMode', #PH (NC, Samsung ST80 "SEQ_PLAY") 2170 INFO => { 2171 Name => 'SamsungINFO', 2172 SubDirectory => { TagTable => 'Image::ExifTool::Samsung::INFO' }, 2173 }, 2174 '@sec' => { #PH (Samsung WB30F) 2175 Name => 'SamsungSec', 2176 SubDirectory => { TagTable => 'Image::ExifTool::Samsung::sec' }, 2177 }, 2178 'smta' => { #PH (Samsung SM-C101) 2179 Name => 'SamsungSmta', 2180 SubDirectory => { 2181 TagTable => 'Image::ExifTool::Samsung::smta', 2182 Start => 4, 2183 }, 2184 }, 2185 cver => 'CodeVersion', #PH (guess, Samsung MV900F) 2186 # ducp - 4 bytes all zero (Samsung ST96,WB750), 52 bytes all zero (Samsung WB30F) 2187 # edli - 52 bytes all zero (Samsung WB30F) 2188 # @etc - 4 bytes all zero (Samsung WB30F) 2189 # saut - 4 bytes all zero (Samsung SM-N900T) 2190 # smrd - string "TRUEBLUE" (Samsung SM-C101) 2191 # ---- TomTom Bandit Action Cam ---- 2192 TTMD => { 2193 Name => 'TomTomMetaData', 2194 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TomTom' }, 2195 }, 2196 # ---- Samsung Gear 360 ---- 2197 vrot => { 2198 Name => 'AccelerometerData', 2199 Notes => q{ 2200 accelerometer readings for each frame of the video, expressed as sets of 2201 yaw, pitch and roll angles in degrees 2202 }, 2203 Format => 'rational64s', 2204 ValueConv => '$val =~ s/^-?\d+ //; \$val', # (ignore leading version/size words) 2205 }, 2206 # m360 - 8 bytes "0 0 0 0 0 0 0 1" 2207 # opax - 164 bytes unknown (center and affine arrays? ref 26) 2208 # opai - 32 bytes (maybe contains a serial number starting at byte 16? - PH) (rgb gains, degamma, gamma? ref 26) 2209 # intv - 16 bytes all zero 2210 # ---- Unknown ---- 2211 # CDET - 128 bytes (unknown origin) 2212 # mtyp - 4 bytes all zero (some drone video) 2213 # kgrf - 8 bytes all zero ? (in udta inside trak atom) 2214 # kgcg - 128 bytes 0's and 1's 2215 # kgsi - 4 bytes "00 00 00 80" 2216 # FIEL - 18 bytes "FIEL\0\x01\0\0\0..." 2217 # 2218 # other 3rd-party tags 2219 # (ref http://code.google.com/p/mp4parser/source/browse/trunk/isoparser/src/main/resources/isoparser-default.properties?r=814) 2220 # 2221 ccid => 'ContentID', 2222 icnu => 'IconURI', 2223 infu => 'InfoURL', 2224 cdis => 'ContentDistributorID', 2225 albr => { Name => 'AlbumArtist', Groups => { 2 => 'Author' } }, 2226 cvru => 'CoverURI', 2227 lrcu => 'LyricsURI', 2228 2229 tags => { # found in Audible .m4b audio books (ref PH) 2230 Name => 'Audible_tags', 2231 SubDirectory => { TagTable => 'Image::ExifTool::Audible::tags' }, 2232 }, 2233 ); 2234 2235 # Unknown information stored in HTC One (M8) videos - PH 2236 %Image::ExifTool::QuickTime::HTCBinary = ( 2237 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2238 GROUPS => { 0 => 'MakerNotes', 1 => 'HTC', 2 => 'Video' }, 2239 TAG_PREFIX => 'HTCBinary', 2240 FORMAT => 'int32u', 2241 FIRST_ENTRY => 0, 2242 # 0 - values: 1 2243 # 1 - values: 0 2244 # 2 - values: 0 2245 # 3 - values: FileSize minus 12 (why?) 2246 # 4 - values: 12 2247 ); 2248 2249 # TomTom Bandit Action Cam metadata (ref PH) 2250 %Image::ExifTool::QuickTime::TomTom = ( 2251 PROCESS_PROC => \&ProcessMOV, 2252 GROUPS => { 2 => 'Video' }, 2253 NOTES => 'Tags found in TomTom Bandit Action Cam MP4 videos.', 2254 TTAD => { 2255 Name => 'TomTomAD', 2256 SubDirectory => { 2257 TagTable => 'Image::ExifTool::QuickTime::Stream', 2258 ProcessProc => \&Image::ExifTool::QuickTime::ProcessTTAD, 2259 }, 2260 }, 2261 TTHL => { Name => 'TomTomHL', Binary => 1, Unknown => 1 }, # (mostly zeros) 2262 # (TTID values are different for each video) 2263 TTID => { Name => 'TomTomID', ValueConv => 'unpack("x4H*",$val)' }, 2264 TTVI => { Name => 'TomTomVI', Format => 'int32u', Unknown => 1 }, # seen: "0 1 61 508 508" 2265 # TTVD seen: "normal 720p 60fps 60fps 16/9 wide 1x" 2266 TTVD => { Name => 'TomTomVD', ValueConv => 'my @a = ($val =~ /[\x20-\x7f]+/g); "@a"' }, 948 2267 ); 949 2268 … … 960 2279 # User-specific media data atoms (ref 11) 961 2280 %Image::ExifTool::QuickTime::MetaData = ( 962 PROCESS_PROC => \& Image::ExifTool::QuickTime::ProcessMetaData,2281 PROCESS_PROC => \&ProcessMetaData, 963 2282 GROUPS => { 2 => 'Video' }, 964 2283 TAG_PREFIX => 'MetaData', … … 967 2286 Name => 'ProductionDate', 968 2287 Groups => { 2 => 'Time' }, 2288 Shift => 'Time', 2289 Writable => 1, 2290 Permanent => 1, 2291 DelValue => '0000/00/00 00:00:00', 969 2292 # translate from format "YYYY/mm/dd HH:MM:SS" 970 2293 ValueConv => '$val=~tr{/}{:}; $val', 2294 ValueConvInv => '$val=~s[^(\d{4}):(\d{2}):][$1/$2/]; $val', 971 2295 PrintConv => '$self->ConvertDateTime($val)', 2296 PrintConvInv => '$self->InverseDateTime($val)', 972 2297 }, 973 2298 0x04 => 'Software', … … 985 2310 Name => 'TimeZone', 986 2311 Groups => { 2 => 'Time' }, 2312 Writable => 1, 2313 Permanent => 1, 2314 DelValue => 0, 987 2315 RawConv => 'Get16s(\$val,0)', 2316 RawConvInv => 'Set16s($val)', 988 2317 PrintConv => 'TimeZoneString($val)', 2318 PrintConvInv => q{ 2319 return undef unless $val =~ /^([-+])(\d{1,2}):?(\d{2})$/' 2320 my $tzmin = $2 * 60 + $3; 2321 $tzmin = -$tzmin if $1 eq '-'; 2322 return $tzmin; 2323 } 989 2324 }, 990 2325 0x0c => { 991 2326 Name => 'ModifyDate', 992 2327 Groups => { 2 => 'Time' }, 2328 Shift => 'Time', 2329 Writable => 1, 2330 Permanent => 1, 2331 DelValue => '0000/00/00 00:00:00', 993 2332 # translate from format "YYYY/mm/dd HH:MM:SS" 994 2333 ValueConv => '$val=~tr{/}{:}; $val', 2334 ValueConvInv => '$val=~s[^(\d{4}):(\d{2}):][$1/$2/]; $val', 995 2335 PrintConv => '$self->ConvertDateTime($val)', 996 }, 2336 PrintConvInv => '$self->InverseDateTime($val)', 2337 }, 2338 ); 2339 2340 # compressed movie atoms (ref http://wiki.multimedia.cx/index.php?title=QuickTime_container#cmov) 2341 %Image::ExifTool::QuickTime::CMovie = ( 2342 PROCESS_PROC => \&ProcessMOV, 2343 GROUPS => { 2 => 'Video' }, 2344 dcom => 'Compression', 2345 # cmvd - compressed moov atom data 997 2346 ); 998 2347 … … 1012 2361 Name => 'VideoProfile', 1013 2362 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::VideoProf' }, 2363 }, 2364 OLYM => { #PH 2365 Name => 'OlympusOLYM', 2366 SubDirectory => { 2367 TagTable => 'Image::ExifTool::Olympus::OLYM', 2368 ByteOrder => 'BigEndian', 2369 }, 1014 2370 }, 1015 2371 ); … … 1130 2486 %Image::ExifTool::QuickTime::Meta = ( 1131 2487 PROCESS_PROC => \&ProcessMOV, 1132 GROUPS => { 2 => 'Video' }, 2488 WRITE_PROC => \&WriteQuickTime, 2489 GROUPS => { 1 => 'Meta', 2 => 'Video' }, 1133 2490 ilst => { 1134 2491 Name => 'ItemList', … … 1144 2501 }, 1145 2502 dinf => { 1146 Name => 'DataInfo rmation',1147 Flags => ['Binary','Unknown'],2503 Name => 'DataInfo', # (don't change this name -- used to recognize directory when writing) 2504 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' }, 1148 2505 }, 1149 2506 ipmc => { … … 1153 2510 iloc => { 1154 2511 Name => 'ItemLocation', 1155 Flags => ['Binary','Unknown'], 2512 RawConv => \&ParseItemLocation, 2513 WriteHook => \&ParseItemLocation, 2514 Notes => 'parsed, but not extracted as a tag', 1156 2515 }, 1157 2516 ipro => { … … 1159 2518 Flags => ['Binary','Unknown'], 1160 2519 }, 1161 iinf => {2520 iinf => [{ 1162 2521 Name => 'ItemInformation', 1163 Flags => ['Binary','Unknown'], 1164 }, 2522 Condition => '$$valPt =~ /^\0/', # (check for version 0) 2523 SubDirectory => { 2524 TagTable => 'Image::ExifTool::QuickTime::ItemInfo', 2525 Start => 6, # (4-byte version/flags + 2-byte count) 2526 }, 2527 },{ 2528 Name => 'ItemInformation', 2529 SubDirectory => { 2530 TagTable => 'Image::ExifTool::QuickTime::ItemInfo', 2531 Start => 8, # (4-byte version/flags + 4-byte count) 2532 }, 2533 }], 1165 2534 'xml ' => { 1166 2535 Name => 'XML', 1167 SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' }, 2536 Flags => [ 'Binary', 'Protected' ], 2537 SubDirectory => { 2538 TagTable => 'Image::ExifTool::XMP::XML', 2539 IgnoreProp => { NonRealTimeMeta => 1 }, # ignore container for Sony 'nrtm' 2540 }, 1168 2541 }, 1169 2542 'keys' => { … … 1175 2548 Flags => ['Binary','Unknown'], 1176 2549 }, 1177 pitm => {2550 pitm => [{ 1178 2551 Name => 'PrimaryItemReference', 1179 Flags => ['Binary','Unknown'], 1180 }, 2552 Condition => '$$valPt =~ /^\0/', # (version 0?) 2553 RawConv => '$$self{PrimaryItem} = unpack("x4n",$val)', 2554 WriteHook => sub { my ($val,$et) = @_; $$et{PrimaryItem} = unpack("x4n",$val); }, 2555 },{ 2556 Name => 'PrimaryItemReference', 2557 RawConv => '$$self{PrimaryItem} = unpack("x4N",$val)', 2558 WriteHook => sub { my ($val,$et) = @_; $$et{PrimaryItem} = unpack("x4N",$val); }, 2559 }], 1181 2560 free => { #PH 1182 2561 Name => 'Free', 1183 2562 Flags => ['Binary','Unknown'], 1184 2563 }, 2564 iprp => { 2565 Name => 'ItemProperties', 2566 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemProp' }, 2567 }, 2568 iref => { 2569 Name => 'ItemReference', 2570 # the version is needed to parse some of the item references 2571 Condition => '$$self{ItemRefVersion} = ord($$valPt); 1', 2572 SubDirectory => { 2573 TagTable => 'Image::ExifTool::QuickTime::ItemRef', 2574 Start => 4, 2575 }, 2576 }, 2577 idat => { 2578 Name => 'MetaImageSize', #PH (NC) 2579 Format => 'int16u', 2580 # (don't know what the first two numbers are for) 2581 PrintConv => '$val =~ s/^(\d+) (\d+) (\d+) (\d+)/${3}x$4/; $val', 2582 }, 2583 uuid => [ 2584 { #PH (Canon R5/R6 HIF) 2585 Name => 'MetaVersion', # (NC) 2586 Condition => '$$valPt=~/^\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48/', 2587 RawConv => 'substr($val, 0x14)', 2588 }, 2589 { 2590 Name => 'UUID-Unknown', 2591 %unknownInfo, 2592 }, 2593 ], 2594 ); 2595 2596 # additional metadata container (ref ISO14496-12:2015) 2597 %Image::ExifTool::QuickTime::OtherMeta = ( 2598 PROCESS_PROC => \&ProcessMOV, 2599 WRITE_PROC => \&WriteQuickTime, 2600 GROUPS => { 2 => 'Video' }, 2601 mere => { 2602 Name => 'MetaRelation', 2603 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MetaRelation' }, 2604 }, 2605 meta => { 2606 Name => 'Meta', 2607 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 2608 }, 2609 ); 2610 2611 # metabox relation (ref ISO14496-12:2015) 2612 %Image::ExifTool::QuickTime::MetaRelation = ( 2613 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2614 GROUPS => { 2 => 'Video' }, 2615 FORMAT => 'int32u', 2616 # 0 => 'MetaRelationVersion', 2617 # 1 => 'FirstMetaboxHandlerType', 2618 # 2 => 'FirstMetaboxHandlerType', 2619 # 3 => { Name => 'MetaboxRelation', Format => 'int8u' }, 2620 ); 2621 2622 %Image::ExifTool::QuickTime::ItemProp = ( 2623 PROCESS_PROC => \&ProcessMOV, 2624 WRITE_PROC => \&WriteQuickTime, 2625 GROUPS => { 2 => 'Image' }, 2626 ipco => { 2627 Name => 'ItemPropertyContainer', 2628 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemPropCont' }, 2629 }, 2630 ipma => { 2631 Name => 'ItemPropertyAssociation', 2632 RawConv => \&ParseItemPropAssoc, 2633 WriteHook => \&ParseItemPropAssoc, 2634 Notes => 'parsed, but not extracted as a tag', 2635 }, 2636 ); 2637 2638 %Image::ExifTool::QuickTime::ItemPropCont = ( 2639 PROCESS_PROC => \&ProcessMOV, 2640 WRITE_PROC => \&WriteQuickTime, 2641 PERMANENT => 1, # (can't be deleted) 2642 GROUPS => { 2 => 'Image' }, 2643 VARS => { START_INDEX => 1 }, # show verbose indices starting at 1 2644 colr => [{ 2645 Name => 'ICC_Profile', 2646 Condition => '$$valPt =~ /^(prof|rICC)/', 2647 SubDirectory => { 2648 TagTable => 'Image::ExifTool::ICC_Profile::Main', 2649 Start => 4, 2650 }, 2651 },{ 2652 Name => 'ColorRepresentation', 2653 ValueConv => 'join(" ", substr($val,0,4), unpack("x4n*",$val))', 2654 }], 2655 irot => { 2656 Name => 'Rotation', 2657 Format => 'int8u', 2658 Writable => 'int8u', 2659 Protected => 1, 2660 ValueConv => '$val * 90', 2661 ValueConvInv => 'int($val / 90 + 0.5)', 2662 }, 2663 ispe => { 2664 Name => 'ImageSpatialExtent', 2665 Condition => '$$valPt =~ /^\0{4}/', # (version/flags == 0/0) 2666 RawConv => q{ 2667 my @dim = unpack("x4N*", $val); 2668 return undef if @dim < 2; 2669 unless ($$self{DOC_NUM}) { 2670 $self->FoundTag(ImageWidth => $dim[0]); 2671 $self->FoundTag(ImageHeight => $dim[1]); 2672 } 2673 return join ' ', @dim; 2674 }, 2675 PrintConv => '$val =~ tr/ /x/; $val', 2676 }, 2677 pixi => { 2678 Name => 'ImagePixelDepth', 2679 Condition => '$$valPt =~ /^\0{4}./s', # (version/flags == 0/0 and count) 2680 RawConv => 'join " ", unpack("x5C*", $val)', 2681 }, 2682 auxC => { 2683 Name => 'AuxiliaryImageType', 2684 Format => 'undef', 2685 RawConv => '$val = substr($val, 4); $val =~ s/\0.*//s; $val', 2686 }, 2687 pasp => { 2688 Name => 'PixelAspectRatio', 2689 Format => 'int32u', 2690 Writable => 'int32u', 2691 Protected => 1, 2692 }, 2693 rloc => { 2694 Name => 'RelativeLocation', 2695 Format => 'int32u', 2696 RawConv => '$val =~ s/^\S+\s+//; $val', # remove version/flags 2697 }, 2698 clap => { 2699 Name => 'CleanAperture', 2700 Format => 'rational64s', 2701 Notes => '4 numbers: width, height, left and top', 2702 }, 2703 hvcC => { 2704 Name => 'HEVCConfiguration', 2705 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HEVCConfig' }, 2706 }, 2707 av1C => { 2708 Name => 'AV1Configuration', 2709 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AV1Config' }, 2710 }, 2711 ); 2712 2713 # HEVC configuration (ref https://github.com/MPEGGroup/isobmff/blob/master/IsoLib/libisomediafile/src/HEVCConfigAtom.c) 2714 %Image::ExifTool::QuickTime::HEVCConfig = ( 2715 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2716 GROUPS => { 2 => 'Video' }, 2717 FIRST_ENTRY => 0, 2718 0 => 'HEVCConfigurationVersion', 2719 1 => { 2720 Name => 'GeneralProfileSpace', 2721 Mask => 0xc0, 2722 PrintConv => { 0 => 'Conforming' }, 2723 }, 2724 1.1 => { 2725 Name => 'GeneralTierFlag', 2726 Mask => 0x20, 2727 PrintConv => { 2728 0 => 'Main Tier', 2729 1 => 'High Tier', 2730 }, 2731 }, 2732 1.2 => { 2733 Name => 'GeneralProfileIDC', 2734 Mask => 0x1f, 2735 PrintConv => { 2736 0 => 'No Profile', 2737 1 => 'Main', 2738 2 => 'Main 10', 2739 3 => 'Main Still Picture', 2740 4 => 'Format Range Extensions', 2741 5 => 'High Throughput', 2742 6 => 'Multiview Main', 2743 7 => 'Scalable Main', 2744 8 => '3D Main', 2745 9 => 'Screen Content Coding Extensions', 2746 10 => 'Scalable Format Range Extensions', 2747 11 => 'High Throughput Screen Content Coding Extensions', 2748 }, 2749 }, 2750 2 => { 2751 Name => 'GenProfileCompatibilityFlags', 2752 Format => 'int32u', 2753 PrintConv => { BITMASK => { 2754 31 => 'No Profile', # (bit 0 in stream) 2755 30 => 'Main', # (bit 1 in stream) 2756 29 => 'Main 10', # (bit 2 in stream) 2757 28 => 'Main Still Picture', # (bit 3 in stream) 2758 27 => 'Format Range Extensions',# (...) 2759 26 => 'High Throughput', 2760 25 => 'Multiview Main', 2761 24 => 'Scalable Main', 2762 23 => '3D Main', 2763 22 => 'Screen Content Coding Extensions', 2764 21 => 'Scalable Format Range Extensions', 2765 20 => 'High Throughput Screen Content Coding Extensions', 2766 }}, 2767 }, 2768 6 => { 2769 Name => 'ConstraintIndicatorFlags', 2770 Format => 'int8u[6]', 2771 }, 2772 12 => { 2773 Name => 'GeneralLevelIDC', 2774 PrintConv => 'sprintf("%d (level %.1f)", $val, $val/30)', 2775 }, 2776 13 => { 2777 Name => 'MinSpatialSegmentationIDC', 2778 Format => 'int16u', 2779 Mask => 0x0fff, 2780 }, 2781 15 => { 2782 Name => 'ParallelismType', 2783 Mask => 0x03, 2784 }, 2785 16 => { 2786 Name => 'ChromaFormat', 2787 Mask => 0x03, 2788 PrintConv => { 2789 0 => 'Monochrome', 2790 1 => '4:2:0', 2791 2 => '4:2:2', 2792 3 => '4:4:4', 2793 }, 2794 }, 2795 17 => { 2796 Name => 'BitDepthLuma', 2797 Mask => 0x07, 2798 ValueConv => '$val + 8', 2799 }, 2800 18 => { 2801 Name => 'BitDepthChroma', 2802 Mask => 0x07, 2803 ValueConv => '$val + 8', 2804 }, 2805 19 => { 2806 Name => 'AverageFrameRate', 2807 Format => 'int16u', 2808 ValueConv => '$val / 256', 2809 }, 2810 21 => { 2811 Name => 'ConstantFrameRate', 2812 Mask => 0xc0, 2813 PrintConv => { 2814 0 => 'Unknown', 2815 1 => 'Constant Frame Rate', 2816 2 => 'Each Temporal Layer is Constant Frame Rate', 2817 }, 2818 }, 2819 21.1 => { 2820 Name => 'NumTemporalLayers', 2821 Mask => 0x38, 2822 }, 2823 21.2 => { 2824 Name => 'TemporalIDNested', 2825 Mask => 0x04, 2826 PrintConv => { 0 => 'No', 1 => 'Yes' }, 2827 }, 2828 #21.3 => { 2829 # Name => 'NALUnitLengthSize', 2830 # Mask => 0x03, 2831 # ValueConv => '$val + 1', 2832 # PrintConv => { 1 => '8-bit', 2 => '16-bit', 4 => '32-bit' }, 2833 #}, 2834 #22 => 'NumberOfNALUnitArrays', 2835 # (don't decode the NAL unit arrays) 2836 ); 2837 2838 # HEVC configuration (ref https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox) 2839 %Image::ExifTool::QuickTime::AV1Config = ( 2840 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2841 GROUPS => { 2 => 'Video' }, 2842 FIRST_ENTRY => 0, 2843 0 => { 2844 Name => 'AV1ConfigurationVersion', 2845 Mask => 0x7f, 2846 }, 2847 1.0 => { 2848 Name => 'SeqProfile', 2849 Mask => 0xe0, 2850 Unknown => 1, 2851 }, 2852 1.1 => { 2853 Name => 'SeqLevelIdx0', 2854 Mask => 0x1f, 2855 Unknown => 1, 2856 }, 2857 2.0 => { 2858 Name => 'SeqTier0', 2859 Mask => 0x80, 2860 Unknown => 1, 2861 }, 2862 2.1 => { 2863 Name => 'HighBitDepth', 2864 Mask => 0x40, 2865 Unknown => 1, 2866 }, 2867 2.2 => { 2868 Name => 'TwelveBit', 2869 Mask => 0x20, 2870 Unknown => 1, 2871 }, 2872 2.3 => { 2873 Name => 'ChromaFormat', # (Monochrome+SubSamplingX+SubSamplingY) 2874 Notes => 'bits: 0x04 = Monochrome, 0x02 = SubSamplingX, 0x01 = SubSamplingY', 2875 Mask => 0x1c, 2876 PrintConv => { 2877 0x00 => 'YUV 4:4:4', 2878 0x02 => 'YUV 4:2:2', 2879 0x03 => 'YUV 4:2:0', 2880 0x07 => 'Monochrome 4:0:0', 2881 }, 2882 }, 2883 2.4 => { 2884 Name => 'ChromaSamplePosition', 2885 Mask => 0x03, 2886 PrintConv => { 2887 0 => 'Unknown', 2888 1 => 'Vertical', 2889 2 => 'Colocated', 2890 3 => '(reserved)', 2891 }, 2892 }, 2893 3 => { 2894 Name => 'InitialDelaySamples', 2895 RawConv => '$val & 0x10 ? undef : ($val & 0x0f) + 1', 2896 Unknown => 1, 2897 }, 2898 ); 2899 2900 %Image::ExifTool::QuickTime::ItemRef = ( 2901 PROCESS_PROC => \&ProcessMOV, 2902 WRITE_PROC => \&WriteQuickTime, 2903 GROUPS => { 2 => 'Image' }, 2904 # (Note: ExifTool's ItemRefVersion may be used to test the iref version number) 2905 NOTES => q{ 2906 The Item reference entries listed in the table below contain information about 2907 the associations between items in the file. This information is used by 2908 ExifTool, but these entries are not extracted as tags. 2909 }, 2910 dimg => { Name => 'DerivedImageRef', RawConv => 'undef' }, 2911 thmb => { Name => 'ThumbnailRef', RawConv => 'undef' }, 2912 auxl => { Name => 'AuxiliaryImageRef', RawConv => 'undef' }, 2913 cdsc => { 2914 Name => 'ContentDescribes', 2915 RawConv => \&ParseContentDescribes, 2916 WriteHook => \&ParseContentDescribes, 2917 }, 2918 ); 2919 2920 %Image::ExifTool::QuickTime::ItemInfo = ( 2921 PROCESS_PROC => \&ProcessMOV, 2922 WRITE_PROC => \&WriteQuickTime, 2923 GROUPS => { 2 => 'Image' }, 2924 # avc1 - AVC image 2925 # hvc1 - HEVC image 2926 # lhv1 - L-HEVC image 2927 # infe - ItemInformationEntry 2928 # infe types: avc1,hvc1,lhv1,Exif,xml1,iovl(overlay image),grid,mime,hvt1(tile image) 2929 infe => { 2930 Name => 'ItemInfoEntry', 2931 RawConv => \&ParseItemInfoEntry, 2932 WriteHook => \&ParseItemInfoEntry, 2933 Notes => 'parsed, but not extracted as a tag', 2934 }, 1185 2935 ); 1186 2936 … … 1188 2938 %Image::ExifTool::QuickTime::TrackRef = ( 1189 2939 PROCESS_PROC => \&ProcessMOV, 1190 GROUPS => { 2 => 'Video' }, 1191 chap => { Name => 'ChapterList', Format => 'int32u' }, 1192 # also: tmcd, sync, scpt, ssrc, iTunesInfo 2940 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 2941 chap => { Name => 'ChapterListTrackID', Format => 'int32u' }, 2942 tmcd => { Name => 'TimeCode', Format => 'int32u' }, 2943 mpod => { #PH (FLIR MP4) 2944 Name => 'ElementaryStreamTrack', 2945 Format => 'int32u', 2946 ValueConv => '$val =~ s/^1 //; $val', # (why 2 numbers? -- ignore the first if "1") 2947 }, 2948 # also: sync, scpt, ssrc, iTunesInfo 2949 cdsc => { 2950 Name => 'ContentDescribes', 2951 Format => 'int32u', 2952 PrintConv => '"Track $val"', 2953 }, 2954 # cdep (Structural Dependency QT tag?) 2955 ); 2956 2957 # track aperture mode dimensions atoms 2958 # (ref https://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap2/qtff2.html) 2959 %Image::ExifTool::QuickTime::TrackAperture = ( 2960 PROCESS_PROC => \&ProcessMOV, 2961 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 2962 clef => { 2963 Name => 'CleanApertureDimensions', 2964 Format => 'fixed32u', 2965 Count => 3, 2966 ValueConv => '$val =~ s/^.*? //; $val', # remove flags word 2967 PrintConv => '$val =~ tr/ /x/; $val', 2968 }, 2969 prof => { 2970 Name => 'ProductionApertureDimensions', 2971 Format => 'fixed32u', 2972 Count => 3, 2973 ValueConv => '$val =~ s/^.*? //; $val', 2974 PrintConv => '$val =~ tr/ /x/; $val', 2975 }, 2976 enof => { 2977 Name => 'EncodedPixelsDimensions', 2978 Format => 'fixed32u', 2979 Count => 3, 2980 ValueConv => '$val =~ s/^.*? //; $val', 2981 PrintConv => '$val =~ tr/ /x/; $val', 2982 }, 1193 2983 ); 1194 2984 … … 1197 2987 %Image::ExifTool::QuickTime::ItemList = ( 1198 2988 PROCESS_PROC => \&ProcessMOV, 1199 GROUPS => { 2 => 'Audio' }, 2989 WRITE_PROC => \&WriteQuickTime, 2990 CHECK_PROC => \&CheckQTValue, 2991 WRITABLE => 1, 2992 PREFERRED => 2, # (preferred over UserData and Keys tags when writing) 2993 FORMAT => 'string', 2994 GROUPS => { 1 => 'ItemList', 2 => 'Audio' }, 2995 WRITE_GROUP => 'ItemList', 2996 LANG_INFO => \&GetLangInfo, 1200 2997 NOTES => q{ 1201 As well as these tags, the 'mdta' handler uses numerical tag ID's which are 1202 added dynamically to this table after processing the Meta Keys information. 2998 This is the preferred location for creating new QuickTime tags. Tags in 2999 this table support alternate languages which are accessed by adding a 3000 3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2 3001 country code to the tag name (eg. "ItemList:Title-fra" or 3002 "ItemList::Title-fra-FR"). When creating a new Meta box to contain the 3003 ItemList directory, by default ExifTool adds an 'mdir' (Metadata) Handler 3004 box because Apple software may ignore ItemList tags otherwise, but the API 3005 L<QuickTimeHandler|../ExifTool.html#QuickTimeHandler> option may be set to 0 to avoid this. 1203 3006 }, 1204 3007 # in this table, binary 1 and 2-byte "data"-type tags are interpreted as 1205 # int8u and int16u. Multi-byte binary "data" tags are extracted as binary data 3008 # int8u and int16u. Multi-byte binary "data" tags are extracted as binary data. 3009 # (Note that the Preferred property is set to 0 for some tags to prevent them 3010 # from being created when a same-named tag already exists in the table) 1206 3011 "\xa9ART" => 'Artist', 1207 3012 "\xa9alb" => 'Album', 3013 "\xa9aut" => { Name => 'Author', Avoid => 1, Groups => { 2 => 'Author' } }, #forum10091 ('auth' is preferred) 1208 3014 "\xa9cmt" => 'Comment', 1209 "\xa9com" => 'Composer', 1210 "\xa9day" => { Name => 'Year', Groups => { 2 => 'Time' } }, 3015 "\xa9com" => { Name => 'Composer', Avoid => 1, }, # ("\xa9wrt" is preferred in ItemList) 3016 "\xa9day" => { 3017 Name => 'ContentCreateDate', 3018 Groups => { 2 => 'Time' }, 3019 Shift => 'Time', 3020 # handle values in the form "2010-02-12T13:27:14-0800" 3021 ValueConv => q{ 3022 require Image::ExifTool::XMP; 3023 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 3024 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 3025 return $val; 3026 }, 3027 ValueConvInv => q{ 3028 require Image::ExifTool::XMP; 3029 $val = Image::ExifTool::XMP::FormatXMPDate($val); 3030 $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon 3031 return $val; 3032 }, 3033 PrintConv => '$self->ConvertDateTime($val)', 3034 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 3035 }, 1211 3036 "\xa9des" => 'Description', #4 1212 3037 "\xa9enc" => 'EncodedBy', #10 … … 1215 3040 "\xa9lyr" => 'Lyrics', 1216 3041 "\xa9nam" => 'Title', 1217 # "\xa9st3" ? #101218 3042 "\xa9too" => 'Encoder', 1219 3043 "\xa9trk" => 'Track', 1220 3044 "\xa9wrt" => 'Composer', 3045 # 3046 # the following tags written by AtomicParsley 0.9.6 3047 # (ref https://exiftool.org/forum/index.php?topic=11455.0) 3048 # 3049 "\xa9st3" => 'Subtitle', 3050 "\xa9con" => 'Conductor', 3051 "\xa9sol" => 'Soloist', 3052 "\xa9arg" => 'Arranger', 3053 "\xa9ope" => 'OriginalArtist', 3054 "\xa9dir" => 'Director', 3055 "\xa9ard" => 'ArtDirector', 3056 "\xa9sne" => 'SoundEngineer', 3057 "\xa9prd" => 'Producer', 3058 "\xa9xpd" => 'ExecutiveProducer', 3059 sdes => 'StoreDescription', 3060 # 1221 3061 '----' => { 1222 3062 Name => 'iTunesInfo', 1223 3063 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::iTunesInfo' }, 1224 3064 }, 1225 aART => 'AlbumArtist',1226 covr => 'CoverArt',3065 aART => { Name => 'AlbumArtist', Groups => { 2 => 'Author' } }, 3066 covr => { Name => 'CoverArt', Groups => { 2 => 'Preview' } }, 1227 3067 cpil => { #10 1228 3068 Name => 'Compilation', 3069 Format => 'int8u', #27 (ref 23 contradicts what AtomicParsley actually writes, which is int8s) 3070 Writable => 'int8s', 1229 3071 PrintConv => { 0 => 'No', 1 => 'Yes' }, 1230 3072 }, 1231 3073 disk => { 1232 3074 Name => 'DiskNumber', 1233 ValueConv => 'length($val) >= 6 ? join(" of ",unpack("x2nn",$val)) : \$val', 3075 Format => 'undef', # (necessary to prevent decoding as string!) 3076 ValueConv => q{ 3077 return \$val unless length($val) >= 6; 3078 my @a = unpack 'x2nn', $val; 3079 return $a[1] ? join(' of ', @a) : $a[0]; 3080 }, 3081 ValueConvInv => q{ 3082 my @a = $val =~ /\d+/g; 3083 return undef if @a == 0 or @a > 2; 3084 push @a, 0 if @a == 1; 3085 return pack('n3', 0, @a); 3086 }, 1234 3087 }, 1235 3088 pgap => { #10 1236 3089 Name => 'PlayGap', 3090 Format => 'int8u', #23 3091 Writable => 'int8s', #27 1237 3092 PrintConv => { 1238 3093 0 => 'Insert Gap', … … 1242 3097 tmpo => { 1243 3098 Name => 'BeatsPerMinute', 1244 Format => 'int16u', # marked as boolean but really int16u in my sample 3099 # marked as boolean but really int16u in my sample 3100 # (but written as int16s by iTunes and AtomicParsley, ref forum11506) 3101 Format => 'int16u', 3102 Writable => 'int16s', 1245 3103 }, 1246 3104 trkn => { 1247 3105 Name => 'TrackNumber', 1248 ValueConv => 'length($val) >= 6 ? join(" of ",unpack("x2nn",$val)) : \$val', 3106 Format => 'undef', # (necessary to prevent decoding as string!) 3107 ValueConv => q{ 3108 return \$val unless length($val) >= 6; 3109 my @a = unpack 'x2nn', $val; 3110 return $a[1] ? join(' of ', @a) : $a[0]; 3111 }, 3112 # (see forum11501 for discussion about the format used) 3113 ValueConvInv => q{ 3114 my @a = $val =~ /\d+/g; 3115 return undef if @a == 0 or @a > 2; 3116 push @a, 0 if @a == 1; 3117 return pack('n4', 0, @a, 0); 3118 }, 1249 3119 }, 1250 3120 # … … 1254 3124 akID => { #10 1255 3125 Name => 'AppleStoreAccountType', 3126 Format => 'int8u', #24 3127 Writable => 'int8s', #27 1256 3128 PrintConv => { 1257 3129 0 => 'iTunes', … … 1259 3131 }, 1260 3132 }, 1261 albm => 'Album', #(ffmpeg source)3133 albm => { Name => 'Album', Avoid => 1 }, #(ffmpeg source) 1262 3134 apID => 'AppleStoreAccount', 1263 3135 atID => { #10 (or TV series) 1264 3136 Name => 'AlbumTitleID', 1265 3137 Format => 'int32u', 3138 Writable => 'int32s', #27 1266 3139 }, 1267 3140 auth => { Name => 'Author', Groups => { 2 => 'Author' } }, … … 1270 3143 Name => 'AppleStoreCatalogID', 1271 3144 Format => 'int32u', 3145 Writable => 'int32s', #27 1272 3146 }, 1273 3147 cprt => { Name => 'Copyright', Groups => { 2 => 'Author' } }, 1274 dscp => 'Description',1275 desc => 'Description', #73148 dscp => { Name => 'Description', Avoid => 1 }, 3149 desc => { Name => 'Description', Avoid => 1 }, #7 1276 3150 gnre => { #10 1277 3151 Name => 'Genre', 3152 Avoid => 1, 3153 # (Note: see https://exiftool.org/forum/index.php?topic=11537.0) 3154 Format => 'undef', 3155 ValueConv => 'unpack("n",$val)', 3156 ValueConvInv => '$val =~ /^\d+$/ ? pack("n",$val) : undef', 1278 3157 PrintConv => q{ 1279 3158 return $val unless $val =~ /^\d+$/; … … 1281 3160 Image::ExifTool::ID3::PrintGenre($val - 1); # note the "- 1" 1282 3161 }, 3162 PrintConvInv => q{ 3163 return $val if $val =~ /^[0-9]+$/; 3164 require Image::ExifTool::ID3; 3165 my $id = Image::ExifTool::ID3::GetGenreID($val); 3166 return unless defined $id and $id =~ /^\d+$/; 3167 return $id + 1; 3168 }, 1283 3169 }, 1284 3170 egid => 'EpisodeGlobalUniqueID', #7 … … 1286 3172 Name => 'GenreID', 1287 3173 Format => 'int32u', 1288 # 4005 = Kids 1289 # 4010 = Teens 1290 }, 1291 grup => 'Grouping', #10 3174 Writable => 'int32s', #27 3175 SeparateTable => 1, 3176 # the following lookup is based on http://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/genres 3177 # (see scripts/parse_genre to parse genre JSON file from above) 3178 PrintConv => { #21/PH 3179 2 => 'Music|Blues', 3180 3 => 'Music|Comedy', 3181 4 => "Music|Children's Music", 3182 5 => 'Music|Classical', 3183 6 => 'Music|Country', 3184 7 => 'Music|Electronic', 3185 8 => 'Music|Holiday', 3186 9 => 'Music|Classical|Opera', 3187 10 => 'Music|Singer/Songwriter', 3188 11 => 'Music|Jazz', 3189 12 => 'Music|Latino', 3190 13 => 'Music|New Age', 3191 14 => 'Music|Pop', 3192 15 => 'Music|R&B/Soul', 3193 16 => 'Music|Soundtrack', 3194 17 => 'Music|Dance', 3195 18 => 'Music|Hip-Hop/Rap', 3196 19 => 'Music|World', 3197 20 => 'Music|Alternative', 3198 21 => 'Music|Rock', 3199 22 => 'Music|Christian & Gospel', 3200 23 => 'Music|Vocal', 3201 24 => 'Music|Reggae', 3202 25 => 'Music|Easy Listening', 3203 26 => 'Podcasts', 3204 27 => 'Music|J-Pop', 3205 28 => 'Music|Enka', 3206 29 => 'Music|Anime', 3207 30 => 'Music|Kayokyoku', 3208 31 => 'Music Videos', 3209 32 => 'TV Shows', 3210 33 => 'Movies', 3211 34 => 'Music', 3212 35 => 'iPod Games', 3213 36 => 'App Store', 3214 37 => 'Tones', 3215 38 => 'Books', 3216 39 => 'Mac App Store', 3217 40 => 'Textbooks', 3218 50 => 'Music|Fitness & Workout', 3219 51 => 'Music|Pop|K-Pop', 3220 52 => 'Music|Karaoke', 3221 53 => 'Music|Instrumental', 3222 74 => 'Audiobooks|News', 3223 75 => 'Audiobooks|Programs & Performances', 3224 500 => 'Fitness Music', 3225 501 => 'Fitness Music|Pop', 3226 502 => 'Fitness Music|Dance', 3227 503 => 'Fitness Music|Hip-Hop', 3228 504 => 'Fitness Music|Rock', 3229 505 => 'Fitness Music|Alt/Indie', 3230 506 => 'Fitness Music|Latino', 3231 507 => 'Fitness Music|Country', 3232 508 => 'Fitness Music|World', 3233 509 => 'Fitness Music|New Age', 3234 510 => 'Fitness Music|Classical', 3235 1001 => 'Music|Alternative|College Rock', 3236 1002 => 'Music|Alternative|Goth Rock', 3237 1003 => 'Music|Alternative|Grunge', 3238 1004 => 'Music|Alternative|Indie Rock', 3239 1005 => 'Music|Alternative|New Wave', 3240 1006 => 'Music|Alternative|Punk', 3241 1007 => 'Music|Blues|Chicago Blues', 3242 1009 => 'Music|Blues|Classic Blues', 3243 1010 => 'Music|Blues|Contemporary Blues', 3244 1011 => 'Music|Blues|Country Blues', 3245 1012 => 'Music|Blues|Delta Blues', 3246 1013 => 'Music|Blues|Electric Blues', 3247 1014 => "Music|Children's Music|Lullabies", 3248 1015 => "Music|Children's Music|Sing-Along", 3249 1016 => "Music|Children's Music|Stories", 3250 1017 => 'Music|Classical|Avant-Garde', 3251 1018 => 'Music|Classical|Baroque Era', 3252 1019 => 'Music|Classical|Chamber Music', 3253 1020 => 'Music|Classical|Chant', 3254 1021 => 'Music|Classical|Choral', 3255 1022 => 'Music|Classical|Classical Crossover', 3256 1023 => 'Music|Classical|Early Music', 3257 1024 => 'Music|Classical|Impressionist', 3258 1025 => 'Music|Classical|Medieval Era', 3259 1026 => 'Music|Classical|Minimalism', 3260 1027 => 'Music|Classical|Modern Era', 3261 1028 => 'Music|Classical|Opera', 3262 1029 => 'Music|Classical|Orchestral', 3263 1030 => 'Music|Classical|Renaissance', 3264 1031 => 'Music|Classical|Romantic Era', 3265 1032 => 'Music|Classical|Wedding Music', 3266 1033 => 'Music|Country|Alternative Country', 3267 1034 => 'Music|Country|Americana', 3268 1035 => 'Music|Country|Bluegrass', 3269 1036 => 'Music|Country|Contemporary Bluegrass', 3270 1037 => 'Music|Country|Contemporary Country', 3271 1038 => 'Music|Country|Country Gospel', 3272 1039 => 'Music|Country|Honky Tonk', 3273 1040 => 'Music|Country|Outlaw Country', 3274 1041 => 'Music|Country|Traditional Bluegrass', 3275 1042 => 'Music|Country|Traditional Country', 3276 1043 => 'Music|Country|Urban Cowboy', 3277 1044 => 'Music|Dance|Breakbeat', 3278 1045 => 'Music|Dance|Exercise', 3279 1046 => 'Music|Dance|Garage', 3280 1047 => 'Music|Dance|Hardcore', 3281 1048 => 'Music|Dance|House', 3282 1049 => "Music|Dance|Jungle/Drum'n'bass", 3283 1050 => 'Music|Dance|Techno', 3284 1051 => 'Music|Dance|Trance', 3285 1052 => 'Music|Jazz|Big Band', 3286 1053 => 'Music|Jazz|Bop', 3287 1054 => 'Music|Easy Listening|Lounge', 3288 1055 => 'Music|Easy Listening|Swing', 3289 1056 => 'Music|Electronic|Ambient', 3290 1057 => 'Music|Electronic|Downtempo', 3291 1058 => 'Music|Electronic|Electronica', 3292 1060 => 'Music|Electronic|IDM/Experimental', 3293 1061 => 'Music|Electronic|Industrial', 3294 1062 => 'Music|Singer/Songwriter|Alternative Folk', 3295 1063 => 'Music|Singer/Songwriter|Contemporary Folk', 3296 1064 => 'Music|Singer/Songwriter|Contemporary Singer/Songwriter', 3297 1065 => 'Music|Singer/Songwriter|Folk-Rock', 3298 1066 => 'Music|Singer/Songwriter|New Acoustic', 3299 1067 => 'Music|Singer/Songwriter|Traditional Folk', 3300 1068 => 'Music|Hip-Hop/Rap|Alternative Rap', 3301 1069 => 'Music|Hip-Hop/Rap|Dirty South', 3302 1070 => 'Music|Hip-Hop/Rap|East Coast Rap', 3303 1071 => 'Music|Hip-Hop/Rap|Gangsta Rap', 3304 1072 => 'Music|Hip-Hop/Rap|Hardcore Rap', 3305 1073 => 'Music|Hip-Hop/Rap|Hip-Hop', 3306 1074 => 'Music|Hip-Hop/Rap|Latin Rap', 3307 1075 => 'Music|Hip-Hop/Rap|Old School Rap', 3308 1076 => 'Music|Hip-Hop/Rap|Rap', 3309 1077 => 'Music|Hip-Hop/Rap|Underground Rap', 3310 1078 => 'Music|Hip-Hop/Rap|West Coast Rap', 3311 1079 => 'Music|Holiday|Chanukah', 3312 1080 => 'Music|Holiday|Christmas', 3313 1081 => "Music|Holiday|Christmas: Children's", 3314 1082 => 'Music|Holiday|Christmas: Classic', 3315 1083 => 'Music|Holiday|Christmas: Classical', 3316 1084 => 'Music|Holiday|Christmas: Jazz', 3317 1085 => 'Music|Holiday|Christmas: Modern', 3318 1086 => 'Music|Holiday|Christmas: Pop', 3319 1087 => 'Music|Holiday|Christmas: R&B', 3320 1088 => 'Music|Holiday|Christmas: Religious', 3321 1089 => 'Music|Holiday|Christmas: Rock', 3322 1090 => 'Music|Holiday|Easter', 3323 1091 => 'Music|Holiday|Halloween', 3324 1092 => 'Music|Holiday|Holiday: Other', 3325 1093 => 'Music|Holiday|Thanksgiving', 3326 1094 => 'Music|Christian & Gospel|CCM', 3327 1095 => 'Music|Christian & Gospel|Christian Metal', 3328 1096 => 'Music|Christian & Gospel|Christian Pop', 3329 1097 => 'Music|Christian & Gospel|Christian Rap', 3330 1098 => 'Music|Christian & Gospel|Christian Rock', 3331 1099 => 'Music|Christian & Gospel|Classic Christian', 3332 1100 => 'Music|Christian & Gospel|Contemporary Gospel', 3333 1101 => 'Music|Christian & Gospel|Gospel', 3334 1103 => 'Music|Christian & Gospel|Praise & Worship', 3335 1104 => 'Music|Christian & Gospel|Southern Gospel', 3336 1105 => 'Music|Christian & Gospel|Traditional Gospel', 3337 1106 => 'Music|Jazz|Avant-Garde Jazz', 3338 1107 => 'Music|Jazz|Contemporary Jazz', 3339 1108 => 'Music|Jazz|Crossover Jazz', 3340 1109 => 'Music|Jazz|Dixieland', 3341 1110 => 'Music|Jazz|Fusion', 3342 1111 => 'Music|Jazz|Latin Jazz', 3343 1112 => 'Music|Jazz|Mainstream Jazz', 3344 1113 => 'Music|Jazz|Ragtime', 3345 1114 => 'Music|Jazz|Smooth Jazz', 3346 1115 => 'Music|Latino|Latin Jazz', 3347 1116 => 'Music|Latino|Contemporary Latin', 3348 1117 => 'Music|Latino|Pop Latino', 3349 1118 => 'Music|Latino|Raices', # (Raíces) 3350 1119 => 'Music|Latino|Urbano latino', 3351 1120 => 'Music|Latino|Baladas y Boleros', 3352 1121 => 'Music|Latino|Rock y Alternativo', 3353 1122 => 'Music|Brazilian', 3354 1123 => 'Music|Latino|Musica Mexicana', # (Música Mexicana) 3355 1124 => 'Music|Latino|Musica tropical', # (Música tropical) 3356 1125 => 'Music|New Age|Environmental', 3357 1126 => 'Music|New Age|Healing', 3358 1127 => 'Music|New Age|Meditation', 3359 1128 => 'Music|New Age|Nature', 3360 1129 => 'Music|New Age|Relaxation', 3361 1130 => 'Music|New Age|Travel', 3362 1131 => 'Music|Pop|Adult Contemporary', 3363 1132 => 'Music|Pop|Britpop', 3364 1133 => 'Music|Pop|Pop/Rock', 3365 1134 => 'Music|Pop|Soft Rock', 3366 1135 => 'Music|Pop|Teen Pop', 3367 1136 => 'Music|R&B/Soul|Contemporary R&B', 3368 1137 => 'Music|R&B/Soul|Disco', 3369 1138 => 'Music|R&B/Soul|Doo Wop', 3370 1139 => 'Music|R&B/Soul|Funk', 3371 1140 => 'Music|R&B/Soul|Motown', 3372 1141 => 'Music|R&B/Soul|Neo-Soul', 3373 1142 => 'Music|R&B/Soul|Quiet Storm', 3374 1143 => 'Music|R&B/Soul|Soul', 3375 1144 => 'Music|Rock|Adult Alternative', 3376 1145 => 'Music|Rock|American Trad Rock', 3377 1146 => 'Music|Rock|Arena Rock', 3378 1147 => 'Music|Rock|Blues-Rock', 3379 1148 => 'Music|Rock|British Invasion', 3380 1149 => 'Music|Rock|Death Metal/Black Metal', 3381 1150 => 'Music|Rock|Glam Rock', 3382 1151 => 'Music|Rock|Hair Metal', 3383 1152 => 'Music|Rock|Hard Rock', 3384 1153 => 'Music|Rock|Metal', 3385 1154 => 'Music|Rock|Jam Bands', 3386 1155 => 'Music|Rock|Prog-Rock/Art Rock', 3387 1156 => 'Music|Rock|Psychedelic', 3388 1157 => 'Music|Rock|Rock & Roll', 3389 1158 => 'Music|Rock|Rockabilly', 3390 1159 => 'Music|Rock|Roots Rock', 3391 1160 => 'Music|Rock|Singer/Songwriter', 3392 1161 => 'Music|Rock|Southern Rock', 3393 1162 => 'Music|Rock|Surf', 3394 1163 => 'Music|Rock|Tex-Mex', 3395 1165 => 'Music|Soundtrack|Foreign Cinema', 3396 1166 => 'Music|Soundtrack|Musicals', 3397 1167 => 'Music|Comedy|Novelty', 3398 1168 => 'Music|Soundtrack|Original Score', 3399 1169 => 'Music|Soundtrack|Soundtrack', 3400 1171 => 'Music|Comedy|Standup Comedy', 3401 1172 => 'Music|Soundtrack|TV Soundtrack', 3402 1173 => 'Music|Vocal|Standards', 3403 1174 => 'Music|Vocal|Traditional Pop', 3404 1175 => 'Music|Jazz|Vocal Jazz', 3405 1176 => 'Music|Vocal|Vocal Pop', 3406 1177 => 'Music|African|Afro-Beat', 3407 1178 => 'Music|African|Afro-Pop', 3408 1179 => 'Music|World|Cajun', 3409 1180 => 'Music|World|Celtic', 3410 1181 => 'Music|World|Celtic Folk', 3411 1182 => 'Music|World|Contemporary Celtic', 3412 1183 => 'Music|Reggae|Modern Dancehall', 3413 1184 => 'Music|World|Drinking Songs', 3414 1185 => 'Music|Indian|Indian Pop', 3415 1186 => 'Music|World|Japanese Pop', 3416 1187 => 'Music|World|Klezmer', 3417 1188 => 'Music|World|Polka', 3418 1189 => 'Music|World|Traditional Celtic', 3419 1190 => 'Music|World|Worldbeat', 3420 1191 => 'Music|World|Zydeco', 3421 1192 => 'Music|Reggae|Roots Reggae', 3422 1193 => 'Music|Reggae|Dub', 3423 1194 => 'Music|Reggae|Ska', 3424 1195 => 'Music|World|Caribbean', 3425 1196 => 'Music|World|South America', 3426 1197 => 'Music|Arabic', 3427 1198 => 'Music|World|North America', 3428 1199 => 'Music|World|Hawaii', 3429 1200 => 'Music|World|Australia', 3430 1201 => 'Music|World|Japan', 3431 1202 => 'Music|World|France', 3432 1203 => 'Music|African', 3433 1204 => 'Music|World|Asia', 3434 1205 => 'Music|World|Europe', 3435 1206 => 'Music|World|South Africa', 3436 1207 => 'Music|Jazz|Hard Bop', 3437 1208 => 'Music|Jazz|Trad Jazz', 3438 1209 => 'Music|Jazz|Cool Jazz', 3439 1210 => 'Music|Blues|Acoustic Blues', 3440 1211 => 'Music|Classical|High Classical', 3441 1220 => 'Music|Brazilian|Axe', # (Axé) 3442 1221 => 'Music|Brazilian|Bossa Nova', 3443 1222 => 'Music|Brazilian|Choro', 3444 1223 => 'Music|Brazilian|Forro', # (Forró) 3445 1224 => 'Music|Brazilian|Frevo', 3446 1225 => 'Music|Brazilian|MPB', 3447 1226 => 'Music|Brazilian|Pagode', 3448 1227 => 'Music|Brazilian|Samba', 3449 1228 => 'Music|Brazilian|Sertanejo', 3450 1229 => 'Music|Brazilian|Baile Funk', 3451 1230 => 'Music|Alternative|Chinese Alt', 3452 1231 => 'Music|Alternative|Korean Indie', 3453 1232 => 'Music|Chinese', 3454 1233 => 'Music|Chinese|Chinese Classical', 3455 1234 => 'Music|Chinese|Chinese Flute', 3456 1235 => 'Music|Chinese|Chinese Opera', 3457 1236 => 'Music|Chinese|Chinese Orchestral', 3458 1237 => 'Music|Chinese|Chinese Regional Folk', 3459 1238 => 'Music|Chinese|Chinese Strings', 3460 1239 => 'Music|Chinese|Taiwanese Folk', 3461 1240 => 'Music|Chinese|Tibetan Native Music', 3462 1241 => 'Music|Hip-Hop/Rap|Chinese Hip-Hop', 3463 1242 => 'Music|Hip-Hop/Rap|Korean Hip-Hop', 3464 1243 => 'Music|Korean', 3465 1244 => 'Music|Korean|Korean Classical', 3466 1245 => 'Music|Korean|Korean Trad Song', 3467 1246 => 'Music|Korean|Korean Trad Instrumental', 3468 1247 => 'Music|Korean|Korean Trad Theater', 3469 1248 => 'Music|Rock|Chinese Rock', 3470 1249 => 'Music|Rock|Korean Rock', 3471 1250 => 'Music|Pop|C-Pop', 3472 1251 => 'Music|Pop|Cantopop/HK-Pop', 3473 1252 => 'Music|Pop|Korean Folk-Pop', 3474 1253 => 'Music|Pop|Mandopop', 3475 1254 => 'Music|Pop|Tai-Pop', 3476 1255 => 'Music|Pop|Malaysian Pop', 3477 1256 => 'Music|Pop|Pinoy Pop', 3478 1257 => 'Music|Pop|Original Pilipino Music', 3479 1258 => 'Music|Pop|Manilla Sound', 3480 1259 => 'Music|Pop|Indo Pop', 3481 1260 => 'Music|Pop|Thai Pop', 3482 1261 => 'Music|Vocal|Trot', 3483 1262 => 'Music|Indian', 3484 1263 => 'Music|Indian|Bollywood', 3485 1264 => 'Music|Indian|Regional Indian|Tamil', 3486 1265 => 'Music|Indian|Regional Indian|Telugu', 3487 1266 => 'Music|Indian|Regional Indian', 3488 1267 => 'Music|Indian|Devotional & Spiritual', 3489 1268 => 'Music|Indian|Sufi', 3490 1269 => 'Music|Indian|Indian Classical', 3491 1270 => 'Music|Russian|Russian Chanson', 3492 1271 => 'Music|World|Dini', 3493 1272 => 'Music|Turkish|Halk', 3494 1273 => 'Music|Turkish|Sanat', 3495 1274 => 'Music|World|Dangdut', 3496 1275 => 'Music|World|Indonesian Religious', 3497 1276 => 'Music|World|Calypso', 3498 1277 => 'Music|World|Soca', 3499 1278 => 'Music|Indian|Ghazals', 3500 1279 => 'Music|Indian|Indian Folk', 3501 1280 => 'Music|Turkish|Arabesque', 3502 1281 => 'Music|African|Afrikaans', 3503 1282 => 'Music|World|Farsi', 3504 1283 => 'Music|World|Israeli', 3505 1284 => 'Music|Arabic|Khaleeji', 3506 1285 => 'Music|Arabic|North African', 3507 1286 => 'Music|Arabic|Arabic Pop', 3508 1287 => 'Music|Arabic|Islamic', 3509 1288 => 'Music|Soundtrack|Sound Effects', 3510 1289 => 'Music|Folk', 3511 1290 => 'Music|Orchestral', 3512 1291 => 'Music|Marching', 3513 1293 => 'Music|Pop|Oldies', 3514 1294 => 'Music|Country|Thai Country', 3515 1295 => 'Music|World|Flamenco', 3516 1296 => 'Music|World|Tango', 3517 1297 => 'Music|World|Fado', 3518 1298 => 'Music|World|Iberia', 3519 1299 => 'Music|Russian', 3520 1300 => 'Music|Turkish', 3521 1301 => 'Podcasts|Arts', 3522 1302 => 'Podcasts|Society & Culture|Personal Journals', 3523 1303 => 'Podcasts|Comedy', 3524 1304 => 'Podcasts|Education', 3525 1305 => 'Podcasts|Kids & Family', 3526 1306 => 'Podcasts|Arts|Food', 3527 1307 => 'Podcasts|Health', 3528 1309 => 'Podcasts|TV & Film', 3529 1310 => 'Podcasts|Music', 3530 1311 => 'Podcasts|News & Politics', 3531 1314 => 'Podcasts|Religion & Spirituality', 3532 1315 => 'Podcasts|Science & Medicine', 3533 1316 => 'Podcasts|Sports & Recreation', 3534 1318 => 'Podcasts|Technology', 3535 1320 => 'Podcasts|Society & Culture|Places & Travel', 3536 1321 => 'Podcasts|Business', 3537 1323 => 'Podcasts|Games & Hobbies', 3538 1324 => 'Podcasts|Society & Culture', 3539 1325 => 'Podcasts|Government & Organizations', 3540 1337 => 'Music Videos|Classical|Piano', 3541 1401 => 'Podcasts|Arts|Literature', 3542 1402 => 'Podcasts|Arts|Design', 3543 1404 => 'Podcasts|Games & Hobbies|Video Games', 3544 1405 => 'Podcasts|Arts|Performing Arts', 3545 1406 => 'Podcasts|Arts|Visual Arts', 3546 1410 => 'Podcasts|Business|Careers', 3547 1412 => 'Podcasts|Business|Investing', 3548 1413 => 'Podcasts|Business|Management & Marketing', 3549 1415 => 'Podcasts|Education|K-12', 3550 1416 => 'Podcasts|Education|Higher Education', 3551 1417 => 'Podcasts|Health|Fitness & Nutrition', 3552 1420 => 'Podcasts|Health|Self-Help', 3553 1421 => 'Podcasts|Health|Sexuality', 3554 1438 => 'Podcasts|Religion & Spirituality|Buddhism', 3555 1439 => 'Podcasts|Religion & Spirituality|Christianity', 3556 1440 => 'Podcasts|Religion & Spirituality|Islam', 3557 1441 => 'Podcasts|Religion & Spirituality|Judaism', 3558 1443 => 'Podcasts|Society & Culture|Philosophy', 3559 1444 => 'Podcasts|Religion & Spirituality|Spirituality', 3560 1446 => 'Podcasts|Technology|Gadgets', 3561 1448 => 'Podcasts|Technology|Tech News', 3562 1450 => 'Podcasts|Technology|Podcasting', 3563 1454 => 'Podcasts|Games & Hobbies|Automotive', 3564 1455 => 'Podcasts|Games & Hobbies|Aviation', 3565 1456 => 'Podcasts|Sports & Recreation|Outdoor', 3566 1459 => 'Podcasts|Arts|Fashion & Beauty', 3567 1460 => 'Podcasts|Games & Hobbies|Hobbies', 3568 1461 => 'Podcasts|Games & Hobbies|Other Games', 3569 1462 => 'Podcasts|Society & Culture|History', 3570 1463 => 'Podcasts|Religion & Spirituality|Hinduism', 3571 1464 => 'Podcasts|Religion & Spirituality|Other', 3572 1465 => 'Podcasts|Sports & Recreation|Professional', 3573 1466 => 'Podcasts|Sports & Recreation|College & High School', 3574 1467 => 'Podcasts|Sports & Recreation|Amateur', 3575 1468 => 'Podcasts|Education|Educational Technology', 3576 1469 => 'Podcasts|Education|Language Courses', 3577 1470 => 'Podcasts|Education|Training', 3578 1471 => 'Podcasts|Business|Business News', 3579 1472 => 'Podcasts|Business|Shopping', 3580 1473 => 'Podcasts|Government & Organizations|National', 3581 1474 => 'Podcasts|Government & Organizations|Regional', 3582 1475 => 'Podcasts|Government & Organizations|Local', 3583 1476 => 'Podcasts|Government & Organizations|Non-Profit', 3584 1477 => 'Podcasts|Science & Medicine|Natural Sciences', 3585 1478 => 'Podcasts|Science & Medicine|Medicine', 3586 1479 => 'Podcasts|Science & Medicine|Social Sciences', 3587 1480 => 'Podcasts|Technology|Software How-To', 3588 1481 => 'Podcasts|Health|Alternative Health', 3589 1482 => 'Podcasts|Arts|Books', 3590 1483 => 'Podcasts|Fiction', 3591 1484 => 'Podcasts|Fiction|Drama', 3592 1485 => 'Podcasts|Fiction|Science Fiction', 3593 1486 => 'Podcasts|Fiction|Comedy Fiction', 3594 1487 => 'Podcasts|History', 3595 1488 => 'Podcasts|True Crime', 3596 1489 => 'Podcasts|News', 3597 1490 => 'Podcasts|News|Business News', 3598 1491 => 'Podcasts|Business|Management', 3599 1492 => 'Podcasts|Business|Marketing', 3600 1493 => 'Podcasts|Business|Entrepreneurship', 3601 1494 => 'Podcasts|Business|Non-Profit', 3602 1495 => 'Podcasts|Comedy|Improv', 3603 1496 => 'Podcasts|Comedy|Comedy Interviews', 3604 1497 => 'Podcasts|Comedy|Stand-Up', 3605 1498 => 'Podcasts|Education|Language Learning', 3606 1499 => 'Podcasts|Education|How To', 3607 1500 => 'Podcasts|Education|Self-Improvement', 3608 1501 => 'Podcasts|Education|Courses', 3609 1502 => 'Podcasts|Leisure', 3610 1503 => 'Podcasts|Leisure|Automotive', 3611 1504 => 'Podcasts|Leisure|Aviation', 3612 1505 => 'Podcasts|Leisure|Hobbies', 3613 1506 => 'Podcasts|Leisure|Crafts', 3614 1507 => 'Podcasts|Leisure|Games', 3615 1508 => 'Podcasts|Leisure|Home & Garden', 3616 1509 => 'Podcasts|Leisure|Video Games', 3617 1510 => 'Podcasts|Leisure|Animation & Manga', 3618 1511 => 'Podcasts|Government', 3619 1512 => 'Podcasts|Health & Fitness', 3620 1513 => 'Podcasts|Health & Fitness|Alternative Health', 3621 1514 => 'Podcasts|Health & Fitness|Fitness', 3622 1515 => 'Podcasts|Health & Fitness|Nutrition', 3623 1516 => 'Podcasts|Health & Fitness|Sexuality', 3624 1517 => 'Podcasts|Health & Fitness|Mental Health', 3625 1518 => 'Podcasts|Health & Fitness|Medicine', 3626 1519 => 'Podcasts|Kids & Family|Education for Kids', 3627 1520 => 'Podcasts|Kids & Family|Stories for Kids', 3628 1521 => 'Podcasts|Kids & Family|Parenting', 3629 1522 => 'Podcasts|Kids & Family|Pets & Animals', 3630 1523 => 'Podcasts|Music|Music Commentary', 3631 1524 => 'Podcasts|Music|Music History', 3632 1525 => 'Podcasts|Music|Music Interviews', 3633 1526 => 'Podcasts|News|Daily News', 3634 1527 => 'Podcasts|News|Politics', 3635 1528 => 'Podcasts|News|Tech News', 3636 1529 => 'Podcasts|News|Sports News', 3637 1530 => 'Podcasts|News|News Commentary', 3638 1531 => 'Podcasts|News|Entertainment News', 3639 1532 => 'Podcasts|Religion & Spirituality|Religion', 3640 1533 => 'Podcasts|Science', 3641 1534 => 'Podcasts|Science|Natural Sciences', 3642 1535 => 'Podcasts|Science|Social Sciences', 3643 1536 => 'Podcasts|Science|Mathematics', 3644 1537 => 'Podcasts|Science|Nature', 3645 1538 => 'Podcasts|Science|Astronomy', 3646 1539 => 'Podcasts|Science|Chemistry', 3647 1540 => 'Podcasts|Science|Earth Sciences', 3648 1541 => 'Podcasts|Science|Life Sciences', 3649 1542 => 'Podcasts|Science|Physics', 3650 1543 => 'Podcasts|Society & Culture|Documentary', 3651 1544 => 'Podcasts|Society & Culture|Relationships', 3652 1545 => 'Podcasts|Sports', 3653 1546 => 'Podcasts|Sports|Soccer', 3654 1547 => 'Podcasts|Sports|Football', 3655 1548 => 'Podcasts|Sports|Basketball', 3656 1549 => 'Podcasts|Sports|Baseball', 3657 1550 => 'Podcasts|Sports|Hockey', 3658 1551 => 'Podcasts|Sports|Running', 3659 1552 => 'Podcasts|Sports|Rugby', 3660 1553 => 'Podcasts|Sports|Golf', 3661 1554 => 'Podcasts|Sports|Cricket', 3662 1555 => 'Podcasts|Sports|Wrestling', 3663 1556 => 'Podcasts|Sports|Tennis', 3664 1557 => 'Podcasts|Sports|Volleyball', 3665 1558 => 'Podcasts|Sports|Swimming', 3666 1559 => 'Podcasts|Sports|Wilderness', 3667 1560 => 'Podcasts|Sports|Fantasy Sports', 3668 1561 => 'Podcasts|TV & Film|TV Reviews', 3669 1562 => 'Podcasts|TV & Film|After Shows', 3670 1563 => 'Podcasts|TV & Film|Film Reviews', 3671 1564 => 'Podcasts|TV & Film|Film History', 3672 1565 => 'Podcasts|TV & Film|Film Interviews', 3673 1602 => 'Music Videos|Blues', 3674 1603 => 'Music Videos|Comedy', 3675 1604 => "Music Videos|Children's Music", 3676 1605 => 'Music Videos|Classical', 3677 1606 => 'Music Videos|Country', 3678 1607 => 'Music Videos|Electronic', 3679 1608 => 'Music Videos|Holiday', 3680 1609 => 'Music Videos|Classical|Opera', 3681 1610 => 'Music Videos|Singer/Songwriter', 3682 1611 => 'Music Videos|Jazz', 3683 1612 => 'Music Videos|Latin', 3684 1613 => 'Music Videos|New Age', 3685 1614 => 'Music Videos|Pop', 3686 1615 => 'Music Videos|R&B/Soul', 3687 1616 => 'Music Videos|Soundtrack', 3688 1617 => 'Music Videos|Dance', 3689 1618 => 'Music Videos|Hip-Hop/Rap', 3690 1619 => 'Music Videos|World', 3691 1620 => 'Music Videos|Alternative', 3692 1621 => 'Music Videos|Rock', 3693 1622 => 'Music Videos|Christian & Gospel', 3694 1623 => 'Music Videos|Vocal', 3695 1624 => 'Music Videos|Reggae', 3696 1625 => 'Music Videos|Easy Listening', 3697 1626 => 'Music Videos|Podcasts', 3698 1627 => 'Music Videos|J-Pop', 3699 1628 => 'Music Videos|Enka', 3700 1629 => 'Music Videos|Anime', 3701 1630 => 'Music Videos|Kayokyoku', 3702 1631 => 'Music Videos|Disney', 3703 1632 => 'Music Videos|French Pop', 3704 1633 => 'Music Videos|German Pop', 3705 1634 => 'Music Videos|German Folk', 3706 1635 => 'Music Videos|Alternative|Chinese Alt', 3707 1636 => 'Music Videos|Alternative|Korean Indie', 3708 1637 => 'Music Videos|Chinese', 3709 1638 => 'Music Videos|Chinese|Chinese Classical', 3710 1639 => 'Music Videos|Chinese|Chinese Flute', 3711 1640 => 'Music Videos|Chinese|Chinese Opera', 3712 1641 => 'Music Videos|Chinese|Chinese Orchestral', 3713 1642 => 'Music Videos|Chinese|Chinese Regional Folk', 3714 1643 => 'Music Videos|Chinese|Chinese Strings', 3715 1644 => 'Music Videos|Chinese|Taiwanese Folk', 3716 1645 => 'Music Videos|Chinese|Tibetan Native Music', 3717 1646 => 'Music Videos|Hip-Hop/Rap|Chinese Hip-Hop', 3718 1647 => 'Music Videos|Hip-Hop/Rap|Korean Hip-Hop', 3719 1648 => 'Music Videos|Korean', 3720 1649 => 'Music Videos|Korean|Korean Classical', 3721 1650 => 'Music Videos|Korean|Korean Trad Song', 3722 1651 => 'Music Videos|Korean|Korean Trad Instrumental', 3723 1652 => 'Music Videos|Korean|Korean Trad Theater', 3724 1653 => 'Music Videos|Rock|Chinese Rock', 3725 1654 => 'Music Videos|Rock|Korean Rock', 3726 1655 => 'Music Videos|Pop|C-Pop', 3727 1656 => 'Music Videos|Pop|Cantopop/HK-Pop', 3728 1657 => 'Music Videos|Pop|Korean Folk-Pop', 3729 1658 => 'Music Videos|Pop|Mandopop', 3730 1659 => 'Music Videos|Pop|Tai-Pop', 3731 1660 => 'Music Videos|Pop|Malaysian Pop', 3732 1661 => 'Music Videos|Pop|Pinoy Pop', 3733 1662 => 'Music Videos|Pop|Original Pilipino Music', 3734 1663 => 'Music Videos|Pop|Manilla Sound', 3735 1664 => 'Music Videos|Pop|Indo Pop', 3736 1665 => 'Music Videos|Pop|Thai Pop', 3737 1666 => 'Music Videos|Vocal|Trot', 3738 1671 => 'Music Videos|Brazilian', 3739 1672 => 'Music Videos|Brazilian|Axe', # (Axé) 3740 1673 => 'Music Videos|Brazilian|Baile Funk', 3741 1674 => 'Music Videos|Brazilian|Bossa Nova', 3742 1675 => 'Music Videos|Brazilian|Choro', 3743 1676 => 'Music Videos|Brazilian|Forro', 3744 1677 => 'Music Videos|Brazilian|Frevo', 3745 1678 => 'Music Videos|Brazilian|MPB', 3746 1679 => 'Music Videos|Brazilian|Pagode', 3747 1680 => 'Music Videos|Brazilian|Samba', 3748 1681 => 'Music Videos|Brazilian|Sertanejo', 3749 1682 => 'Music Videos|Classical|High Classical', 3750 1683 => 'Music Videos|Fitness & Workout', 3751 1684 => 'Music Videos|Instrumental', 3752 1685 => 'Music Videos|Jazz|Big Band', 3753 1686 => 'Music Videos|Pop|K-Pop', 3754 1687 => 'Music Videos|Karaoke', 3755 1688 => 'Music Videos|Rock|Heavy Metal', 3756 1689 => 'Music Videos|Spoken Word', 3757 1690 => 'Music Videos|Indian', 3758 1691 => 'Music Videos|Indian|Bollywood', 3759 1692 => 'Music Videos|Indian|Regional Indian|Tamil', 3760 1693 => 'Music Videos|Indian|Regional Indian|Telugu', 3761 1694 => 'Music Videos|Indian|Regional Indian', 3762 1695 => 'Music Videos|Indian|Devotional & Spiritual', 3763 1696 => 'Music Videos|Indian|Sufi', 3764 1697 => 'Music Videos|Indian|Indian Classical', 3765 1698 => 'Music Videos|Russian|Russian Chanson', 3766 1699 => 'Music Videos|World|Dini', 3767 1700 => 'Music Videos|Turkish|Halk', 3768 1701 => 'Music Videos|Turkish|Sanat', 3769 1702 => 'Music Videos|World|Dangdut', 3770 1703 => 'Music Videos|World|Indonesian Religious', 3771 1704 => 'Music Videos|Indian|Indian Pop', 3772 1705 => 'Music Videos|World|Calypso', 3773 1706 => 'Music Videos|World|Soca', 3774 1707 => 'Music Videos|Indian|Ghazals', 3775 1708 => 'Music Videos|Indian|Indian Folk', 3776 1709 => 'Music Videos|Turkish|Arabesque', 3777 1710 => 'Music Videos|African|Afrikaans', 3778 1711 => 'Music Videos|World|Farsi', 3779 1712 => 'Music Videos|World|Israeli', 3780 1713 => 'Music Videos|Arabic', 3781 1714 => 'Music Videos|Arabic|Khaleeji', 3782 1715 => 'Music Videos|Arabic|North African', 3783 1716 => 'Music Videos|Arabic|Arabic Pop', 3784 1717 => 'Music Videos|Arabic|Islamic', 3785 1718 => 'Music Videos|Soundtrack|Sound Effects', 3786 1719 => 'Music Videos|Folk', 3787 1720 => 'Music Videos|Orchestral', 3788 1721 => 'Music Videos|Marching', 3789 1723 => 'Music Videos|Pop|Oldies', 3790 1724 => 'Music Videos|Country|Thai Country', 3791 1725 => 'Music Videos|World|Flamenco', 3792 1726 => 'Music Videos|World|Tango', 3793 1727 => 'Music Videos|World|Fado', 3794 1728 => 'Music Videos|World|Iberia', 3795 1729 => 'Music Videos|Russian', 3796 1730 => 'Music Videos|Turkish', 3797 1731 => 'Music Videos|Alternative|College Rock', 3798 1732 => 'Music Videos|Alternative|Goth Rock', 3799 1733 => 'Music Videos|Alternative|Grunge', 3800 1734 => 'Music Videos|Alternative|Indie Rock', 3801 1735 => 'Music Videos|Alternative|New Wave', 3802 1736 => 'Music Videos|Alternative|Punk', 3803 1737 => 'Music Videos|Blues|Acoustic Blues', 3804 1738 => 'Music Videos|Blues|Chicago Blues', 3805 1739 => 'Music Videos|Blues|Classic Blues', 3806 1740 => 'Music Videos|Blues|Contemporary Blues', 3807 1741 => 'Music Videos|Blues|Country Blues', 3808 1742 => 'Music Videos|Blues|Delta Blues', 3809 1743 => 'Music Videos|Blues|Electric Blues', 3810 1744 => "Music Videos|Children's Music|Lullabies", 3811 1745 => "Music Videos|Children's Music|Sing-Along", 3812 1746 => "Music Videos|Children's Music|Stories", 3813 1747 => 'Music Videos|Christian & Gospel|CCM', 3814 1748 => 'Music Videos|Christian & Gospel|Christian Metal', 3815 1749 => 'Music Videos|Christian & Gospel|Christian Pop', 3816 1750 => 'Music Videos|Christian & Gospel|Christian Rap', 3817 1751 => 'Music Videos|Christian & Gospel|Christian Rock', 3818 1752 => 'Music Videos|Christian & Gospel|Classic Christian', 3819 1753 => 'Music Videos|Christian & Gospel|Contemporary Gospel', 3820 1754 => 'Music Videos|Christian & Gospel|Gospel', 3821 1755 => 'Music Videos|Christian & Gospel|Praise & Worship', 3822 1756 => 'Music Videos|Christian & Gospel|Southern Gospel', 3823 1757 => 'Music Videos|Christian & Gospel|Traditional Gospel', 3824 1758 => 'Music Videos|Classical|Avant-Garde', 3825 1759 => 'Music Videos|Classical|Baroque Era', 3826 1760 => 'Music Videos|Classical|Chamber Music', 3827 1761 => 'Music Videos|Classical|Chant', 3828 1762 => 'Music Videos|Classical|Choral', 3829 1763 => 'Music Videos|Classical|Classical Crossover', 3830 1764 => 'Music Videos|Classical|Early Music', 3831 1765 => 'Music Videos|Classical|Impressionist', 3832 1766 => 'Music Videos|Classical|Medieval Era', 3833 1767 => 'Music Videos|Classical|Minimalism', 3834 1768 => 'Music Videos|Classical|Modern Era', 3835 1769 => 'Music Videos|Classical|Orchestral', 3836 1770 => 'Music Videos|Classical|Renaissance', 3837 1771 => 'Music Videos|Classical|Romantic Era', 3838 1772 => 'Music Videos|Classical|Wedding Music', 3839 1773 => 'Music Videos|Comedy|Novelty', 3840 1774 => 'Music Videos|Comedy|Standup Comedy', 3841 1775 => 'Music Videos|Country|Alternative Country', 3842 1776 => 'Music Videos|Country|Americana', 3843 1777 => 'Music Videos|Country|Bluegrass', 3844 1778 => 'Music Videos|Country|Contemporary Bluegrass', 3845 1779 => 'Music Videos|Country|Contemporary Country', 3846 1780 => 'Music Videos|Country|Country Gospel', 3847 1781 => 'Music Videos|Country|Honky Tonk', 3848 1782 => 'Music Videos|Country|Outlaw Country', 3849 1783 => 'Music Videos|Country|Traditional Bluegrass', 3850 1784 => 'Music Videos|Country|Traditional Country', 3851 1785 => 'Music Videos|Country|Urban Cowboy', 3852 1786 => 'Music Videos|Dance|Breakbeat', 3853 1787 => 'Music Videos|Dance|Exercise', 3854 1788 => 'Music Videos|Dance|Garage', 3855 1789 => 'Music Videos|Dance|Hardcore', 3856 1790 => 'Music Videos|Dance|House', 3857 1791 => "Music Videos|Dance|Jungle/Drum'n'bass", 3858 1792 => 'Music Videos|Dance|Techno', 3859 1793 => 'Music Videos|Dance|Trance', 3860 1794 => 'Music Videos|Easy Listening|Lounge', 3861 1795 => 'Music Videos|Easy Listening|Swing', 3862 1796 => 'Music Videos|Electronic|Ambient', 3863 1797 => 'Music Videos|Electronic|Downtempo', 3864 1798 => 'Music Videos|Electronic|Electronica', 3865 1799 => 'Music Videos|Electronic|IDM/Experimental', 3866 1800 => 'Music Videos|Electronic|Industrial', 3867 1801 => 'Music Videos|Hip-Hop/Rap|Alternative Rap', 3868 1802 => 'Music Videos|Hip-Hop/Rap|Dirty South', 3869 1803 => 'Music Videos|Hip-Hop/Rap|East Coast Rap', 3870 1804 => 'Music Videos|Hip-Hop/Rap|Gangsta Rap', 3871 1805 => 'Music Videos|Hip-Hop/Rap|Hardcore Rap', 3872 1806 => 'Music Videos|Hip-Hop/Rap|Hip-Hop', 3873 1807 => 'Music Videos|Hip-Hop/Rap|Latin Rap', 3874 1808 => 'Music Videos|Hip-Hop/Rap|Old School Rap', 3875 1809 => 'Music Videos|Hip-Hop/Rap|Rap', 3876 1810 => 'Music Videos|Hip-Hop/Rap|Underground Rap', 3877 1811 => 'Music Videos|Hip-Hop/Rap|West Coast Rap', 3878 1812 => 'Music Videos|Holiday|Chanukah', 3879 1813 => 'Music Videos|Holiday|Christmas', 3880 1814 => "Music Videos|Holiday|Christmas: Children's", 3881 1815 => 'Music Videos|Holiday|Christmas: Classic', 3882 1816 => 'Music Videos|Holiday|Christmas: Classical', 3883 1817 => 'Music Videos|Holiday|Christmas: Jazz', 3884 1818 => 'Music Videos|Holiday|Christmas: Modern', 3885 1819 => 'Music Videos|Holiday|Christmas: Pop', 3886 1820 => 'Music Videos|Holiday|Christmas: R&B', 3887 1821 => 'Music Videos|Holiday|Christmas: Religious', 3888 1822 => 'Music Videos|Holiday|Christmas: Rock', 3889 1823 => 'Music Videos|Holiday|Easter', 3890 1824 => 'Music Videos|Holiday|Halloween', 3891 1825 => 'Music Videos|Holiday|Thanksgiving', 3892 1826 => 'Music Videos|Jazz|Avant-Garde Jazz', 3893 1828 => 'Music Videos|Jazz|Bop', 3894 1829 => 'Music Videos|Jazz|Contemporary Jazz', 3895 1830 => 'Music Videos|Jazz|Cool Jazz', 3896 1831 => 'Music Videos|Jazz|Crossover Jazz', 3897 1832 => 'Music Videos|Jazz|Dixieland', 3898 1833 => 'Music Videos|Jazz|Fusion', 3899 1834 => 'Music Videos|Jazz|Hard Bop', 3900 1835 => 'Music Videos|Jazz|Latin Jazz', 3901 1836 => 'Music Videos|Jazz|Mainstream Jazz', 3902 1837 => 'Music Videos|Jazz|Ragtime', 3903 1838 => 'Music Videos|Jazz|Smooth Jazz', 3904 1839 => 'Music Videos|Jazz|Trad Jazz', 3905 1840 => 'Music Videos|Latin|Alternative & Rock in Spanish', 3906 1841 => 'Music Videos|Latin|Baladas y Boleros', 3907 1842 => 'Music Videos|Latin|Contemporary Latin', 3908 1843 => 'Music Videos|Latin|Latin Jazz', 3909 1844 => 'Music Videos|Latin|Latin Urban', 3910 1845 => 'Music Videos|Latin|Pop in Spanish', 3911 1846 => 'Music Videos|Latin|Raices', 3912 1847 => 'Music Videos|Latin|Musica Mexicana', # (Música Mexicana) 3913 1848 => 'Music Videos|Latin|Salsa y Tropical', 3914 1849 => 'Music Videos|New Age|Healing', 3915 1850 => 'Music Videos|New Age|Meditation', 3916 1851 => 'Music Videos|New Age|Nature', 3917 1852 => 'Music Videos|New Age|Relaxation', 3918 1853 => 'Music Videos|New Age|Travel', 3919 1854 => 'Music Videos|Pop|Adult Contemporary', 3920 1855 => 'Music Videos|Pop|Britpop', 3921 1856 => 'Music Videos|Pop|Pop/Rock', 3922 1857 => 'Music Videos|Pop|Soft Rock', 3923 1858 => 'Music Videos|Pop|Teen Pop', 3924 1859 => 'Music Videos|R&B/Soul|Contemporary R&B', 3925 1860 => 'Music Videos|R&B/Soul|Disco', 3926 1861 => 'Music Videos|R&B/Soul|Doo Wop', 3927 1862 => 'Music Videos|R&B/Soul|Funk', 3928 1863 => 'Music Videos|R&B/Soul|Motown', 3929 1864 => 'Music Videos|R&B/Soul|Neo-Soul', 3930 1865 => 'Music Videos|R&B/Soul|Soul', 3931 1866 => 'Music Videos|Reggae|Modern Dancehall', 3932 1867 => 'Music Videos|Reggae|Dub', 3933 1868 => 'Music Videos|Reggae|Roots Reggae', 3934 1869 => 'Music Videos|Reggae|Ska', 3935 1870 => 'Music Videos|Rock|Adult Alternative', 3936 1871 => 'Music Videos|Rock|American Trad Rock', 3937 1872 => 'Music Videos|Rock|Arena Rock', 3938 1873 => 'Music Videos|Rock|Blues-Rock', 3939 1874 => 'Music Videos|Rock|British Invasion', 3940 1875 => 'Music Videos|Rock|Death Metal/Black Metal', 3941 1876 => 'Music Videos|Rock|Glam Rock', 3942 1877 => 'Music Videos|Rock|Hair Metal', 3943 1878 => 'Music Videos|Rock|Hard Rock', 3944 1879 => 'Music Videos|Rock|Jam Bands', 3945 1880 => 'Music Videos|Rock|Prog-Rock/Art Rock', 3946 1881 => 'Music Videos|Rock|Psychedelic', 3947 1882 => 'Music Videos|Rock|Rock & Roll', 3948 1883 => 'Music Videos|Rock|Rockabilly', 3949 1884 => 'Music Videos|Rock|Roots Rock', 3950 1885 => 'Music Videos|Rock|Singer/Songwriter', 3951 1886 => 'Music Videos|Rock|Southern Rock', 3952 1887 => 'Music Videos|Rock|Surf', 3953 1888 => 'Music Videos|Rock|Tex-Mex', 3954 1889 => 'Music Videos|Singer/Songwriter|Alternative Folk', 3955 1890 => 'Music Videos|Singer/Songwriter|Contemporary Folk', 3956 1891 => 'Music Videos|Singer/Songwriter|Contemporary Singer/Songwriter', 3957 1892 => 'Music Videos|Singer/Songwriter|Folk-Rock', 3958 1893 => 'Music Videos|Singer/Songwriter|New Acoustic', 3959 1894 => 'Music Videos|Singer/Songwriter|Traditional Folk', 3960 1895 => 'Music Videos|Soundtrack|Foreign Cinema', 3961 1896 => 'Music Videos|Soundtrack|Musicals', 3962 1897 => 'Music Videos|Soundtrack|Original Score', 3963 1898 => 'Music Videos|Soundtrack|Soundtrack', 3964 1899 => 'Music Videos|Soundtrack|TV Soundtrack', 3965 1900 => 'Music Videos|Vocal|Standards', 3966 1901 => 'Music Videos|Vocal|Traditional Pop', 3967 1902 => 'Music Videos|Jazz|Vocal Jazz', 3968 1903 => 'Music Videos|Vocal|Vocal Pop', 3969 1904 => 'Music Videos|African', 3970 1905 => 'Music Videos|African|Afro-Beat', 3971 1906 => 'Music Videos|African|Afro-Pop', 3972 1907 => 'Music Videos|World|Asia', 3973 1908 => 'Music Videos|World|Australia', 3974 1909 => 'Music Videos|World|Cajun', 3975 1910 => 'Music Videos|World|Caribbean', 3976 1911 => 'Music Videos|World|Celtic', 3977 1912 => 'Music Videos|World|Celtic Folk', 3978 1913 => 'Music Videos|World|Contemporary Celtic', 3979 1914 => 'Music Videos|World|Europe', 3980 1915 => 'Music Videos|World|France', 3981 1916 => 'Music Videos|World|Hawaii', 3982 1917 => 'Music Videos|World|Japan', 3983 1918 => 'Music Videos|World|Klezmer', 3984 1919 => 'Music Videos|World|North America', 3985 1920 => 'Music Videos|World|Polka', 3986 1921 => 'Music Videos|World|South Africa', 3987 1922 => 'Music Videos|World|South America', 3988 1923 => 'Music Videos|World|Traditional Celtic', 3989 1924 => 'Music Videos|World|Worldbeat', 3990 1925 => 'Music Videos|World|Zydeco', 3991 1926 => 'Music Videos|Christian & Gospel', 3992 1928 => 'Music Videos|Classical|Art Song', 3993 1929 => 'Music Videos|Classical|Brass & Woodwinds', 3994 1930 => 'Music Videos|Classical|Solo Instrumental', 3995 1931 => 'Music Videos|Classical|Contemporary Era', 3996 1932 => 'Music Videos|Classical|Oratorio', 3997 1933 => 'Music Videos|Classical|Cantata', 3998 1934 => 'Music Videos|Classical|Electronic', 3999 1935 => 'Music Videos|Classical|Sacred', 4000 1936 => 'Music Videos|Classical|Guitar', 4001 1938 => 'Music Videos|Classical|Violin', 4002 1939 => 'Music Videos|Classical|Cello', 4003 1940 => 'Music Videos|Classical|Percussion', 4004 1941 => 'Music Videos|Electronic|Dubstep', 4005 1942 => 'Music Videos|Electronic|Bass', 4006 1943 => 'Music Videos|Hip-Hop/Rap|UK Hip-Hop', 4007 1944 => 'Music Videos|Reggae|Lovers Rock', 4008 1945 => 'Music Videos|Alternative|EMO', 4009 1946 => 'Music Videos|Alternative|Pop Punk', 4010 1947 => 'Music Videos|Alternative|Indie Pop', 4011 1948 => 'Music Videos|New Age|Yoga', 4012 1949 => 'Music Videos|Pop|Tribute', 4013 1950 => 'Music Videos|Pop|Shows', 4014 1951 => 'Music Videos|Cuban', 4015 1952 => 'Music Videos|Cuban|Mambo', 4016 1953 => 'Music Videos|Cuban|Chachacha', 4017 1954 => 'Music Videos|Cuban|Guajira', 4018 1955 => 'Music Videos|Cuban|Son', 4019 1956 => 'Music Videos|Cuban|Bolero', 4020 1957 => 'Music Videos|Cuban|Guaracha', 4021 1958 => 'Music Videos|Cuban|Timba', 4022 1959 => 'Music Videos|Soundtrack|Video Game', 4023 1960 => 'Music Videos|Indian|Regional Indian|Punjabi|Punjabi Pop', 4024 1961 => 'Music Videos|Indian|Regional Indian|Bengali|Rabindra Sangeet', 4025 1962 => 'Music Videos|Indian|Regional Indian|Malayalam', 4026 1963 => 'Music Videos|Indian|Regional Indian|Kannada', 4027 1964 => 'Music Videos|Indian|Regional Indian|Marathi', 4028 1965 => 'Music Videos|Indian|Regional Indian|Gujarati', 4029 1966 => 'Music Videos|Indian|Regional Indian|Assamese', 4030 1967 => 'Music Videos|Indian|Regional Indian|Bhojpuri', 4031 1968 => 'Music Videos|Indian|Regional Indian|Haryanvi', 4032 1969 => 'Music Videos|Indian|Regional Indian|Odia', 4033 1970 => 'Music Videos|Indian|Regional Indian|Rajasthani', 4034 1971 => 'Music Videos|Indian|Regional Indian|Urdu', 4035 1972 => 'Music Videos|Indian|Regional Indian|Punjabi', 4036 1973 => 'Music Videos|Indian|Regional Indian|Bengali', 4037 1974 => 'Music Videos|Indian|Indian Classical|Carnatic Classical', 4038 1975 => 'Music Videos|Indian|Indian Classical|Hindustani Classical', 4039 1976 => 'Music Videos|African|Afro House', 4040 1977 => 'Music Videos|African|Afro Soul', 4041 1978 => 'Music Videos|African|Afrobeats', 4042 1979 => 'Music Videos|African|Benga', 4043 1980 => 'Music Videos|African|Bongo-Flava', 4044 1981 => 'Music Videos|African|Coupe-Decale', 4045 1982 => 'Music Videos|African|Gqom', 4046 1983 => 'Music Videos|African|Highlife', 4047 1984 => 'Music Videos|African|Kuduro', 4048 1985 => 'Music Videos|African|Kizomba', 4049 1986 => 'Music Videos|African|Kwaito', 4050 1987 => 'Music Videos|African|Mbalax', 4051 1988 => 'Music Videos|African|Ndombolo', 4052 1989 => 'Music Videos|African|Shangaan Electro', 4053 1990 => 'Music Videos|African|Soukous', 4054 1991 => 'Music Videos|African|Taarab', 4055 1992 => 'Music Videos|African|Zouglou', 4056 1993 => 'Music Videos|Turkish|Ozgun', 4057 1994 => 'Music Videos|Turkish|Fantezi', 4058 1995 => 'Music Videos|Turkish|Religious', 4059 1996 => 'Music Videos|Pop|Turkish Pop', 4060 1997 => 'Music Videos|Rock|Turkish Rock', 4061 1998 => 'Music Videos|Alternative|Turkish Alternative', 4062 1999 => 'Music Videos|Hip-Hop/Rap|Turkish Hip-Hop/Rap', 4063 2000 => 'Music Videos|African|Maskandi', 4064 2001 => 'Music Videos|Russian|Russian Romance', 4065 2002 => 'Music Videos|Russian|Russian Bard', 4066 2003 => 'Music Videos|Russian|Russian Pop', 4067 2004 => 'Music Videos|Russian|Russian Rock', 4068 2005 => 'Music Videos|Russian|Russian Hip-Hop', 4069 2006 => 'Music Videos|Arabic|Levant', 4070 2007 => 'Music Videos|Arabic|Levant|Dabke', 4071 2008 => 'Music Videos|Arabic|Maghreb Rai', 4072 2009 => 'Music Videos|Arabic|Khaleeji|Khaleeji Jalsat', 4073 2010 => 'Music Videos|Arabic|Khaleeji|Khaleeji Shailat', 4074 2011 => 'Music Videos|Tarab', 4075 2012 => 'Music Videos|Tarab|Iraqi Tarab', 4076 2013 => 'Music Videos|Tarab|Egyptian Tarab', 4077 2014 => 'Music Videos|Tarab|Khaleeji Tarab', 4078 2015 => 'Music Videos|Pop|Levant Pop', 4079 2016 => 'Music Videos|Pop|Iraqi Pop', 4080 2017 => 'Music Videos|Pop|Egyptian Pop', 4081 2018 => 'Music Videos|Pop|Maghreb Pop', 4082 2019 => 'Music Videos|Pop|Khaleeji Pop', 4083 2020 => 'Music Videos|Hip-Hop/Rap|Levant Hip-Hop', 4084 2021 => 'Music Videos|Hip-Hop/Rap|Egyptian Hip-Hop', 4085 2022 => 'Music Videos|Hip-Hop/Rap|Maghreb Hip-Hop', 4086 2023 => 'Music Videos|Hip-Hop/Rap|Khaleeji Hip-Hop', 4087 2024 => 'Music Videos|Alternative|Indie Levant', 4088 2025 => 'Music Videos|Alternative|Indie Egyptian', 4089 2026 => 'Music Videos|Alternative|Indie Maghreb', 4090 2027 => 'Music Videos|Electronic|Levant Electronic', 4091 2028 => "Music Videos|Electronic|Electro-Cha'abi", 4092 2029 => 'Music Videos|Electronic|Maghreb Electronic', 4093 2030 => 'Music Videos|Folk|Iraqi Folk', 4094 2031 => 'Music Videos|Folk|Khaleeji Folk', 4095 2032 => 'Music Videos|Dance|Maghreb Dance', 4096 4000 => 'TV Shows|Comedy', 4097 4001 => 'TV Shows|Drama', 4098 4002 => 'TV Shows|Animation', 4099 4003 => 'TV Shows|Action & Adventure', 4100 4004 => 'TV Shows|Classics', 4101 4005 => 'TV Shows|Kids & Family', 4102 4006 => 'TV Shows|Nonfiction', 4103 4007 => 'TV Shows|Reality TV', 4104 4008 => 'TV Shows|Sci-Fi & Fantasy', 4105 4009 => 'TV Shows|Sports', 4106 4010 => 'TV Shows|Teens', 4107 4011 => 'TV Shows|Latino TV', 4108 4401 => 'Movies|Action & Adventure', 4109 4402 => 'Movies|Anime', 4110 4403 => 'Movies|Classics', 4111 4404 => 'Movies|Comedy', 4112 4405 => 'Movies|Documentary', 4113 4406 => 'Movies|Drama', 4114 4407 => 'Movies|Foreign', 4115 4408 => 'Movies|Horror', 4116 4409 => 'Movies|Independent', 4117 4410 => 'Movies|Kids & Family', 4118 4411 => 'Movies|Musicals', 4119 4412 => 'Movies|Romance', 4120 4413 => 'Movies|Sci-Fi & Fantasy', 4121 4414 => 'Movies|Short Films', 4122 4415 => 'Movies|Special Interest', 4123 4416 => 'Movies|Thriller', 4124 4417 => 'Movies|Sports', 4125 4418 => 'Movies|Western', 4126 4419 => 'Movies|Urban', 4127 4420 => 'Movies|Holiday', 4128 4421 => 'Movies|Made for TV', 4129 4422 => 'Movies|Concert Films', 4130 4423 => 'Movies|Music Documentaries', 4131 4424 => 'Movies|Music Feature Films', 4132 4425 => 'Movies|Japanese Cinema', 4133 4426 => 'Movies|Jidaigeki', 4134 4427 => 'Movies|Tokusatsu', 4135 4428 => 'Movies|Korean Cinema', 4136 4429 => 'Movies|Russian', 4137 4430 => 'Movies|Turkish', 4138 4431 => 'Movies|Bollywood', 4139 4432 => 'Movies|Regional Indian', 4140 4433 => 'Movies|Middle Eastern', 4141 4434 => 'Movies|African', 4142 6000 => 'App Store|Business', 4143 6001 => 'App Store|Weather', 4144 6002 => 'App Store|Utilities', 4145 6003 => 'App Store|Travel', 4146 6004 => 'App Store|Sports', 4147 6005 => 'App Store|Social Networking', 4148 6006 => 'App Store|Reference', 4149 6007 => 'App Store|Productivity', 4150 6008 => 'App Store|Photo & Video', 4151 6009 => 'App Store|News', 4152 6010 => 'App Store|Navigation', 4153 6011 => 'App Store|Music', 4154 6012 => 'App Store|Lifestyle', 4155 6013 => 'App Store|Health & Fitness', 4156 6014 => 'App Store|Games', 4157 6015 => 'App Store|Finance', 4158 6016 => 'App Store|Entertainment', 4159 6017 => 'App Store|Education', 4160 6018 => 'App Store|Books', 4161 6020 => 'App Store|Medical', 4162 6021 => 'App Store|Magazines & Newspapers', 4163 6022 => 'App Store|Catalogs', 4164 6023 => 'App Store|Food & Drink', 4165 6024 => 'App Store|Shopping', 4166 6025 => 'App Store|Stickers', 4167 6026 => 'App Store|Developer Tools', 4168 6027 => 'App Store|Graphics & Design', 4169 7001 => 'App Store|Games|Action', 4170 7002 => 'App Store|Games|Adventure', 4171 7003 => 'App Store|Games|Casual', 4172 7004 => 'App Store|Games|Board', 4173 7005 => 'App Store|Games|Card', 4174 7006 => 'App Store|Games|Casino', 4175 7007 => 'App Store|Games|Dice', 4176 7008 => 'App Store|Games|Educational', 4177 7009 => 'App Store|Games|Family', 4178 7011 => 'App Store|Games|Music', 4179 7012 => 'App Store|Games|Puzzle', 4180 7013 => 'App Store|Games|Racing', 4181 7014 => 'App Store|Games|Role Playing', 4182 7015 => 'App Store|Games|Simulation', 4183 7016 => 'App Store|Games|Sports', 4184 7017 => 'App Store|Games|Strategy', 4185 7018 => 'App Store|Games|Trivia', 4186 7019 => 'App Store|Games|Word', 4187 8001 => 'Tones|Ringtones|Alternative', 4188 8002 => 'Tones|Ringtones|Blues', 4189 8003 => "Tones|Ringtones|Children's Music", 4190 8004 => 'Tones|Ringtones|Classical', 4191 8005 => 'Tones|Ringtones|Comedy', 4192 8006 => 'Tones|Ringtones|Country', 4193 8007 => 'Tones|Ringtones|Dance', 4194 8008 => 'Tones|Ringtones|Electronic', 4195 8009 => 'Tones|Ringtones|Enka', 4196 8010 => 'Tones|Ringtones|French Pop', 4197 8011 => 'Tones|Ringtones|German Folk', 4198 8012 => 'Tones|Ringtones|German Pop', 4199 8013 => 'Tones|Ringtones|Hip-Hop/Rap', 4200 8014 => 'Tones|Ringtones|Holiday', 4201 8015 => 'Tones|Ringtones|Inspirational', 4202 8016 => 'Tones|Ringtones|J-Pop', 4203 8017 => 'Tones|Ringtones|Jazz', 4204 8018 => 'Tones|Ringtones|Kayokyoku', 4205 8019 => 'Tones|Ringtones|Latin', 4206 8020 => 'Tones|Ringtones|New Age', 4207 8021 => 'Tones|Ringtones|Classical|Opera', 4208 8022 => 'Tones|Ringtones|Pop', 4209 8023 => 'Tones|Ringtones|R&B/Soul', 4210 8024 => 'Tones|Ringtones|Reggae', 4211 8025 => 'Tones|Ringtones|Rock', 4212 8026 => 'Tones|Ringtones|Singer/Songwriter', 4213 8027 => 'Tones|Ringtones|Soundtrack', 4214 8028 => 'Tones|Ringtones|Spoken Word', 4215 8029 => 'Tones|Ringtones|Vocal', 4216 8030 => 'Tones|Ringtones|World', 4217 8050 => 'Tones|Alert Tones|Sound Effects', 4218 8051 => 'Tones|Alert Tones|Dialogue', 4219 8052 => 'Tones|Alert Tones|Music', 4220 8053 => 'Tones|Ringtones', 4221 8054 => 'Tones|Alert Tones', 4222 8055 => 'Tones|Ringtones|Alternative|Chinese Alt', 4223 8056 => 'Tones|Ringtones|Alternative|College Rock', 4224 8057 => 'Tones|Ringtones|Alternative|Goth Rock', 4225 8058 => 'Tones|Ringtones|Alternative|Grunge', 4226 8059 => 'Tones|Ringtones|Alternative|Indie Rock', 4227 8060 => 'Tones|Ringtones|Alternative|Korean Indie', 4228 8061 => 'Tones|Ringtones|Alternative|New Wave', 4229 8062 => 'Tones|Ringtones|Alternative|Punk', 4230 8063 => 'Tones|Ringtones|Anime', 4231 8064 => 'Tones|Ringtones|Arabic', 4232 8065 => 'Tones|Ringtones|Arabic|Arabic Pop', 4233 8066 => 'Tones|Ringtones|Arabic|Islamic', 4234 8067 => 'Tones|Ringtones|Arabic|Khaleeji', 4235 8068 => 'Tones|Ringtones|Arabic|North African', 4236 8069 => 'Tones|Ringtones|Blues|Acoustic Blues', 4237 8070 => 'Tones|Ringtones|Blues|Chicago Blues', 4238 8071 => 'Tones|Ringtones|Blues|Classic Blues', 4239 8072 => 'Tones|Ringtones|Blues|Contemporary Blues', 4240 8073 => 'Tones|Ringtones|Blues|Country Blues', 4241 8074 => 'Tones|Ringtones|Blues|Delta Blues', 4242 8075 => 'Tones|Ringtones|Blues|Electric Blues', 4243 8076 => 'Tones|Ringtones|Brazilian', 4244 8077 => 'Tones|Ringtones|Brazilian|Axe', # (Axé) 4245 8078 => 'Tones|Ringtones|Brazilian|Baile Funk', 4246 8079 => 'Tones|Ringtones|Brazilian|Bossa Nova', 4247 8080 => 'Tones|Ringtones|Brazilian|Choro', 4248 8081 => 'Tones|Ringtones|Brazilian|Forro', # (Forró) 4249 8082 => 'Tones|Ringtones|Brazilian|Frevo', 4250 8083 => 'Tones|Ringtones|Brazilian|MPB', 4251 8084 => 'Tones|Ringtones|Brazilian|Pagode', 4252 8085 => 'Tones|Ringtones|Brazilian|Samba', 4253 8086 => 'Tones|Ringtones|Brazilian|Sertanejo', 4254 8087 => "Tones|Ringtones|Children's Music|Lullabies", 4255 8088 => "Tones|Ringtones|Children's Music|Sing-Along", 4256 8089 => "Tones|Ringtones|Children's Music|Stories", 4257 8090 => 'Tones|Ringtones|Chinese', 4258 8091 => 'Tones|Ringtones|Chinese|Chinese Classical', 4259 8092 => 'Tones|Ringtones|Chinese|Chinese Flute', 4260 8093 => 'Tones|Ringtones|Chinese|Chinese Opera', 4261 8094 => 'Tones|Ringtones|Chinese|Chinese Orchestral', 4262 8095 => 'Tones|Ringtones|Chinese|Chinese Regional Folk', 4263 8096 => 'Tones|Ringtones|Chinese|Chinese Strings', 4264 8097 => 'Tones|Ringtones|Chinese|Taiwanese Folk', 4265 8098 => 'Tones|Ringtones|Chinese|Tibetan Native Music', 4266 8099 => 'Tones|Ringtones|Christian & Gospel', 4267 8100 => 'Tones|Ringtones|Christian & Gospel|CCM', 4268 8101 => 'Tones|Ringtones|Christian & Gospel|Christian Metal', 4269 8102 => 'Tones|Ringtones|Christian & Gospel|Christian Pop', 4270 8103 => 'Tones|Ringtones|Christian & Gospel|Christian Rap', 4271 8104 => 'Tones|Ringtones|Christian & Gospel|Christian Rock', 4272 8105 => 'Tones|Ringtones|Christian & Gospel|Classic Christian', 4273 8106 => 'Tones|Ringtones|Christian & Gospel|Contemporary Gospel', 4274 8107 => 'Tones|Ringtones|Christian & Gospel|Gospel', 4275 8108 => 'Tones|Ringtones|Christian & Gospel|Praise & Worship', 4276 8109 => 'Tones|Ringtones|Christian & Gospel|Southern Gospel', 4277 8110 => 'Tones|Ringtones|Christian & Gospel|Traditional Gospel', 4278 8111 => 'Tones|Ringtones|Classical|Avant-Garde', 4279 8112 => 'Tones|Ringtones|Classical|Baroque Era', 4280 8113 => 'Tones|Ringtones|Classical|Chamber Music', 4281 8114 => 'Tones|Ringtones|Classical|Chant', 4282 8115 => 'Tones|Ringtones|Classical|Choral', 4283 8116 => 'Tones|Ringtones|Classical|Classical Crossover', 4284 8117 => 'Tones|Ringtones|Classical|Early Music', 4285 8118 => 'Tones|Ringtones|Classical|High Classical', 4286 8119 => 'Tones|Ringtones|Classical|Impressionist', 4287 8120 => 'Tones|Ringtones|Classical|Medieval Era', 4288 8121 => 'Tones|Ringtones|Classical|Minimalism', 4289 8122 => 'Tones|Ringtones|Classical|Modern Era', 4290 8123 => 'Tones|Ringtones|Classical|Orchestral', 4291 8124 => 'Tones|Ringtones|Classical|Renaissance', 4292 8125 => 'Tones|Ringtones|Classical|Romantic Era', 4293 8126 => 'Tones|Ringtones|Classical|Wedding Music', 4294 8127 => 'Tones|Ringtones|Comedy|Novelty', 4295 8128 => 'Tones|Ringtones|Comedy|Standup Comedy', 4296 8129 => 'Tones|Ringtones|Country|Alternative Country', 4297 8130 => 'Tones|Ringtones|Country|Americana', 4298 8131 => 'Tones|Ringtones|Country|Bluegrass', 4299 8132 => 'Tones|Ringtones|Country|Contemporary Bluegrass', 4300 8133 => 'Tones|Ringtones|Country|Contemporary Country', 4301 8134 => 'Tones|Ringtones|Country|Country Gospel', 4302 8135 => 'Tones|Ringtones|Country|Honky Tonk', 4303 8136 => 'Tones|Ringtones|Country|Outlaw Country', 4304 8137 => 'Tones|Ringtones|Country|Thai Country', 4305 8138 => 'Tones|Ringtones|Country|Traditional Bluegrass', 4306 8139 => 'Tones|Ringtones|Country|Traditional Country', 4307 8140 => 'Tones|Ringtones|Country|Urban Cowboy', 4308 8141 => 'Tones|Ringtones|Dance|Breakbeat', 4309 8142 => 'Tones|Ringtones|Dance|Exercise', 4310 8143 => 'Tones|Ringtones|Dance|Garage', 4311 8144 => 'Tones|Ringtones|Dance|Hardcore', 4312 8145 => 'Tones|Ringtones|Dance|House', 4313 8146 => "Tones|Ringtones|Dance|Jungle/Drum'n'bass", 4314 8147 => 'Tones|Ringtones|Dance|Techno', 4315 8148 => 'Tones|Ringtones|Dance|Trance', 4316 8149 => 'Tones|Ringtones|Disney', 4317 8150 => 'Tones|Ringtones|Easy Listening', 4318 8151 => 'Tones|Ringtones|Easy Listening|Lounge', 4319 8152 => 'Tones|Ringtones|Easy Listening|Swing', 4320 8153 => 'Tones|Ringtones|Electronic|Ambient', 4321 8154 => 'Tones|Ringtones|Electronic|Downtempo', 4322 8155 => 'Tones|Ringtones|Electronic|Electronica', 4323 8156 => 'Tones|Ringtones|Electronic|IDM/Experimental', 4324 8157 => 'Tones|Ringtones|Electronic|Industrial', 4325 8158 => 'Tones|Ringtones|Fitness & Workout', 4326 8159 => 'Tones|Ringtones|Folk', 4327 8160 => 'Tones|Ringtones|Hip-Hop/Rap|Alternative Rap', 4328 8161 => 'Tones|Ringtones|Hip-Hop/Rap|Chinese Hip-Hop', 4329 8162 => 'Tones|Ringtones|Hip-Hop/Rap|Dirty South', 4330 8163 => 'Tones|Ringtones|Hip-Hop/Rap|East Coast Rap', 4331 8164 => 'Tones|Ringtones|Hip-Hop/Rap|Gangsta Rap', 4332 8165 => 'Tones|Ringtones|Hip-Hop/Rap|Hardcore Rap', 4333 8166 => 'Tones|Ringtones|Hip-Hop/Rap|Hip-Hop', 4334 8167 => 'Tones|Ringtones|Hip-Hop/Rap|Korean Hip-Hop', 4335 8168 => 'Tones|Ringtones|Hip-Hop/Rap|Latin Rap', 4336 8169 => 'Tones|Ringtones|Hip-Hop/Rap|Old School Rap', 4337 8170 => 'Tones|Ringtones|Hip-Hop/Rap|Rap', 4338 8171 => 'Tones|Ringtones|Hip-Hop/Rap|Underground Rap', 4339 8172 => 'Tones|Ringtones|Hip-Hop/Rap|West Coast Rap', 4340 8173 => 'Tones|Ringtones|Holiday|Chanukah', 4341 8174 => 'Tones|Ringtones|Holiday|Christmas', 4342 8175 => "Tones|Ringtones|Holiday|Christmas: Children's", 4343 8176 => 'Tones|Ringtones|Holiday|Christmas: Classic', 4344 8177 => 'Tones|Ringtones|Holiday|Christmas: Classical', 4345 8178 => 'Tones|Ringtones|Holiday|Christmas: Jazz', 4346 8179 => 'Tones|Ringtones|Holiday|Christmas: Modern', 4347 8180 => 'Tones|Ringtones|Holiday|Christmas: Pop', 4348 8181 => 'Tones|Ringtones|Holiday|Christmas: R&B', 4349 8182 => 'Tones|Ringtones|Holiday|Christmas: Religious', 4350 8183 => 'Tones|Ringtones|Holiday|Christmas: Rock', 4351 8184 => 'Tones|Ringtones|Holiday|Easter', 4352 8185 => 'Tones|Ringtones|Holiday|Halloween', 4353 8186 => 'Tones|Ringtones|Holiday|Thanksgiving', 4354 8187 => 'Tones|Ringtones|Indian', 4355 8188 => 'Tones|Ringtones|Indian|Bollywood', 4356 8189 => 'Tones|Ringtones|Indian|Devotional & Spiritual', 4357 8190 => 'Tones|Ringtones|Indian|Ghazals', 4358 8191 => 'Tones|Ringtones|Indian|Indian Classical', 4359 8192 => 'Tones|Ringtones|Indian|Indian Folk', 4360 8193 => 'Tones|Ringtones|Indian|Indian Pop', 4361 8194 => 'Tones|Ringtones|Indian|Regional Indian', 4362 8195 => 'Tones|Ringtones|Indian|Sufi', 4363 8196 => 'Tones|Ringtones|Indian|Regional Indian|Tamil', 4364 8197 => 'Tones|Ringtones|Indian|Regional Indian|Telugu', 4365 8198 => 'Tones|Ringtones|Instrumental', 4366 8199 => 'Tones|Ringtones|Jazz|Avant-Garde Jazz', 4367 8201 => 'Tones|Ringtones|Jazz|Big Band', 4368 8202 => 'Tones|Ringtones|Jazz|Bop', 4369 8203 => 'Tones|Ringtones|Jazz|Contemporary Jazz', 4370 8204 => 'Tones|Ringtones|Jazz|Cool Jazz', 4371 8205 => 'Tones|Ringtones|Jazz|Crossover Jazz', 4372 8206 => 'Tones|Ringtones|Jazz|Dixieland', 4373 8207 => 'Tones|Ringtones|Jazz|Fusion', 4374 8208 => 'Tones|Ringtones|Jazz|Hard Bop', 4375 8209 => 'Tones|Ringtones|Jazz|Latin Jazz', 4376 8210 => 'Tones|Ringtones|Jazz|Mainstream Jazz', 4377 8211 => 'Tones|Ringtones|Jazz|Ragtime', 4378 8212 => 'Tones|Ringtones|Jazz|Smooth Jazz', 4379 8213 => 'Tones|Ringtones|Jazz|Trad Jazz', 4380 8214 => 'Tones|Ringtones|Pop|K-Pop', 4381 8215 => 'Tones|Ringtones|Karaoke', 4382 8216 => 'Tones|Ringtones|Korean', 4383 8217 => 'Tones|Ringtones|Korean|Korean Classical', 4384 8218 => 'Tones|Ringtones|Korean|Korean Trad Instrumental', 4385 8219 => 'Tones|Ringtones|Korean|Korean Trad Song', 4386 8220 => 'Tones|Ringtones|Korean|Korean Trad Theater', 4387 8221 => 'Tones|Ringtones|Latin|Alternative & Rock in Spanish', 4388 8222 => 'Tones|Ringtones|Latin|Baladas y Boleros', 4389 8223 => 'Tones|Ringtones|Latin|Contemporary Latin', 4390 8224 => 'Tones|Ringtones|Latin|Latin Jazz', 4391 8225 => 'Tones|Ringtones|Latin|Latin Urban', 4392 8226 => 'Tones|Ringtones|Latin|Pop in Spanish', 4393 8227 => 'Tones|Ringtones|Latin|Raices', 4394 8228 => 'Tones|Ringtones|Latin|Musica Mexicana', # (Música Mexicana) 4395 8229 => 'Tones|Ringtones|Latin|Salsa y Tropical', 4396 8230 => 'Tones|Ringtones|Marching Bands', 4397 8231 => 'Tones|Ringtones|New Age|Healing', 4398 8232 => 'Tones|Ringtones|New Age|Meditation', 4399 8233 => 'Tones|Ringtones|New Age|Nature', 4400 8234 => 'Tones|Ringtones|New Age|Relaxation', 4401 8235 => 'Tones|Ringtones|New Age|Travel', 4402 8236 => 'Tones|Ringtones|Orchestral', 4403 8237 => 'Tones|Ringtones|Pop|Adult Contemporary', 4404 8238 => 'Tones|Ringtones|Pop|Britpop', 4405 8239 => 'Tones|Ringtones|Pop|C-Pop', 4406 8240 => 'Tones|Ringtones|Pop|Cantopop/HK-Pop', 4407 8241 => 'Tones|Ringtones|Pop|Indo Pop', 4408 8242 => 'Tones|Ringtones|Pop|Korean Folk-Pop', 4409 8243 => 'Tones|Ringtones|Pop|Malaysian Pop', 4410 8244 => 'Tones|Ringtones|Pop|Mandopop', 4411 8245 => 'Tones|Ringtones|Pop|Manilla Sound', 4412 8246 => 'Tones|Ringtones|Pop|Oldies', 4413 8247 => 'Tones|Ringtones|Pop|Original Pilipino Music', 4414 8248 => 'Tones|Ringtones|Pop|Pinoy Pop', 4415 8249 => 'Tones|Ringtones|Pop|Pop/Rock', 4416 8250 => 'Tones|Ringtones|Pop|Soft Rock', 4417 8251 => 'Tones|Ringtones|Pop|Tai-Pop', 4418 8252 => 'Tones|Ringtones|Pop|Teen Pop', 4419 8253 => 'Tones|Ringtones|Pop|Thai Pop', 4420 8254 => 'Tones|Ringtones|R&B/Soul|Contemporary R&B', 4421 8255 => 'Tones|Ringtones|R&B/Soul|Disco', 4422 8256 => 'Tones|Ringtones|R&B/Soul|Doo Wop', 4423 8257 => 'Tones|Ringtones|R&B/Soul|Funk', 4424 8258 => 'Tones|Ringtones|R&B/Soul|Motown', 4425 8259 => 'Tones|Ringtones|R&B/Soul|Neo-Soul', 4426 8260 => 'Tones|Ringtones|R&B/Soul|Soul', 4427 8261 => 'Tones|Ringtones|Reggae|Modern Dancehall', 4428 8262 => 'Tones|Ringtones|Reggae|Dub', 4429 8263 => 'Tones|Ringtones|Reggae|Roots Reggae', 4430 8264 => 'Tones|Ringtones|Reggae|Ska', 4431 8265 => 'Tones|Ringtones|Rock|Adult Alternative', 4432 8266 => 'Tones|Ringtones|Rock|American Trad Rock', 4433 8267 => 'Tones|Ringtones|Rock|Arena Rock', 4434 8268 => 'Tones|Ringtones|Rock|Blues-Rock', 4435 8269 => 'Tones|Ringtones|Rock|British Invasion', 4436 8270 => 'Tones|Ringtones|Rock|Chinese Rock', 4437 8271 => 'Tones|Ringtones|Rock|Death Metal/Black Metal', 4438 8272 => 'Tones|Ringtones|Rock|Glam Rock', 4439 8273 => 'Tones|Ringtones|Rock|Hair Metal', 4440 8274 => 'Tones|Ringtones|Rock|Hard Rock', 4441 8275 => 'Tones|Ringtones|Rock|Metal', 4442 8276 => 'Tones|Ringtones|Rock|Jam Bands', 4443 8277 => 'Tones|Ringtones|Rock|Korean Rock', 4444 8278 => 'Tones|Ringtones|Rock|Prog-Rock/Art Rock', 4445 8279 => 'Tones|Ringtones|Rock|Psychedelic', 4446 8280 => 'Tones|Ringtones|Rock|Rock & Roll', 4447 8281 => 'Tones|Ringtones|Rock|Rockabilly', 4448 8282 => 'Tones|Ringtones|Rock|Roots Rock', 4449 8283 => 'Tones|Ringtones|Rock|Singer/Songwriter', 4450 8284 => 'Tones|Ringtones|Rock|Southern Rock', 4451 8285 => 'Tones|Ringtones|Rock|Surf', 4452 8286 => 'Tones|Ringtones|Rock|Tex-Mex', 4453 8287 => 'Tones|Ringtones|Singer/Songwriter|Alternative Folk', 4454 8288 => 'Tones|Ringtones|Singer/Songwriter|Contemporary Folk', 4455 8289 => 'Tones|Ringtones|Singer/Songwriter|Contemporary Singer/Songwriter', 4456 8290 => 'Tones|Ringtones|Singer/Songwriter|Folk-Rock', 4457 8291 => 'Tones|Ringtones|Singer/Songwriter|New Acoustic', 4458 8292 => 'Tones|Ringtones|Singer/Songwriter|Traditional Folk', 4459 8293 => 'Tones|Ringtones|Soundtrack|Foreign Cinema', 4460 8294 => 'Tones|Ringtones|Soundtrack|Musicals', 4461 8295 => 'Tones|Ringtones|Soundtrack|Original Score', 4462 8296 => 'Tones|Ringtones|Soundtrack|Sound Effects', 4463 8297 => 'Tones|Ringtones|Soundtrack|Soundtrack', 4464 8298 => 'Tones|Ringtones|Soundtrack|TV Soundtrack', 4465 8299 => 'Tones|Ringtones|Vocal|Standards', 4466 8300 => 'Tones|Ringtones|Vocal|Traditional Pop', 4467 8301 => 'Tones|Ringtones|Vocal|Trot', 4468 8302 => 'Tones|Ringtones|Jazz|Vocal Jazz', 4469 8303 => 'Tones|Ringtones|Vocal|Vocal Pop', 4470 8304 => 'Tones|Ringtones|African', 4471 8305 => 'Tones|Ringtones|African|Afrikaans', 4472 8306 => 'Tones|Ringtones|African|Afro-Beat', 4473 8307 => 'Tones|Ringtones|African|Afro-Pop', 4474 8308 => 'Tones|Ringtones|Turkish|Arabesque', 4475 8309 => 'Tones|Ringtones|World|Asia', 4476 8310 => 'Tones|Ringtones|World|Australia', 4477 8311 => 'Tones|Ringtones|World|Cajun', 4478 8312 => 'Tones|Ringtones|World|Calypso', 4479 8313 => 'Tones|Ringtones|World|Caribbean', 4480 8314 => 'Tones|Ringtones|World|Celtic', 4481 8315 => 'Tones|Ringtones|World|Celtic Folk', 4482 8316 => 'Tones|Ringtones|World|Contemporary Celtic', 4483 8317 => 'Tones|Ringtones|World|Dangdut', 4484 8318 => 'Tones|Ringtones|World|Dini', 4485 8319 => 'Tones|Ringtones|World|Europe', 4486 8320 => 'Tones|Ringtones|World|Fado', 4487 8321 => 'Tones|Ringtones|World|Farsi', 4488 8322 => 'Tones|Ringtones|World|Flamenco', 4489 8323 => 'Tones|Ringtones|World|France', 4490 8324 => 'Tones|Ringtones|Turkish|Halk', 4491 8325 => 'Tones|Ringtones|World|Hawaii', 4492 8326 => 'Tones|Ringtones|World|Iberia', 4493 8327 => 'Tones|Ringtones|World|Indonesian Religious', 4494 8328 => 'Tones|Ringtones|World|Israeli', 4495 8329 => 'Tones|Ringtones|World|Japan', 4496 8330 => 'Tones|Ringtones|World|Klezmer', 4497 8331 => 'Tones|Ringtones|World|North America', 4498 8332 => 'Tones|Ringtones|World|Polka', 4499 8333 => 'Tones|Ringtones|Russian', 4500 8334 => 'Tones|Ringtones|Russian|Russian Chanson', 4501 8335 => 'Tones|Ringtones|Turkish|Sanat', 4502 8336 => 'Tones|Ringtones|World|Soca', 4503 8337 => 'Tones|Ringtones|World|South Africa', 4504 8338 => 'Tones|Ringtones|World|South America', 4505 8339 => 'Tones|Ringtones|World|Tango', 4506 8340 => 'Tones|Ringtones|World|Traditional Celtic', 4507 8341 => 'Tones|Ringtones|Turkish', 4508 8342 => 'Tones|Ringtones|World|Worldbeat', 4509 8343 => 'Tones|Ringtones|World|Zydeco', 4510 8345 => 'Tones|Ringtones|Classical|Art Song', 4511 8346 => 'Tones|Ringtones|Classical|Brass & Woodwinds', 4512 8347 => 'Tones|Ringtones|Classical|Solo Instrumental', 4513 8348 => 'Tones|Ringtones|Classical|Contemporary Era', 4514 8349 => 'Tones|Ringtones|Classical|Oratorio', 4515 8350 => 'Tones|Ringtones|Classical|Cantata', 4516 8351 => 'Tones|Ringtones|Classical|Electronic', 4517 8352 => 'Tones|Ringtones|Classical|Sacred', 4518 8353 => 'Tones|Ringtones|Classical|Guitar', 4519 8354 => 'Tones|Ringtones|Classical|Piano', 4520 8355 => 'Tones|Ringtones|Classical|Violin', 4521 8356 => 'Tones|Ringtones|Classical|Cello', 4522 8357 => 'Tones|Ringtones|Classical|Percussion', 4523 8358 => 'Tones|Ringtones|Electronic|Dubstep', 4524 8359 => 'Tones|Ringtones|Electronic|Bass', 4525 8360 => 'Tones|Ringtones|Hip-Hop/Rap|UK Hip Hop', 4526 8361 => 'Tones|Ringtones|Reggae|Lovers Rock', 4527 8362 => 'Tones|Ringtones|Alternative|EMO', 4528 8363 => 'Tones|Ringtones|Alternative|Pop Punk', 4529 8364 => 'Tones|Ringtones|Alternative|Indie Pop', 4530 8365 => 'Tones|Ringtones|New Age|Yoga', 4531 8366 => 'Tones|Ringtones|Pop|Tribute', 4532 8367 => 'Tones|Ringtones|Pop|Shows', 4533 8368 => 'Tones|Ringtones|Cuban', 4534 8369 => 'Tones|Ringtones|Cuban|Mambo', 4535 8370 => 'Tones|Ringtones|Cuban|Chachacha', 4536 8371 => 'Tones|Ringtones|Cuban|Guajira', 4537 8372 => 'Tones|Ringtones|Cuban|Son', 4538 8373 => 'Tones|Ringtones|Cuban|Bolero', 4539 8374 => 'Tones|Ringtones|Cuban|Guaracha', 4540 8375 => 'Tones|Ringtones|Cuban|Timba', 4541 8376 => 'Tones|Ringtones|Soundtrack|Video Game', 4542 8377 => 'Tones|Ringtones|Indian|Regional Indian|Punjabi|Punjabi Pop', 4543 8378 => 'Tones|Ringtones|Indian|Regional Indian|Bengali|Rabindra Sangeet', 4544 8379 => 'Tones|Ringtones|Indian|Regional Indian|Malayalam', 4545 8380 => 'Tones|Ringtones|Indian|Regional Indian|Kannada', 4546 8381 => 'Tones|Ringtones|Indian|Regional Indian|Marathi', 4547 8382 => 'Tones|Ringtones|Indian|Regional Indian|Gujarati', 4548 8383 => 'Tones|Ringtones|Indian|Regional Indian|Assamese', 4549 8384 => 'Tones|Ringtones|Indian|Regional Indian|Bhojpuri', 4550 8385 => 'Tones|Ringtones|Indian|Regional Indian|Haryanvi', 4551 8386 => 'Tones|Ringtones|Indian|Regional Indian|Odia', 4552 8387 => 'Tones|Ringtones|Indian|Regional Indian|Rajasthani', 4553 8388 => 'Tones|Ringtones|Indian|Regional Indian|Urdu', 4554 8389 => 'Tones|Ringtones|Indian|Regional Indian|Punjabi', 4555 8390 => 'Tones|Ringtones|Indian|Regional Indian|Bengali', 4556 8391 => 'Tones|Ringtones|Indian|Indian Classical|Carnatic Classical', 4557 8392 => 'Tones|Ringtones|Indian|Indian Classical|Hindustani Classical', 4558 8393 => 'Tones|Ringtones|African|Afro House', 4559 8394 => 'Tones|Ringtones|African|Afro Soul', 4560 8395 => 'Tones|Ringtones|African|Afrobeats', 4561 8396 => 'Tones|Ringtones|African|Benga', 4562 8397 => 'Tones|Ringtones|African|Bongo-Flava', 4563 8398 => 'Tones|Ringtones|African|Coupe-Decale', 4564 8399 => 'Tones|Ringtones|African|Gqom', 4565 8400 => 'Tones|Ringtones|African|Highlife', 4566 8401 => 'Tones|Ringtones|African|Kuduro', 4567 8402 => 'Tones|Ringtones|African|Kizomba', 4568 8403 => 'Tones|Ringtones|African|Kwaito', 4569 8404 => 'Tones|Ringtones|African|Mbalax', 4570 8405 => 'Tones|Ringtones|African|Ndombolo', 4571 8406 => 'Tones|Ringtones|African|Shangaan Electro', 4572 8407 => 'Tones|Ringtones|African|Soukous', 4573 8408 => 'Tones|Ringtones|African|Taarab', 4574 8409 => 'Tones|Ringtones|African|Zouglou', 4575 8410 => 'Tones|Ringtones|Turkish|Ozgun', 4576 8411 => 'Tones|Ringtones|Turkish|Fantezi', 4577 8412 => 'Tones|Ringtones|Turkish|Religious', 4578 8413 => 'Tones|Ringtones|Pop|Turkish Pop', 4579 8414 => 'Tones|Ringtones|Rock|Turkish Rock', 4580 8415 => 'Tones|Ringtones|Alternative|Turkish Alternative', 4581 8416 => 'Tones|Ringtones|Hip-Hop/Rap|Turkish Hip-Hop/Rap', 4582 8417 => 'Tones|Ringtones|African|Maskandi', 4583 8418 => 'Tones|Ringtones|Russian|Russian Romance', 4584 8419 => 'Tones|Ringtones|Russian|Russian Bard', 4585 8420 => 'Tones|Ringtones|Russian|Russian Pop', 4586 8421 => 'Tones|Ringtones|Russian|Russian Rock', 4587 8422 => 'Tones|Ringtones|Russian|Russian Hip-Hop', 4588 8423 => 'Tones|Ringtones|Arabic|Levant', 4589 8424 => 'Tones|Ringtones|Arabic|Levant|Dabke', 4590 8425 => 'Tones|Ringtones|Arabic|Maghreb Rai', 4591 8426 => 'Tones|Ringtones|Arabic|Khaleeji|Khaleeji Jalsat', 4592 8427 => 'Tones|Ringtones|Arabic|Khaleeji|Khaleeji Shailat', 4593 8428 => 'Tones|Ringtones|Tarab', 4594 8429 => 'Tones|Ringtones|Tarab|Iraqi Tarab', 4595 8430 => 'Tones|Ringtones|Tarab|Egyptian Tarab', 4596 8431 => 'Tones|Ringtones|Tarab|Khaleeji Tarab', 4597 8432 => 'Tones|Ringtones|Pop|Levant Pop', 4598 8433 => 'Tones|Ringtones|Pop|Iraqi Pop', 4599 8434 => 'Tones|Ringtones|Pop|Egyptian Pop', 4600 8435 => 'Tones|Ringtones|Pop|Maghreb Pop', 4601 8436 => 'Tones|Ringtones|Pop|Khaleeji Pop', 4602 8437 => 'Tones|Ringtones|Hip-Hop/Rap|Levant Hip-Hop', 4603 8438 => 'Tones|Ringtones|Hip-Hop/Rap|Egyptian Hip-Hop', 4604 8439 => 'Tones|Ringtones|Hip-Hop/Rap|Maghreb Hip-Hop', 4605 8440 => 'Tones|Ringtones|Hip-Hop/Rap|Khaleeji Hip-Hop', 4606 8441 => 'Tones|Ringtones|Alternative|Indie Levant', 4607 8442 => 'Tones|Ringtones|Alternative|Indie Egyptian', 4608 8443 => 'Tones|Ringtones|Alternative|Indie Maghreb', 4609 8444 => 'Tones|Ringtones|Electronic|Levant Electronic', 4610 8445 => "Tones|Ringtones|Electronic|Electro-Cha'abi", 4611 8446 => 'Tones|Ringtones|Electronic|Maghreb Electronic', 4612 8447 => 'Tones|Ringtones|Folk|Iraqi Folk', 4613 8448 => 'Tones|Ringtones|Folk|Khaleeji Folk', 4614 8449 => 'Tones|Ringtones|Dance|Maghreb Dance', 4615 9002 => 'Books|Nonfiction', 4616 9003 => 'Books|Romance', 4617 9004 => 'Books|Travel & Adventure', 4618 9007 => 'Books|Arts & Entertainment', 4619 9008 => 'Books|Biographies & Memoirs', 4620 9009 => 'Books|Business & Personal Finance', 4621 9010 => 'Books|Children & Teens', 4622 9012 => 'Books|Humor', 4623 9015 => 'Books|History', 4624 9018 => 'Books|Religion & Spirituality', 4625 9019 => 'Books|Science & Nature', 4626 9020 => 'Books|Sci-Fi & Fantasy', 4627 9024 => 'Books|Lifestyle & Home', 4628 9025 => 'Books|Self-Development', 4629 9026 => 'Books|Comics & Graphic Novels', 4630 9027 => 'Books|Computers & Internet', 4631 9028 => 'Books|Cookbooks, Food & Wine', 4632 9029 => 'Books|Professional & Technical', 4633 9030 => 'Books|Parenting', 4634 9031 => 'Books|Fiction & Literature', 4635 9032 => 'Books|Mysteries & Thrillers', 4636 9033 => 'Books|Reference', 4637 9034 => 'Books|Politics & Current Events', 4638 9035 => 'Books|Sports & Outdoors', 4639 10001 => 'Books|Lifestyle & Home|Antiques & Collectibles', 4640 10002 => 'Books|Arts & Entertainment|Art & Architecture', 4641 10003 => 'Books|Religion & Spirituality|Bibles', 4642 10004 => 'Books|Self-Development|Spirituality', 4643 10005 => 'Books|Business & Personal Finance|Industries & Professions', 4644 10006 => 'Books|Business & Personal Finance|Marketing & Sales', 4645 10007 => 'Books|Business & Personal Finance|Small Business & Entrepreneurship', 4646 10008 => 'Books|Business & Personal Finance|Personal Finance', 4647 10009 => 'Books|Business & Personal Finance|Reference', 4648 10010 => 'Books|Business & Personal Finance|Careers', 4649 10011 => 'Books|Business & Personal Finance|Economics', 4650 10012 => 'Books|Business & Personal Finance|Investing', 4651 10013 => 'Books|Business & Personal Finance|Finance', 4652 10014 => 'Books|Business & Personal Finance|Management & Leadership', 4653 10015 => 'Books|Comics & Graphic Novels|Graphic Novels', 4654 10016 => 'Books|Comics & Graphic Novels|Manga', 4655 10017 => 'Books|Computers & Internet|Computers', 4656 10018 => 'Books|Computers & Internet|Databases', 4657 10019 => 'Books|Computers & Internet|Digital Media', 4658 10020 => 'Books|Computers & Internet|Internet', 4659 10021 => 'Books|Computers & Internet|Network', 4660 10022 => 'Books|Computers & Internet|Operating Systems', 4661 10023 => 'Books|Computers & Internet|Programming', 4662 10024 => 'Books|Computers & Internet|Software', 4663 10025 => 'Books|Computers & Internet|System Administration', 4664 10026 => 'Books|Cookbooks, Food & Wine|Beverages', 4665 10027 => 'Books|Cookbooks, Food & Wine|Courses & Dishes', 4666 10028 => 'Books|Cookbooks, Food & Wine|Special Diet', 4667 10029 => 'Books|Cookbooks, Food & Wine|Special Occasions', 4668 10030 => 'Books|Cookbooks, Food & Wine|Methods', 4669 10031 => 'Books|Cookbooks, Food & Wine|Reference', 4670 10032 => 'Books|Cookbooks, Food & Wine|Regional & Ethnic', 4671 10033 => 'Books|Cookbooks, Food & Wine|Specific Ingredients', 4672 10034 => 'Books|Lifestyle & Home|Crafts & Hobbies', 4673 10035 => 'Books|Professional & Technical|Design', 4674 10036 => 'Books|Arts & Entertainment|Theater', 4675 10037 => 'Books|Professional & Technical|Education', 4676 10038 => 'Books|Nonfiction|Family & Relationships', 4677 10039 => 'Books|Fiction & Literature|Action & Adventure', 4678 10040 => 'Books|Fiction & Literature|African American', 4679 10041 => 'Books|Fiction & Literature|Religious', 4680 10042 => 'Books|Fiction & Literature|Classics', 4681 10043 => 'Books|Fiction & Literature|Erotica', 4682 10044 => 'Books|Sci-Fi & Fantasy|Fantasy', 4683 10045 => 'Books|Fiction & Literature|Gay', 4684 10046 => 'Books|Fiction & Literature|Ghost', 4685 10047 => 'Books|Fiction & Literature|Historical', 4686 10048 => 'Books|Fiction & Literature|Horror', 4687 10049 => 'Books|Fiction & Literature|Literary', 4688 10050 => 'Books|Mysteries & Thrillers|Hard-Boiled', 4689 10051 => 'Books|Mysteries & Thrillers|Historical', 4690 10052 => 'Books|Mysteries & Thrillers|Police Procedural', 4691 10053 => 'Books|Mysteries & Thrillers|Short Stories', 4692 10054 => 'Books|Mysteries & Thrillers|British Detectives', 4693 10055 => 'Books|Mysteries & Thrillers|Women Sleuths', 4694 10056 => 'Books|Romance|Erotic Romance', 4695 10057 => 'Books|Romance|Contemporary', 4696 10058 => 'Books|Romance|Paranormal', 4697 10059 => 'Books|Romance|Historical', 4698 10060 => 'Books|Romance|Short Stories', 4699 10061 => 'Books|Romance|Suspense', 4700 10062 => 'Books|Romance|Western', 4701 10063 => 'Books|Sci-Fi & Fantasy|Science Fiction', 4702 10064 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature', 4703 10065 => 'Books|Fiction & Literature|Short Stories', 4704 10066 => 'Books|Reference|Foreign Languages', 4705 10067 => 'Books|Arts & Entertainment|Games', 4706 10068 => 'Books|Lifestyle & Home|Gardening', 4707 10069 => 'Books|Self-Development|Health & Fitness', 4708 10070 => 'Books|History|Africa', 4709 10071 => 'Books|History|Americas', 4710 10072 => 'Books|History|Ancient', 4711 10073 => 'Books|History|Asia', 4712 10074 => 'Books|History|Australia & Oceania', 4713 10075 => 'Books|History|Europe', 4714 10076 => 'Books|History|Latin America', 4715 10077 => 'Books|History|Middle East', 4716 10078 => 'Books|History|Military', 4717 10079 => 'Books|History|United States', 4718 10080 => 'Books|History|World', 4719 10081 => "Books|Children & Teens|Children's Fiction", 4720 10082 => "Books|Children & Teens|Children's Nonfiction", 4721 10083 => 'Books|Professional & Technical|Law', 4722 10084 => 'Books|Fiction & Literature|Literary Criticism', 4723 10085 => 'Books|Science & Nature|Mathematics', 4724 10086 => 'Books|Professional & Technical|Medical', 4725 10087 => 'Books|Arts & Entertainment|Music', 4726 10088 => 'Books|Science & Nature|Nature', 4727 10089 => 'Books|Arts & Entertainment|Performing Arts', 4728 10090 => 'Books|Lifestyle & Home|Pets', 4729 10091 => 'Books|Nonfiction|Philosophy', 4730 10092 => 'Books|Arts & Entertainment|Photography', 4731 10093 => 'Books|Fiction & Literature|Poetry', 4732 10094 => 'Books|Self-Development|Psychology', 4733 10095 => 'Books|Reference|Almanacs & Yearbooks', 4734 10096 => 'Books|Reference|Atlases & Maps', 4735 10097 => 'Books|Reference|Catalogs & Directories', 4736 10098 => 'Books|Reference|Consumer Guides', 4737 10099 => 'Books|Reference|Dictionaries & Thesauruses', 4738 10100 => 'Books|Reference|Encyclopedias', 4739 10101 => 'Books|Reference|Etiquette', 4740 10102 => 'Books|Reference|Quotations', 4741 10103 => 'Books|Reference|Words & Language', 4742 10104 => 'Books|Reference|Writing', 4743 10105 => 'Books|Religion & Spirituality|Bible Studies', 4744 10106 => 'Books|Religion & Spirituality|Buddhism', 4745 10107 => 'Books|Religion & Spirituality|Christianity', 4746 10108 => 'Books|Religion & Spirituality|Hinduism', 4747 10109 => 'Books|Religion & Spirituality|Islam', 4748 10110 => 'Books|Religion & Spirituality|Judaism', 4749 10111 => 'Books|Science & Nature|Astronomy', 4750 10112 => 'Books|Science & Nature|Chemistry', 4751 10113 => 'Books|Science & Nature|Earth Sciences', 4752 10114 => 'Books|Science & Nature|Essays', 4753 10115 => 'Books|Science & Nature|History', 4754 10116 => 'Books|Science & Nature|Life Sciences', 4755 10117 => 'Books|Science & Nature|Physics', 4756 10118 => 'Books|Science & Nature|Reference', 4757 10119 => 'Books|Self-Development|Self-Improvement', 4758 10120 => 'Books|Nonfiction|Social Science', 4759 10121 => 'Books|Sports & Outdoors|Baseball', 4760 10122 => 'Books|Sports & Outdoors|Basketball', 4761 10123 => 'Books|Sports & Outdoors|Coaching', 4762 10124 => 'Books|Sports & Outdoors|Extreme Sports', 4763 10125 => 'Books|Sports & Outdoors|Football', 4764 10126 => 'Books|Sports & Outdoors|Golf', 4765 10127 => 'Books|Sports & Outdoors|Hockey', 4766 10128 => 'Books|Sports & Outdoors|Mountaineering', 4767 10129 => 'Books|Sports & Outdoors|Outdoors', 4768 10130 => 'Books|Sports & Outdoors|Racket Sports', 4769 10131 => 'Books|Sports & Outdoors|Reference', 4770 10132 => 'Books|Sports & Outdoors|Soccer', 4771 10133 => 'Books|Sports & Outdoors|Training', 4772 10134 => 'Books|Sports & Outdoors|Water Sports', 4773 10135 => 'Books|Sports & Outdoors|Winter Sports', 4774 10136 => 'Books|Reference|Study Aids', 4775 10137 => 'Books|Professional & Technical|Engineering', 4776 10138 => 'Books|Nonfiction|Transportation', 4777 10139 => 'Books|Travel & Adventure|Africa', 4778 10140 => 'Books|Travel & Adventure|Asia', 4779 10141 => 'Books|Travel & Adventure|Specialty Travel', 4780 10142 => 'Books|Travel & Adventure|Canada', 4781 10143 => 'Books|Travel & Adventure|Caribbean', 4782 10144 => 'Books|Travel & Adventure|Latin America', 4783 10145 => 'Books|Travel & Adventure|Essays & Memoirs', 4784 10146 => 'Books|Travel & Adventure|Europe', 4785 10147 => 'Books|Travel & Adventure|Middle East', 4786 10148 => 'Books|Travel & Adventure|United States', 4787 10149 => 'Books|Nonfiction|True Crime', 4788 11001 => 'Books|Sci-Fi & Fantasy|Fantasy|Contemporary', 4789 11002 => 'Books|Sci-Fi & Fantasy|Fantasy|Epic', 4790 11003 => 'Books|Sci-Fi & Fantasy|Fantasy|Historical', 4791 11004 => 'Books|Sci-Fi & Fantasy|Fantasy|Paranormal', 4792 11005 => 'Books|Sci-Fi & Fantasy|Fantasy|Short Stories', 4793 11006 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|Adventure', 4794 11007 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|High Tech', 4795 11008 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|Short Stories', 4796 11009 => 'Books|Professional & Technical|Education|Language Arts & Disciplines', 4797 11010 => 'Books|Communications & Media', 4798 11011 => 'Books|Communications & Media|Broadcasting', 4799 11012 => 'Books|Communications & Media|Digital Media', 4800 11013 => 'Books|Communications & Media|Journalism', 4801 11014 => 'Books|Communications & Media|Photojournalism', 4802 11015 => 'Books|Communications & Media|Print', 4803 11016 => 'Books|Communications & Media|Speech', 4804 11017 => 'Books|Communications & Media|Writing', 4805 11018 => 'Books|Arts & Entertainment|Art & Architecture|Urban Planning', 4806 11019 => 'Books|Arts & Entertainment|Dance', 4807 11020 => 'Books|Arts & Entertainment|Fashion', 4808 11021 => 'Books|Arts & Entertainment|Film', 4809 11022 => 'Books|Arts & Entertainment|Interior Design', 4810 11023 => 'Books|Arts & Entertainment|Media Arts', 4811 11024 => 'Books|Arts & Entertainment|Radio', 4812 11025 => 'Books|Arts & Entertainment|TV', 4813 11026 => 'Books|Arts & Entertainment|Visual Arts', 4814 11027 => 'Books|Biographies & Memoirs|Arts & Entertainment', 4815 11028 => 'Books|Biographies & Memoirs|Business', 4816 11029 => 'Books|Biographies & Memoirs|Culinary', 4817 11030 => 'Books|Biographies & Memoirs|Gay & Lesbian', 4818 11031 => 'Books|Biographies & Memoirs|Historical', 4819 11032 => 'Books|Biographies & Memoirs|Literary', 4820 11033 => 'Books|Biographies & Memoirs|Media & Journalism', 4821 11034 => 'Books|Biographies & Memoirs|Military', 4822 11035 => 'Books|Biographies & Memoirs|Politics', 4823 11036 => 'Books|Biographies & Memoirs|Religious', 4824 11037 => 'Books|Biographies & Memoirs|Science & Technology', 4825 11038 => 'Books|Biographies & Memoirs|Sports', 4826 11039 => 'Books|Biographies & Memoirs|Women', 4827 11040 => 'Books|Romance|New Adult', 4828 11042 => 'Books|Romance|Romantic Comedy', 4829 11043 => 'Books|Romance|Gay & Lesbian', 4830 11044 => 'Books|Fiction & Literature|Essays', 4831 11045 => 'Books|Fiction & Literature|Anthologies', 4832 11046 => 'Books|Fiction & Literature|Comparative Literature', 4833 11047 => 'Books|Fiction & Literature|Drama', 4834 11049 => 'Books|Fiction & Literature|Fairy Tales, Myths & Fables', 4835 11050 => 'Books|Fiction & Literature|Family', 4836 11051 => 'Books|Comics & Graphic Novels|Manga|School Drama', 4837 11052 => 'Books|Comics & Graphic Novels|Manga|Human Drama', 4838 11053 => 'Books|Comics & Graphic Novels|Manga|Family Drama', 4839 11054 => 'Books|Sports & Outdoors|Boxing', 4840 11055 => 'Books|Sports & Outdoors|Cricket', 4841 11056 => 'Books|Sports & Outdoors|Cycling', 4842 11057 => 'Books|Sports & Outdoors|Equestrian', 4843 11058 => 'Books|Sports & Outdoors|Martial Arts & Self Defense', 4844 11059 => 'Books|Sports & Outdoors|Motor Sports', 4845 11060 => 'Books|Sports & Outdoors|Rugby', 4846 11061 => 'Books|Sports & Outdoors|Running', 4847 11062 => 'Books|Self-Development|Diet & Nutrition', 4848 11063 => 'Books|Science & Nature|Agriculture', 4849 11064 => 'Books|Science & Nature|Atmosphere', 4850 11065 => 'Books|Science & Nature|Biology', 4851 11066 => 'Books|Science & Nature|Ecology', 4852 11067 => 'Books|Science & Nature|Environment', 4853 11068 => 'Books|Science & Nature|Geography', 4854 11069 => 'Books|Science & Nature|Geology', 4855 11070 => 'Books|Nonfiction|Social Science|Anthropology', 4856 11071 => 'Books|Nonfiction|Social Science|Archaeology', 4857 11072 => 'Books|Nonfiction|Social Science|Civics', 4858 11073 => 'Books|Nonfiction|Social Science|Government', 4859 11074 => 'Books|Nonfiction|Social Science|Social Studies', 4860 11075 => 'Books|Nonfiction|Social Science|Social Welfare', 4861 11076 => 'Books|Nonfiction|Social Science|Society', 4862 11077 => 'Books|Nonfiction|Philosophy|Aesthetics', 4863 11078 => 'Books|Nonfiction|Philosophy|Epistemology', 4864 11079 => 'Books|Nonfiction|Philosophy|Ethics', 4865 11080 => 'Books|Nonfiction|Philosophy|Language', 4866 11081 => 'Books|Nonfiction|Philosophy|Logic', 4867 11082 => 'Books|Nonfiction|Philosophy|Metaphysics', 4868 11083 => 'Books|Nonfiction|Philosophy|Political', 4869 11084 => 'Books|Nonfiction|Philosophy|Religion', 4870 11085 => 'Books|Reference|Manuals', 4871 11086 => 'Books|Kids', 4872 11087 => 'Books|Kids|Animals', 4873 11088 => 'Books|Kids|Basic Concepts', 4874 11089 => 'Books|Kids|Basic Concepts|Alphabet', 4875 11090 => 'Books|Kids|Basic Concepts|Body', 4876 11091 => 'Books|Kids|Basic Concepts|Colors', 4877 11092 => 'Books|Kids|Basic Concepts|Counting & Numbers', 4878 11093 => 'Books|Kids|Basic Concepts|Date & Time', 4879 11094 => 'Books|Kids|Basic Concepts|General', 4880 11095 => 'Books|Kids|Basic Concepts|Money', 4881 11096 => 'Books|Kids|Basic Concepts|Opposites', 4882 11097 => 'Books|Kids|Basic Concepts|Seasons', 4883 11098 => 'Books|Kids|Basic Concepts|Senses & Sensation', 4884 11099 => 'Books|Kids|Basic Concepts|Size & Shape', 4885 11100 => 'Books|Kids|Basic Concepts|Sounds', 4886 11101 => 'Books|Kids|Basic Concepts|Words', 4887 11102 => 'Books|Kids|Biography', 4888 11103 => 'Books|Kids|Careers & Occupations', 4889 11104 => 'Books|Kids|Computers & Technology', 4890 11105 => 'Books|Kids|Cooking & Food', 4891 11106 => 'Books|Kids|Arts & Entertainment', 4892 11107 => 'Books|Kids|Arts & Entertainment|Art', 4893 11108 => 'Books|Kids|Arts & Entertainment|Crafts', 4894 11109 => 'Books|Kids|Arts & Entertainment|Music', 4895 11110 => 'Books|Kids|Arts & Entertainment|Performing Arts', 4896 11111 => 'Books|Kids|Family', 4897 11112 => 'Books|Kids|Fiction', 4898 11113 => 'Books|Kids|Fiction|Action & Adventure', 4899 11114 => 'Books|Kids|Fiction|Animals', 4900 11115 => 'Books|Kids|Fiction|Classics', 4901 11116 => 'Books|Kids|Fiction|Comics & Graphic Novels', 4902 11117 => 'Books|Kids|Fiction|Culture, Places & People', 4903 11118 => 'Books|Kids|Fiction|Family & Relationships', 4904 11119 => 'Books|Kids|Fiction|Fantasy', 4905 11120 => 'Books|Kids|Fiction|Fairy Tales, Myths & Fables', 4906 11121 => 'Books|Kids|Fiction|Favorite Characters', 4907 11122 => 'Books|Kids|Fiction|Historical', 4908 11123 => 'Books|Kids|Fiction|Holidays & Celebrations', 4909 11124 => 'Books|Kids|Fiction|Monsters & Ghosts', 4910 11125 => 'Books|Kids|Fiction|Mysteries', 4911 11126 => 'Books|Kids|Fiction|Nature', 4912 11127 => 'Books|Kids|Fiction|Religion', 4913 11128 => 'Books|Kids|Fiction|Sci-Fi', 4914 11129 => 'Books|Kids|Fiction|Social Issues', 4915 11130 => 'Books|Kids|Fiction|Sports & Recreation', 4916 11131 => 'Books|Kids|Fiction|Transportation', 4917 11132 => 'Books|Kids|Games & Activities', 4918 11133 => 'Books|Kids|General Nonfiction', 4919 11134 => 'Books|Kids|Health', 4920 11135 => 'Books|Kids|History', 4921 11136 => 'Books|Kids|Holidays & Celebrations', 4922 11137 => 'Books|Kids|Holidays & Celebrations|Birthdays', 4923 11138 => 'Books|Kids|Holidays & Celebrations|Christmas & Advent', 4924 11139 => 'Books|Kids|Holidays & Celebrations|Easter & Lent', 4925 11140 => 'Books|Kids|Holidays & Celebrations|General', 4926 11141 => 'Books|Kids|Holidays & Celebrations|Halloween', 4927 11142 => 'Books|Kids|Holidays & Celebrations|Hanukkah', 4928 11143 => 'Books|Kids|Holidays & Celebrations|Other', 4929 11144 => 'Books|Kids|Holidays & Celebrations|Passover', 4930 11145 => 'Books|Kids|Holidays & Celebrations|Patriotic Holidays', 4931 11146 => 'Books|Kids|Holidays & Celebrations|Ramadan', 4932 11147 => 'Books|Kids|Holidays & Celebrations|Thanksgiving', 4933 11148 => "Books|Kids|Holidays & Celebrations|Valentine's Day", 4934 11149 => 'Books|Kids|Humor', 4935 11150 => 'Books|Kids|Humor|Jokes & Riddles', 4936 11151 => 'Books|Kids|Poetry', 4937 11152 => 'Books|Kids|Learning to Read', 4938 11153 => 'Books|Kids|Learning to Read|Chapter Books', 4939 11154 => 'Books|Kids|Learning to Read|Early Readers', 4940 11155 => 'Books|Kids|Learning to Read|Intermediate Readers', 4941 11156 => 'Books|Kids|Nursery Rhymes', 4942 11157 => 'Books|Kids|Government', 4943 11158 => 'Books|Kids|Reference', 4944 11159 => 'Books|Kids|Religion', 4945 11160 => 'Books|Kids|Science & Nature', 4946 11161 => 'Books|Kids|Social Issues', 4947 11162 => 'Books|Kids|Social Studies', 4948 11163 => 'Books|Kids|Sports & Recreation', 4949 11164 => 'Books|Kids|Transportation', 4950 11165 => 'Books|Young Adult', 4951 11166 => 'Books|Young Adult|Animals', 4952 11167 => 'Books|Young Adult|Biography', 4953 11168 => 'Books|Young Adult|Careers & Occupations', 4954 11169 => 'Books|Young Adult|Computers & Technology', 4955 11170 => 'Books|Young Adult|Cooking & Food', 4956 11171 => 'Books|Young Adult|Arts & Entertainment', 4957 11172 => 'Books|Young Adult|Arts & Entertainment|Art', 4958 11173 => 'Books|Young Adult|Arts & Entertainment|Crafts', 4959 11174 => 'Books|Young Adult|Arts & Entertainment|Music', 4960 11175 => 'Books|Young Adult|Arts & Entertainment|Performing Arts', 4961 11176 => 'Books|Young Adult|Family', 4962 11177 => 'Books|Young Adult|Fiction', 4963 11178 => 'Books|Young Adult|Fiction|Action & Adventure', 4964 11179 => 'Books|Young Adult|Fiction|Animals', 4965 11180 => 'Books|Young Adult|Fiction|Classics', 4966 11181 => 'Books|Young Adult|Fiction|Comics & Graphic Novels', 4967 11182 => 'Books|Young Adult|Fiction|Culture, Places & People', 4968 11183 => 'Books|Young Adult|Fiction|Dystopian', 4969 11184 => 'Books|Young Adult|Fiction|Family & Relationships', 4970 11185 => 'Books|Young Adult|Fiction|Fantasy', 4971 11186 => 'Books|Young Adult|Fiction|Fairy Tales, Myths & Fables', 4972 11187 => 'Books|Young Adult|Fiction|Favorite Characters', 4973 11188 => 'Books|Young Adult|Fiction|Historical', 4974 11189 => 'Books|Young Adult|Fiction|Holidays & Celebrations', 4975 11190 => 'Books|Young Adult|Fiction|Horror, Monsters & Ghosts', 4976 11191 => 'Books|Young Adult|Fiction|Crime & Mystery', 4977 11192 => 'Books|Young Adult|Fiction|Nature', 4978 11193 => 'Books|Young Adult|Fiction|Religion', 4979 11194 => 'Books|Young Adult|Fiction|Romance', 4980 11195 => 'Books|Young Adult|Fiction|Sci-Fi', 4981 11196 => 'Books|Young Adult|Fiction|Coming of Age', 4982 11197 => 'Books|Young Adult|Fiction|Sports & Recreation', 4983 11198 => 'Books|Young Adult|Fiction|Transportation', 4984 11199 => 'Books|Young Adult|Games & Activities', 4985 11200 => 'Books|Young Adult|General Nonfiction', 4986 11201 => 'Books|Young Adult|Health', 4987 11202 => 'Books|Young Adult|History', 4988 11203 => 'Books|Young Adult|Holidays & Celebrations', 4989 11204 => 'Books|Young Adult|Holidays & Celebrations|Birthdays', 4990 11205 => 'Books|Young Adult|Holidays & Celebrations|Christmas & Advent', 4991 11206 => 'Books|Young Adult|Holidays & Celebrations|Easter & Lent', 4992 11207 => 'Books|Young Adult|Holidays & Celebrations|General', 4993 11208 => 'Books|Young Adult|Holidays & Celebrations|Halloween', 4994 11209 => 'Books|Young Adult|Holidays & Celebrations|Hanukkah', 4995 11210 => 'Books|Young Adult|Holidays & Celebrations|Other', 4996 11211 => 'Books|Young Adult|Holidays & Celebrations|Passover', 4997 11212 => 'Books|Young Adult|Holidays & Celebrations|Patriotic Holidays', 4998 11213 => 'Books|Young Adult|Holidays & Celebrations|Ramadan', 4999 11214 => 'Books|Young Adult|Holidays & Celebrations|Thanksgiving', 5000 11215 => "Books|Young Adult|Holidays & Celebrations|Valentine's Day", 5001 11216 => 'Books|Young Adult|Humor', 5002 11217 => 'Books|Young Adult|Humor|Jokes & Riddles', 5003 11218 => 'Books|Young Adult|Poetry', 5004 11219 => 'Books|Young Adult|Politics & Government', 5005 11220 => 'Books|Young Adult|Reference', 5006 11221 => 'Books|Young Adult|Religion', 5007 11222 => 'Books|Young Adult|Science & Nature', 5008 11223 => 'Books|Young Adult|Coming of Age', 5009 11224 => 'Books|Young Adult|Social Studies', 5010 11225 => 'Books|Young Adult|Sports & Recreation', 5011 11226 => 'Books|Young Adult|Transportation', 5012 11227 => 'Books|Communications & Media', 5013 11228 => 'Books|Military & Warfare', 5014 11229 => 'Books|Romance|Inspirational', 5015 11231 => 'Books|Romance|Holiday', 5016 11232 => 'Books|Romance|Wholesome', 5017 11233 => 'Books|Romance|Military', 5018 11234 => 'Books|Arts & Entertainment|Art History', 5019 11236 => 'Books|Arts & Entertainment|Design', 5020 11243 => 'Books|Business & Personal Finance|Accounting', 5021 11244 => 'Books|Business & Personal Finance|Hospitality', 5022 11245 => 'Books|Business & Personal Finance|Real Estate', 5023 11246 => 'Books|Humor|Jokes & Riddles', 5024 11247 => 'Books|Religion & Spirituality|Comparative Religion', 5025 11255 => 'Books|Cookbooks, Food & Wine|Culinary Arts', 5026 11259 => 'Books|Mysteries & Thrillers|Cozy', 5027 11260 => 'Books|Politics & Current Events|Current Events', 5028 11261 => 'Books|Politics & Current Events|Foreign Policy & International Relations', 5029 11262 => 'Books|Politics & Current Events|Local Government', 5030 11263 => 'Books|Politics & Current Events|National Government', 5031 11264 => 'Books|Politics & Current Events|Political Science', 5032 11265 => 'Books|Politics & Current Events|Public Administration', 5033 11266 => 'Books|Politics & Current Events|World Affairs', 5034 11273 => 'Books|Nonfiction|Family & Relationships|Family & Childcare', 5035 11274 => 'Books|Nonfiction|Family & Relationships|Love & Romance', 5036 11275 => 'Books|Sci-Fi & Fantasy|Fantasy|Urban', 5037 11276 => 'Books|Reference|Foreign Languages|Arabic', 5038 11277 => 'Books|Reference|Foreign Languages|Bilingual Editions', 5039 11278 => 'Books|Reference|Foreign Languages|African Languages', 5040 11279 => 'Books|Reference|Foreign Languages|Ancient Languages', 5041 11280 => 'Books|Reference|Foreign Languages|Chinese', 5042 11281 => 'Books|Reference|Foreign Languages|English', 5043 11282 => 'Books|Reference|Foreign Languages|French', 5044 11283 => 'Books|Reference|Foreign Languages|German', 5045 11284 => 'Books|Reference|Foreign Languages|Hebrew', 5046 11285 => 'Books|Reference|Foreign Languages|Hindi', 5047 11286 => 'Books|Reference|Foreign Languages|Italian', 5048 11287 => 'Books|Reference|Foreign Languages|Japanese', 5049 11288 => 'Books|Reference|Foreign Languages|Korean', 5050 11289 => 'Books|Reference|Foreign Languages|Linguistics', 5051 11290 => 'Books|Reference|Foreign Languages|Other Languages', 5052 11291 => 'Books|Reference|Foreign Languages|Portuguese', 5053 11292 => 'Books|Reference|Foreign Languages|Russian', 5054 11293 => 'Books|Reference|Foreign Languages|Spanish', 5055 11294 => 'Books|Reference|Foreign Languages|Speech Pathology', 5056 11295 => 'Books|Science & Nature|Mathematics|Advanced Mathematics', 5057 11296 => 'Books|Science & Nature|Mathematics|Algebra', 5058 11297 => 'Books|Science & Nature|Mathematics|Arithmetic', 5059 11298 => 'Books|Science & Nature|Mathematics|Calculus', 5060 11299 => 'Books|Science & Nature|Mathematics|Geometry', 5061 11300 => 'Books|Science & Nature|Mathematics|Statistics', 5062 11301 => 'Books|Professional & Technical|Medical|Veterinary', 5063 11302 => 'Books|Professional & Technical|Medical|Neuroscience', 5064 11303 => 'Books|Professional & Technical|Medical|Immunology', 5065 11304 => 'Books|Professional & Technical|Medical|Nursing', 5066 11305 => 'Books|Professional & Technical|Medical|Pharmacology & Toxicology', 5067 11306 => 'Books|Professional & Technical|Medical|Anatomy & Physiology', 5068 11307 => 'Books|Professional & Technical|Medical|Dentistry', 5069 11308 => 'Books|Professional & Technical|Medical|Emergency Medicine', 5070 11309 => 'Books|Professional & Technical|Medical|Genetics', 5071 11310 => 'Books|Professional & Technical|Medical|Psychiatry', 5072 11311 => 'Books|Professional & Technical|Medical|Radiology', 5073 11312 => 'Books|Professional & Technical|Medical|Alternative Medicine', 5074 11317 => 'Books|Nonfiction|Philosophy|Political Philosophy', 5075 11319 => 'Books|Nonfiction|Philosophy|Philosophy of Language', 5076 11320 => 'Books|Nonfiction|Philosophy|Philosophy of Religion', 5077 11327 => 'Books|Nonfiction|Social Science|Sociology', 5078 11329 => 'Books|Professional & Technical|Engineering|Aeronautics', 5079 11330 => 'Books|Professional & Technical|Engineering|Chemical & Petroleum Engineering', 5080 11331 => 'Books|Professional & Technical|Engineering|Civil Engineering', 5081 11332 => 'Books|Professional & Technical|Engineering|Computer Science', 5082 11333 => 'Books|Professional & Technical|Engineering|Electrical Engineering', 5083 11334 => 'Books|Professional & Technical|Engineering|Environmental Engineering', 5084 11335 => 'Books|Professional & Technical|Engineering|Mechanical Engineering', 5085 11336 => 'Books|Professional & Technical|Engineering|Power Resources', 5086 11337 => 'Books|Comics & Graphic Novels|Manga|Boys', 5087 11338 => 'Books|Comics & Graphic Novels|Manga|Men', 5088 11339 => 'Books|Comics & Graphic Novels|Manga|Girls', 5089 11340 => 'Books|Comics & Graphic Novels|Manga|Women', 5090 11341 => 'Books|Comics & Graphic Novels|Manga|Other', 5091 11342 => 'Books|Comics & Graphic Novels|Manga|Yaoi', 5092 11343 => 'Books|Comics & Graphic Novels|Manga|Comic Essays', 5093 12001 => 'Mac App Store|Business', 5094 12002 => 'Mac App Store|Developer Tools', 5095 12003 => 'Mac App Store|Education', 5096 12004 => 'Mac App Store|Entertainment', 5097 12005 => 'Mac App Store|Finance', 5098 12006 => 'Mac App Store|Games', 5099 12007 => 'Mac App Store|Health & Fitness', 5100 12008 => 'Mac App Store|Lifestyle', 5101 12010 => 'Mac App Store|Medical', 5102 12011 => 'Mac App Store|Music', 5103 12012 => 'Mac App Store|News', 5104 12013 => 'Mac App Store|Photography', 5105 12014 => 'Mac App Store|Productivity', 5106 12015 => 'Mac App Store|Reference', 5107 12016 => 'Mac App Store|Social Networking', 5108 12017 => 'Mac App Store|Sports', 5109 12018 => 'Mac App Store|Travel', 5110 12019 => 'Mac App Store|Utilities', 5111 12020 => 'Mac App Store|Video', 5112 12021 => 'Mac App Store|Weather', 5113 12022 => 'Mac App Store|Graphics & Design', 5114 12201 => 'Mac App Store|Games|Action', 5115 12202 => 'Mac App Store|Games|Adventure', 5116 12203 => 'Mac App Store|Games|Casual', 5117 12204 => 'Mac App Store|Games|Board', 5118 12205 => 'Mac App Store|Games|Card', 5119 12206 => 'Mac App Store|Games|Casino', 5120 12207 => 'Mac App Store|Games|Dice', 5121 12208 => 'Mac App Store|Games|Educational', 5122 12209 => 'Mac App Store|Games|Family', 5123 12210 => 'Mac App Store|Games|Kids', 5124 12211 => 'Mac App Store|Games|Music', 5125 12212 => 'Mac App Store|Games|Puzzle', 5126 12213 => 'Mac App Store|Games|Racing', 5127 12214 => 'Mac App Store|Games|Role Playing', 5128 12215 => 'Mac App Store|Games|Simulation', 5129 12216 => 'Mac App Store|Games|Sports', 5130 12217 => 'Mac App Store|Games|Strategy', 5131 12218 => 'Mac App Store|Games|Trivia', 5132 12219 => 'Mac App Store|Games|Word', 5133 13001 => 'App Store|Magazines & Newspapers|News & Politics', 5134 13002 => 'App Store|Magazines & Newspapers|Fashion & Style', 5135 13003 => 'App Store|Magazines & Newspapers|Home & Garden', 5136 13004 => 'App Store|Magazines & Newspapers|Outdoors & Nature', 5137 13005 => 'App Store|Magazines & Newspapers|Sports & Leisure', 5138 13006 => 'App Store|Magazines & Newspapers|Automotive', 5139 13007 => 'App Store|Magazines & Newspapers|Arts & Photography', 5140 13008 => 'App Store|Magazines & Newspapers|Brides & Weddings', 5141 13009 => 'App Store|Magazines & Newspapers|Business & Investing', 5142 13010 => "App Store|Magazines & Newspapers|Children's Magazines", 5143 13011 => 'App Store|Magazines & Newspapers|Computers & Internet', 5144 13012 => 'App Store|Magazines & Newspapers|Cooking, Food & Drink', 5145 13013 => 'App Store|Magazines & Newspapers|Crafts & Hobbies', 5146 13014 => 'App Store|Magazines & Newspapers|Electronics & Audio', 5147 13015 => 'App Store|Magazines & Newspapers|Entertainment', 5148 13017 => 'App Store|Magazines & Newspapers|Health, Mind & Body', 5149 13018 => 'App Store|Magazines & Newspapers|History', 5150 13019 => 'App Store|Magazines & Newspapers|Literary Magazines & Journals', 5151 13020 => "App Store|Magazines & Newspapers|Men's Interest", 5152 13021 => 'App Store|Magazines & Newspapers|Movies & Music', 5153 13023 => 'App Store|Magazines & Newspapers|Parenting & Family', 5154 13024 => 'App Store|Magazines & Newspapers|Pets', 5155 13025 => 'App Store|Magazines & Newspapers|Professional & Trade', 5156 13026 => 'App Store|Magazines & Newspapers|Regional News', 5157 13027 => 'App Store|Magazines & Newspapers|Science', 5158 13028 => 'App Store|Magazines & Newspapers|Teens', 5159 13029 => 'App Store|Magazines & Newspapers|Travel & Regional', 5160 13030 => "App Store|Magazines & Newspapers|Women's Interest", 5161 15000 => 'Textbooks|Arts & Entertainment', 5162 15001 => 'Textbooks|Arts & Entertainment|Art & Architecture', 5163 15002 => 'Textbooks|Arts & Entertainment|Art & Architecture|Urban Planning', 5164 15003 => 'Textbooks|Arts & Entertainment|Art History', 5165 15004 => 'Textbooks|Arts & Entertainment|Dance', 5166 15005 => 'Textbooks|Arts & Entertainment|Design', 5167 15006 => 'Textbooks|Arts & Entertainment|Fashion', 5168 15007 => 'Textbooks|Arts & Entertainment|Film', 5169 15008 => 'Textbooks|Arts & Entertainment|Games', 5170 15009 => 'Textbooks|Arts & Entertainment|Interior Design', 5171 15010 => 'Textbooks|Arts & Entertainment|Media Arts', 5172 15011 => 'Textbooks|Arts & Entertainment|Music', 5173 15012 => 'Textbooks|Arts & Entertainment|Performing Arts', 5174 15013 => 'Textbooks|Arts & Entertainment|Photography', 5175 15014 => 'Textbooks|Arts & Entertainment|Theater', 5176 15015 => 'Textbooks|Arts & Entertainment|TV', 5177 15016 => 'Textbooks|Arts & Entertainment|Visual Arts', 5178 15017 => 'Textbooks|Biographies & Memoirs', 5179 15018 => 'Textbooks|Business & Personal Finance', 5180 15019 => 'Textbooks|Business & Personal Finance|Accounting', 5181 15020 => 'Textbooks|Business & Personal Finance|Careers', 5182 15021 => 'Textbooks|Business & Personal Finance|Economics', 5183 15022 => 'Textbooks|Business & Personal Finance|Finance', 5184 15023 => 'Textbooks|Business & Personal Finance|Hospitality', 5185 15024 => 'Textbooks|Business & Personal Finance|Industries & Professions', 5186 15025 => 'Textbooks|Business & Personal Finance|Investing', 5187 15026 => 'Textbooks|Business & Personal Finance|Management & Leadership', 5188 15027 => 'Textbooks|Business & Personal Finance|Marketing & Sales', 5189 15028 => 'Textbooks|Business & Personal Finance|Personal Finance', 5190 15029 => 'Textbooks|Business & Personal Finance|Real Estate', 5191 15030 => 'Textbooks|Business & Personal Finance|Reference', 5192 15031 => 'Textbooks|Business & Personal Finance|Small Business & Entrepreneurship', 5193 15032 => 'Textbooks|Children & Teens', 5194 15033 => 'Textbooks|Children & Teens|Fiction', 5195 15034 => 'Textbooks|Children & Teens|Nonfiction', 5196 15035 => 'Textbooks|Comics & Graphic Novels', 5197 15036 => 'Textbooks|Comics & Graphic Novels|Graphic Novels', 5198 15037 => 'Textbooks|Comics & Graphic Novels|Manga', 5199 15038 => 'Textbooks|Communications & Media', 5200 15039 => 'Textbooks|Communications & Media|Broadcasting', 5201 15040 => 'Textbooks|Communications & Media|Digital Media', 5202 15041 => 'Textbooks|Communications & Media|Journalism', 5203 15042 => 'Textbooks|Communications & Media|Photojournalism', 5204 15043 => 'Textbooks|Communications & Media|Print', 5205 15044 => 'Textbooks|Communications & Media|Speech', 5206 15045 => 'Textbooks|Communications & Media|Writing', 5207 15046 => 'Textbooks|Computers & Internet', 5208 15047 => 'Textbooks|Computers & Internet|Computers', 5209 15048 => 'Textbooks|Computers & Internet|Databases', 5210 15049 => 'Textbooks|Computers & Internet|Digital Media', 5211 15050 => 'Textbooks|Computers & Internet|Internet', 5212 15051 => 'Textbooks|Computers & Internet|Network', 5213 15052 => 'Textbooks|Computers & Internet|Operating Systems', 5214 15053 => 'Textbooks|Computers & Internet|Programming', 5215 15054 => 'Textbooks|Computers & Internet|Software', 5216 15055 => 'Textbooks|Computers & Internet|System Administration', 5217 15056 => 'Textbooks|Cookbooks, Food & Wine', 5218 15057 => 'Textbooks|Cookbooks, Food & Wine|Beverages', 5219 15058 => 'Textbooks|Cookbooks, Food & Wine|Courses & Dishes', 5220 15059 => 'Textbooks|Cookbooks, Food & Wine|Culinary Arts', 5221 15060 => 'Textbooks|Cookbooks, Food & Wine|Methods', 5222 15061 => 'Textbooks|Cookbooks, Food & Wine|Reference', 5223 15062 => 'Textbooks|Cookbooks, Food & Wine|Regional & Ethnic', 5224 15063 => 'Textbooks|Cookbooks, Food & Wine|Special Diet', 5225 15064 => 'Textbooks|Cookbooks, Food & Wine|Special Occasions', 5226 15065 => 'Textbooks|Cookbooks, Food & Wine|Specific Ingredients', 5227 15066 => 'Textbooks|Engineering', 5228 15067 => 'Textbooks|Engineering|Aeronautics', 5229 15068 => 'Textbooks|Engineering|Chemical & Petroleum Engineering', 5230 15069 => 'Textbooks|Engineering|Civil Engineering', 5231 15070 => 'Textbooks|Engineering|Computer Science', 5232 15071 => 'Textbooks|Engineering|Electrical Engineering', 5233 15072 => 'Textbooks|Engineering|Environmental Engineering', 5234 15073 => 'Textbooks|Engineering|Mechanical Engineering', 5235 15074 => 'Textbooks|Engineering|Power Resources', 5236 15075 => 'Textbooks|Fiction & Literature', 5237 15076 => 'Textbooks|Fiction & Literature|Latino', 5238 15077 => 'Textbooks|Fiction & Literature|Action & Adventure', 5239 15078 => 'Textbooks|Fiction & Literature|African American', 5240 15079 => 'Textbooks|Fiction & Literature|Anthologies', 5241 15080 => 'Textbooks|Fiction & Literature|Classics', 5242 15081 => 'Textbooks|Fiction & Literature|Comparative Literature', 5243 15082 => 'Textbooks|Fiction & Literature|Erotica', 5244 15083 => 'Textbooks|Fiction & Literature|Gay', 5245 15084 => 'Textbooks|Fiction & Literature|Ghost', 5246 15085 => 'Textbooks|Fiction & Literature|Historical', 5247 15086 => 'Textbooks|Fiction & Literature|Horror', 5248 15087 => 'Textbooks|Fiction & Literature|Literary', 5249 15088 => 'Textbooks|Fiction & Literature|Literary Criticism', 5250 15089 => 'Textbooks|Fiction & Literature|Poetry', 5251 15090 => 'Textbooks|Fiction & Literature|Religious', 5252 15091 => 'Textbooks|Fiction & Literature|Short Stories', 5253 15092 => 'Textbooks|Health, Mind & Body', 5254 15093 => 'Textbooks|Health, Mind & Body|Fitness', 5255 15094 => 'Textbooks|Health, Mind & Body|Self-Improvement', 5256 15095 => 'Textbooks|History', 5257 15096 => 'Textbooks|History|Africa', 5258 15097 => 'Textbooks|History|Americas', 5259 15098 => 'Textbooks|History|Americas|Canada', 5260 15099 => 'Textbooks|History|Americas|Latin America', 5261 15100 => 'Textbooks|History|Americas|United States', 5262 15101 => 'Textbooks|History|Ancient', 5263 15102 => 'Textbooks|History|Asia', 5264 15103 => 'Textbooks|History|Australia & Oceania', 5265 15104 => 'Textbooks|History|Europe', 5266 15105 => 'Textbooks|History|Middle East', 5267 15106 => 'Textbooks|History|Military', 5268 15107 => 'Textbooks|History|World', 5269 15108 => 'Textbooks|Humor', 5270 15109 => 'Textbooks|Language Studies', 5271 15110 => 'Textbooks|Language Studies|African Languages', 5272 15111 => 'Textbooks|Language Studies|Ancient Languages', 5273 15112 => 'Textbooks|Language Studies|Arabic', 5274 15113 => 'Textbooks|Language Studies|Bilingual Editions', 5275 15114 => 'Textbooks|Language Studies|Chinese', 5276 15115 => 'Textbooks|Language Studies|English', 5277 15116 => 'Textbooks|Language Studies|French', 5278 15117 => 'Textbooks|Language Studies|German', 5279 15118 => 'Textbooks|Language Studies|Hebrew', 5280 15119 => 'Textbooks|Language Studies|Hindi', 5281 15120 => 'Textbooks|Language Studies|Indigenous Languages', 5282 15121 => 'Textbooks|Language Studies|Italian', 5283 15122 => 'Textbooks|Language Studies|Japanese', 5284 15123 => 'Textbooks|Language Studies|Korean', 5285 15124 => 'Textbooks|Language Studies|Linguistics', 5286 15125 => 'Textbooks|Language Studies|Other Language', 5287 15126 => 'Textbooks|Language Studies|Portuguese', 5288 15127 => 'Textbooks|Language Studies|Russian', 5289 15128 => 'Textbooks|Language Studies|Spanish', 5290 15129 => 'Textbooks|Language Studies|Speech Pathology', 5291 15130 => 'Textbooks|Lifestyle & Home', 5292 15131 => 'Textbooks|Lifestyle & Home|Antiques & Collectibles', 5293 15132 => 'Textbooks|Lifestyle & Home|Crafts & Hobbies', 5294 15133 => 'Textbooks|Lifestyle & Home|Gardening', 5295 15134 => 'Textbooks|Lifestyle & Home|Pets', 5296 15135 => 'Textbooks|Mathematics', 5297 15136 => 'Textbooks|Mathematics|Advanced Mathematics', 5298 15137 => 'Textbooks|Mathematics|Algebra', 5299 15138 => 'Textbooks|Mathematics|Arithmetic', 5300 15139 => 'Textbooks|Mathematics|Calculus', 5301 15140 => 'Textbooks|Mathematics|Geometry', 5302 15141 => 'Textbooks|Mathematics|Statistics', 5303 15142 => 'Textbooks|Medicine', 5304 15143 => 'Textbooks|Medicine|Anatomy & Physiology', 5305 15144 => 'Textbooks|Medicine|Dentistry', 5306 15145 => 'Textbooks|Medicine|Emergency Medicine', 5307 15146 => 'Textbooks|Medicine|Genetics', 5308 15147 => 'Textbooks|Medicine|Immunology', 5309 15148 => 'Textbooks|Medicine|Neuroscience', 5310 15149 => 'Textbooks|Medicine|Nursing', 5311 15150 => 'Textbooks|Medicine|Pharmacology & Toxicology', 5312 15151 => 'Textbooks|Medicine|Psychiatry', 5313 15152 => 'Textbooks|Medicine|Psychology', 5314 15153 => 'Textbooks|Medicine|Radiology', 5315 15154 => 'Textbooks|Medicine|Veterinary', 5316 15155 => 'Textbooks|Mysteries & Thrillers', 5317 15156 => 'Textbooks|Mysteries & Thrillers|British Detectives', 5318 15157 => 'Textbooks|Mysteries & Thrillers|Hard-Boiled', 5319 15158 => 'Textbooks|Mysteries & Thrillers|Historical', 5320 15159 => 'Textbooks|Mysteries & Thrillers|Police Procedural', 5321 15160 => 'Textbooks|Mysteries & Thrillers|Short Stories', 5322 15161 => 'Textbooks|Mysteries & Thrillers|Women Sleuths', 5323 15162 => 'Textbooks|Nonfiction', 5324 15163 => 'Textbooks|Nonfiction|Family & Relationships', 5325 15164 => 'Textbooks|Nonfiction|Transportation', 5326 15165 => 'Textbooks|Nonfiction|True Crime', 5327 15166 => 'Textbooks|Parenting', 5328 15167 => 'Textbooks|Philosophy', 5329 15168 => 'Textbooks|Philosophy|Aesthetics', 5330 15169 => 'Textbooks|Philosophy|Epistemology', 5331 15170 => 'Textbooks|Philosophy|Ethics', 5332 15171 => 'Textbooks|Philosophy|Philosophy of Language', 5333 15172 => 'Textbooks|Philosophy|Logic', 5334 15173 => 'Textbooks|Philosophy|Metaphysics', 5335 15174 => 'Textbooks|Philosophy|Political Philosophy', 5336 15175 => 'Textbooks|Philosophy|Philosophy of Religion', 5337 15176 => 'Textbooks|Politics & Current Events', 5338 15177 => 'Textbooks|Politics & Current Events|Current Events', 5339 15178 => 'Textbooks|Politics & Current Events|Foreign Policy & International Relations', 5340 15179 => 'Textbooks|Politics & Current Events|Local Governments', 5341 15180 => 'Textbooks|Politics & Current Events|National Governments', 5342 15181 => 'Textbooks|Politics & Current Events|Political Science', 5343 15182 => 'Textbooks|Politics & Current Events|Public Administration', 5344 15183 => 'Textbooks|Politics & Current Events|World Affairs', 5345 15184 => 'Textbooks|Professional & Technical', 5346 15185 => 'Textbooks|Professional & Technical|Design', 5347 15186 => 'Textbooks|Professional & Technical|Language Arts & Disciplines', 5348 15187 => 'Textbooks|Professional & Technical|Engineering', 5349 15188 => 'Textbooks|Professional & Technical|Law', 5350 15189 => 'Textbooks|Professional & Technical|Medical', 5351 15190 => 'Textbooks|Reference', 5352 15191 => 'Textbooks|Reference|Almanacs & Yearbooks', 5353 15192 => 'Textbooks|Reference|Atlases & Maps', 5354 15193 => 'Textbooks|Reference|Catalogs & Directories', 5355 15194 => 'Textbooks|Reference|Consumer Guides', 5356 15195 => 'Textbooks|Reference|Dictionaries & Thesauruses', 5357 15196 => 'Textbooks|Reference|Encyclopedias', 5358 15197 => 'Textbooks|Reference|Etiquette', 5359 15198 => 'Textbooks|Reference|Quotations', 5360 15199 => 'Textbooks|Reference|Study Aids', 5361 15200 => 'Textbooks|Reference|Words & Language', 5362 15201 => 'Textbooks|Reference|Writing', 5363 15202 => 'Textbooks|Religion & Spirituality', 5364 15203 => 'Textbooks|Religion & Spirituality|Bible Studies', 5365 15204 => 'Textbooks|Religion & Spirituality|Bibles', 5366 15205 => 'Textbooks|Religion & Spirituality|Buddhism', 5367 15206 => 'Textbooks|Religion & Spirituality|Christianity', 5368 15207 => 'Textbooks|Religion & Spirituality|Comparative Religion', 5369 15208 => 'Textbooks|Religion & Spirituality|Hinduism', 5370 15209 => 'Textbooks|Religion & Spirituality|Islam', 5371 15210 => 'Textbooks|Religion & Spirituality|Judaism', 5372 15211 => 'Textbooks|Religion & Spirituality|Spirituality', 5373 15212 => 'Textbooks|Romance', 5374 15213 => 'Textbooks|Romance|Contemporary', 5375 15214 => 'Textbooks|Romance|Erotic Romance', 5376 15215 => 'Textbooks|Romance|Paranormal', 5377 15216 => 'Textbooks|Romance|Historical', 5378 15217 => 'Textbooks|Romance|Short Stories', 5379 15218 => 'Textbooks|Romance|Suspense', 5380 15219 => 'Textbooks|Romance|Western', 5381 15220 => 'Textbooks|Sci-Fi & Fantasy', 5382 15221 => 'Textbooks|Sci-Fi & Fantasy|Fantasy', 5383 15222 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Contemporary', 5384 15223 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Epic', 5385 15224 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Historical', 5386 15225 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Paranormal', 5387 15226 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Short Stories', 5388 15227 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction', 5389 15228 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature', 5390 15229 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|Adventure', 5391 15230 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|High Tech', 5392 15231 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|Short Stories', 5393 15232 => 'Textbooks|Science & Nature', 5394 15233 => 'Textbooks|Science & Nature|Agriculture', 5395 15234 => 'Textbooks|Science & Nature|Astronomy', 5396 15235 => 'Textbooks|Science & Nature|Atmosphere', 5397 15236 => 'Textbooks|Science & Nature|Biology', 5398 15237 => 'Textbooks|Science & Nature|Chemistry', 5399 15238 => 'Textbooks|Science & Nature|Earth Sciences', 5400 15239 => 'Textbooks|Science & Nature|Ecology', 5401 15240 => 'Textbooks|Science & Nature|Environment', 5402 15241 => 'Textbooks|Science & Nature|Essays', 5403 15242 => 'Textbooks|Science & Nature|Geography', 5404 15243 => 'Textbooks|Science & Nature|Geology', 5405 15244 => 'Textbooks|Science & Nature|History', 5406 15245 => 'Textbooks|Science & Nature|Life Sciences', 5407 15246 => 'Textbooks|Science & Nature|Nature', 5408 15247 => 'Textbooks|Science & Nature|Physics', 5409 15248 => 'Textbooks|Science & Nature|Reference', 5410 15249 => 'Textbooks|Social Science', 5411 15250 => 'Textbooks|Social Science|Anthropology', 5412 15251 => 'Textbooks|Social Science|Archaeology', 5413 15252 => 'Textbooks|Social Science|Civics', 5414 15253 => 'Textbooks|Social Science|Government', 5415 15254 => 'Textbooks|Social Science|Social Studies', 5416 15255 => 'Textbooks|Social Science|Social Welfare', 5417 15256 => 'Textbooks|Social Science|Society', 5418 15257 => 'Textbooks|Social Science|Society|African Studies', 5419 15258 => 'Textbooks|Social Science|Society|American Studies', 5420 15259 => 'Textbooks|Social Science|Society|Asia Pacific Studies', 5421 15260 => 'Textbooks|Social Science|Society|Cross-Cultural Studies', 5422 15261 => 'Textbooks|Social Science|Society|European Studies', 5423 15262 => 'Textbooks|Social Science|Society|Immigration & Emigration', 5424 15263 => 'Textbooks|Social Science|Society|Indigenous Studies', 5425 15264 => 'Textbooks|Social Science|Society|Latin & Caribbean Studies', 5426 15265 => 'Textbooks|Social Science|Society|Middle Eastern Studies', 5427 15266 => 'Textbooks|Social Science|Society|Race & Ethnicity Studies', 5428 15267 => 'Textbooks|Social Science|Society|Sexuality Studies', 5429 15268 => "Textbooks|Social Science|Society|Women's Studies", 5430 15269 => 'Textbooks|Social Science|Sociology', 5431 15270 => 'Textbooks|Sports & Outdoors', 5432 15271 => 'Textbooks|Sports & Outdoors|Baseball', 5433 15272 => 'Textbooks|Sports & Outdoors|Basketball', 5434 15273 => 'Textbooks|Sports & Outdoors|Coaching', 5435 15274 => 'Textbooks|Sports & Outdoors|Equestrian', 5436 15275 => 'Textbooks|Sports & Outdoors|Extreme Sports', 5437 15276 => 'Textbooks|Sports & Outdoors|Football', 5438 15277 => 'Textbooks|Sports & Outdoors|Golf', 5439 15278 => 'Textbooks|Sports & Outdoors|Hockey', 5440 15279 => 'Textbooks|Sports & Outdoors|Motor Sports', 5441 15280 => 'Textbooks|Sports & Outdoors|Mountaineering', 5442 15281 => 'Textbooks|Sports & Outdoors|Outdoors', 5443 15282 => 'Textbooks|Sports & Outdoors|Racket Sports', 5444 15283 => 'Textbooks|Sports & Outdoors|Reference', 5445 15284 => 'Textbooks|Sports & Outdoors|Soccer', 5446 15285 => 'Textbooks|Sports & Outdoors|Training', 5447 15286 => 'Textbooks|Sports & Outdoors|Water Sports', 5448 15287 => 'Textbooks|Sports & Outdoors|Winter Sports', 5449 15288 => 'Textbooks|Teaching & Learning', 5450 15289 => 'Textbooks|Teaching & Learning|Adult Education', 5451 15290 => 'Textbooks|Teaching & Learning|Curriculum & Teaching', 5452 15291 => 'Textbooks|Teaching & Learning|Educational Leadership', 5453 15292 => 'Textbooks|Teaching & Learning|Educational Technology', 5454 15293 => 'Textbooks|Teaching & Learning|Family & Childcare', 5455 15294 => 'Textbooks|Teaching & Learning|Information & Library Science', 5456 15295 => 'Textbooks|Teaching & Learning|Learning Resources', 5457 15296 => 'Textbooks|Teaching & Learning|Psychology & Research', 5458 15297 => 'Textbooks|Teaching & Learning|Special Education', 5459 15298 => 'Textbooks|Travel & Adventure', 5460 15299 => 'Textbooks|Travel & Adventure|Africa', 5461 15300 => 'Textbooks|Travel & Adventure|Americas', 5462 15301 => 'Textbooks|Travel & Adventure|Americas|Canada', 5463 15302 => 'Textbooks|Travel & Adventure|Americas|Latin America', 5464 15303 => 'Textbooks|Travel & Adventure|Americas|United States', 5465 15304 => 'Textbooks|Travel & Adventure|Asia', 5466 15305 => 'Textbooks|Travel & Adventure|Caribbean', 5467 15306 => 'Textbooks|Travel & Adventure|Essays & Memoirs', 5468 15307 => 'Textbooks|Travel & Adventure|Europe', 5469 15308 => 'Textbooks|Travel & Adventure|Middle East', 5470 15309 => 'Textbooks|Travel & Adventure|Oceania', 5471 15310 => 'Textbooks|Travel & Adventure|Specialty Travel', 5472 15311 => 'Textbooks|Comics & Graphic Novels|Comics', 5473 15312 => 'Textbooks|Reference|Manuals', 5474 16001 => 'App Store|Stickers|Emoji & Expressions', 5475 16003 => 'App Store|Stickers|Animals & Nature', 5476 16005 => 'App Store|Stickers|Art', 5477 16006 => 'App Store|Stickers|Celebrations', 5478 16007 => 'App Store|Stickers|Celebrities', 5479 16008 => 'App Store|Stickers|Comics & Cartoons', 5480 16009 => 'App Store|Stickers|Eating & Drinking', 5481 16010 => 'App Store|Stickers|Gaming', 5482 16014 => 'App Store|Stickers|Movies & TV', 5483 16015 => 'App Store|Stickers|Music', 5484 16017 => 'App Store|Stickers|People', 5485 16019 => 'App Store|Stickers|Places & Objects', 5486 16021 => 'App Store|Stickers|Sports & Activities', 5487 16025 => 'App Store|Stickers|Kids & Family', 5488 16026 => 'App Store|Stickers|Fashion', 5489 100000 => 'Music|Christian & Gospel', 5490 100001 => 'Music|Classical|Art Song', 5491 100002 => 'Music|Classical|Brass & Woodwinds', 5492 100003 => 'Music|Classical|Solo Instrumental', 5493 100004 => 'Music|Classical|Contemporary Era', 5494 100005 => 'Music|Classical|Oratorio', 5495 100006 => 'Music|Classical|Cantata', 5496 100007 => 'Music|Classical|Electronic', 5497 100008 => 'Music|Classical|Sacred', 5498 100009 => 'Music|Classical|Guitar', 5499 100010 => 'Music|Classical|Piano', 5500 100011 => 'Music|Classical|Violin', 5501 100012 => 'Music|Classical|Cello', 5502 100013 => 'Music|Classical|Percussion', 5503 100014 => 'Music|Electronic|Dubstep', 5504 100015 => 'Music|Electronic|Bass', 5505 100016 => 'Music|Hip-Hop/Rap|UK Hip-Hop', 5506 100017 => 'Music|Reggae|Lovers Rock', 5507 100018 => 'Music|Alternative|EMO', 5508 100019 => 'Music|Alternative|Pop Punk', 5509 100020 => 'Music|Alternative|Indie Pop', 5510 100021 => 'Music|New Age|Yoga', 5511 100022 => 'Music|Pop|Tribute', 5512 100023 => 'Music|Pop|Shows', 5513 100024 => 'Music|Cuban', 5514 100025 => 'Music|Cuban|Mambo', 5515 100026 => 'Music|Cuban|Chachacha', 5516 100027 => 'Music|Cuban|Guajira', 5517 100028 => 'Music|Cuban|Son', 5518 100029 => 'Music|Cuban|Bolero', 5519 100030 => 'Music|Cuban|Guaracha', 5520 100031 => 'Music|Cuban|Timba', 5521 100032 => 'Music|Soundtrack|Video Game', 5522 100033 => 'Music|Indian|Regional Indian|Punjabi|Punjabi Pop', 5523 100034 => 'Music|Indian|Regional Indian|Bengali|Rabindra Sangeet', 5524 100035 => 'Music|Indian|Regional Indian|Malayalam', 5525 100036 => 'Music|Indian|Regional Indian|Kannada', 5526 100037 => 'Music|Indian|Regional Indian|Marathi', 5527 100038 => 'Music|Indian|Regional Indian|Gujarati', 5528 100039 => 'Music|Indian|Regional Indian|Assamese', 5529 100040 => 'Music|Indian|Regional Indian|Bhojpuri', 5530 100041 => 'Music|Indian|Regional Indian|Haryanvi', 5531 100042 => 'Music|Indian|Regional Indian|Odia', 5532 100043 => 'Music|Indian|Regional Indian|Rajasthani', 5533 100044 => 'Music|Indian|Regional Indian|Urdu', 5534 100045 => 'Music|Indian|Regional Indian|Punjabi', 5535 100046 => 'Music|Indian|Regional Indian|Bengali', 5536 100047 => 'Music|Indian|Indian Classical|Carnatic Classical', 5537 100048 => 'Music|Indian|Indian Classical|Hindustani Classical', 5538 100049 => 'Music|African|Afro House', 5539 100050 => 'Music|African|Afro Soul', 5540 100051 => 'Music|African|Afrobeats', 5541 100052 => 'Music|African|Benga', 5542 100053 => 'Music|African|Bongo-Flava', 5543 100054 => 'Music|African|Coupe-Decale', 5544 100055 => 'Music|African|Gqom', 5545 100056 => 'Music|African|Highlife', 5546 100057 => 'Music|African|Kuduro', 5547 100058 => 'Music|African|Kizomba', 5548 100059 => 'Music|African|Kwaito', 5549 100060 => 'Music|African|Mbalax', 5550 100061 => 'Music|African|Ndombolo', 5551 100062 => 'Music|African|Shangaan Electro', 5552 100063 => 'Music|African|Soukous', 5553 100064 => 'Music|African|Taarab', 5554 100065 => 'Music|African|Zouglou', 5555 100066 => 'Music|Turkish|Ozgun', 5556 100067 => 'Music|Turkish|Fantezi', 5557 100068 => 'Music|Turkish|Religious', 5558 100069 => 'Music|Pop|Turkish Pop', 5559 100070 => 'Music|Rock|Turkish Rock', 5560 100071 => 'Music|Alternative|Turkish Alternative', 5561 100072 => 'Music|Hip-Hop/Rap|Turkish Hip-Hop/Rap', 5562 100073 => 'Music|African|Maskandi', 5563 100074 => 'Music|Russian|Russian Romance', 5564 100075 => 'Music|Russian|Russian Bard', 5565 100076 => 'Music|Russian|Russian Pop', 5566 100077 => 'Music|Russian|Russian Rock', 5567 100078 => 'Music|Russian|Russian Hip-Hop', 5568 100079 => 'Music|Arabic|Levant', 5569 100080 => 'Music|Arabic|Levant|Dabke', 5570 100081 => 'Music|Arabic|Maghreb Rai', 5571 100082 => 'Music|Arabic|Khaleeji|Khaleeji Jalsat', 5572 100083 => 'Music|Arabic|Khaleeji|Khaleeji Shailat', 5573 100084 => 'Music|Tarab', 5574 100085 => 'Music|Tarab|Iraqi Tarab', 5575 100086 => 'Music|Tarab|Egyptian Tarab', 5576 100087 => 'Music|Tarab|Khaleeji Tarab', 5577 100088 => 'Music|Pop|Levant Pop', 5578 100089 => 'Music|Pop|Iraqi Pop', 5579 100090 => 'Music|Pop|Egyptian Pop', 5580 100091 => 'Music|Pop|Maghreb Pop', 5581 100092 => 'Music|Pop|Khaleeji Pop', 5582 100093 => 'Music|Hip-Hop/Rap|Levant Hip-Hop', 5583 100094 => 'Music|Hip-Hop/Rap|Egyptian Hip-Hop', 5584 100095 => 'Music|Hip-Hop/Rap|Maghreb Hip-Hop', 5585 100096 => 'Music|Hip-Hop/Rap|Khaleeji Hip-Hop', 5586 100097 => 'Music|Alternative|Indie Levant', 5587 100098 => 'Music|Alternative|Indie Egyptian', 5588 100099 => 'Music|Alternative|Indie Maghreb', 5589 100100 => 'Music|Electronic|Levant Electronic', 5590 100101 => "Music|Electronic|Electro-Cha'abi", 5591 100102 => 'Music|Electronic|Maghreb Electronic', 5592 100103 => 'Music|Folk|Iraqi Folk', 5593 100104 => 'Music|Folk|Khaleeji Folk', 5594 100105 => 'Music|Dance|Maghreb Dance', 5595 40000000 => 'iTunes U', 5596 40000001 => 'iTunes U|Business & Economics', 5597 40000002 => 'iTunes U|Business & Economics|Economics', 5598 40000003 => 'iTunes U|Business & Economics|Finance', 5599 40000004 => 'iTunes U|Business & Economics|Hospitality', 5600 40000005 => 'iTunes U|Business & Economics|Management', 5601 40000006 => 'iTunes U|Business & Economics|Marketing', 5602 40000007 => 'iTunes U|Business & Economics|Personal Finance', 5603 40000008 => 'iTunes U|Business & Economics|Real Estate', 5604 40000009 => 'iTunes U|Engineering', 5605 40000010 => 'iTunes U|Engineering|Chemical & Petroleum Engineering', 5606 40000011 => 'iTunes U|Engineering|Civil Engineering', 5607 40000012 => 'iTunes U|Engineering|Computer Science', 5608 40000013 => 'iTunes U|Engineering|Electrical Engineering', 5609 40000014 => 'iTunes U|Engineering|Environmental Engineering', 5610 40000015 => 'iTunes U|Engineering|Mechanical Engineering', 5611 40000016 => 'iTunes U|Music, Art, & Design', 5612 40000017 => 'iTunes U|Music, Art, & Design|Architecture', 5613 40000019 => 'iTunes U|Music, Art, & Design|Art History', 5614 40000020 => 'iTunes U|Music, Art, & Design|Dance', 5615 40000021 => 'iTunes U|Music, Art, & Design|Film', 5616 40000022 => 'iTunes U|Music, Art, & Design|Design', 5617 40000023 => 'iTunes U|Music, Art, & Design|Interior Design', 5618 40000024 => 'iTunes U|Music, Art, & Design|Music', 5619 40000025 => 'iTunes U|Music, Art, & Design|Theater', 5620 40000026 => 'iTunes U|Health & Medicine', 5621 40000027 => 'iTunes U|Health & Medicine|Anatomy & Physiology', 5622 40000028 => 'iTunes U|Health & Medicine|Behavioral Science', 5623 40000029 => 'iTunes U|Health & Medicine|Dentistry', 5624 40000030 => 'iTunes U|Health & Medicine|Diet & Nutrition', 5625 40000031 => 'iTunes U|Health & Medicine|Emergency Medicine', 5626 40000032 => 'iTunes U|Health & Medicine|Genetics', 5627 40000033 => 'iTunes U|Health & Medicine|Gerontology', 5628 40000034 => 'iTunes U|Health & Medicine|Health & Exercise Science', 5629 40000035 => 'iTunes U|Health & Medicine|Immunology', 5630 40000036 => 'iTunes U|Health & Medicine|Neuroscience', 5631 40000037 => 'iTunes U|Health & Medicine|Pharmacology & Toxicology', 5632 40000038 => 'iTunes U|Health & Medicine|Psychiatry', 5633 40000039 => 'iTunes U|Health & Medicine|Global Health', 5634 40000040 => 'iTunes U|Health & Medicine|Radiology', 5635 40000041 => 'iTunes U|History', 5636 40000042 => 'iTunes U|History|Ancient History', 5637 40000043 => 'iTunes U|History|Medieval History', 5638 40000044 => 'iTunes U|History|Military History', 5639 40000045 => 'iTunes U|History|Modern History', 5640 40000046 => 'iTunes U|History|African History', 5641 40000047 => 'iTunes U|History|Asia-Pacific History', 5642 40000048 => 'iTunes U|History|European History', 5643 40000049 => 'iTunes U|History|Middle Eastern History', 5644 40000050 => 'iTunes U|History|North American History', 5645 40000051 => 'iTunes U|History|South American History', 5646 40000053 => 'iTunes U|Communications & Journalism', 5647 40000054 => 'iTunes U|Philosophy', 5648 40000055 => 'iTunes U|Religion & Spirituality', 5649 40000056 => 'iTunes U|Languages', 5650 40000057 => 'iTunes U|Languages|African Languages', 5651 40000058 => 'iTunes U|Languages|Ancient Languages', 5652 40000061 => 'iTunes U|Languages|English', 5653 40000063 => 'iTunes U|Languages|French', 5654 40000064 => 'iTunes U|Languages|German', 5655 40000065 => 'iTunes U|Languages|Italian', 5656 40000066 => 'iTunes U|Languages|Linguistics', 5657 40000068 => 'iTunes U|Languages|Spanish', 5658 40000069 => 'iTunes U|Languages|Speech Pathology', 5659 40000070 => 'iTunes U|Writing & Literature', 5660 40000071 => 'iTunes U|Writing & Literature|Anthologies', 5661 40000072 => 'iTunes U|Writing & Literature|Biography', 5662 40000073 => 'iTunes U|Writing & Literature|Classics', 5663 40000074 => 'iTunes U|Writing & Literature|Literary Criticism', 5664 40000075 => 'iTunes U|Writing & Literature|Fiction', 5665 40000076 => 'iTunes U|Writing & Literature|Poetry', 5666 40000077 => 'iTunes U|Mathematics', 5667 40000078 => 'iTunes U|Mathematics|Advanced Mathematics', 5668 40000079 => 'iTunes U|Mathematics|Algebra', 5669 40000080 => 'iTunes U|Mathematics|Arithmetic', 5670 40000081 => 'iTunes U|Mathematics|Calculus', 5671 40000082 => 'iTunes U|Mathematics|Geometry', 5672 40000083 => 'iTunes U|Mathematics|Statistics', 5673 40000084 => 'iTunes U|Science', 5674 40000085 => 'iTunes U|Science|Agricultural', 5675 40000086 => 'iTunes U|Science|Astronomy', 5676 40000087 => 'iTunes U|Science|Atmosphere', 5677 40000088 => 'iTunes U|Science|Biology', 5678 40000089 => 'iTunes U|Science|Chemistry', 5679 40000090 => 'iTunes U|Science|Ecology', 5680 40000091 => 'iTunes U|Science|Geography', 5681 40000092 => 'iTunes U|Science|Geology', 5682 40000093 => 'iTunes U|Science|Physics', 5683 40000094 => 'iTunes U|Social Science', 5684 40000095 => 'iTunes U|Law & Politics|Law', 5685 40000096 => 'iTunes U|Law & Politics|Political Science', 5686 40000097 => 'iTunes U|Law & Politics|Public Administration', 5687 40000098 => 'iTunes U|Social Science|Psychology', 5688 40000099 => 'iTunes U|Social Science|Social Welfare', 5689 40000100 => 'iTunes U|Social Science|Sociology', 5690 40000101 => 'iTunes U|Society', 5691 40000103 => 'iTunes U|Society|Asia Pacific Studies', 5692 40000104 => 'iTunes U|Society|European Studies', 5693 40000105 => 'iTunes U|Society|Indigenous Studies', 5694 40000106 => 'iTunes U|Society|Latin & Caribbean Studies', 5695 40000107 => 'iTunes U|Society|Middle Eastern Studies', 5696 40000108 => "iTunes U|Society|Women's Studies", 5697 40000109 => 'iTunes U|Teaching & Learning', 5698 40000110 => 'iTunes U|Teaching & Learning|Curriculum & Teaching', 5699 40000111 => 'iTunes U|Teaching & Learning|Educational Leadership', 5700 40000112 => 'iTunes U|Teaching & Learning|Family & Childcare', 5701 40000113 => 'iTunes U|Teaching & Learning|Learning Resources', 5702 40000114 => 'iTunes U|Teaching & Learning|Psychology & Research', 5703 40000115 => 'iTunes U|Teaching & Learning|Special Education', 5704 40000116 => 'iTunes U|Music, Art, & Design|Culinary Arts', 5705 40000117 => 'iTunes U|Music, Art, & Design|Fashion', 5706 40000118 => 'iTunes U|Music, Art, & Design|Media Arts', 5707 40000119 => 'iTunes U|Music, Art, & Design|Photography', 5708 40000120 => 'iTunes U|Music, Art, & Design|Visual Art', 5709 40000121 => 'iTunes U|Business & Economics|Entrepreneurship', 5710 40000122 => 'iTunes U|Communications & Journalism|Broadcasting', 5711 40000123 => 'iTunes U|Communications & Journalism|Digital Media', 5712 40000124 => 'iTunes U|Communications & Journalism|Journalism', 5713 40000125 => 'iTunes U|Communications & Journalism|Photojournalism', 5714 40000126 => 'iTunes U|Communications & Journalism|Print', 5715 40000127 => 'iTunes U|Communications & Journalism|Speech', 5716 40000128 => 'iTunes U|Communications & Journalism|Writing', 5717 40000129 => 'iTunes U|Health & Medicine|Nursing', 5718 40000130 => 'iTunes U|Languages|Arabic', 5719 40000131 => 'iTunes U|Languages|Chinese', 5720 40000132 => 'iTunes U|Languages|Hebrew', 5721 40000133 => 'iTunes U|Languages|Hindi', 5722 40000134 => 'iTunes U|Languages|Indigenous Languages', 5723 40000135 => 'iTunes U|Languages|Japanese', 5724 40000136 => 'iTunes U|Languages|Korean', 5725 40000137 => 'iTunes U|Languages|Other Languages', 5726 40000138 => 'iTunes U|Languages|Portuguese', 5727 40000139 => 'iTunes U|Languages|Russian', 5728 40000140 => 'iTunes U|Law & Politics', 5729 40000141 => 'iTunes U|Law & Politics|Foreign Policy & International Relations', 5730 40000142 => 'iTunes U|Law & Politics|Local Governments', 5731 40000143 => 'iTunes U|Law & Politics|National Governments', 5732 40000144 => 'iTunes U|Law & Politics|World Affairs', 5733 40000145 => 'iTunes U|Writing & Literature|Comparative Literature', 5734 40000146 => 'iTunes U|Philosophy|Aesthetics', 5735 40000147 => 'iTunes U|Philosophy|Epistemology', 5736 40000148 => 'iTunes U|Philosophy|Ethics', 5737 40000149 => 'iTunes U|Philosophy|Metaphysics', 5738 40000150 => 'iTunes U|Philosophy|Political Philosophy', 5739 40000151 => 'iTunes U|Philosophy|Logic', 5740 40000152 => 'iTunes U|Philosophy|Philosophy of Language', 5741 40000153 => 'iTunes U|Philosophy|Philosophy of Religion', 5742 40000154 => 'iTunes U|Social Science|Archaeology', 5743 40000155 => 'iTunes U|Social Science|Anthropology', 5744 40000156 => 'iTunes U|Religion & Spirituality|Buddhism', 5745 40000157 => 'iTunes U|Religion & Spirituality|Christianity', 5746 40000158 => 'iTunes U|Religion & Spirituality|Comparative Religion', 5747 40000159 => 'iTunes U|Religion & Spirituality|Hinduism', 5748 40000160 => 'iTunes U|Religion & Spirituality|Islam', 5749 40000161 => 'iTunes U|Religion & Spirituality|Judaism', 5750 40000162 => 'iTunes U|Religion & Spirituality|Other Religions', 5751 40000163 => 'iTunes U|Religion & Spirituality|Spirituality', 5752 40000164 => 'iTunes U|Science|Environment', 5753 40000165 => 'iTunes U|Society|African Studies', 5754 40000166 => 'iTunes U|Society|American Studies', 5755 40000167 => 'iTunes U|Society|Cross-cultural Studies', 5756 40000168 => 'iTunes U|Society|Immigration & Emigration', 5757 40000169 => 'iTunes U|Society|Race & Ethnicity Studies', 5758 40000170 => 'iTunes U|Society|Sexuality Studies', 5759 40000171 => 'iTunes U|Teaching & Learning|Educational Technology', 5760 40000172 => 'iTunes U|Teaching & Learning|Information/Library Science', 5761 40000173 => 'iTunes U|Languages|Dutch', 5762 40000174 => 'iTunes U|Languages|Luxembourgish', 5763 40000175 => 'iTunes U|Languages|Swedish', 5764 40000176 => 'iTunes U|Languages|Norwegian', 5765 40000177 => 'iTunes U|Languages|Finnish', 5766 40000178 => 'iTunes U|Languages|Danish', 5767 40000179 => 'iTunes U|Languages|Polish', 5768 40000180 => 'iTunes U|Languages|Turkish', 5769 40000181 => 'iTunes U|Languages|Flemish', 5770 50000024 => 'Audiobooks', 5771 50000040 => 'Audiobooks|Fiction', 5772 50000041 => 'Audiobooks|Arts & Entertainment', 5773 50000042 => 'Audiobooks|Biographies & Memoirs', 5774 50000043 => 'Audiobooks|Business & Personal Finance', 5775 50000044 => 'Audiobooks|Kids & Young Adults', 5776 50000045 => 'Audiobooks|Classics', 5777 50000046 => 'Audiobooks|Comedy', 5778 50000047 => 'Audiobooks|Drama & Poetry', 5779 50000048 => 'Audiobooks|Speakers & Storytellers', 5780 50000049 => 'Audiobooks|History', 5781 50000050 => 'Audiobooks|Languages', 5782 50000051 => 'Audiobooks|Mysteries & Thrillers', 5783 50000052 => 'Audiobooks|Nonfiction', 5784 50000053 => 'Audiobooks|Religion & Spirituality', 5785 50000054 => 'Audiobooks|Science & Nature', 5786 50000055 => 'Audiobooks|Sci Fi & Fantasy', 5787 50000056 => 'Audiobooks|Self-Development', 5788 50000057 => 'Audiobooks|Sports & Outdoors', 5789 50000058 => 'Audiobooks|Technology', 5790 50000059 => 'Audiobooks|Travel & Adventure', 5791 50000061 => 'Music|Spoken Word', 5792 50000063 => 'Music|Disney', 5793 50000064 => 'Music|French Pop', 5794 50000066 => 'Music|German Pop', 5795 50000068 => 'Music|German Folk', 5796 50000069 => 'Audiobooks|Romance', 5797 50000070 => 'Audiobooks|Audiobooks Latino', 5798 50000071 => 'Books|Comics & Graphic Novels|Manga|Action', 5799 50000072 => 'Books|Comics & Graphic Novels|Manga|Comedy', 5800 50000073 => 'Books|Comics & Graphic Novels|Manga|Erotica', 5801 50000074 => 'Books|Comics & Graphic Novels|Manga|Fantasy', 5802 50000075 => 'Books|Comics & Graphic Novels|Manga|Four Cell Manga', 5803 50000076 => 'Books|Comics & Graphic Novels|Manga|Gay & Lesbian', 5804 50000077 => 'Books|Comics & Graphic Novels|Manga|Hard-Boiled', 5805 50000078 => 'Books|Comics & Graphic Novels|Manga|Heroes', 5806 50000079 => 'Books|Comics & Graphic Novels|Manga|Historical Fiction', 5807 50000080 => 'Books|Comics & Graphic Novels|Manga|Mecha', 5808 50000081 => 'Books|Comics & Graphic Novels|Manga|Mystery', 5809 50000082 => 'Books|Comics & Graphic Novels|Manga|Nonfiction', 5810 50000083 => 'Books|Comics & Graphic Novels|Manga|Religious', 5811 50000084 => 'Books|Comics & Graphic Novels|Manga|Romance', 5812 50000085 => 'Books|Comics & Graphic Novels|Manga|Romantic Comedy', 5813 50000086 => 'Books|Comics & Graphic Novels|Manga|Science Fiction', 5814 50000087 => 'Books|Comics & Graphic Novels|Manga|Sports', 5815 50000088 => 'Books|Fiction & Literature|Light Novels', 5816 50000089 => 'Books|Comics & Graphic Novels|Manga|Horror', 5817 50000090 => 'Books|Comics & Graphic Novels|Comics', 5818 50000091 => 'Books|Romance|Multicultural', 5819 50000092 => 'Audiobooks|Erotica', 5820 50000093 => 'Audiobooks|Light Novels', 5821 }, 5822 }, 5823 grup => { Name => 'Grouping', Avoid => 1 }, #10 1292 5824 hdvd => { #10 1293 5825 Name => 'HDVideo', 5826 Format => 'int8u', #24 5827 Writable => 'int8s', #27 1294 5828 PrintConv => { 0 => 'No', 1 => 'Yes' }, 1295 5829 }, … … 1298 5832 pcst => { #7 1299 5833 Name => 'Podcast', 5834 Format => 'int8u', #23 5835 Writable => 'int8s', #27 1300 5836 PrintConv => { 0 => 'No', 1 => 'Yes' }, 1301 5837 }, … … 1304 5840 Name => 'PlayListID', 1305 5841 Format => 'int8u', # actually int64u, but split it up 5842 Writable => 'int32s', #27 1306 5843 }, 1307 5844 purd => 'PurchaseDate', #7 … … 1309 5846 rtng => { #10 1310 5847 Name => 'Rating', 5848 Format => 'int8u', #23 5849 Writable => 'int8s', #27 1311 5850 PrintConv => { 1312 5851 0 => 'none', 5852 1 => 'Explicit', 1313 5853 2 => 'Clean', 1314 4 => 'Explicit ',5854 4 => 'Explicit (old)', 1315 5855 }, 1316 5856 }, … … 1318 5858 Name => 'AppleStoreCountry', 1319 5859 Format => 'int32u', 1320 PrintConv => { 1321 143460 => 'Australia', 1322 143445 => 'Austria', 1323 143446 => 'Belgium', 1324 143455 => 'Canada', 1325 143458 => 'Denmark', 1326 143447 => 'Finland', 1327 143442 => 'France', 1328 143443 => 'Germany', 1329 143448 => 'Greece', 1330 143449 => 'Ireland', 1331 143450 => 'Italy', 1332 143462 => 'Japan', 1333 143451 => 'Luxembourg', 1334 143452 => 'Netherlands', 1335 143461 => 'New Zealand', 1336 143457 => 'Norway', 1337 143453 => 'Portugal', 1338 143454 => 'Spain', 1339 143456 => 'Sweden', 1340 143459 => 'Switzerland', 1341 143444 => 'United Kingdom', 1342 143441 => 'United States', 5860 Writable => 'int32s', #27 5861 SeparateTable => 1, 5862 PrintConv => { #21 5863 143441 => 'United States', # US 5864 143442 => 'France', # FR 5865 143443 => 'Germany', # DE 5866 143444 => 'United Kingdom', # GB 5867 143445 => 'Austria', # AT 5868 143446 => 'Belgium', # BE 5869 143447 => 'Finland', # FI 5870 143448 => 'Greece', # GR 5871 143449 => 'Ireland', # IE 5872 143450 => 'Italy', # IT 5873 143451 => 'Luxembourg', # LU 5874 143452 => 'Netherlands', # NL 5875 143453 => 'Portugal', # PT 5876 143454 => 'Spain', # ES 5877 143455 => 'Canada', # CA 5878 143456 => 'Sweden', # SE 5879 143457 => 'Norway', # NO 5880 143458 => 'Denmark', # DK 5881 143459 => 'Switzerland', # CH 5882 143460 => 'Australia', # AU 5883 143461 => 'New Zealand', # NZ 5884 143462 => 'Japan', # JP 5885 143463 => 'Hong Kong', # HK 5886 143464 => 'Singapore', # SG 5887 143465 => 'China', # CN 5888 143466 => 'Republic of Korea', # KR 5889 143467 => 'India', # IN 5890 143468 => 'Mexico', # MX 5891 143469 => 'Russia', # RU 5892 143470 => 'Taiwan', # TW 5893 143471 => 'Vietnam', # VN 5894 143472 => 'South Africa', # ZA 5895 143473 => 'Malaysia', # MY 5896 143474 => 'Philippines', # PH 5897 143475 => 'Thailand', # TH 5898 143476 => 'Indonesia', # ID 5899 143477 => 'Pakistan', # PK 5900 143478 => 'Poland', # PL 5901 143479 => 'Saudi Arabia', # SA 5902 143480 => 'Turkey', # TR 5903 143481 => 'United Arab Emirates', # AE 5904 143482 => 'Hungary', # HU 5905 143483 => 'Chile', # CL 5906 143484 => 'Nepal', # NP 5907 143485 => 'Panama', # PA 5908 143486 => 'Sri Lanka', # LK 5909 143487 => 'Romania', # RO 5910 143489 => 'Czech Republic', # CZ 5911 143491 => 'Israel', # IL 5912 143492 => 'Ukraine', # UA 5913 143493 => 'Kuwait', # KW 5914 143494 => 'Croatia', # HR 5915 143495 => 'Costa Rica', # CR 5916 143496 => 'Slovakia', # SK 5917 143497 => 'Lebanon', # LB 5918 143498 => 'Qatar', # QA 5919 143499 => 'Slovenia', # SI 5920 143501 => 'Colombia', # CO 5921 143502 => 'Venezuela', # VE 5922 143503 => 'Brazil', # BR 5923 143504 => 'Guatemala', # GT 5924 143505 => 'Argentina', # AR 5925 143506 => 'El Salvador', # SV 5926 143507 => 'Peru', # PE 5927 143508 => 'Dominican Republic', # DO 5928 143509 => 'Ecuador', # EC 5929 143510 => 'Honduras', # HN 5930 143511 => 'Jamaica', # JM 5931 143512 => 'Nicaragua', # NI 5932 143513 => 'Paraguay', # PY 5933 143514 => 'Uruguay', # UY 5934 143515 => 'Macau', # MO 5935 143516 => 'Egypt', # EG 5936 143517 => 'Kazakhstan', # KZ 5937 143518 => 'Estonia', # EE 5938 143519 => 'Latvia', # LV 5939 143520 => 'Lithuania', # LT 5940 143521 => 'Malta', # MT 5941 143523 => 'Moldova', # MD 5942 143524 => 'Armenia', # AM 5943 143525 => 'Botswana', # BW 5944 143526 => 'Bulgaria', # BG 5945 143528 => 'Jordan', # JO 5946 143529 => 'Kenya', # KE 5947 143530 => 'Macedonia', # MK 5948 143531 => 'Madagascar', # MG 5949 143532 => 'Mali', # ML 5950 143533 => 'Mauritius', # MU 5951 143534 => 'Niger', # NE 5952 143535 => 'Senegal', # SN 5953 143536 => 'Tunisia', # TN 5954 143537 => 'Uganda', # UG 5955 143538 => 'Anguilla', # AI 5956 143539 => 'Bahamas', # BS 5957 143540 => 'Antigua and Barbuda', # AG 5958 143541 => 'Barbados', # BB 5959 143542 => 'Bermuda', # BM 5960 143543 => 'British Virgin Islands', # VG 5961 143544 => 'Cayman Islands', # KY 5962 143545 => 'Dominica', # DM 5963 143546 => 'Grenada', # GD 5964 143547 => 'Montserrat', # MS 5965 143548 => 'St. Kitts and Nevis', # KN 5966 143549 => 'St. Lucia', # LC 5967 143550 => 'St. Vincent and The Grenadines', # VC 5968 143551 => 'Trinidad and Tobago', # TT 5969 143552 => 'Turks and Caicos', # TC 5970 143553 => 'Guyana', # GY 5971 143554 => 'Suriname', # SR 5972 143555 => 'Belize', # BZ 5973 143556 => 'Bolivia', # BO 5974 143557 => 'Cyprus', # CY 5975 143558 => 'Iceland', # IS 5976 143559 => 'Bahrain', # BH 5977 143560 => 'Brunei Darussalam', # BN 5978 143561 => 'Nigeria', # NG 5979 143562 => 'Oman', # OM 5980 143563 => 'Algeria', # DZ 5981 143564 => 'Angola', # AO 5982 143565 => 'Belarus', # BY 5983 143566 => 'Uzbekistan', # UZ 5984 143568 => 'Azerbaijan', # AZ 5985 143571 => 'Yemen', # YE 5986 143572 => 'Tanzania', # TZ 5987 143573 => 'Ghana', # GH 5988 143575 => 'Albania', # AL 5989 143576 => 'Benin', # BJ 5990 143577 => 'Bhutan', # BT 5991 143578 => 'Burkina Faso', # BF 5992 143579 => 'Cambodia', # KH 5993 143580 => 'Cape Verde', # CV 5994 143581 => 'Chad', # TD 5995 143582 => 'Republic of the Congo', # CG 5996 143583 => 'Fiji', # FJ 5997 143584 => 'Gambia', # GM 5998 143585 => 'Guinea-Bissau', # GW 5999 143586 => 'Kyrgyzstan', # KG 6000 143587 => "Lao People's Democratic Republic", # LA 6001 143588 => 'Liberia', # LR 6002 143589 => 'Malawi', # MW 6003 143590 => 'Mauritania', # MR 6004 143591 => 'Federated States of Micronesia', # FM 6005 143592 => 'Mongolia', # MN 6006 143593 => 'Mozambique', # MZ 6007 143594 => 'Namibia', # NA 6008 143595 => 'Palau', # PW 6009 143597 => 'Papua New Guinea', # PG 6010 143598 => 'Sao Tome and Principe', # ST (São Tomé and Príncipe) 6011 143599 => 'Seychelles', # SC 6012 143600 => 'Sierra Leone', # SL 6013 143601 => 'Solomon Islands', # SB 6014 143602 => 'Swaziland', # SZ 6015 143603 => 'Tajikistan', # TJ 6016 143604 => 'Turkmenistan', # TM 6017 143605 => 'Zimbabwe', # ZW 1343 6018 }, 1344 6019 }, … … 1351 6026 stik => { #10 1352 6027 Name => 'MediaType', 6028 Format => 'int8u', #23 6029 Writable => 'int8s', #27 6030 PrintConvColumns => 2, 1353 6031 PrintConv => { #(http://weblog.xanga.com/gryphondwb/615474010/iphone-ringtones---what-did-itunes-741-really-do.html) 1354 0 => 'Movie ',6032 0 => 'Movie (old)', #forum9059 (was Movie) 1355 6033 1 => 'Normal (Music)', 1356 6034 2 => 'Audiobook', 1357 6035 5 => 'Whacked Bookmark', 1358 6036 6 => 'Music Video', 1359 9 => ' Short Film',6037 9 => 'Movie', #forum9059 (was Short Film) 1360 6038 10 => 'TV Show', 1361 6039 11 => 'Booklet', 1362 6040 14 => 'Ringtone', 1363 }, 1364 }, 1365 titl => 'Title', 6041 21 => 'Podcast', #15 6042 23 => 'iTunes U', #forum9059 6043 }, 6044 }, 6045 rate => 'RatingPercent', #PH 6046 titl => { Name => 'Title', Avoid => 1 }, 1366 6047 tven => 'TVEpisodeID', #7 1367 6048 tves => { #7/10 1368 6049 Name => 'TVEpisode', 1369 6050 Format => 'int32u', 6051 Writable => 'int32s', #27 1370 6052 }, 1371 6053 tvnn => 'TVNetworkName', #7 … … 1376 6058 }, 1377 6059 yrrc => 'Year', #(ffmpeg source) 6060 itnu => { #PH (iTunes 10.5) 6061 Name => 'iTunesU', 6062 Format => 'int8u', #27 6063 Writable => 'int8s', #27 6064 Description => 'iTunes U', 6065 PrintConv => { 0 => 'No', 1 => 'Yes' }, 6066 }, 6067 #https://github.com/communitymedia/mediautilities/blob/master/src/net/sourceforge/jaad/mp4/boxes/BoxTypes.java 6068 gshh => { Name => 'GoogleHostHeader', Format => 'string' }, 6069 gspm => { Name => 'GooglePingMessage', Format => 'string' }, 6070 gspu => { Name => 'GooglePingURL', Format => 'string' }, 6071 gssd => { Name => 'GoogleSourceData', Format => 'string' }, 6072 gsst => { Name => 'GoogleStartTime', Format => 'string' }, 6073 gstd => { 6074 Name => 'GoogleTrackDuration', 6075 Format => 'string', 6076 ValueConv => '$val / 1000', 6077 ValueConvInv => '$val * 1000', 6078 PrintConv => 'ConvertDuration($val)', 6079 PrintConvInv => q{ 6080 $val =~ s/ s$//; 6081 my @a = split /(:| days )/, $val; 6082 my $sign = ($val =~ s/^-//) ? -1 : 1; 6083 $a[0] += shift(@a) * 24 if @a == 4; 6084 $a[0] += shift(@a) * 60 while @a > 1; 6085 return $a[0] * $sign; 6086 }, 6087 }, 6088 6089 # atoms observed in AAX audiobooks (ref PH) 6090 "\xa9cpy" => { Name => 'Copyright', Avoid => 1, Groups => { 2 => 'Author' } }, 6091 "\xa9pub" => 'Publisher', 6092 "\xa9nrt" => 'Narrator', 6093 '@pti' => 'ParentTitle', # (guess -- same as "\xa9nam") 6094 '@PST' => 'ParentShortTitle', # (guess -- same as "\xa9nam") 6095 '@ppi' => 'ParentProductID', # (guess -- same as 'prID') 6096 '@sti' => 'ShortTitle', # (guess -- same as "\xa9nam") 6097 prID => 'ProductID', 6098 rldt => { Name => 'ReleaseDate', Groups => { 2 => 'Time' }}, 6099 CDEK => { Name => 'Unknown_CDEK', Unknown => 1 }, # eg: "B004ZMTFEG" - used in URL's ("asin=") 6100 CDET => { Name => 'Unknown_CDET', Unknown => 1 }, # eg: "ADBL" 6101 VERS => 'ProductVersion', 6102 GUID => 'GUID', 6103 AACR => { Name => 'Unknown_AACR', Unknown => 1 }, # eg: "CR!1T1H1QH6WX7T714G2BMFX3E9MC4S" 6104 # ausr - 30 bytes (User Alias?) 6105 "\xa9xyz" => { #PH (written by Google Photos) 6106 Name => 'GPSCoordinates', 6107 Groups => { 2 => 'Location' }, 6108 ValueConv => \&ConvertISO6709, 6109 ValueConvInv => \&ConvInvISO6709, 6110 PrintConv => \&PrintGPSCoordinates, 6111 PrintConvInv => \&PrintInvGPSCoordinates, 6112 }, 6113 # the following tags written by iTunes 12.5.1.21 6114 # (ref https://www.ventismedia.com/mantis/view.php?id=14963 6115 # https://community.mp3tag.de/t/x-mp4-new-tag-problems/19488) 6116 "\xa9wrk" => 'Work', #PH 6117 "\xa9mvn" => 'MovementName', #PH 6118 "\xa9mvi" => { #PH 6119 Name => 'MovementNumber', 6120 Format => 'int16u', #27 6121 Writable => 'int16s', #27 6122 }, 6123 "\xa9mvc" => { #PH 6124 Name => 'MovementCount', 6125 Format => 'int16u', #27 6126 Writable => 'int16s', #27 6127 }, 6128 shwm => { #PH 6129 Name => 'ShowMovement', 6130 Format => 'int8u', #27 6131 Writable => 'int8s', #27 6132 PrintConv => { 0 => 'No', 1 => 'Yes' }, 6133 }, 6134 ); 6135 6136 # tag decoded from timed face records 6137 %Image::ExifTool::QuickTime::FaceInfo = ( 6138 PROCESS_PROC => \&ProcessMOV, 6139 GROUPS => { 2 => 'Video' }, 6140 crec => { 6141 Name => 'FaceRec', 6142 SubDirectory => { 6143 TagTable => 'Image::ExifTool::QuickTime::FaceRec', 6144 }, 6145 }, 6146 ); 6147 6148 # tag decoded from timed face records 6149 %Image::ExifTool::QuickTime::FaceRec = ( 6150 PROCESS_PROC => \&ProcessMOV, 6151 GROUPS => { 2 => 'Video' }, 6152 cits => { 6153 Name => 'FaceItem', 6154 SubDirectory => { 6155 TagTable => 'Image::ExifTool::QuickTime::Keys', 6156 ProcessProc => \&Process_mebx, 6157 }, 6158 }, 1378 6159 ); 1379 6160 1380 6161 # item list keys (ref PH) 1381 6162 %Image::ExifTool::QuickTime::Keys = ( 1382 PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessKeys, 6163 PROCESS_PROC => \&ProcessKeys, 6164 WRITE_PROC => \&WriteKeys, 6165 CHECK_PROC => \&CheckQTValue, 6166 VARS => { LONG_TAGS => 3 }, 6167 WRITABLE => 1, 6168 # (not PREFERRED when writing) 6169 GROUPS => { 1 => 'Keys' }, 6170 WRITE_GROUP => 'Keys', 6171 LANG_INFO => \&GetLangInfo, 6172 FORMAT => 'string', 1383 6173 NOTES => q{ 1384 This directory contains a list of key names which are used to decode 1385 ItemList tags written by the "mdta" handler. The prefix of 1386 "com.apple.quicktime." has been removed from all TagID's below. 6174 This directory contains a list of key names which are used to decode tags 6175 written by the "mdta" handler. Also in this table are a few tags found in 6176 timed metadata that are not yet writable by ExifTool. The prefix of 6177 "com.apple.quicktime." has been removed from the TagID's below. These tags 6178 support alternate languages in the same way as the 6179 L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags. Note 6180 that by default, 6181 L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> and 6182 L<UserData|Image::ExifTool::TagNames/QuickTime UserData Tags> tags are 6183 preferred when writing, so to create a tag when a same-named tag exists in 6184 either of these tables, either the "Keys" location must be specified (eg. 6185 C<-Keys:Author=Phil> on the command line), or the PREFERRED level must be 6186 changed via L<the config file|../config.html#PREF>. 1387 6187 }, 1388 6188 version => 'Version', … … 1396 6196 Name => 'CreationDate', 1397 6197 Groups => { 2 => 'Time' }, 6198 Shift => 'Time', 1398 6199 ValueConv => q{ 1399 6200 require Image::ExifTool::XMP; … … 1402 6203 return $val; 1403 6204 }, 6205 ValueConvInv => q{ 6206 require Image::ExifTool::XMP; 6207 $val = Image::ExifTool::XMP::FormatXMPDate($val); 6208 $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon 6209 return $val; 6210 }, 1404 6211 PrintConv => '$self->ConvertDateTime($val)', 6212 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 1405 6213 }, 1406 6214 description => { }, 1407 6215 director => { }, 6216 displayname => { Name => 'DisplayName' }, 6217 title => { }, #22 1408 6218 genre => { }, 1409 6219 information => { }, 1410 6220 keywords => { }, 6221 producer => { }, #22 1411 6222 make => { Name => 'Make', Groups => { 2 => 'Camera' } }, 1412 6223 model => { Name => 'Model', Groups => { 2 => 'Camera' } }, … … 1418 6229 Name => 'FrameReadoutTime', 1419 6230 ValueConv => '$val * 1e-6', 6231 ValueConvInv => 'int($val * 1e6 + 0.5)', 1420 6232 PrintConv => '$val * 1e6 . " microseconds"', 6233 PrintConvInv => '$val =~ s/ .*//; $val * 1e-6', 1421 6234 }, 1422 6235 'location.ISO6709' => { … … 1424 6237 Groups => { 2 => 'Location' }, 1425 6238 ValueConv => \&ConvertISO6709, 6239 ValueConvInv => \&ConvInvISO6709, 1426 6240 PrintConv => \&PrintGPSCoordinates, 6241 PrintConvInv => \&PrintInvGPSCoordinates, 1427 6242 }, 1428 6243 'location.name' => { Name => 'LocationName', Groups => { 2 => 'Location' } }, … … 1441 6256 Name => 'LocationDate', 1442 6257 Groups => { 2 => 'Time' }, 6258 Shift => 'Time', 1443 6259 ValueConv => q{ 1444 6260 require Image::ExifTool::XMP; … … 1447 6263 return $val; 1448 6264 }, 6265 ValueConvInv => q{ 6266 require Image::ExifTool::XMP; 6267 $val = Image::ExifTool::XMP::FormatXMPDate($val); 6268 $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon 6269 return $val; 6270 }, 1449 6271 PrintConv => '$self->ConvertDateTime($val)', 6272 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 1450 6273 }, 1451 6274 'direction.facing' => { Name => 'CameraDirection', Groups => { 2 => 'Location' } }, 1452 'direction.motion' => { Name => 'CameraMotion', Groups => { 2 => 'Location' } },1453 'location.body' => { Name => 'LocationBody',Groups => { 2 => 'Location' } },6275 'direction.motion' => { Name => 'CameraMotion', Groups => { 2 => 'Location' } }, 6276 'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } }, 1454 6277 'player.version' => 'PlayerVersion', 1455 6278 'player.movie.visual.brightness'=> 'Brightness', … … 1467 6290 PrintConv => { 0 => 'Off', 1 => 'On' }, 1468 6291 }, 6292 'rating.user' => 'UserRating', # (Canon ELPH 510 HS) 6293 'collection.user' => 'UserCollection', #22 6294 'Encoded_With' => 'EncodedWith', 6295 # 6296 # the following tags aren't in the com.apple.quicktime namespace: 6297 # 6298 'com.apple.photos.captureMode' => 'CaptureMode', 6299 'com.android.version' => 'AndroidVersion', 6300 # 6301 # also seen 6302 # 6303 # com.divergentmedia.clipwrap.model ('NEX-FS700EK') 6304 # com.divergentmedia.clipwrap.model1 ('49') 6305 # com.divergentmedia.clipwrap.model2 ('0') 6306 # com.divergentmedia.clipwrap.manufacturer ('Sony') 6307 # com.divergentmedia.clipwrap.originalDateTime ('2013/2/6 10:30:40+0200') 6308 # 6309 # seen in timed metadata (mebx), and added dynamically to the table 6310 # via SaveMetaKeys(). NOTE: these tags are not writable! 6311 # 6312 # (mdta)com.apple.quicktime.video-orientation (dtyp=66, int16s) 6313 'video-orientation' => { Name => 'VideoOrientation', Writable => 0 }, 6314 # (mdta)com.apple.quicktime.live-photo-info (dtyp=com.apple.quicktime.com.apple.quicktime.live-photo-info) 6315 'live-photo-info' => { 6316 Name => 'LivePhotoInfo', 6317 Writable => 0, 6318 # not sure what these values mean, but unpack them anyway - PH 6319 # (ignore the fact that the "f" and "l" unpacks won't work on a big-endian machine) 6320 ValueConv => 'join " ",unpack "VfVVf6c4lCCcclf4Vvv", $val', 6321 }, 6322 # (mdta)com.apple.quicktime.still-image-time (dtyp=65, int8s) 6323 'still-image-time' => { # (found in live photo) 6324 Name => 'StillImageTime', 6325 Writable => 0, 6326 Notes => q{ 6327 this tag always has a value of -1; the time of the still image is obtained 6328 from the associated SampleTime 6329 }, 6330 }, 6331 # (mdta)com.apple.quicktime.detected-face (dtyp='com.apple.quicktime.detected-face') 6332 'detected-face' => { 6333 Name => 'FaceInfo', 6334 Writable => 0, 6335 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FaceInfo' }, 6336 }, 6337 # ---- detected-face fields ( ---- 6338 # --> back here after a round trip through FaceInfo -> FaceRec -> FaceItem 6339 # (fiel)com.apple.quicktime.detected-face.bounds (dtyp=80, float[8]) 6340 'detected-face.bounds' => { 6341 Name => 'DetectedFaceBounds', 6342 Writable => 0, 6343 # round to a reasonable number of decimal places 6344 PrintConv => 'my @a=split " ",$val;$_=int($_*1e6+.5)/1e6 foreach @a;join " ",@a', 6345 PrintConvInv => '$val', 6346 }, 6347 # (fiel)com.apple.quicktime.detected-face.face-id (dtyp=77, int32u) 6348 'detected-face.face-id' => { Name => 'DetectedFaceID', Writable => 0 }, 6349 # (fiel)com.apple.quicktime.detected-face.roll-angle (dtyp=23, float) 6350 'detected-face.roll-angle' => { Name => 'DetectedFaceRollAngle', Writable => 0 }, 6351 # (fiel)com.apple.quicktime.detected-face.yaw-angle (dtyp=23, float) 6352 'detected-face.yaw-angle' => { Name => 'DetectedFaceYawAngle', Writable => 0 }, 6353 # 6354 # seen in Apple ProRes RAW file 6355 # 6356 # (mdta)com.apple.proapps.manufacturer (eg. "Sony") 6357 # (mdta)com.apple.proapps.exif.{Exif}.FNumber (float, eg. 1.0) 6358 # (mdta)org.smpte.rdd18.lens.irisfnumber (eg. "F1.0") 6359 # (mdta)com.apple.proapps.exif.{Exif}.ShutterSpeedValue (float, eg. 1.006) 6360 # (mdta)org.smpte.rdd18.camera.shutterspeed_angle (eg. "179.2deg") 6361 # (mdta)org.smpte.rdd18.camera.neutraldensityfilterwheelsetting (eg. "ND1") 6362 # (mdta)org.smpte.rdd18.camera.whitebalance (eg. "4300K") 6363 # (mdta)com.apple.proapps.exif.{Exif}.ExposureIndex (float, eg. 4000) 6364 # (mdta)org.smpte.rdd18.camera.isosensitivity (eg. "4000") 6365 # (mdta)com.apple.proapps.image.{TIFF}.Make (eg. "Atmos") 6366 # (mdta)com.apple.proapps.image.{TIFF}.Model (eg. "ShogunInferno") 6367 # (mdta)com.apple.proapps.image.{TIFF}.Software (eg. "9.0") 1469 6368 ); 1470 6369 … … 1473 6372 PROCESS_PROC => \&ProcessMOV, 1474 6373 GROUPS => { 2 => 'Audio' }, 6374 NOTES => q{ 6375 ExifTool will extract any iTunesInfo tags that exist, even if they are not 6376 defined in this table. 6377 }, 1475 6378 # 'mean'/'name'/'data' atoms form a triplet, but unfortunately 1476 # I can't find any source for decoding 'data'.6379 # I haven't been able to find any documentation on this. 1477 6380 # 'mean' is normally 'com.apple.iTunes' 1478 # 'name' values: 'tool', 'iTunNORM' (volume normalization),1479 # 'iTunSMPB', 'iTunes_CDDB_IDs', 'iTunes_CDDB_TrackNumber'1480 6381 mean => { 1481 6382 Name => 'Mean', 1482 Unknown => 1, 6383 # the 'Triplet' flag tells ProcessMOV() to generate 6384 # a single tag from the mean/name/data triplet 6385 Triplet => 1, 6386 Hidden => 1, 1483 6387 }, 1484 6388 name => { 1485 6389 Name => 'Name', 1486 Unknown => 1, 6390 Triplet => 1, 6391 Hidden => 1, 1487 6392 }, 1488 6393 data => { 1489 6394 Name => 'Data', 1490 Flags => ['Binary','Unknown'], 6395 Triplet => 1, 6396 Hidden => 1, 6397 }, 6398 # the tag ID's below are composed from "mean/name", 6399 # but "mean/" is omitted if it is "com.apple.iTunes/": 6400 'iTunMOVI' => { 6401 Name => 'iTunMOVI', 6402 SubDirectory => { TagTable => 'Image::ExifTool::PLIST::Main' }, 6403 }, 6404 'tool' => { 6405 Name => 'iTunTool', 6406 Description => 'iTunTool', 6407 Format => 'int32u', 6408 PrintConv => 'sprintf("0x%.8x",$val)', 6409 }, 6410 'iTunEXTC' => { 6411 Name => 'ContentRating', 6412 Notes => 'standard | rating | score | reasons', 6413 # eg. 'us-tv|TV-14|500|V', 'mpaa|PG-13|300|For violence and sexuality' 6414 # (see http://shadowofged.blogspot.ca/2008/06/itunes-content-ratings.html) 6415 }, 6416 'iTunNORM' => { 6417 Name => 'VolumeNormalization', 6418 PrintConv => '$val=~s/ 0+(\w)/ $1/g; $val=~s/^\s+//; $val', 6419 }, 6420 'iTunSMPB' => { 6421 Name => 'iTunSMPB', 6422 Description => 'iTunSMPB', 6423 # hex format, similar to iTunNORM, but 12 words instead of 10, 6424 # and 4th word is 16 hex digits (all others are 8) 6425 # (gives AAC encoder delay, ref http://code.google.com/p/l-smash/issues/detail?id=1) 6426 PrintConv => '$val=~s/ 0+(\w)/ $1/g; $val=~s/^\s+//; $val', 6427 }, 6428 # (CDDB = Compact Disc DataBase) 6429 # iTunes_CDDB_1 = <CDDB1 disk ID>+<# tracks>+<logical block address for each track>... 6430 'iTunes_CDDB_1' => 'CDDB1Info', 6431 'iTunes_CDDB_TrackNumber' => 'CDDBTrackNumber', 6432 'Encoding Params' => { 6433 Name => 'EncodingParams', 6434 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::EncodingParams' }, 6435 }, 6436 # also heard about 'iTunPGAP', but I haven't seen a sample 6437 DISCNUMBER => 'DiscNumber', #PH 6438 TRACKNUMBER => 'TrackNumber', #PH 6439 popularimeter => 'Popularimeter', #PH 6440 ); 6441 6442 # iTunes audio encoding parameters 6443 # ref https://developer.apple.com/library/mac/#documentation/MusicAudio/Reference/AudioCodecServicesRef/Reference/reference.html 6444 %Image::ExifTool::QuickTime::EncodingParams = ( 6445 PROCESS_PROC => \&ProcessEncodingParams, 6446 GROUPS => { 2 => 'Audio' }, 6447 # (I have commented out the ones that don't have integer values because they 6448 # probably don't appear, and definitely wouldn't work with current decoding - PH) 6449 6450 # global codec properties 6451 #'lnam' => 'AudioCodecName', 6452 #'lmak' => 'AudioCodecManufacturer', 6453 #'lfor' => 'AudioCodecFormat', 6454 'vpk?' => 'AudioHasVariablePacketByteSizes', 6455 #'ifm#' => 'AudioSupportedInputFormats', 6456 #'ofm#' => 'AudioSupportedOutputFormats', 6457 #'aisr' => 'AudioAvailableInputSampleRates', 6458 #'aosr' => 'AudioAvailableOutputSampleRates', 6459 'abrt' => 'AudioAvailableBitRateRange', 6460 'mnip' => 'AudioMinimumNumberInputPackets', 6461 'mnop' => 'AudioMinimumNumberOutputPackets', 6462 'cmnc' => 'AudioAvailableNumberChannels', 6463 'lmrc' => 'AudioDoesSampleRateConversion', 6464 #'aicl' => 'AudioAvailableInputChannelLayoutTags', 6465 #'aocl' => 'AudioAvailableOutputChannelLayoutTags', 6466 #'if4o' => 'AudioInputFormatsForOutputFormat', 6467 #'of4i' => 'AudioOutputFormatsForInputFormat', 6468 #'acfi' => 'AudioFormatInfo', 6469 6470 # instance codec properties 6471 'tbuf' => 'AudioInputBufferSize', 6472 'pakf' => 'AudioPacketFrameSize', 6473 'pakb' => 'AudioMaximumPacketByteSize', 6474 #'ifmt' => 'AudioCurrentInputFormat', 6475 #'ofmt' => 'AudioCurrentOutputFormat', 6476 #'kuki' => 'AudioMagicCookie', 6477 'ubuf' => 'AudioUsedInputBufferSize', 6478 'init' => 'AudioIsInitialized', 6479 'brat' => 'AudioCurrentTargetBitRate', 6480 #'cisr' => 'AudioCurrentInputSampleRate', 6481 #'cosr' => 'AudioCurrentOutputSampleRate', 6482 'srcq' => 'AudioQualitySetting', 6483 #'brta' => 'AudioApplicableBitRateRange', 6484 #'isra' => 'AudioApplicableInputSampleRates', 6485 #'osra' => 'AudioApplicableOutputSampleRates', 6486 'pad0' => 'AudioZeroFramesPadded', 6487 'prmm' => 'AudioCodecPrimeMethod', 6488 #'prim' => 'AudioCodecPrimeInfo', 6489 #'icl ' => 'AudioInputChannelLayout', 6490 #'ocl ' => 'AudioOutputChannelLayout', 6491 #'acs ' => 'AudioCodecSettings', 6492 #'acfl' => 'AudioCodecFormatList', 6493 'acbf' => 'AudioBitRateControlMode', 6494 'vbrq' => 'AudioVBRQuality', 6495 'mdel' => 'AudioMinimumDelayMode', 6496 6497 # deprecated 6498 'pakd' => 'AudioRequiresPacketDescription', 6499 #'brt#' => 'AudioAvailableBitRates', 6500 'acef' => 'AudioExtendFrequencies', 6501 'ursr' => 'AudioUseRecommendedSampleRate', 6502 'oppr' => 'AudioOutputPrecedence', 6503 #'loud' => 'AudioCurrentLoudnessStatistics', 6504 6505 # others 6506 'vers' => 'AudioEncodingParamsVersion', #PH 6507 'cdcv' => { #PH 6508 Name => 'AudioComponentVersion', 6509 ValueConv => 'join ".", unpack("ncc", pack("N",$val))', 1491 6510 }, 1492 6511 ); … … 1565 6584 payt => { 1566 6585 Name => 'PayloadType', 6586 Format => 'undef', # (necessary to prevent decoding as string!) 1567 6587 ValueConv => 'unpack("N",$val) . " " . substr($val, 5)', 1568 6588 PrintConv => '$val=~s/ /, /;$val', 1569 6589 }, 1570 );1571 1572 # Kodak DcMD atoms (ref PH)1573 %Image::ExifTool::QuickTime::DcMD = (1574 PROCESS_PROC => \&ProcessMOV,1575 GROUPS => { 2 => 'Video' },1576 NOTES => 'Metadata directory found in MOV videos from some Kodak cameras.',1577 Cmbo => {1578 Name => 'CameraByteOrder',1579 PrintConv => {1580 II => 'Little-endian (Intel, II)',1581 MM => 'Big-endian (Motorola, MM)',1582 },1583 },1584 DcME => {1585 Name => 'DcME',1586 SubDirectory => {1587 TagTable => 'Image::ExifTool::QuickTime::DcME',1588 },1589 },1590 );1591 1592 # Kodak DcME atoms (ref PH)1593 %Image::ExifTool::QuickTime::DcME = (1594 PROCESS_PROC => \&ProcessMOV,1595 GROUPS => { 2 => 'Video' },1596 # Mtmd = binary data ("00 00 00 00 00 00 00 01" x 3)1597 # Keyw = keywords? (six bytes all zero)1598 # Rate = 2 bytes "00 00"1599 6590 ); 1600 6591 … … 1602 6593 %Image::ExifTool::QuickTime::Media = ( 1603 6594 PROCESS_PROC => \&ProcessMOV, 1604 GROUPS => { 2 => 'Video' }, 6595 WRITE_PROC => \&WriteQuickTime, 6596 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 1605 6597 NOTES => 'MP4 media box.', 1606 6598 mdhd => { … … 1621 6613 %Image::ExifTool::QuickTime::MediaHeader = ( 1622 6614 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1623 GROUPS => { 2 => 'Video' }, 6615 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 6616 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 6617 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 1624 6618 FORMAT => 'int32u', 6619 DATAMEMBER => [ 0, 1, 2, 3, 4 ], 1625 6620 0 => { 1626 6621 Name => 'MediaHeaderVersion', … … 1657 6652 RawConv => '$val ? $val : undef', 1658 6653 # allow both Macintosh (for MOV files) and ISO (for MP4 files) language codes 1659 ValueConv => ' $val < 0x400? $val : pack "C*", map { (($val>>$_)&0x1f)+0x60 } 10, 5, 0',6654 ValueConv => '($val < 0x400 or $val == 0x7fff) ? $val : pack "C*", map { (($val>>$_)&0x1f)+0x60 } 10, 5, 0', 1660 6655 PrintConv => q{ 1661 6656 return $val unless $val =~ /^\d+$/; … … 1669 6664 %Image::ExifTool::QuickTime::MediaInfo = ( 1670 6665 PROCESS_PROC => \&ProcessMOV, 1671 GROUPS => { 2 => 'Video' }, 6666 WRITE_PROC => \&WriteQuickTime, 6667 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 1672 6668 NOTES => 'MP4 media info box.', 1673 6669 vmhd => { … … 1688 6684 }, 1689 6685 dinf => { 1690 Name => 'DataInfo', 6686 Name => 'DataInfo', # (don't change this name -- used to recognize directory when writing) 1691 6687 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' }, 1692 6688 }, … … 1743 6739 %Image::ExifTool::QuickTime::SampleTable = ( 1744 6740 PROCESS_PROC => \&ProcessMOV, 6741 WRITE_PROC => \&WriteQuickTime, 1745 6742 GROUPS => { 2 => 'Video' }, 1746 6743 NOTES => 'MP4 sample table box.', … … 1751 6748 SubDirectory => { 1752 6749 TagTable => 'Image::ExifTool::QuickTime::AudioSampleDesc', 1753 Start => 8, # skip version number and count6750 ProcessProc => \&ProcessSampleDesc, 1754 6751 }, 1755 6752 },{ … … 1758 6755 SubDirectory => { 1759 6756 TagTable => 'Image::ExifTool::QuickTime::ImageDesc', 1760 Start => 8, # skip version number and count6757 ProcessProc => \&ProcessSampleDesc, 1761 6758 }, 1762 6759 },{ … … 1765 6762 SubDirectory => { 1766 6763 TagTable => 'Image::ExifTool::QuickTime::HintSampleDesc', 1767 Start => 8, # skip version number and count 6764 ProcessProc => \&ProcessSampleDesc, 6765 }, 6766 },{ 6767 Name => 'MetaSampleDesc', 6768 Condition => '$$self{HandlerType} and $$self{HandlerType} eq "meta"', 6769 SubDirectory => { 6770 TagTable => 'Image::ExifTool::QuickTime::MetaSampleDesc', 6771 ProcessProc => \&ProcessSampleDesc, 1768 6772 }, 1769 6773 },{ … … 1771 6775 SubDirectory => { 1772 6776 TagTable => 'Image::ExifTool::QuickTime::OtherSampleDesc', 1773 Start => 8, # skip version number and count6777 ProcessProc => \&ProcessSampleDesc, 1774 6778 }, 1775 6779 }, … … 1781 6785 Notes => 'average rate calculated from time-to-sample table for video media', 1782 6786 Condition => '$$self{HandlerType} and $$self{HandlerType} eq "vide"', 6787 Format => 'undef', # (necessary to prevent decoding as string!) 1783 6788 # (must be RawConv so appropriate MediaTS is used in calculation) 1784 6789 RawConv => 'Image::ExifTool::QuickTime::CalcSampleRate($self, \$val)', … … 1841 6846 Name => 'SampleGroupDescription', 1842 6847 Flags => ['Binary','Unknown'], 6848 # bytes 4-7 give grouping type (ref ISO/IEC 14496-15:2014) 6849 # tsas - temporal sublayer sample 6850 # stsa - step-wise temporal layer access 6851 # avss - AVC sample 6852 # tscl - temporal layer scalability 6853 # sync - sync sample 1843 6854 }, 1844 6855 subs => { … … 1850 6861 Flags => ['Binary','Unknown'], 1851 6862 }, 6863 stps => { 6864 Name => 'PartialSyncSamples', 6865 ValueConv => 'join " ",unpack("x8N*",$val)', 6866 }, 6867 # mark - 8 bytes all zero (GoPro) 1852 6868 ); 1853 6869 1854 # MP4 audio sample description box (ref 5 )6870 # MP4 audio sample description box (ref 5/AtomicParsley 0.9.4 parsley.cpp) 1855 6871 %Image::ExifTool::QuickTime::AudioSampleDesc = ( 1856 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6872 PROCESS_PROC => \&ProcessHybrid, 6873 VARS => { ID_LABEL => 'ID/Index' }, 1857 6874 GROUPS => { 2 => 'Audio' }, 1858 FORMAT => 'int16u', 1859 NOTES => 'MP4 audio sample description.', 1860 2 => { 6875 NOTES => q{ 6876 MP4 audio sample description. This hybrid atom contains both data and child 6877 atoms. 6878 }, 6879 4 => { 1861 6880 Name => 'AudioFormat', 1862 6881 Format => 'undef[4]', 1863 6882 RawConv => q{ 6883 $$self{AudioFormat} = $val; 1864 6884 return undef unless $val =~ /^[\w ]{4}$/i; 1865 6885 # check for protected audio format … … 1867 6887 return $val; 1868 6888 }, 1869 }, 1870 10 => { #PH 6889 # see this link for print conversions (not complete): 6890 # https://github.com/yannickcr/brooser/blob/master/php/librairies/getid3/module.audio-video.quicktime.php 6891 }, 6892 20 => { #PH 1871 6893 Name => 'AudioVendorID', 6894 Condition => '$$self{AudioFormat} ne "mp4s"', 1872 6895 Format => 'undef[4]', 1873 6896 RawConv => '$val eq "\0\0\0\0" ? undef : $val', … … 1875 6898 SeparateTable => 'VendorID', 1876 6899 }, 1877 12 => 'AudioChannels', 1878 13 => 'AudioBitsPerSample', 1879 16 => { Name => 'AudioSampleRate', Format => 'fixed32u' }, 1880 28 => { #PH 1881 Name => 'AudioFormat', 6900 24 => { Name => 'AudioChannels', Format => 'int16u' }, 6901 26 => { Name => 'AudioBitsPerSample', Format => 'int16u' }, 6902 32 => { Name => 'AudioSampleRate', Format => 'fixed32u' }, 6903 # 6904 # Observed offsets for child atoms of various AudioFormat types: 6905 # 6906 # AudioFormat Offset Child atoms 6907 # ----------- ------ ---------------- 6908 # mp4a 52 * wave, chan, esds, SA3D(Insta360 spherical video params?,also GoPro Max) 6909 # in24 52 wave, chan 6910 # "ms\0\x11" 52 wave 6911 # sowt 52 chan 6912 # mp4a 36 * esds, pinf 6913 # drms 36 esds, sinf 6914 # samr 36 damr 6915 # alac 36 alac 6916 # ac-3 36 dac3 6917 # 6918 # (* child atoms found at different offsets in mp4a) 6919 # 6920 pinf => { 6921 Name => 'PurchaseInfo', 6922 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ProtectionInfo' }, 6923 }, 6924 sinf => { # "protection scheme information" 6925 Name => 'ProtectionInfo', #3 6926 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ProtectionInfo' }, 6927 }, 6928 # f - 16/36 bytes 6929 # esds - 31/40/42/43 bytes - ES descriptor (ref 3) 6930 damr => { #3 6931 Name => 'DecodeConfig', 6932 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DecodeConfig' }, 6933 }, 6934 wave => { 6935 Name => 'Wave', 6936 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Wave' }, 6937 }, 6938 chan => { 6939 Name => 'AudioChannelLayout', 6940 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ChannelLayout' }, 6941 } 6942 # alac - 28 bytes 6943 # adrm - AAX DRM atom? 148 bytes 6944 # aabd - AAX unknown 17kB (contains 'aavd' strings) 6945 # SA3D - written by Garmin VIRB360 6946 ); 6947 6948 # AMR decode config box (ref 3) 6949 %Image::ExifTool::QuickTime::DecodeConfig = ( 6950 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6951 GROUPS => { 2 => 'Audio' }, 6952 0 => { 6953 Name => 'EncoderVendor', 1882 6954 Format => 'undef[4]', 1883 RawConv => '$val =~ /^[\w ]{4}$/i ? $val : undef', 1884 Notes => 'in Casio MOV videos', 1885 }, 6955 }, 6956 4 => 'EncoderVersion', 6957 # 5 - int16u - packet modes 6958 # 7 - int8u - number of packet mode changes 6959 # 8 - int8u - bytes per packet 1886 6960 ); 1887 6961 6962 %Image::ExifTool::QuickTime::ProtectionInfo = ( 6963 PROCESS_PROC => \&ProcessMOV, 6964 GROUPS => { 2 => 'Audio' }, 6965 NOTES => 'Child atoms found in "sinf" and/or "pinf" atoms.', 6966 frma => 'OriginalFormat', 6967 # imif - IPMP information 6968 schm => { 6969 Name => 'SchemeType', 6970 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeType' }, 6971 }, 6972 schi => { 6973 Name => 'SchemeInfo', 6974 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeInfo' }, 6975 }, 6976 enda => { 6977 Name => 'Endianness', 6978 Format => 'int16u', 6979 PrintConv => { 6980 0 => 'Big-endian (Motorola, MM)', 6981 1 => 'Little-endian (Intel, II)', 6982 }, 6983 }, 6984 # skcr 6985 ); 6986 6987 %Image::ExifTool::QuickTime::Wave = ( 6988 PROCESS_PROC => \&ProcessMOV, 6989 frma => 'PurchaseFileFormat', 6990 enda => { 6991 Name => 'Endianness', 6992 Format => 'int16u', 6993 PrintConv => { 6994 0 => 'Big-endian (Motorola, MM)', 6995 1 => 'Little-endian (Intel, II)', 6996 }, 6997 }, 6998 # "ms\0\x11" - 20 bytes 6999 ); 7000 7001 # audio channel layout (ref CoreAudioTypes.h) 7002 %Image::ExifTool::QuickTime::ChannelLayout = ( 7003 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7004 GROUPS => { 2 => 'Audio' }, 7005 DATAMEMBER => [ 0, 8 ], 7006 NOTES => 'Audio channel layout.', 7007 # 0 - version and flags 7008 4 => { 7009 Name => 'LayoutFlags', 7010 Format => 'int16u', 7011 RawConv => '$$self{LayoutFlags} = $val', 7012 PrintConvColumns => 2, 7013 PrintConv => { 7014 0 => 'UseDescriptions', 7015 1 => 'UseBitmap', 7016 100 => 'Mono', 7017 101 => 'Stereo', 7018 102 => 'StereoHeadphones', 7019 100 => 'Mono', 7020 101 => 'Stereo', 7021 102 => 'StereoHeadphones', 7022 103 => 'MatrixStereo', 7023 104 => 'MidSide', 7024 105 => 'XY', 7025 106 => 'Binaural', 7026 107 => 'Ambisonic_B_Format', 7027 108 => 'Quadraphonic', 7028 109 => 'Pentagonal', 7029 110 => 'Hexagonal', 7030 111 => 'Octagonal', 7031 112 => 'Cube', 7032 113 => 'MPEG_3_0_A', 7033 114 => 'MPEG_3_0_B', 7034 115 => 'MPEG_4_0_A', 7035 116 => 'MPEG_4_0_B', 7036 117 => 'MPEG_5_0_A', 7037 118 => 'MPEG_5_0_B', 7038 119 => 'MPEG_5_0_C', 7039 120 => 'MPEG_5_0_D', 7040 121 => 'MPEG_5_1_A', 7041 122 => 'MPEG_5_1_B', 7042 123 => 'MPEG_5_1_C', 7043 124 => 'MPEG_5_1_D', 7044 125 => 'MPEG_6_1_A', 7045 126 => 'MPEG_7_1_A', 7046 127 => 'MPEG_7_1_B', 7047 128 => 'MPEG_7_1_C', 7048 129 => 'Emagic_Default_7_1', 7049 130 => 'SMPTE_DTV', 7050 131 => 'ITU_2_1', 7051 132 => 'ITU_2_2', 7052 133 => 'DVD_4', 7053 134 => 'DVD_5', 7054 135 => 'DVD_6', 7055 136 => 'DVD_10', 7056 137 => 'DVD_11', 7057 138 => 'DVD_18', 7058 139 => 'AudioUnit_6_0', 7059 140 => 'AudioUnit_7_0', 7060 141 => 'AAC_6_0', 7061 142 => 'AAC_6_1', 7062 143 => 'AAC_7_0', 7063 144 => 'AAC_Octagonal', 7064 145 => 'TMH_10_2_std', 7065 146 => 'TMH_10_2_full', 7066 147 => 'DiscreteInOrder', 7067 148 => 'AudioUnit_7_0_Front', 7068 149 => 'AC3_1_0_1', 7069 150 => 'AC3_3_0', 7070 151 => 'AC3_3_1', 7071 152 => 'AC3_3_0_1', 7072 153 => 'AC3_2_1_1', 7073 154 => 'AC3_3_1_1', 7074 155 => 'EAC_6_0_A', 7075 156 => 'EAC_7_0_A', 7076 157 => 'EAC3_6_1_A', 7077 158 => 'EAC3_6_1_B', 7078 159 => 'EAC3_6_1_C', 7079 160 => 'EAC3_7_1_A', 7080 161 => 'EAC3_7_1_B', 7081 162 => 'EAC3_7_1_C', 7082 163 => 'EAC3_7_1_D', 7083 164 => 'EAC3_7_1_E', 7084 165 => 'EAC3_7_1_F', 7085 166 => 'EAC3_7_1_G', 7086 167 => 'EAC3_7_1_H', 7087 168 => 'DTS_3_1', 7088 169 => 'DTS_4_1', 7089 170 => 'DTS_6_0_A', 7090 171 => 'DTS_6_0_B', 7091 172 => 'DTS_6_0_C', 7092 173 => 'DTS_6_1_A', 7093 174 => 'DTS_6_1_B', 7094 175 => 'DTS_6_1_C', 7095 176 => 'DTS_7_0', 7096 177 => 'DTS_7_1', 7097 178 => 'DTS_8_0_A', 7098 179 => 'DTS_8_0_B', 7099 180 => 'DTS_8_1_A', 7100 181 => 'DTS_8_1_B', 7101 182 => 'DTS_6_1_D', 7102 183 => 'AAC_7_1_B', 7103 0xffff => 'Unknown', 7104 }, 7105 }, 7106 6 => { 7107 Name => 'AudioChannels', 7108 Condition => '$$self{LayoutFlags} != 0 and $$self{LayoutFlags} != 1', 7109 Format => 'int16u', 7110 }, 7111 8 => { 7112 Name => 'AudioChannelTypes', 7113 Condition => '$$self{LayoutFlags} == 1', 7114 Format => 'int32u', 7115 PrintConv => { BITMASK => { 7116 0 => 'Left', 7117 1 => 'Right', 7118 2 => 'Center', 7119 3 => 'LFEScreen', 7120 4 => 'LeftSurround', 7121 5 => 'RightSurround', 7122 6 => 'LeftCenter', 7123 7 => 'RightCenter', 7124 8 => 'CenterSurround', 7125 9 => 'LeftSurroundDirect', 7126 10 => 'RightSurroundDirect', 7127 11 => 'TopCenterSurround', 7128 12 => 'VerticalHeightLeft', 7129 13 => 'VerticalHeightCenter', 7130 14 => 'VerticalHeightRight', 7131 15 => 'TopBackLeft', 7132 16 => 'TopBackCenter', 7133 17 => 'TopBackRight', 7134 }}, 7135 }, 7136 12 => { 7137 Name => 'NumChannelDescriptions', 7138 Condition => '$$self{LayoutFlags} == 1', 7139 Format => 'int32u', 7140 RawConv => '$$self{NumChannelDescriptions} = $val', 7141 }, 7142 16 => { 7143 Name => 'Channel1Label', 7144 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0', 7145 Format => 'int32u', 7146 SeparateTable => 'ChannelLabel', 7147 PrintConv => \%channelLabel, 7148 }, 7149 20 => { 7150 Name => 'Channel1Flags', 7151 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0', 7152 Format => 'int32u', 7153 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7154 }, 7155 24 => { 7156 Name => 'Channel1Coordinates', 7157 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0', 7158 Notes => q{ 7159 3 numbers: for rectangular coordinates left/right, back/front, down/up; for 7160 spherical coordinates left/right degrees, down/up degrees, distance 7161 }, 7162 Format => 'float[3]', 7163 }, 7164 36 => { 7165 Name => 'Channel2Label', 7166 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1', 7167 Format => 'int32u', 7168 SeparateTable => 'ChannelLabel', 7169 PrintConv => \%channelLabel, 7170 }, 7171 40 => { 7172 Name => 'Channel2Flags', 7173 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1', 7174 Format => 'int32u', 7175 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7176 }, 7177 44 => { 7178 Name => 'Channel2Coordinates', 7179 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1', 7180 Format => 'float[3]', 7181 }, 7182 56 => { 7183 Name => 'Channel3Label', 7184 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2', 7185 Format => 'int32u', 7186 SeparateTable => 'ChannelLabel', 7187 PrintConv => \%channelLabel, 7188 }, 7189 60 => { 7190 Name => 'Channel3Flags', 7191 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2', 7192 Format => 'int32u', 7193 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7194 }, 7195 64 => { 7196 Name => 'Channel3Coordinates', 7197 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2', 7198 Format => 'float[3]', 7199 }, 7200 76 => { 7201 Name => 'Channel4Label', 7202 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3', 7203 Format => 'int32u', 7204 SeparateTable => 'ChannelLabel', 7205 PrintConv => \%channelLabel, 7206 }, 7207 80 => { 7208 Name => 'Channel4Flags', 7209 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3', 7210 Format => 'int32u', 7211 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7212 }, 7213 84 => { 7214 Name => 'Channel4Coordinates', 7215 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3', 7216 Format => 'float[3]', 7217 }, 7218 96 => { 7219 Name => 'Channel5Label', 7220 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4', 7221 Format => 'int32u', 7222 SeparateTable => 'ChannelLabel', 7223 PrintConv => \%channelLabel, 7224 }, 7225 100 => { 7226 Name => 'Channel5Flags', 7227 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4', 7228 Format => 'int32u', 7229 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7230 }, 7231 104 => { 7232 Name => 'Channel5Coordinates', 7233 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4', 7234 Format => 'float[3]', 7235 }, 7236 116 => { 7237 Name => 'Channel6Label', 7238 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5', 7239 Format => 'int32u', 7240 SeparateTable => 'ChannelLabel', 7241 PrintConv => \%channelLabel, 7242 }, 7243 120 => { 7244 Name => 'Channel6Flags', 7245 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5', 7246 Format => 'int32u', 7247 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7248 }, 7249 124 => { 7250 Name => 'Channel6Coordinates', 7251 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5', 7252 Format => 'float[3]', 7253 }, 7254 136 => { 7255 Name => 'Channel7Label', 7256 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6', 7257 Format => 'int32u', 7258 SeparateTable => 'ChannelLabel', 7259 PrintConv => \%channelLabel, 7260 }, 7261 140 => { 7262 Name => 'Channel7Flags', 7263 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6', 7264 Format => 'int32u', 7265 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7266 }, 7267 144 => { 7268 Name => 'Channel7Coordinates', 7269 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6', 7270 Format => 'float[3]', 7271 }, 7272 156 => { 7273 Name => 'Channel8Label', 7274 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7', 7275 Format => 'int32u', 7276 SeparateTable => 'ChannelLabel', 7277 PrintConv => \%channelLabel, 7278 }, 7279 160 => { 7280 Name => 'Channel8Flags', 7281 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7', 7282 Format => 'int32u', 7283 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7284 }, 7285 164 => { 7286 Name => 'Channel8Coordinates', 7287 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7', 7288 Format => 'float[3]', 7289 }, 7290 # (arbitrarily decode only first 8 channels) 7291 ); 7292 7293 # scheme type atom 7294 # ref http://xhelmboyx.tripod.com/formats/mp4-layout.txt 7295 %Image::ExifTool::QuickTime::SchemeType = ( 7296 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7297 GROUPS => { 2 => 'Audio' }, 7298 # 0 - 4 bytes version 7299 4 => { Name => 'SchemeType', Format => 'undef[4]' }, 7300 8 => { Name => 'SchemeVersion', Format => 'int16u' }, 7301 10 => { Name => 'SchemeURL', Format => 'string[$size-10]' }, 7302 ); 7303 7304 %Image::ExifTool::QuickTime::SchemeInfo = ( 7305 PROCESS_PROC => \&ProcessMOV, 7306 GROUPS => { 2 => 'Audio' }, 7307 user => { 7308 Name => 'UserID', 7309 Groups => { 2 => 'Author' }, 7310 ValueConv => '"0x" . unpack("H*",$val)', 7311 }, 7312 cert => { # ref http://www.onvif.org/specs/stream/ONVIF-ExportFileFormat-Spec-v100.pdf 7313 Name => 'Certificate', 7314 ValueConv => '"0x" . unpack("H*",$val)', 7315 }, 7316 'key ' => { 7317 Name => 'KeyID', 7318 ValueConv => '"0x" . unpack("H*",$val)', 7319 }, 7320 iviv => { 7321 Name => 'InitializationVector', 7322 ValueConv => 'unpack("H*",$val)', 7323 }, 7324 righ => { 7325 Name => 'Rights', 7326 Groups => { 2 => 'Author' }, 7327 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Rights' }, 7328 }, 7329 name => { Name => 'UserName', Groups => { 2 => 'Author' } }, 7330 # chtb 7331 # priv - private data 7332 # sign 7333 # adkm - Adobe DRM key management system (ref http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf) 7334 # iKMS 7335 # iSFM 7336 # iSLT 7337 ); 7338 7339 %Image::ExifTool::QuickTime::Rights = ( 7340 PROCESS_PROC => \&ProcessRights, 7341 GROUPS => { 2 => 'Audio' }, 7342 veID => 'ItemVendorID', #PH ("VendorID" ref 19) 7343 plat => 'Platform', #18? 7344 aver => 'VersionRestrictions', #19 ("appversion?" ref 18) 7345 tran => 'TransactionID', #18 7346 song => 'ItemID', #19 ("appid" ref 18) 7347 tool => { 7348 Name => 'ItemTool', #PH (guess) ("itunes build?" ref 18) 7349 Format => 'string', 7350 }, 7351 medi => 'MediaFlags', #PH (?) 7352 mode => 'ModeFlags', #PH (?) 0x04 is HD flag (https://compilr.com/heksesang/requiem-mac/UnDrm.java) 7353 ); 7354 1888 7355 # MP4 hint sample description box (ref 5) 7356 # (ref https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-SW1) 1889 7357 %Image::ExifTool::QuickTime::HintSampleDesc = ( 1890 PROCESS_PROC => \& Image::ExifTool::ProcessBinaryData,1891 FORMAT => 'int16u',7358 PROCESS_PROC => \&ProcessHybrid, 7359 VARS => { ID_LABEL => 'ID/Index' }, 1892 7360 NOTES => 'MP4 hint sample description.', 1893 2 => { Name => 'HintFormat', Format => 'undef[4]' }, 7361 4 => { Name => 'HintFormat', Format => 'undef[4]' }, 7362 # 14 - int16u DataReferenceIndex 7363 16 => { Name => 'HintTrackVersion', Format => 'int16u' }, 7364 # 18 - int16u LastCompatibleHintTrackVersion 7365 20 => { Name => 'MaxPacketSize', Format => 'int32u' }, 7366 # 7367 # Observed offsets for child atoms of various HintFormat types: 7368 # 7369 # HintFormat Offset Child atoms 7370 # ----------- ------ ---------------- 7371 # "rtp " 24 tims 7372 # 7373 tims => { Name => 'RTPTimeScale', Format => 'int32u' }, 7374 tsro => { Name => 'TimestampRandomOffset', Format => 'int32u' }, 7375 snro => { Name => 'SequenceNumberRandomOffset', Format => 'int32u' }, 7376 ); 7377 7378 # MP4 metadata sample description box 7379 %Image::ExifTool::QuickTime::MetaSampleDesc = ( 7380 PROCESS_PROC => \&ProcessHybrid, 7381 NOTES => 'MP4 metadata sample description.', 7382 4 => { 7383 Name => 'MetaFormat', 7384 Format => 'undef[4]', 7385 RawConv => '$$self{MetaFormat} = $val', 7386 }, 7387 # 7388 # Observed offsets for child atoms of various MetaFormat types: 7389 # 7390 # MetaFormat Offset Child atoms 7391 # ----------- ------ ---------------- 7392 # mebx 24 keys,btrt,lidp,lidl 7393 # fdsc - - 7394 # gpmd - - 7395 # rtmd - - 7396 # CTMD - - 7397 # 7398 'keys' => { #PH (iPhone7+ hevc) 7399 Name => 'Keys', 7400 SubDirectory => { 7401 TagTable => 'Image::ExifTool::QuickTime::Keys', 7402 ProcessProc => \&ProcessMetaKeys, 7403 }, 7404 }, 7405 btrt => { 7406 Name => 'BitrateInfo', 7407 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Bitrate' }, 7408 }, 1894 7409 ); 1895 7410 1896 7411 # MP4 generic sample description box 1897 7412 %Image::ExifTool::QuickTime::OtherSampleDesc = ( 1898 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1899 FORMAT => 'int16u', 1900 2 => { Name => 'OtherFormat', Format => 'undef[4]' }, 7413 PROCESS_PROC => \&ProcessHybrid, 7414 4 => { 7415 Name => 'OtherFormat', 7416 Format => 'undef[4]', 7417 RawConv => '$$self{MetaFormat} = $val', # (yes, use MetaFormat for this too) 7418 }, 7419 # 7420 # Observed offsets for child atoms of various OtherFormat types: 7421 # 7422 # OtherFormat Offset Child atoms 7423 # ----------- ------ ---------------- 7424 # avc1 86 avcC 7425 # mp4a 36 esds 7426 # mp4s 16 esds 7427 # tmcd 34 name 7428 # data - - 7429 # 7430 ftab => { Name => 'FontTable', Format => 'undef', ValueConv => 'substr($val, 5)' }, 7431 name => { Name => 'OtherName', Format => 'undef', ValueConv => 'substr($val, 4)' }, 7432 # mrlh = GM header? 7433 # mrlv = GM data 7434 # mrld = GM data (448-byte records): 7435 # 0 - int32u count 7436 # 4 - int32u ? (related to units) 0=none,1=m/km,2=L,3=kph,4=C,7=deg,8=rpm,9=kPa,10=G,11=V,15=Nm,16=% 7437 # 8 - int32u ? (0,1,3,4,5) 7438 # 12 - string[64] units 7439 # 76 - int32u ? (1,3,7,15) 7440 # 80 - int32u 0 7441 # 84 - undef[4] ? 7442 # 88 - int16u[6] ? 7443 # 100 - undef[32] ? 7444 # 132 - string[64] measurement name 7445 # 196 - string[64] measurement name 1901 7446 ); 1902 7447 … … 1904 7449 %Image::ExifTool::QuickTime::DataInfo = ( 1905 7450 PROCESS_PROC => \&ProcessMOV, 7451 WRITE_PROC => \&WriteQuickTime, # (necessary to parse dref even though we don't change it) 1906 7452 NOTES => 'MP4 data information box.', 1907 7453 dref => { … … 1924 7470 Name => 'Text', 1925 7471 Flags => ['Binary','Unknown'], 7472 }, 7473 tmcd => { 7474 Name => 'TimeCode', 7475 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TimeCode' }, 7476 }, 7477 ); 7478 7479 # TimeCode header 7480 %Image::ExifTool::QuickTime::TimeCode = ( 7481 PROCESS_PROC => \&ProcessMOV, 7482 tcmi => { 7483 Name => 'TCMediaInfo', 7484 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TCMediaInfo' }, 7485 }, 7486 ); 7487 7488 # TimeCode media info (ref 12) 7489 %Image::ExifTool::QuickTime::TCMediaInfo = ( 7490 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7491 GROUPS => { 2 => 'Video' }, 7492 4 => { 7493 Name => 'TextFont', 7494 Format => 'int16u', 7495 PrintConv => { 0 => 'System' }, 7496 }, 7497 6 => { 7498 Name => 'TextFace', 7499 Format => 'int16u', 7500 PrintConv => { 7501 0 => 'Plain', 7502 BITMASK => { 7503 0 => 'Bold', 7504 1 => 'Italic', 7505 2 => 'Underline', 7506 3 => 'Outline', 7507 4 => 'Shadow', 7508 5 => 'Condense', 7509 6 => 'Extend', 7510 }, 7511 }, 7512 }, 7513 8 => { 7514 Name => 'TextSize', 7515 Format => 'int16u', 7516 }, 7517 # 10 - reserved 7518 12 => { 7519 Name => 'TextColor', 7520 Format => 'int16u[3]', 7521 }, 7522 18 => { 7523 Name => 'BackgroundColor', 7524 Format => 'int16u[3]', 7525 }, 7526 24 => { 7527 Name => 'FontName', 7528 Format => 'pstring', 7529 ValueConv => '$self->Decode($val, $self->Options("CharsetQuickTime"))', 1926 7530 }, 1927 7531 ); … … 1946 7550 %Image::ExifTool::QuickTime::DataRef = ( 1947 7551 PROCESS_PROC => \&ProcessMOV, 7552 WRITE_PROC => \&WriteQuickTime, # (necessary to parse dref even though we don't change it) 1948 7553 NOTES => 'MP4 data reference box.', 1949 7554 'url ' => { 1950 7555 Name => 'URL', 7556 Format => 'undef', # (necessary to prevent decoding as string!) 1951 7557 RawConv => q{ 1952 7558 # ignore if self-contained (flags bit 0 set) … … 1955 7561 }, 1956 7562 }, 7563 "url\0" => { # (written by GoPro) 7564 Name => 'URL', 7565 Format => 'undef', # (necessary to prevent decoding as string!) 7566 RawConv => q{ 7567 # ignore if self-contained (flags bit 0 set) 7568 return undef if unpack("N",$val) & 0x01; 7569 $_ = substr($val,4); s/\0.*//s; $_; 7570 }, 7571 }, 1957 7572 'urn ' => { 1958 7573 Name => 'URN', 7574 Format => 'undef', # (necessary to prevent decoding as string!) 1959 7575 RawConv => q{ 1960 7576 return undef if unpack("N",$val) & 0x01; 1961 $_ = substr($val,4); s/\0 .*//s; $_;7577 $_ = substr($val,4); s/\0+/; /; s/\0.*//s; $_; 1962 7578 }, 1963 7579 }, … … 1980 7596 Name => 'HandlerType', 1981 7597 Format => 'undef[4]', 1982 RawConv => '$$self{HandlerType} = $val unless $val eq "alis"; $val', 7598 RawConv => '$$self{HandlerType} = $val unless $val eq "alis" or $val eq "url "; $val', 7599 PrintConvColumns => 2, 1983 7600 PrintConv => { 1984 7601 alis => 'Alias Data', #PH … … 1987 7604 ipsm => 'IPMP', #3 1988 7605 m7sm => 'MPEG-7 Stream', #3 7606 meta => 'NRT Metadata', #PH 1989 7607 mdir => 'Metadata', #3 1990 7608 mdta => 'Metadata Tags', #PH … … 1992 7610 ocsm => 'Object Content', #3 1993 7611 odsm => 'Object Descriptor', #3 7612 priv => 'Private', #PH 1994 7613 sdsm => 'Scene Description', #3 1995 7614 soun => 'Audio Track', 1996 7615 text => 'Text', #PH (but what type? subtitle?) 7616 tmcd => 'Time Code', #PH 1997 7617 'url '=> 'URL', #3 1998 7618 vide => 'Video Track', 7619 subp => 'Subpicture', #http://www.google.nl/patents/US7778526 7620 nrtm => 'Non-Real Time Metadata', #PH (Sony ILCE-7S) [how is this different from "meta"?] 7621 pict => 'Picture', # (HEIC images) 7622 camm => 'Camera Metadata', # (Insta360 MP4) 7623 psmd => 'Panasonic Static Metadata', #PH (Leica C-Lux CAM-DC25) 7624 data => 'Data', #PH (GPS and G-sensor data from DataKam) 7625 sbtl => 'Subtitle', #PH (TomTom Bandit Action Cam) 1999 7626 }, 2000 7627 }, … … 2034 7661 28 => { 2035 7662 Name => 'PreviewImage', 7663 Groups => { 2 => 'Preview' }, 2036 7664 Format => 'undef[$val{13}]', 2037 7665 RawConv => '$self->ValidateImage(\$val, $tag)', 7666 }, 7667 ); 7668 7669 # atoms in Pittasoft "free" atom 7670 %Image::ExifTool::QuickTime::Pittasoft = ( 7671 PROCESS_PROC => \&ProcessMOV, 7672 NOTES => 'Tags found in Pittasoft Blackvue dashcam "free" data.', 7673 cprt => 'Copyright', 7674 thum => { 7675 Name => 'PreviewImage', 7676 Groups => { 2 => 'Preview' }, 7677 Binary => 1, 7678 RawConv => q{ 7679 return undef unless length $val > 4; 7680 my $len = unpack('N', $val); 7681 return undef unless length $val >= 4 + $len; 7682 return substr($val, 4, $len); 7683 }, 7684 }, 7685 ptnm => { 7686 Name => 'OriginalFileName', 7687 ValueConv => 'substr($val, 4, -1)', 7688 }, 7689 ptrh => { 7690 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' }, 7691 # contains these atoms: 7692 # ptvi - 27 bytes: '..avc1...' 7693 # ptso - 16 bytes: '..mp4a...' 7694 }, 7695 'gps ' => { 7696 Name => 'GPSLog', 7697 Binary => 1, # (ASCII NMEA track log with leading timestamps) 7698 Notes => 'parsed to extract GPS separately when ExtractEmbedded is used', 7699 RawConv => q{ 7700 $val =~ s/\0+$//; # remove trailing nulls 7701 if (length $val and $$self{OPTIONS}{ExtractEmbedded}) { 7702 my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); 7703 Image::ExifTool::QuickTime::ProcessNMEA($self, { DataPt => \$val }, $tagTbl); 7704 } 7705 return $val; 7706 }, 7707 }, 7708 '3gf ' => { 7709 Name => 'AccelData', 7710 SubDirectory => { 7711 TagTable => 'Image::ExifTool::QuickTime::Stream', 7712 ProcessProc => \&Process_3gf, 7713 }, 7714 }, 7715 sttm => { 7716 Name => 'StartTime', 7717 Format => 'int64u', 7718 Groups => { 2 => 'Time' }, 7719 RawConv => '$$self{StartTime} = $val', 7720 # (ms since Jan 1, 1970, in local time zone - PH) 7721 ValueConv => q{ 7722 my $secs = int($val / 1000); 7723 return ConvertUnixTime($secs) . sprintf(".%03d",$val - $secs * 1000); 7724 }, 7725 PrintConv => '$self->ConvertDateTime($val)', 2038 7726 }, 2039 7727 ); … … 2043 7731 GROUPS => { 2 => 'Video' }, 2044 7732 Rotation => { 7733 Notes => q{ 7734 writing this tag updates QuickTime MatrixStructure for all tracks with a 7735 non-zero image size 7736 }, 2045 7737 Require => { 2046 7738 0 => 'QuickTime:MatrixStructure', 2047 7739 1 => 'QuickTime:HandlerType', 2048 7740 }, 7741 Writable => 1, 7742 Protected => 1, 7743 WriteAlso => { 7744 MatrixStructure => 'Image::ExifTool::QuickTime::GetRotationMatrix($val)', 7745 }, 2049 7746 ValueConv => 'Image::ExifTool::QuickTime::CalcRotation($self)', 7747 ValueConvInv => '$val', 2050 7748 }, 2051 7749 AvgBitrate => { 2052 7750 Priority => 0, # let QuickTime::AvgBitrate take priority 2053 7751 Require => { 2054 0 => 'QuickTime::M ovieDataSize',7752 0 => 'QuickTime::MediaDataSize', 2055 7753 1 => 'QuickTime::Duration', 2056 7754 }, … … 2058 7756 return undef unless $val[1]; 2059 7757 $val[1] /= $$self{TimeScale} if $$self{TimeScale}; 2060 return int($val[0] * 8 / $val[1] + 0.5); 7758 my $key = 'MediaDataSize'; 7759 my $size = $val[0]; 7760 for (;;) { 7761 $key = $self->NextTagKey($key) or last; 7762 $size += $self->GetValue($key, 'ValueConv'); 7763 } 7764 return int($size * 8 / $val[1] + 0.5); 2061 7765 }, 2062 7766 PrintConv => 'ConvertBitrate($val)', … … 2066 7770 Groups => { 2 => 'Location' }, 2067 7771 ValueConv => 'my @c = split " ", $val; $c[0]', 2068 PrintConv => q{ 2069 require Image::ExifTool::GPS; 2070 Image::ExifTool::GPS::ToDMS($self, $val, 1, 'N'); 2071 }, 7772 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', 2072 7773 }, 2073 7774 GPSLongitude => { … … 2075 7776 Groups => { 2 => 'Location' }, 2076 7777 ValueConv => 'my @c = split " ", $val; $c[1]', 2077 PrintConv => q{ 2078 require Image::ExifTool::GPS; 2079 Image::ExifTool::GPS::ToDMS($self, $val, 1, 'E'); 2080 }, 7778 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', 2081 7779 }, 2082 7780 # split altitude into GPSAltitude/GPSAltitudeRef like EXIF and XMP … … 2098 7796 }, 2099 7797 }, 7798 GPSLatitude2 => { 7799 Name => 'GPSLatitude', 7800 Require => 'QuickTime:LocationInformation', 7801 Groups => { 2 => 'Location' }, 7802 ValueConv => '$val =~ /Lat=([-+.\d]+)/; $1', 7803 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', 7804 }, 7805 GPSLongitude2 => { 7806 Name => 'GPSLongitude', 7807 Require => 'QuickTime:LocationInformation', 7808 Groups => { 2 => 'Location' }, 7809 ValueConv => '$val =~ /Lon=([-+.\d]+)/; $1', 7810 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', 7811 }, 7812 GPSAltitude2 => { 7813 Name => 'GPSAltitude', 7814 Require => 'QuickTime:LocationInformation', 7815 Groups => { 2 => 'Location' }, 7816 ValueConv => '$val =~ /Alt=([-+.\d]+)/; abs($1)', 7817 PrintConv => '"$val m"', 7818 }, 7819 GPSAltitudeRef2 => { 7820 Name => 'GPSAltitudeRef', 7821 Require => 'QuickTime:LocationInformation', 7822 Groups => { 2 => 'Location' }, 7823 ValueConv => '$val =~ /Alt=([-+.\d]+)/; $1 < 0 ? 1 : 0', 7824 PrintConv => { 7825 0 => 'Above Sea Level', 7826 1 => 'Below Sea Level', 7827 }, 7828 }, 7829 CDDBDiscPlayTime => { 7830 Require => 'CDDB1Info', 7831 Groups => { 2 => 'Audio' }, 7832 ValueConv => '$val =~ /^..([a-z0-9]{4})/i ? hex($1) : undef', 7833 PrintConv => 'ConvertDuration($val)', 7834 }, 7835 CDDBDiscTracks => { 7836 Require => 'CDDB1Info', 7837 Groups => { 2 => 'Audio' }, 7838 ValueConv => '$val =~ /^.{6}([a-z0-9]{2})/i ? hex($1) : undef', 7839 }, 2100 7840 ); 2101 7841 … … 2103 7843 Image::ExifTool::AddCompositeTags('Image::ExifTool::QuickTime'); 2104 7844 7845 7846 #------------------------------------------------------------------------------ 7847 # AutoLoad our routines when necessary 7848 # 7849 sub AUTOLOAD 7850 { 7851 # (Note: no need to autoload routines in QuickTimeStream that use Stream table) 7852 if ($AUTOLOAD eq 'Image::ExifTool::QuickTime::Process_mebx') { 7853 require 'Image/ExifTool/QuickTimeStream.pl'; 7854 no strict 'refs'; 7855 return &$AUTOLOAD(@_); 7856 } else { 7857 return Image::ExifTool::DoAutoLoad($AUTOLOAD, @_); 7858 } 7859 } 7860 7861 #------------------------------------------------------------------------------ 7862 # Get rotation matrix 7863 # Inputs: 0) angle in degrees 7864 # Returns: 9-element rotation matrix as a string (with 0 x/y offsets) 7865 sub GetRotationMatrix($) 7866 { 7867 my $ang = 3.1415926536 * shift() / 180; 7868 my $cos = cos $ang; 7869 my $sin = sin $ang; 7870 my $msn = -$sin; 7871 return "$cos $sin 0 $msn $cos 0 0 0 1"; 7872 } 7873 7874 #------------------------------------------------------------------------------ 7875 # Get rotation angle from a matrix 7876 # Inputs: 0) rotation matrix as a string 7877 # Return: positive rotation angle in degrees rounded to 3 decimal points, 7878 # or undef on error 7879 sub GetRotationAngle($) 7880 { 7881 my $rotMatrix = shift; 7882 my @a = split ' ', $rotMatrix; 7883 return undef if $a[0]==0 and $a[1]==0; 7884 # calculate the rotation angle (assume uniform rotation) 7885 my $angle = atan2($a[1], $a[0]) * 180 / 3.14159; 7886 $angle += 360 if $angle < 0; 7887 return int($angle * 1000 + 0.5) / 1000; 7888 } 2105 7889 2106 7890 #------------------------------------------------------------------------------ … … 2110 7894 sub CalcRotation($) 2111 7895 { 2112 my $e xifTool= shift;2113 my $value = $$e xifTool{VALUE};7896 my $et = shift; 7897 my $value = $$et{VALUE}; 2114 7898 my ($i, $track); 2115 # get the video track family 1 group ( ie. "Track1");7899 # get the video track family 1 group (eg. "Track1"); 2116 7900 for ($i=0; ; ++$i) { 2117 7901 my $idx = $i ? " ($i)" : ''; … … 2119 7903 last unless $$value{$tag}; 2120 7904 next unless $$value{$tag} eq 'vide'; 2121 $track = $e xifTool->GetGroup($tag, 1);7905 $track = $et->GetGroup($tag, 1); 2122 7906 last; 2123 7907 } … … 2128 7912 my $tag = "MatrixStructure$idx"; 2129 7913 last unless $$value{$tag}; 2130 next unless $exifTool->GetGroup($tag, 1) eq $track; 2131 my @a = split ' ', $$value{$tag}; 2132 return undef unless $a[0] or $a[1]; 2133 # calculate the rotation angle (assume uniform rotation) 2134 my $angle = atan2($a[1], $a[0]) * 180 / 3.14159; 2135 $angle += 360 if $angle < 0; 2136 return int($angle * 1000 + 0.5) / 1000; 7914 next unless $et->GetGroup($tag, 1) eq $track; 7915 return GetRotationAngle($$value{$tag}); 2137 7916 } 2138 7917 return undef; 7918 } 7919 7920 #------------------------------------------------------------------------------ 7921 # Get MatrixStructure for a given rotation angle 7922 # Inputs: 0) rotation angle (deg), 1) ExifTool ref 7923 # Returns: matrix structure as a string, or undef if it can't be rotated 7924 # - requires ImageSizeLookahead to determine the video image size, and doesn't 7925 # rotate matrix unless image size is valid 7926 sub GetMatrixStructure($$) 7927 { 7928 my ($val, $et) = @_; 7929 my @a = split ' ', $val; 7930 # pass straight through if it already has an offset 7931 return $val unless $a[6] == 0 and $a[7] == 0; 7932 my @s = split ' ', $$et{ImageSizeLookahead}; 7933 my ($w, $h) = @s[12,13]; 7934 return undef unless $w and $h; # don't rotate 0-sized track 7935 $_ = Image::ExifTool::QuickTime::FixWrongFormat($_) foreach $w,$h; 7936 # apply necessary offsets for the standard rotations 7937 my $angle = GetRotationAngle($val); 7938 return undef unless defined $angle; 7939 if ($angle == 90) { 7940 @a[6,7] = ($h, 0); 7941 } elsif ($angle == 180) { 7942 @a[6,7] = ($w, $h); 7943 } elsif ($angle == 270) { 7944 @a[6,7] = (0, $w); 7945 } 7946 return "@a"; 2139 7947 } 2140 7948 … … 2145 7953 sub CalcSampleRate($$) 2146 7954 { 2147 my ($e xifTool, $valPt) = @_;7955 my ($et, $valPt) = @_; 2148 7956 my @dat = unpack('N*', $$valPt); 2149 7957 my ($num, $dur) = (0, 0); … … 2153 7961 $dur += $dat[$i] * $dat[$i+1]; # total sample duration 2154 7962 } 2155 return undef unless $num and $dur and $$e xifTool{MediaTS};2156 return $num * $$e xifTool{MediaTS} / $dur;7963 return undef unless $num and $dur and $$et{MediaTS}; 7964 return $num * $$et{MediaTS} / $dur; 2157 7965 } 2158 7966 … … 2163 7971 my $val = shift; 2164 7972 return undef unless $val; 2165 if ($val & 0xffff0000) { 2166 $val = unpack('n',pack('N',$val)); 2167 } 2168 return $val; 7973 return $val & 0xfff00000 ? unpack('n',pack('N',$val)) : $val; 2169 7974 } 2170 7975 … … 2172 7977 # Convert ISO 6709 string to standard lag/lon format 2173 7978 # Inputs: 0) ISO 6709 string (lat, lon, and optional alt) 2174 # Returns: position in decimal degre ss with altitude if available7979 # Returns: position in decimal degrees with altitude if available 2175 7980 # Notes: Wikipedia indicates altitude may be in feet -- how is this specified? 2176 7981 sub ConvertISO6709($) 2177 7982 { 2178 7983 my $val = shift; 2179 if ($val =~ /^([-+]\d{2}(?:\.\d*)?)([-+]\d{3}(?:\.\d*)?)([-+]\d+)?/) { 7984 if ($val =~ /^([-+]\d{1,2}(?:\.\d*)?)([-+]\d{1,3}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) { 7985 # +DD.DDD+DDD.DDD+AA.AAA 2180 7986 $val = ($1 + 0) . ' ' . ($2 + 0); 2181 7987 $val .= ' ' . ($3 + 0) if $3; 2182 } elsif ($val =~ /^([-+])(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2}(?:\.\d*)?)([-+]\d+)?/) { 7988 } elsif ($val =~ /^([-+])(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) { 7989 # +DDMM.MMM+DDDMM.MMM+AA.AAA 2183 7990 my $lat = $2 + $3 / 60; 2184 7991 $lat = -$lat if $1 eq '-'; … … 2187 7994 $val = "$lat $lon"; 2188 7995 $val .= ' ' . ($7 + 0) if $7; 2189 } elsif ($val =~ /^([-+])(\d{2})(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2})(\d{2}(?:\.\d*)?)([-+]\d+)?/) { 7996 } elsif ($val =~ /^([-+])(\d{2})(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2})(\d{2}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) { 7997 # +DDMMSS.SSS+DDDMMSS.SSS+AA.AAA 2190 7998 my $lat = $2 + $3 / 60 + $4 / 3600; 2191 7999 $lat = -$lat if $1 eq '-'; … … 2199 8007 2200 8008 #------------------------------------------------------------------------------ 8009 # Convert Nero chapter list (ref ffmpeg libavformat/movenc.c) 8010 # Inputs: 0) binary chpl data 8011 # Returns: chapter list 8012 sub ConvertChapterList($) 8013 { 8014 my $val = shift; 8015 my $size = length $val; 8016 return '<invalid>' if $size < 9; 8017 my $num = Get8u(\$val, 8); 8018 my ($i, @chapters); 8019 my $pos = 9; 8020 for ($i=0; $i<$num; ++$i) { 8021 last if $pos + 9 > $size; 8022 my $dur = Get64u(\$val, $pos) / 10000000; 8023 my $len = Get8u(\$val, $pos + 8); 8024 last if $pos + 9 + $len > $size; 8025 my $title = substr($val, $pos + 9, $len); 8026 $pos += 9 + $len; 8027 push @chapters, "$dur $title"; 8028 } 8029 return \@chapters; # return as a list 8030 } 8031 8032 #------------------------------------------------------------------------------ 8033 # Print conversion for a Nero chapter list item 8034 # Inputs: 0) ValueConv chapter string 8035 # Returns: formatted chapter string 8036 sub PrintChapter($) 8037 { 8038 my $val = shift; 8039 $val =~ /^(\S+) (.*)/ or return $val; 8040 my ($dur, $title) = ($1, $2); 8041 my $h = int($dur / 3600); 8042 $dur -= $h * 3600; 8043 my $m = int($dur / 60); 8044 my $s = $dur - $m * 60; 8045 my $ss = sprintf('%06.3f', $s); 8046 if ($ss >= 60) { 8047 $ss = '00.000'; 8048 ++$m >= 60 and $m -= 60, ++$h; 8049 } 8050 return sprintf("[%d:%.2d:%s] %s",$h,$m,$ss,$title); 8051 } 8052 8053 #------------------------------------------------------------------------------ 2201 8054 # Format GPSCoordinates for printing 2202 8055 # Inputs: 0) string with numerical lat, lon and optional alt, separated by spaces … … 2205 8058 sub PrintGPSCoordinates($) 2206 8059 { 2207 my ($val, $exifTool) = @_; 2208 require Image::ExifTool::GPS; 8060 my ($val, $et) = @_; 2209 8061 my @v = split ' ', $val; 2210 my $prt = Image::ExifTool::GPS::ToDMS($e xifTool, $v[0], 1, "N") . ', ' .2211 Image::ExifTool::GPS::ToDMS($e xifTool, $v[1], 1, "E");8062 my $prt = Image::ExifTool::GPS::ToDMS($et, $v[0], 1, "N") . ', ' . 8063 Image::ExifTool::GPS::ToDMS($et, $v[1], 1, "E"); 2212 8064 if (defined $v[2]) { 2213 8065 $prt .= ', ' . ($v[2] < 0 ? -$v[2] . ' m Below' : $v[2] . ' m Above') . ' Sea Level'; … … 2218 8070 #------------------------------------------------------------------------------ 2219 8071 # Unpack packed ISO 639/T language code 2220 # Inputs: 0) packed language code (or undef )2221 # Returns: language code, or undef for default language, or 'err' for format error2222 sub UnpackLang($ )8072 # Inputs: 0) packed language code (or undef/0), 1) true to not treat 'und' and 'eng' as default 8073 # Returns: language code, or undef/0 for default language, or 'err' for format error 8074 sub UnpackLang($;$) 2223 8075 { 2224 my $lang = shift;8076 my ($lang, $noDef) = @_; 2225 8077 if ($lang) { 2226 8078 # language code is packed in 5-bit characters 2227 $lang = pack "C*", map { (($lang>>$_)&0x1f)+0x60 } 10, 5, 0;8079 $lang = pack 'C*', map { (($lang>>$_)&0x1f)+0x60 } 10, 5, 0; 2228 8080 # validate language code 2229 8081 if ($lang =~ /^[a-z]+$/) { 2230 8082 # treat 'eng' or 'und' as the default language 2231 undef $lang if $lang eq 'und' or $lang eq 'eng';8083 undef $lang if ($lang eq 'und' or $lang eq 'eng') and not $noDef; 2232 8084 } else { 2233 8085 $lang = 'err'; # invalid language code … … 2238 8090 2239 8091 #------------------------------------------------------------------------------ 8092 # Get language code string given QuickTime language and country codes 8093 # Inputs: 0) numerical language code, 1) numerical country code, 2) no defaults 8094 # Returns: language code string (ie. "fra-FR") or undef for default language 8095 sub GetLangCode($;$$) 8096 { 8097 my ($lang, $ctry, $noDef) = @_; 8098 # ignore country ('ctry') and language lists ('lang') for now 8099 undef $ctry if $ctry and $ctry <= 255; 8100 undef $lang if $lang and $lang <= 255; 8101 $lang = UnpackLang($lang, $noDef); 8102 # add country code if specified 8103 if ($ctry) { 8104 $ctry = unpack('a2',pack('n',$ctry)); # unpack as ISO 3166-1 8105 # treat 'ZZ' like a default country (see ref 12) 8106 undef $ctry if $ctry eq 'ZZ'; 8107 if ($ctry and $ctry =~ /^[A-Z]{2}$/) { 8108 $lang or $lang = 'und'; 8109 $lang .= "-$ctry"; 8110 } 8111 } 8112 return $lang; 8113 } 8114 8115 #------------------------------------------------------------------------------ 8116 # Get langInfo hash and save details about alt-lang tags 8117 # Inputs: 0) ExifTool ref, 1) tagInfo hash ref, 2) locale code 8118 # Returns: new tagInfo hash ref, or undef if invalid 8119 sub GetLangInfoQT($$$) 8120 { 8121 my ($et, $tagInfo, $langCode) = @_; 8122 my $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $langCode); 8123 if ($langInfo) { 8124 $$et{QTLang} or $$et{QTLang} = [ ]; 8125 push @{$$et{QTLang}}, $$langInfo{Name}; 8126 } 8127 return $langInfo; 8128 } 8129 8130 #------------------------------------------------------------------------------ 8131 # Get variable-length integer from data (used by ParseItemLocation) 8132 # Inputs: 0) data ref, 1) start position, 2) integer size in bytes (0, 4 or 8), 8133 # 3) default value 8134 # Returns: integer value, and updates current position 8135 sub GetVarInt($$$;$) 8136 { 8137 my ($dataPt, $pos, $n, $default) = @_; 8138 my $len = length $$dataPt; 8139 $_[1] = $pos + $n; # update current position 8140 return undef if $pos + $n > $len; 8141 if ($n == 0) { 8142 return $default || 0; 8143 } elsif ($n == 4) { 8144 return Get32u($dataPt, $pos); 8145 } elsif ($n == 8) { 8146 return Get64u($dataPt, $pos); 8147 } 8148 return undef; 8149 } 8150 8151 #------------------------------------------------------------------------------ 8152 # Get null-terminated string from binary data (used by ParseItemInfoEntry) 8153 # Inputs: 0) data ref, 1) start position 8154 # Returns: string, and updates current position 8155 sub GetString($$) 8156 { 8157 my ($dataPt, $pos) = @_; 8158 my $len = length $$dataPt; 8159 my $str = ''; 8160 while ($pos < $len) { 8161 my $ch = substr($$dataPt, $pos, 1); 8162 ++$pos; 8163 last if ord($ch) == 0; 8164 $str .= $ch; 8165 } 8166 $_[1] = $pos; # update current position 8167 return $str; 8168 } 8169 8170 #------------------------------------------------------------------------------ 8171 # Get a printable version of the tag ID 8172 # Inputs: 0) tag ID, 1) Flag: 0x01 - print as 4- or 8-digit hex value if necessary 8173 # 0x02 - put leading backslash before escaped character 8174 # Returns: Printable tag ID 8175 sub PrintableTagID($;$) 8176 { 8177 my $tag = $_[0]; 8178 my $n = ($tag =~ s/([\x00-\x1f\x7f-\xff])/'x'.unpack('H*',$1)/eg); 8179 if ($n and $_[1]) { 8180 if ($n > 2 and $_[1] & 0x01) { 8181 $tag = '0x' . unpack('H8', $_[0]); 8182 $tag =~ s/^0x0000/0x/; 8183 } elsif ($_[1] & 0x02) { 8184 ($tag = $_[0]) =~ s/([\x00-\x1f\x7f-\xff])/'\\x'.unpack('H*',$1)/eg; 8185 } 8186 } 8187 return $tag; 8188 } 8189 8190 #============================================================================== 8191 # The following ParseXxx routines parse various boxes to extract this 8192 # information about embedded items in a $$et{ItemInfo} hash, keyed by item ID: 8193 # 8194 # iloc: 8195 # ConstructionMethod - offset type: 0=file, 1=idat, 2=item 8196 # DataReferenceIndex - 0 for "this file", otherwise index in dref box 8197 # BaseOffset - base for file offsets 8198 # Extents - list of details for data in file: 8199 # 0) index (extent_index) 8200 # 1) offset (extent_offset) 8201 # 2) length (extent_length) 8202 # 3) nlen (length_size) 8203 # 4) lenPt (pointer to length word) 8204 # infe: 8205 # ProtectionIndex - index if item is protected (0 for unprotected) 8206 # Name - item name 8207 # ContentType - mime type of item 8208 # ContentEncoding - item encoding 8209 # URI - URI of a 'uri '-type item 8210 # ipma: 8211 # Association - list of associated properties in the ipco container 8212 # Essential - list of "essential" flags for the associated properties 8213 # cdsc: 8214 # RefersTo - hash lookup of flags based on referred item ID 8215 # other: 8216 # DocNum - exiftool document number for this item 8217 # 8218 #------------------------------------------------------------------------------ 8219 # Parse item location (iloc) box (ref ISO 14496-12:2015 pg.79) 8220 # Inputs: 0) iloc data, 1) ExifTool ref 8221 # Returns: undef, and fills in ExifTool ItemInfo hash 8222 # Notes: see also Handle_iloc() in WriteQuickTime.pl 8223 sub ParseItemLocation($$) 8224 { 8225 my ($val, $et) = @_; 8226 my ($i, $j, $num, $pos, $id); 8227 my ($extent_index, $extent_offset, $extent_length); 8228 8229 my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose'); 8230 my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { }); 8231 my $len = length $val; 8232 return undef if $len < 8; 8233 my $ver = Get8u(\$val, 0); 8234 my $siz = Get16u(\$val, 4); 8235 my $noff = ($siz >> 12); 8236 my $nlen = ($siz >> 8) & 0x0f; 8237 my $nbas = ($siz >> 4) & 0x0f; 8238 my $nind = $siz & 0x0f; 8239 if ($ver < 2) { 8240 $num = Get16u(\$val, 6); 8241 $pos = 8; 8242 } else { 8243 return undef if $len < 10; 8244 $num = Get32u(\$val, 6); 8245 $pos = 10; 8246 } 8247 for ($i=0; $i<$num; ++$i) { 8248 if ($ver < 2) { 8249 return undef if $pos + 2 > $len; 8250 $id = Get16u(\$val, $pos); 8251 $pos += 2; 8252 } else { 8253 return undef if $pos + 4 > $len; 8254 $id = Get32u(\$val, $pos); 8255 $pos += 4; 8256 } 8257 if ($ver == 1 or $ver == 2) { 8258 return undef if $pos + 2 > $len; 8259 $$items{$id}{ConstructionMethod} = Get16u(\$val, $pos) & 0x0f; 8260 $pos += 2; 8261 } 8262 return undef if $pos + 2 > $len; 8263 $$items{$id}{DataReferenceIndex} = Get16u(\$val, $pos); 8264 $pos += 2; 8265 $$items{$id}{BaseOffset} = GetVarInt(\$val, $pos, $nbas); 8266 return undef if $pos + 2 > $len; 8267 my $ext_num = Get16u(\$val, $pos); 8268 $pos += 2; 8269 my @extents; 8270 for ($j=0; $j<$ext_num; ++$j) { 8271 if ($ver == 1 or $ver == 2) { 8272 $extent_index = GetVarInt(\$val, $pos, $nind, 1); 8273 } 8274 $extent_offset = GetVarInt(\$val, $pos, $noff); 8275 $extent_length = GetVarInt(\$val, $pos, $nlen); 8276 return undef unless defined $extent_length; 8277 $et->VPrint(1, "$$et{INDENT} Item $id: const_meth=", 8278 defined $$items{$id}{ConstructionMethod} ? $$items{$id}{ConstructionMethod} : '', 8279 sprintf(" base=0x%x offset=0x%x len=0x%x\n", $$items{$id}{BaseOffset}, 8280 $extent_offset, $extent_length)) if $verbose; 8281 push @extents, [ $extent_index, $extent_offset, $extent_length, $nlen, $pos-$nlen ]; 8282 } 8283 # save item location information keyed on 1-based item ID: 8284 $$items{$id}{Extents} = \@extents; 8285 } 8286 return undef; 8287 } 8288 8289 #------------------------------------------------------------------------------ 8290 # Parse content describes entry (cdsc) box 8291 # Inputs: 0) cdsc data, 1) ExifTool ref 8292 # Returns: undef, and fills in ExifTool ItemInfo hash 8293 sub ParseContentDescribes($$) 8294 { 8295 my ($val, $et) = @_; 8296 my ($id, $count, @to); 8297 if ($$et{ItemRefVersion}) { 8298 return undef if length $val < 10; 8299 ($id, $count, @to) = unpack('NnN*', $val); 8300 } else { 8301 return undef if length $val < 6; 8302 ($id, $count, @to) = unpack('nnn*', $val); 8303 } 8304 if ($count > @to) { 8305 my $str = 'Missing values in ContentDescribes box'; 8306 $$et{IsWriting} ? $et->Error($str) : $et->Warn($str); 8307 } elsif ($count < @to) { 8308 $et->Warn('Ignored extra values in ContentDescribes box', 1); 8309 @to = $count; 8310 } 8311 # add all referenced item ID's to a "RefersTo" lookup 8312 $$et{ItemInfo}{$id}{RefersTo}{$_} = 1 foreach @to; 8313 return undef; 8314 } 8315 8316 #------------------------------------------------------------------------------ 8317 # Parse item information entry (infe) box (ref ISO 14496-12:2015 pg.82) 8318 # Inputs: 0) infe data, 1) ExifTool ref 8319 # Returns: undef, and fills in ExifTool ItemInfo hash 8320 sub ParseItemInfoEntry($$) 8321 { 8322 my ($val, $et) = @_; 8323 my $id; 8324 8325 my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose'); 8326 my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { }); 8327 my $len = length $val; 8328 return undef if $len < 4; 8329 my $ver = Get8u(\$val, 0); 8330 my $pos = 4; 8331 return undef if $pos + 4 > $len; 8332 if ($ver == 0 or $ver == 1) { 8333 $id = Get16u(\$val, $pos); 8334 $$items{$id}{ProtectionIndex} = Get16u(\$val, $pos + 2); 8335 $pos += 4; 8336 $$items{$id}{Name} = GetString(\$val, $pos); 8337 $$items{$id}{ContentType} = GetString(\$val, $pos); 8338 $$items{$id}{ContentEncoding} = GetString(\$val, $pos); 8339 } else { 8340 if ($ver == 2) { 8341 $id = Get16u(\$val, $pos); 8342 $pos += 2; 8343 } elsif ($ver == 3) { 8344 $id = Get32u(\$val, $pos); 8345 $pos += 4; 8346 } 8347 return undef if $pos + 6 > $len; 8348 $$items{$id}{ProtectionIndex} = Get16u(\$val, $pos); 8349 my $type = substr($val, $pos + 2, 4); 8350 $$items{$id}{Type} = $type; 8351 $pos += 6; 8352 $$items{$id}{Name} = GetString(\$val, $pos); 8353 if ($type eq 'mime') { 8354 $$items{$id}{ContentType} = GetString(\$val, $pos); 8355 $$items{$id}{ContentEncoding} = GetString(\$val, $pos); 8356 } elsif ($type eq 'uri ') { 8357 $$items{$id}{URI} = GetString(\$val, $pos); 8358 } 8359 } 8360 $et->VPrint(1, "$$et{INDENT} Item $id: Type=", $$items{$id}{Type} || '', 8361 ' Name=', $$items{$id}{Name} || '', 8362 ' ContentType=', $$items{$id}{ContentType} || '', 8363 "\n") if $verbose > 1; 8364 return undef; 8365 } 8366 8367 #------------------------------------------------------------------------------ 8368 # Parse item property association (ipma) box (ref https://github.com/gpac/gpac/blob/master/src/isomedia/iff.c) 8369 # Inputs: 0) ipma data, 1) ExifTool ref 8370 # Returns: undef, and fills in ExifTool ItemInfo hash 8371 sub ParseItemPropAssoc($$) 8372 { 8373 my ($val, $et) = @_; 8374 my ($i, $j, $id); 8375 8376 my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose'); 8377 my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { }); 8378 my $len = length $val; 8379 return undef if $len < 8; 8380 my $ver = Get8u(\$val, 0); 8381 my $flg = Get32u(\$val, 0); 8382 my $num = Get32u(\$val, 4); 8383 my $pos = 8; 8384 for ($i=0; $i<$num; ++$i) { 8385 if ($ver == 0) { 8386 return undef if $pos + 3 > $len; 8387 $id = Get16u(\$val, $pos); 8388 $pos += 2; 8389 } else { 8390 return undef if $pos + 5 > $len; 8391 $id = Get32u(\$val, $pos); 8392 $pos += 4; 8393 } 8394 my $n = Get8u(\$val, $pos++); 8395 my (@association, @essential); 8396 if ($flg & 0x01) { 8397 return undef if $pos + $n * 2 > $len; 8398 for ($j=0; $j<$n; ++$j) { 8399 my $tmp = Get16u(\$val, $pos + $j * 2); 8400 push @association, $tmp & 0x7fff; 8401 push @essential, ($tmp & 0x8000) ? 1 : 0; 8402 } 8403 $pos += $n * 2; 8404 } else { 8405 return undef if $pos + $n > $len; 8406 for ($j=0; $j<$n; ++$j) { 8407 my $tmp = Get8u(\$val, $pos + $j); 8408 push @association, $tmp & 0x7f; 8409 push @essential, ($tmp & 0x80) ? 1 : 0; 8410 } 8411 $pos += $n; 8412 } 8413 $$items{$id}{Association} = \@association; 8414 $$items{$id}{Essential} = \@essential; 8415 $et->VPrint(1, "$$et{INDENT} Item $id properties: @association\n") if $verbose > 1; 8416 } 8417 return undef; 8418 } 8419 8420 #------------------------------------------------------------------------------ 8421 # Process item information now 8422 # Inputs: 0) ExifTool ref 8423 sub HandleItemInfo($) 8424 { 8425 my $et = shift; 8426 my $raf = $$et{RAF}; 8427 my $items = $$et{ItemInfo}; 8428 my $verbose = $et->Options('Verbose'); 8429 my $buff; 8430 8431 # extract information from EXIF/XMP metadata items 8432 if ($items and $raf) { 8433 push @{$$et{PATH}}, 'ItemInformation'; 8434 my $curPos = $raf->Tell(); 8435 my $primary = $$et{PrimaryItem}; 8436 my $id; 8437 $et->VerboseDir('Processing items from ItemInformation', scalar(keys %$items)); 8438 foreach $id (sort { $a <=> $b } keys %$items) { 8439 my $item = $$items{$id}; 8440 my $type = $$item{ContentType} || $$item{Type} || next; 8441 if ($verbose) { 8442 # add up total length of this item for the verbose output 8443 my $len = 0; 8444 if ($$item{Extents} and @{$$item{Extents}}) { 8445 $len += $$_[2] foreach @{$$item{Extents}}; 8446 } 8447 $et->VPrint(0, "$$et{INDENT}Item $id) '${type}' ($len bytes)\n"); 8448 } 8449 # get ExifTool name for this item 8450 my $name = { Exif => 'EXIF', 'application/rdf+xml' => 'XMP' }->{$type} || ''; 8451 my ($warn, $extent); 8452 $warn = "Can't currently decode encoded $type metadata" if $$item{ContentEncoding}; 8453 $warn = "Can't currently decode protected $type metadata" if $$item{ProtectionIndex}; 8454 $warn = "Can't currently extract $type with construction method $$item{ConstructionMethod}" if $$item{ConstructionMethod}; 8455 $et->WarnOnce($warn) if $warn and $name; 8456 $warn = 'Not this file' if $$item{DataReferenceIndex}; # (can only extract from "this file") 8457 unless (($$item{Extents} and @{$$item{Extents}}) or $warn) { 8458 $warn = "No Extents for $type item"; 8459 $et->WarnOnce($warn) if $name; 8460 } 8461 if ($warn) { 8462 $et->VPrint(0, "$$et{INDENT} [not extracted] ($warn)\n") if $verbose > 2; 8463 next; 8464 } 8465 my $base = $$item{BaseOffset} || 0; 8466 if ($verbose > 2) { 8467 # do verbose hex dump 8468 my $len = 0; 8469 undef $buff; 8470 my $val = ''; 8471 my $maxLen = $verbose > 3 ? 2048 : 96; 8472 foreach $extent (@{$$item{Extents}}) { 8473 my $n = $$extent[2]; 8474 my $more = $maxLen - $len; 8475 if ($more > 0 and $n) { 8476 $more = $n if $more > $n; 8477 $val .= $buff if defined $buff; 8478 $raf->Seek($$extent[1] + $base, 0) or last; 8479 $raf->Read($buff, $more) or last; 8480 } 8481 $len += $n; 8482 } 8483 if (defined $buff) { 8484 $buff = $val . $buff if length $val; 8485 $et->VerboseDump(\$buff, DataPos => $$item{Extents}[0][1] + $base); 8486 my $snip = $len - length $buff; 8487 $et->VPrint(0, "$$et{INDENT} [snip $snip bytes]\n") if $snip; 8488 } 8489 } 8490 next unless $name; 8491 # assemble the data for this item 8492 undef $buff; 8493 my $val = ''; 8494 foreach $extent (@{$$item{Extents}}) { 8495 $val .= $buff if defined $buff; 8496 $raf->Seek($$extent[1] + $base, 0) or last; 8497 $raf->Read($buff, $$extent[2]) or last; 8498 } 8499 next unless defined $buff; 8500 $buff = $val . $buff if length $val; 8501 next unless length $buff; # ignore empty directories 8502 my ($start, $subTable, $proc); 8503 my $pos = $$item{Extents}[0][1] + $base; 8504 if ($name eq 'EXIF' and length $buff >= 4) { 8505 if ($buff =~ /^(MM\0\x2a|II\x2a\0)/) { 8506 $et->Warn('Missing Exif header'); 8507 $start = 0; 8508 } elsif ($buff =~ /^Exif\0\0/) { 8509 # (haven't seen this yet, but it is just a matter of time 8510 # until someone screws it up like this) 8511 $et->Warn('Missing Exif header size'); 8512 $start = 6; 8513 } else { 8514 my $n = unpack('N', $buff); 8515 $start = 4 + $n; # skip "Exif\0\0" header if it exists 8516 if ($start > length($buff)) { 8517 $et->Warn('Invalid EXIF header'); 8518 next; 8519 } 8520 if ($$et{HTML_DUMP}) { 8521 $et->HDump($pos, 4, 'Exif header length', "Value: $n"); 8522 $et->HDump($pos+4, $start-4, 'Exif header') if $n; 8523 } 8524 } 8525 $subTable = GetTagTable('Image::ExifTool::Exif::Main'); 8526 $proc = \&Image::ExifTool::ProcessTIFF; 8527 } else { 8528 $start = 0; 8529 $subTable = GetTagTable('Image::ExifTool::XMP::Main'); 8530 } 8531 my %dirInfo = ( 8532 DataPt => \$buff, 8533 DataLen => length $buff, 8534 DirStart => $start, 8535 DirLen => length($buff) - $start, 8536 DataPos => $pos, 8537 Base => $pos + $start, # (needed for HtmlDump and IsOffset tags in binary data) 8538 ); 8539 # handle processing of metadata for sub-documents 8540 if (defined $primary and $$item{RefersTo} and not $$item{RefersTo}{$primary}) { 8541 # set document number if this doesn't refer to the primary document 8542 $$et{DOC_NUM} = ++$$et{DOC_COUNT}; 8543 # associate this document number with the lowest item index 8544 my ($lowest) = sort { $a <=> $b } keys %{$$item{RefersTo}}; 8545 $$items{$lowest}{DocNum} = $$et{DOC_NUM}; 8546 } 8547 $et->ProcessDirectory(\%dirInfo, $subTable, $proc); 8548 delete $$et{DOC_NUM}; 8549 } 8550 $raf->Seek($curPos, 0); # seek back to original position 8551 pop @{$$et{PATH}}; 8552 } 8553 # process the item properties now that we should know their associations and document numbers 8554 if ($$et{ItemPropertyContainer}) { 8555 my ($dirInfo, $subTable, $proc) = @{$$et{ItemPropertyContainer}}; 8556 $$et{IsItemProperty} = 1; # set item property flag 8557 $et->ProcessDirectory($dirInfo, $subTable, $proc); 8558 delete $$et{ItemPropertyContainer}; 8559 delete $$et{IsItemProperty}; 8560 delete $$et{DOC_NUM}; 8561 } 8562 delete $$et{ItemInfo}; 8563 } 8564 8565 #------------------------------------------------------------------------------ 8566 # Warn if ExtractEmbedded option isn't used 8567 # Inputs: 0) ExifTool ref 8568 sub EEWarn($) 8569 { 8570 my $et = shift; 8571 $et->WarnOnce('The ExtractEmbedded option may find more tags in the media data',3); 8572 } 8573 8574 #------------------------------------------------------------------------------ 8575 # Get quicktime format from flags word 8576 # Inputs: 0) quicktime atom flags, 1) data length 8577 # Returns: ExifTool format string 8578 sub QuickTimeFormat($$) 8579 { 8580 my ($flags, $len) = @_; 8581 my $format; 8582 if ($flags == 0x15 or $flags == 0x16) { 8583 $format = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len}; 8584 $format .= $flags == 0x15 ? 's' : 'u' if $format; 8585 } elsif ($flags == 0x17) { 8586 $format = 'float'; 8587 } elsif ($flags == 0x18) { 8588 $format = 'double'; 8589 } elsif ($flags == 0x00) { 8590 $format = { 1=>'int8u', 2=>'int16u' }->{$len}; 8591 } 8592 return $format; 8593 } 8594 8595 #------------------------------------------------------------------------------ 2240 8596 # Process MPEG-4 MTDT atom (ref 11) 2241 8597 # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref … … 2243 8599 sub ProcessMetaData($$$) 2244 8600 { 2245 my ($e xifTool, $dirInfo, $tagTablePtr) = @_;8601 my ($et, $dirInfo, $tagTablePtr) = @_; 2246 8602 my $dataPt = $$dirInfo{DataPt}; 2247 8603 my $dirLen = length $$dataPt; 2248 my $verbose = $e xifTool->Options('Verbose');8604 my $verbose = $et->Options('Verbose'); 2249 8605 return 0 unless $dirLen >= 2; 2250 8606 my $count = Get16u($dataPt, 0); 2251 $verbose and $e xifTool->VerboseDir('MetaData', $count);8607 $verbose and $et->VerboseDir('MetaData', $count); 2252 8608 my $i; 2253 8609 my $pos = 2; … … 2260 8616 my $enc = Get16u($dataPt, $pos + 8); 2261 8617 my $val = substr($$dataPt, $pos + 10, $size); 2262 my $tagInfo = $e xifTool->GetTagInfo($tagTablePtr, $tag);8618 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 2263 8619 if ($tagInfo) { 2264 8620 # convert language code to ASCII (ignore read-only bit) … … 2266 8622 # handle alternate languages 2267 8623 if ($lang) { 2268 my $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $lang);8624 my $langInfo = GetLangInfoQT($et, $tagInfo, $lang); 2269 8625 $tagInfo = $langInfo if $langInfo; 2270 8626 } 2271 $verbose and $e xifTool->VerboseInfo($tag, $tagInfo,8627 $verbose and $et->VerboseInfo($tag, $tagInfo, 2272 8628 Value => $val, 2273 8629 DataPt => $dataPt, … … 2276 8632 ); 2277 8633 # convert from UTF-16 BE if necessary 2278 $val = $e xifTool->Decode($val, 'UCS2') if $enc == 1;8634 $val = $et->Decode($val, 'UCS2') if $enc == 1; 2279 8635 if ($enc == 0 and $$tagInfo{Unknown}) { 2280 8636 # binary data 2281 $e xifTool->FoundTag($tagInfo, \$val);8637 $et->FoundTag($tagInfo, \$val); 2282 8638 } else { 2283 $e xifTool->FoundTag($tagInfo, $val);8639 $et->FoundTag($tagInfo, $val); 2284 8640 } 2285 8641 } … … 2290 8646 2291 8647 #------------------------------------------------------------------------------ 2292 # Process Meta keys and add tags to the ItemList table ('mdta' handler) (ref PH) 8648 # Process sample description table 8649 # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8650 # Returns: 1 on success 8651 # (ref https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25691) 8652 sub ProcessSampleDesc($$$) 8653 { 8654 my ($et, $dirInfo, $tagTablePtr) = @_; 8655 my $dataPt = $$dirInfo{DataPt}; 8656 my $pos = $$dirInfo{DirStart} || 0; 8657 my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $pos); 8658 return 0 if $pos + 8 > $dirLen; 8659 8660 my $num = Get32u($dataPt, 4); # get number of sample entries in table 8661 $pos += 8; 8662 my $i; 8663 for ($i=0; $i<$num; ++$i) { # loop through sample entries 8664 last if $pos + 8 > $dirLen; 8665 my $size = Get32u($dataPt, $pos); 8666 last if $pos + $size > $dirLen; 8667 $$dirInfo{DirStart} = $pos; 8668 $$dirInfo{DirLen} = $size; 8669 ProcessHybrid($et, $dirInfo, $tagTablePtr); 8670 $pos += $size; 8671 } 8672 return 1; 8673 } 8674 8675 #------------------------------------------------------------------------------ 8676 # Process hybrid binary data + QuickTime container (ref PH) 8677 # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8678 # Returns: 1 on success 8679 sub ProcessHybrid($$$) 8680 { 8681 my ($et, $dirInfo, $tagTablePtr) = @_; 8682 # brute-force search for child atoms after first 8 bytes of binary data 8683 my $dataPt = $$dirInfo{DataPt}; 8684 my $dirStart = $$dirInfo{DirStart} || 0; 8685 my $dirLen = $$dirInfo{DirLen} || length($$dataPt) - $dirStart; 8686 my $end = $dirStart + $dirLen; 8687 my $pos = $dirStart + 8; # skip length/version 8688 my $try = $pos; 8689 my $childPos; 8690 8691 while ($pos <= $end - 8) { 8692 my $tag = substr($$dataPt, $try+4, 4); 8693 # look only for well-behaved tag ID's 8694 $tag =~ /[^\w ]/ and $try = ++$pos, next; 8695 my $size = Get32u($dataPt, $try); 8696 if ($size + $try == $end) { 8697 # the atom ends exactly at the end of the parent -- this must be it 8698 $childPos = $pos; 8699 $$dirInfo{DirLen} = $pos; # the binary data ends at the first child atom 8700 last; 8701 } 8702 if ($size < 8 or $size + $try > $end - 8) { 8703 $try = ++$pos; # fail. try next position 8704 } else { 8705 $try += $size; # could be another atom following this 8706 } 8707 } 8708 # process binary data 8709 $$dirInfo{MixedTags} = 1; # ignore non-integer tag ID's 8710 $et->ProcessBinaryData($dirInfo, $tagTablePtr); 8711 # process child atoms if found 8712 if ($childPos) { 8713 $$dirInfo{DirStart} = $childPos; 8714 $$dirInfo{DirLen} = $end - $childPos; 8715 ProcessMOV($et, $dirInfo, $tagTablePtr); 8716 } 8717 return 1; 8718 } 8719 8720 #------------------------------------------------------------------------------ 8721 # Process iTunes 'righ' atom (ref PH) 8722 # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8723 # Returns: 1 on success 8724 sub ProcessRights($$$) 8725 { 8726 my ($et, $dirInfo, $tagTablePtr) = @_; 8727 my $dataPt = $$dirInfo{DataPt}; 8728 my $dataPos = $$dirInfo{Base}; 8729 my $dirLen = length $$dataPt; 8730 my $unknown = $$et{OPTIONS}{Unknown} || $$et{OPTIONS}{Verbose}; 8731 my $pos; 8732 $et->VerboseDir('righ', $dirLen / 8); 8733 for ($pos = 0; $pos + 8 <= $dirLen; $pos += 8) { 8734 my $tag = substr($$dataPt, $pos, 4); 8735 last if $tag eq "\0\0\0\0"; 8736 my $val = substr($$dataPt, $pos + 4, 4); 8737 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 8738 unless ($tagInfo) { 8739 next unless $unknown; 8740 my $name = PrintableTagID($tag); 8741 $tagInfo = { 8742 Name => "Unknown_$name", 8743 Description => "Unknown $name", 8744 Unknown => 1, 8745 }, 8746 AddTagToTable($tagTablePtr, $tag, $tagInfo); 8747 } 8748 $val = '0x' . unpack('H*', $val) unless $$tagInfo{Format}; 8749 $et->HandleTag($tagTablePtr, $tag, $val, 8750 DataPt => $dataPt, 8751 DataPos => $dataPos, 8752 Start => $pos + 4, 8753 Size => 4, 8754 ); 8755 } 8756 return 1; 8757 } 8758 8759 #------------------------------------------------------------------------------ 8760 # Process iTunes Encoding Params (ref PH) 8761 # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8762 # Returns: 1 on success 8763 sub ProcessEncodingParams($$$) 8764 { 8765 my ($et, $dirInfo, $tagTablePtr) = @_; 8766 my $dataPt = $$dirInfo{DataPt}; 8767 my $dirLen = length $$dataPt; 8768 my $pos; 8769 $et->VerboseDir('Encoding Params', $dirLen / 8); 8770 for ($pos = 0; $pos + 8 <= $dirLen; $pos += 8) { 8771 my ($tag, $val) = unpack("x${pos}a4N", $$dataPt); 8772 $et->HandleTag($tagTablePtr, $tag, $val); 8773 } 8774 return 1; 8775 } 8776 8777 #------------------------------------------------------------------------------ 8778 # Read Meta Keys and add tags to ItemList table ('mdta' handler) (ref PH) 2293 8779 # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 2294 8780 # Returns: 1 on success 2295 8781 sub ProcessKeys($$$) 2296 8782 { 2297 my ($exifTool, $dirInfo, $tagTablePtr) = @_; 8783 local $_; 8784 my ($et, $dirInfo, $tagTablePtr) = @_; 2298 8785 my $dataPt = $$dirInfo{DataPt}; 2299 8786 my $dirLen = length $$dataPt; 2300 8787 my $out; 2301 if ($e xifTool->Options('Verbose')) {2302 $e xifTool->VerboseDir('Keys');2303 $out = $e xifTool->Options('TextOut');8788 if ($et->Options('Verbose')) { 8789 $et->VerboseDir('Keys'); 8790 $out = $et->Options('TextOut'); 2304 8791 } 2305 8792 my $pos = 8; 2306 8793 my $index = 1; 2307 my $infoTable = GetTagTable('Image::ExifTool::QuickTime::ItemList'); 2308 my $userTable = GetTagTable('Image::ExifTool::QuickTime::UserData'); 8794 ++$$et{KeysCount}; # increment key count for this directory 8795 my $itemList = GetTagTable('Image::ExifTool::QuickTime::ItemList'); 8796 my $userData = GetTagTable('Image::ExifTool::QuickTime::UserData'); 2309 8797 while ($pos < $dirLen - 4) { 2310 8798 my $len = unpack("x${pos}N", $$dataPt); … … 2314 8802 my $tag = substr($$dataPt, $pos + 8, $len - 8); 2315 8803 $tag =~ s/\0.*//s; # truncate at null 2316 if ($ns eq 'mdta') { 2317 $tag =~ s/^com\.apple\.quicktime\.//; # remove common apple quicktime domain 2318 } 2319 next unless $tag; 8804 $tag =~ s/^com\.(apple\.quicktime\.)?// if $ns eq 'mdta'; # remove apple quicktime domain 8805 $tag = "Tag_$ns" unless $tag; 2320 8806 # (I have some samples where the tag is a reversed ItemList or UserData tag ID) 2321 my $tagInfo = $e xifTool->GetTagInfo($tagTablePtr, $tag);8807 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 2322 8808 unless ($tagInfo) { 2323 $tagInfo = $e xifTool->GetTagInfo($infoTable, $tag);8809 $tagInfo = $et->GetTagInfo($itemList, $tag); 2324 8810 unless ($tagInfo) { 2325 $tagInfo = $e xifTool->GetTagInfo($userTable, $tag);8811 $tagInfo = $et->GetTagInfo($userData, $tag); 2326 8812 if (not $tagInfo and $tag =~ /^\w{3}\xa9$/) { 2327 8813 $tag = pack('N', unpack('V', $tag)); 2328 $tagInfo = $e xifTool->GetTagInfo($infoTable, $tag);2329 $tagInfo or $tagInfo = $e xifTool->GetTagInfo($userTable, $tag);8814 $tagInfo = $et->GetTagInfo($itemList, $tag); 8815 $tagInfo or $tagInfo = $et->GetTagInfo($userData, $tag); 2330 8816 } 2331 8817 } 2332 8818 } 2333 my $newInfo;8819 my ($newInfo, $msg); 2334 8820 if ($tagInfo) { 8821 # copy tag information into new Keys tag 2335 8822 $newInfo = { 2336 8823 Name => $$tagInfo{Name}, 2337 8824 Format => $$tagInfo{Format}, 2338 8825 ValueConv => $$tagInfo{ValueConv}, 8826 ValueConvInv => $$tagInfo{ValueConvInv}, 2339 8827 PrintConv => $$tagInfo{PrintConv}, 8828 PrintConvInv => $$tagInfo{PrintConvInv}, 8829 Writable => defined $$tagInfo{Writable} ? $$tagInfo{Writable} : 1, 8830 SubDirectory => $$tagInfo{SubDirectory}, 2340 8831 }; 2341 8832 my $groups = $$tagInfo{Groups}; 2342 $$newInfo{Groups} = { %$groups } if $groups; 2343 } elsif ($tag =~ /^[-\w.]+$/) { 8833 $$newInfo{Groups} = $groups ? { %$groups } : { }; 8834 $$newInfo{Groups}{$_} or $$newInfo{Groups}{$_} = $$tagTablePtr{GROUPS}{$_} foreach 0..2; 8835 $$newInfo{Groups}{1} = 'Keys'; 8836 } elsif ($tag =~ /^[-\w. ]+$/ or $tag =~ /\w{4}/) { 2344 8837 # create info for tags with reasonable id's 2345 my $name = $tag; 2346 $name =~ s/\.(.)/\U$1/g; 2347 $newInfo = { Name => ucfirst($name) }; 8838 my $name = ucfirst $tag; 8839 $name =~ tr/-0-9a-zA-Z_. //dc; 8840 $name =~ s/[. ]+(.?)/\U$1/g; 8841 $name =~ s/_([a-z])/_\U$1/g; 8842 $name =~ s/([a-z])_([A-Z])/$1$2/g; 8843 $name = "Tag_$name" if length $name < 2; 8844 $newInfo = { Name => $name, Groups => { 1 => 'Keys' } }; 8845 $msg = ' (Unknown)'; 2348 8846 } 2349 8847 # substitute this tag in the ItemList table with the given index 2350 delete $$infoTable{$index}; 8848 my $id = $$et{KeysCount} . '.' . $index; 8849 if (ref $$itemList{$id} eq 'HASH') { 8850 # delete other languages too if they exist 8851 my $oldInfo = $$itemList{$id}; 8852 if ($$oldInfo{OtherLang}) { 8853 delete $$itemList{$_} foreach @{$$oldInfo{OtherLang}}; 8854 } 8855 delete $$itemList{$id}; 8856 } 2351 8857 if ($newInfo) { 2352 Image::ExifTool::AddTagToTable($infoTable, $index, $newInfo); 2353 $out and printf $out "%sAdded ItemList Tag 0x%.4x = $tag\n", $exifTool->{INDENT}, $index; 8858 AddTagToTable($itemList, $id, $newInfo); 8859 $msg or $msg = ''; 8860 $out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $tag$msg\n"; 2354 8861 } 2355 8862 $pos += $len; … … 2360 8867 2361 8868 #------------------------------------------------------------------------------ 8869 # Process keys in MetaSampleDesc directory 8870 # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8871 # Returns: 1 on success 8872 sub ProcessMetaKeys($$$) 8873 { 8874 my ($et, $dirInfo, $tagTablePtr) = @_; 8875 # save this information to decode timed metadata samples when ExtractEmbedded is used 8876 SaveMetaKeys($et, $dirInfo, $tagTablePtr) if $$et{OPTIONS}{ExtractEmbedded}; 8877 return 1; 8878 } 8879 8880 #------------------------------------------------------------------------------ 2362 8881 # Process a QuickTime atom 2363 8882 # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) optional tag table ref … … 2365 8884 sub ProcessMOV($$;$) 2366 8885 { 2367 my ($exifTool, $dirInfo, $tagTablePtr) = @_; 8886 local $_; 8887 my ($et, $dirInfo, $tagTablePtr) = @_; 2368 8888 my $raf = $$dirInfo{RAF}; 2369 8889 my $dataPt = $$dirInfo{DataPt}; 2370 my $verbose = $exifTool->Options('Verbose'); 8890 my $verbose = $et->Options('Verbose'); 8891 my $validate = $$et{OPTIONS}{Validate}; 2371 8892 my $dataPos = $$dirInfo{Base} || 0; 2372 my ($buff, $tag, $size, $track); 2373 8893 my $dirID = $$dirInfo{DirID} || ''; 8894 my $charsetQuickTime = $et->Options('CharsetQuickTime'); 8895 my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index); 8896 my ($dirEnd, $unkOpt, %saveOptions, $atomCount); 8897 8898 my $topLevel = not $$et{InQuickTime}; 8899 $$et{InQuickTime} = 1; 8900 $$et{HandlerType} = $$et{MetaFormat} = '' unless defined $$et{HandlerType}; 8901 8902 unless (defined $$et{KeysCount}) { 8903 $$et{KeysCount} = 0; # initialize ItemList key directory count 8904 $doDefaultLang = 1; # flag to generate default language tags 8905 } 2374 8906 # more convenient to package data as a RandomAccess file 2375 $raf or $raf = new File::RandomAccess($dataPt); 8907 unless ($raf) { 8908 $raf = new File::RandomAccess($dataPt); 8909 $dirEnd = $dataPos + $$dirInfo{DirLen} + ($$dirInfo{DirStart} || 0) if $$dirInfo{DirLen}; 8910 } 2376 8911 # skip leading bytes if necessary 2377 8912 if ($$dirInfo{DirStart}) { … … 2382 8917 $raf->Read($buff,8) == 8 or return 0; 2383 8918 $dataPos += 8; 2384 $tagTablePtr or $tagTablePtr = GetTagTable('Image::ExifTool::QuickTime::Main'); 8919 if ($tagTablePtr) { 8920 $isUserData = ($tagTablePtr eq \%Image::ExifTool::QuickTime::UserData); 8921 } else { 8922 $tagTablePtr = GetTagTable('Image::ExifTool::QuickTime::Main'); 8923 } 2385 8924 ($size, $tag) = unpack('Na4', $buff); 2386 8925 if ($dataPt) { 2387 $verbose and $e xifTool->VerboseDir($$dirInfo{DirName});8926 $verbose and $et->VerboseDir($$dirInfo{DirName}); 2388 8927 } else { 2389 8928 # check on file type if called with a RAF 2390 8929 $$tagTablePtr{$tag} or return 0; 2391 if ($tag eq 'ftyp' ) {2392 # read ahead 4 bytesto see what type of file this is8930 if ($tag eq 'ftyp' and $size >= 12) { 8931 # read ftyp atom to see what type of file this is 2393 8932 my $fileType; 2394 if ($raf->Read($buff, 4) == 4) { 2395 $raf->Seek(-4, 1); 8933 if ($raf->Read($buff, $size-8) == $size-8) { 8934 $raf->Seek(-($size-8), 1); 8935 my $type = substr($buff, 0, 4); 2396 8936 # see if we know the extension for this file type 2397 $fileType = $1 if $ftypLookup{$buff} and $ftypLookup{$buff} =~ /\(\.(\w+)/; 8937 if ($ftypLookup{$type} and $ftypLookup{$type} =~ /\(\.(\w+)/) { 8938 $fileType = $1; 8939 # check compatible brands 8940 } elsif ($buff =~ /^.{8}(.{4})+(mp41|mp42|avc1)/s) { 8941 $fileType = 'MP4'; 8942 } elsif ($buff =~ /^.{8}(.{4})+(f4v )/s) { 8943 $fileType = 'F4V'; 8944 } elsif ($buff =~ /^.{8}(.{4})+(qt )/s) { 8945 $fileType = 'MOV'; 8946 } 2398 8947 } 2399 8948 $fileType or $fileType = 'MP4'; # default to MP4 2400 $exifTool->SetFileType($fileType, $mimeLookup{$fileType} || 'video/mp4'); 8949 $et->SetFileType($fileType, $mimeLookup{$fileType} || 'video/mp4'); 8950 # temporarily set ExtractEmbedded option for CRX files 8951 $saveOptions{ExtractEmbedded} = $et->Options(ExtractEmbedded => 1) if $fileType eq 'CRX'; 2401 8952 } else { 2402 $e xifTool->SetFileType(); # MOV8953 $et->SetFileType(); # MOV 2403 8954 } 2404 8955 SetByteOrder('MM'); 8956 $$et{PRIORITY_DIR} = 'XMP'; # have XMP take priority 8957 } 8958 $$raf{NoBuffer} = 1 if $et->Options('FastScan'); # disable buffering in FastScan mode 8959 8960 my $ee = $$et{OPTIONS}{ExtractEmbedded}; 8961 if ($ee) { 8962 $unkOpt = $$et{OPTIONS}{Unknown}; 8963 require 'Image/ExifTool/QuickTimeStream.pl'; 8964 } 8965 if ($$tagTablePtr{VARS}) { 8966 $index = $$tagTablePtr{VARS}{START_INDEX}; 8967 $atomCount = $$tagTablePtr{VARS}{ATOM_COUNT}; 2405 8968 } 2406 8969 for (;;) { 8970 my ($eeTag, $ignore); 8971 last if defined $atomCount and --$atomCount < 0; 2407 8972 if ($size < 8) { 2408 last if $size == 0; 2409 $size == 1 or $exifTool->Warn('Invalid atom size'), last; 2410 $raf->Read($buff, 8) == 8 or last; 8973 if ($size == 0) { 8974 if ($dataPt) { 8975 # a zero size isn't legal for contained atoms, but Canon uses it to 8976 # terminate the CNTH atom (eg. CanonEOS100D.mov), so tolerate it here 8977 my $pos = $raf->Tell() - 4; 8978 $raf->Seek(0,2); 8979 my $str = $$dirInfo{DirName} . ' with ' . ($raf->Tell() - $pos) . ' bytes'; 8980 $et->VPrint(0,"$$et{INDENT}\[Terminator found in $str remaining]"); 8981 } else { 8982 my $t = PrintableTagID($tag,2); 8983 $et->VPrint(0,"$$et{INDENT}Tag '${t}' extends to end of file"); 8984 } 8985 last; 8986 } 8987 $size == 1 or $et->Warn('Invalid atom size'), last; 8988 # read extended atom size 8989 $raf->Read($buff, 8) == 8 or $et->Warn('Truncated atom header'), last; 2411 8990 $dataPos += 8; 2412 8991 my ($hi, $lo) = unpack('NN', $buff); 2413 $size = $lo;2414 8992 if ($hi or $lo > 0x7fffffff) { 2415 8993 if ($hi > 0x7fffffff) { 2416 $e xifTool->Warn('Invalid atom size');8994 $et->Warn('Invalid atom size'); 2417 8995 last; 2418 } elsif (not $e xifTool->Options('LargeFileSupport')) {2419 $e xifTool->Warn('End of processing at large atom (LargeFileSupport not enabled)');8996 } elsif (not $et->Options('LargeFileSupport')) { 8997 $et->Warn('End of processing at large atom (LargeFileSupport not enabled)'); 2420 8998 last; 2421 8999 } 2422 9000 } 2423 $size = $hi * 4294967296 + $lo; 9001 $size = $hi * 4294967296 + $lo - 16; 9002 $size < 0 and $et->Warn('Invalid extended size'), last; 9003 } else { 9004 $size -= 8; 2424 9005 } 2425 $size -= 8; 2426 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag); 9006 if ($validate) { 9007 $$et{ValidatePath} or $$et{ValidatePath} = { }; 9008 my $path = join('-', @{$$et{PATH}}, $tag); 9009 $path =~ s/-Track-/-$$et{SET_GROUP1}-/ if $$et{SET_GROUP1}; 9010 if ($$et{ValidatePath}{$path} and not $dupTagOK{$tag} and not $dupDirOK{$dirID}) { 9011 my $i = Get32u(\$tag,0); 9012 my $str = $i < 255 ? "index $i" : "tag '" . PrintableTagID($tag,2) . "'"; 9013 $et->WarnOnce("Duplicate $str at " . join('-', @{$$et{PATH}})); 9014 $$et{ValidatePath} = { } if $path eq 'MOV-moov'; # avoid warnings for all contained dups 9015 } 9016 $$et{ValidatePath}{$path} = 1; 9017 } 9018 if ($isUserData and $$et{SET_GROUP1}) { 9019 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 9020 # add track name to UserData tags inside tracks 9021 $tag = $$et{SET_GROUP1} . $tag; 9022 if (not $$tagTablePtr{$tag} and $tagInfo) { 9023 my %newInfo = %$tagInfo; 9024 foreach ('Name', 'Description') { 9025 next unless $$tagInfo{$_}; 9026 $newInfo{$_} = $$et{SET_GROUP1} . $$tagInfo{$_}; 9027 $newInfo{$_} =~ s/^(Track\d+)Track/$1/; # remove duplicate "Track" in name 9028 } 9029 AddTagToTable($tagTablePtr, $tag, \%newInfo); 9030 } 9031 } 9032 # set flag to store additional information for ExtractEmbedded option 9033 my $handlerType = $$et{HandlerType}; 9034 if ($eeBox{$handlerType} and $eeBox{$handlerType}{$tag}) { 9035 if ($ee) { 9036 # (there is another 'gps ' box with a track log that doesn't contain offsets) 9037 if ($tag ne 'gps ' or $eeBox{$handlerType}{$tag} eq $dirID) { 9038 $eeTag = 1; 9039 $$et{OPTIONS}{Unknown} = 1; # temporarily enable "Unknown" option 9040 } 9041 } elsif ($handlerType ne 'vide' and not $$et{OPTIONS}{Validate}) { 9042 EEWarn($et); 9043 } 9044 } elsif ($ee and $ee > 1 and $eeBox2{$handlerType} and $eeBox2{$handlerType}{$tag}) { 9045 $eeTag = 1; 9046 $$et{OPTIONS}{Unknown} = 1; 9047 } 9048 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 9049 9050 $$et{OPTIONS}{Unknown} = $unkOpt if $eeTag; # restore Unknown option 9051 2427 9052 # allow numerical tag ID's 2428 9053 unless ($tagInfo) { 2429 my $ num =unpack('N', $tag);2430 if ($$tagTablePtr{$ num}) {2431 $tagInfo = $e xifTool->GetTagInfo($tagTablePtr, $num);2432 $tag = $ num;9054 my $id = $$et{KeysCount} . '.' . unpack('N', $tag); 9055 if ($$tagTablePtr{$id}) { 9056 $tagInfo = $et->GetTagInfo($tagTablePtr, $id); 9057 $tag = $id; 2433 9058 } 2434 9059 } 2435 9060 # generate tagInfo if Unknown option set 2436 if (not defined $tagInfo and ($ exifTool->{OPTIONS}->{Unknown} or9061 if (not defined $tagInfo and ($$et{OPTIONS}{Unknown} or 2437 9062 $verbose or $tag =~ /^\xa9/)) 2438 9063 { 2439 my $name = $tag; 2440 my $n = ($name =~ s/([\x00-\x1f\x7f-\xff])/'x'.unpack('H*',$1)/eg); 2441 # print in hex if tag is numerical 2442 $name = sprintf('0x%.4x',unpack('N',$tag)) if $n > 2; 9064 my $name = PrintableTagID($tag,1); 2443 9065 if ($name =~ /^xa9(.*)/) { 2444 9066 $tagInfo = { … … 2450 9072 Name => "Unknown_$name", 2451 9073 Description => "Unknown $name", 2452 Unknown => 1, 2453 Binary => 1, 9074 %unknownInfo, 2454 9075 }; 2455 9076 } 2456 Image::ExifTool::AddTagToTable($tagTablePtr, $tag, $tagInfo);9077 AddTagToTable($tagTablePtr, $tag, $tagInfo); 2457 9078 } 2458 9079 # save required tag sizes 2459 $exifTool->HandleTag($tagTablePtr, "$tag-size", $size) if $$tagTablePtr{"$tag-size"}; 2460 # load values only if associated with a tag (or verbose) and < 16MB long 2461 if ((defined $tagInfo or $verbose) and $size < 0x1000000) { 9080 if ($$tagTablePtr{"$tag-size"}) { 9081 $et->HandleTag($tagTablePtr, "$tag-size", $size); 9082 $et->HandleTag($tagTablePtr, "$tag-offset", $raf->Tell()) if $$tagTablePtr{"$tag-offset"}; 9083 } 9084 # load values only if associated with a tag (or verbose) and not too big 9085 if ($size > 0x2000000) { # start to get worried above 32 MB 9086 # check for RIFF trailer (written by Auto-Vox dashcam) 9087 if ($buff =~ /^(gpsa|gps0|gsen|gsea)...\0/s) { # (yet seen only gpsa as first record) 9088 $et->VPrint(0, "Found RIFF trailer"); 9089 if ($et->Options('ExtractEmbedded')) { 9090 $raf->Seek(-8, 1) or last; # seek back to start of trailer 9091 my $tbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); 9092 ProcessRIFFTrailer($et, { RAF => $raf }, $tbl); 9093 } else { 9094 EEWarn($et); 9095 } 9096 last; 9097 } 9098 $ignore = 1; 9099 if ($tagInfo and not $$tagInfo{Unknown} and not $eeTag) { 9100 my $t = PrintableTagID($tag,2); 9101 if ($size > 0x8000000) { 9102 $et->Warn("Skipping '${t}' atom > 128 MB", 1); 9103 } else { 9104 $et->Warn("Skipping '${t}' atom > 32 MB", 2) or $ignore = 0; 9105 } 9106 } 9107 } 9108 if (defined $tagInfo and not $ignore) { 9109 # set document number for this item property if necessary 9110 if ($$et{IsItemProperty}) { 9111 my $items = $$et{ItemInfo}; 9112 my ($id, $prop, $docNum, $lowest); 9113 my $primary = $$et{PrimaryItem} || 0; 9114 ItemID: foreach $id (keys %$items) { 9115 next unless $$items{$id}{Association}; 9116 my $item = $$items{$id}; 9117 foreach $prop (@{$$item{Association}}) { 9118 next unless $prop == $index; 9119 if ($id == $primary or (not $dontInherit{$tag} and 9120 (not $$item{RefersTo} or $$item{RefersTo}{$primary}))) 9121 { 9122 # this is associated with the primary item or an item describing 9123 # the primary item, so consider this part of the main document 9124 undef $docNum; 9125 undef $lowest; 9126 last ItemID; 9127 } elsif ($$item{DocNum}) { 9128 # this property is already associated with an item that has 9129 # an ExifTool document number, so use the lowest associated DocNum 9130 $docNum = $$item{DocNum} if not defined $docNum or $docNum > $$item{DocNum}; 9131 } elsif (not defined $lowest or $lowest > $id) { 9132 # keep track of the lowest associated item ID 9133 $lowest = $id; 9134 } 9135 } 9136 } 9137 if (not defined $docNum and defined $lowest) { 9138 # this is the first time we've seen metadata from this item, 9139 # so use a new document number 9140 $docNum = ++$$et{DOC_COUNT}; 9141 $$items{$lowest}{DocNum} = $docNum; 9142 } 9143 $$et{DOC_NUM} = $docNum; 9144 } 2462 9145 my $val; 2463 unless ($raf->Read($val, $size) == $size) { 2464 $exifTool->Warn("Truncated '$tag' data"); 9146 my $missing = $size - $raf->Read($val, $size); 9147 if ($missing) { 9148 my $t = PrintableTagID($tag,2); 9149 $et->Warn("Truncated '${t}' data (missing $missing bytes)"); 2465 9150 last; 2466 9151 } 2467 9152 # use value to get tag info if necessary 2468 $tagInfo or $tagInfo = $e xifTool->GetTagInfo($tagTablePtr, $tag, \$val);9153 $tagInfo or $tagInfo = $et->GetTagInfo($tagTablePtr, $tag, \$val); 2469 9154 my $hasData = ($$dirInfo{HasData} and $val =~ /\0...data\0/s); 2470 9155 if ($verbose and not $hasData) { 2471 $exifTool->VerboseInfo($tag, $tagInfo, 2472 Value => $val, 2473 DataPt => \$val, 9156 my $tval; 9157 if ($tagInfo and $$tagInfo{Format}) { 9158 $tval = ReadValue(\$val, 0, $$tagInfo{Format}, $$tagInfo{Count}, length($val)); 9159 } 9160 $et->VerboseInfo($tag, $tagInfo, 9161 Value => $tval, 9162 DataPt => \$val, 2474 9163 DataPos => $dataPos, 9164 Size => $size, 9165 Format => $tagInfo ? $$tagInfo{Format} : undef, 9166 Index => $index, 2475 9167 ); 9168 # print iref item ID numbers 9169 if ($dirID eq 'iref') { 9170 my ($id, $count, @to, $i); 9171 if ($$et{ItemRefVersion}) { 9172 ($id, $count, @to) = unpack('NnN*', $val) if length $val >= 10; 9173 } else { 9174 ($id, $count, @to) = unpack('nnn*', $val) if length $val >= 6; 9175 } 9176 defined $id or $id = '<err>', $count = 0; 9177 $id .= " (wrong count: $count)" if $count != @to; 9178 # convert sequential numbers to a range 9179 for ($i=1; $i<@to; ) { 9180 $to[$i-1] =~ /(\d+)$/ and $to[$i] == $1 + 1 or ++$i, next; 9181 $to[$i-1] =~ s/(-.*)?$/-$to[$i]/; 9182 splice @to, $i, 1; 9183 } 9184 $et->VPrint(1, "$$et{INDENT} Item $id refers to: ",join(',',@to),"\n"); 9185 } 9186 } 9187 # extract metadata from stream if ExtractEmbedded option is enabled 9188 if ($eeTag) { 9189 ParseTag($et, $tag, \$val); 9190 # forget this tag if we generated it only for ExtractEmbedded 9191 undef $tagInfo if $tagInfo and $$tagInfo{Unknown} and not $unkOpt; 9192 } 9193 9194 # handle iTunesInfo mean/name/data triplets 9195 if ($tagInfo and $$tagInfo{Triplet}) { 9196 if ($tag eq 'data' and $triplet{mean} and $triplet{name}) { 9197 $tag = $triplet{name}; 9198 # add 'mean' to name unless it is 'com.apple.iTunes' 9199 $tag = $triplet{mean} . '/' . $tag unless $triplet{mean} eq 'com.apple.iTunes'; 9200 $tagInfo = $et->GetTagInfo($tagTablePtr, $tag, \$val); 9201 unless ($tagInfo) { 9202 my $name = $triplet{name}; 9203 my $desc = $name; 9204 $name =~ tr/-_a-zA-Z0-9//dc; 9205 $desc =~ tr/_/ /; 9206 $tagInfo = { 9207 Name => $name, 9208 Description => $desc, 9209 }; 9210 AddTagToTable($tagTablePtr, $tag, $tagInfo); 9211 } 9212 # ignore 8-byte header 9213 $val = substr($val, 8) if length($val) >= 8; 9214 unless ($$tagInfo{Format} or $$tagInfo{SubDirectory}) { 9215 # extract as binary if it contains any non-ASCII or control characters 9216 if ($val =~ /[^\x20-\x7e]/) { 9217 my $buff = $val; 9218 $val = \$buff; 9219 } 9220 } 9221 undef %triplet; 9222 } else { 9223 undef %triplet if $tag eq 'mean'; 9224 $triplet{$tag} = substr($val,4) if length($val) > 4; 9225 undef $tagInfo; # don't store this tag 9226 } 2476 9227 } 2477 9228 if ($tagInfo) { … … 2485 9236 } 2486 9237 my %dirInfo = ( 2487 DataPt => \$val, 2488 DataLen => $size, 2489 DirStart => $start, 2490 DirLen => $size - $start, 2491 DirName => $$subdir{DirName} || $$tagInfo{Name}, 2492 HasData => $$subdir{HasData}, 2493 Multi => $$subdir{Multi}, 2494 DataPos => $dPos, 2495 # Base needed for IsOffset tags in binary data 2496 Base => $base, 9238 DataPt => \$val, 9239 DataLen => $size, 9240 DirStart => $start, 9241 DirLen => $size - $start, 9242 DirName => $$subdir{DirName} || $$tagInfo{Name}, 9243 DirID => $tag, 9244 HasData => $$subdir{HasData}, 9245 Multi => $$subdir{Multi}, 9246 IgnoreProp => $$subdir{IgnoreProp}, # (XML hack) 9247 DataPos => $dPos, 9248 Base => $base, # (needed for IsOffset tags in binary data) 2497 9249 ); 9250 $dirInfo{BlockInfo} = $tagInfo if $$tagInfo{BlockExtract}; 2498 9251 if ($$subdir{ByteOrder} and $$subdir{ByteOrder} =~ /^Little/) { 2499 9252 SetByteOrder('II'); 2500 9253 } 2501 my $oldGroup1 = $exifTool->{SET_GROUP1}; 2502 if ($$tagInfo{Name} eq 'Track') { 9254 my $oldGroup1 = $$et{SET_GROUP1}; 9255 if ($$tagInfo{SubDirectory} and $$tagInfo{SubDirectory}{TagTable} and 9256 $$tagInfo{SubDirectory}{TagTable} eq 'Image::ExifTool::QuickTime::Track') 9257 { 2503 9258 $track or $track = 0; 2504 $ exifTool->{SET_GROUP1} = 'Track' . (++$track);9259 $$et{SET_GROUP1} = 'Track' . (++$track); 2505 9260 } 2506 9261 my $subTable = GetTagTable($$subdir{TagTable}); 2507 9262 my $proc = $$subdir{ProcessProc}; 2508 $exifTool->ProcessDirectory(\%dirInfo, $subTable, $proc) if $size > $start; 2509 $exifTool->{SET_GROUP1} = $oldGroup1; 9263 # make ProcessMOV() the default processing procedure for subdirectories 9264 $proc = \&ProcessMOV unless $proc or $$subTable{PROCESS_PROC}; 9265 if ($size > $start) { 9266 # delay processing of ipco box until after all other boxes 9267 if ($tag eq 'ipco' and not $$et{IsItemProperty}) { 9268 $$et{ItemPropertyContainer} = [ \%dirInfo, $subTable, $proc ]; 9269 $et->VPrint(0,"$$et{INDENT}\[Process ipco box later]"); 9270 } else { 9271 $et->ProcessDirectory(\%dirInfo, $subTable, $proc); 9272 } 9273 } 9274 if ($tag eq 'stbl') { 9275 # process sample data when exiting SampleTable box if extracting embedded 9276 ProcessSamples($et) if $ee; 9277 } elsif ($tag eq 'minf') { 9278 $$et{HandlerType} = ''; # reset handler type at end of media info box 9279 } 9280 $$et{SET_GROUP1} = $oldGroup1; 2510 9281 SetByteOrder('MM'); 2511 9282 } elsif ($hasData) { … … 2517 9288 my ($len, $type, $flags, $ctry, $lang) = unpack("x${pos}Na4Nnn", $val); 2518 9289 last if $pos + $len > $size; 2519 my $value;9290 my ($value, $langInfo, $oldDir); 2520 9291 my $format = $$tagInfo{Format}; 2521 9292 if ($type eq 'data' and $len >= 16) { … … 2530 9301 if ($stringEncoding{$flags}) { 2531 9302 # handle all string formats 2532 $value = $exifTool->Decode($value, $stringEncoding{$flags}); 9303 $value = $et->Decode($value, $stringEncoding{$flags}); 9304 # (shouldn't be null terminated, but some software writes it anyway) 9305 $value =~ s/\0$// unless $$tagInfo{Binary}; 2533 9306 } else { 2534 if (not $format) { 2535 if ($flags == 0x15 or $flags == 0x16) { 2536 $format = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len}; 2537 $format .= $flags == 0x15 ? 's' : 'u' if $format; 2538 } elsif ($flags == 0x17) { 2539 $format = 'float'; 2540 } elsif ($flags == 0x18) { 2541 $format = 'double'; 2542 } elsif ($flags == 0x00) { 2543 # read 1 and 2-byte binary as integers 2544 if ($len == 1) { 2545 $format = 'int8u', 2546 } elsif ($len == 2) { 2547 $format = 'int16u', 2548 } 2549 } 2550 } 9307 $format = QuickTimeFormat($flags, $len) unless $format; 2551 9308 if ($format) { 2552 9309 $value = ReadValue(\$value, 0, $format, $$tagInfo{Count}, $len); … … 2558 9315 } 2559 9316 } 2560 my $langInfo;2561 9317 if ($ctry or $lang) { 2562 # ignore country ('ctry') and language lists ('lang') for now 2563 undef $ctry if $ctry and $ctry <= 255; 2564 undef $lang if $lang and $lang <= 255; 2565 $lang = UnpackLang($lang); 2566 # add country code if specified 2567 if ($ctry) { 2568 $ctry = unpack('a2',pack('n',$ctry)); # unpack as ISO 3166-1 2569 # treat 'ZZ' like a default country (see ref 12) 2570 undef $ctry if $ctry eq 'ZZ'; 2571 if ($ctry and $ctry =~ /^[A-Z]{2}$/) { 2572 $lang or $lang = 'und'; 2573 $lang .= "-$ctry"; 9318 my $langCode = GetLangCode($lang, $ctry); 9319 if ($langCode) { 9320 # get tagInfo for other language 9321 $langInfo = GetLangInfoQT($et, $tagInfo, $langCode); 9322 # save other language tag ID's so we can delete later if necessary 9323 if ($langInfo) { 9324 $$tagInfo{OtherLang} or $$tagInfo{OtherLang} = [ ]; 9325 push @{$$tagInfo{OtherLang}}, $$langInfo{TagID}; 2574 9326 } 2575 9327 } 2576 $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $lang) if $lang;2577 9328 } 2578 9329 $langInfo or $langInfo = $tagInfo; 2579 $e xifTool->VerboseInfo($tag, $langInfo,9330 $et->VerboseInfo($tag, $langInfo, 2580 9331 Value => ref $value ? $$value : $value, 2581 9332 DataPt => \$val, … … 2584 9335 Size => $len, 2585 9336 Format => $format, 2586 Extra => sprintf(", Type='$type', Flags=0x%x",$flags) 9337 Index => $index, 9338 Extra => sprintf(", Type='${type}', Flags=0x%x, Lang=0x%.4x",$flags,$lang), 2587 9339 ) if $verbose; 2588 $exifTool->FoundTag($langInfo, $value) if defined $value; 9340 # use "Keys" in path instead of ItemList if this was defined by a Keys tag 9341 my $isKey = $$tagInfo{Groups} && $$tagInfo{Groups}{1} && $$tagInfo{Groups}{1} eq 'Keys'; 9342 if ($isKey) { 9343 $oldDir = $$et{PATH}[-1]; 9344 $$et{PATH}[-1] = 'Keys'; 9345 } 9346 $et->FoundTag($langInfo, $value) if defined $value; 9347 $$et{PATH}[-1] = $oldDir if $isKey; 2589 9348 $pos += $len; 2590 9349 } 2591 } elsif ($tag =~ /^\xa9/ ) {9350 } elsif ($tag =~ /^\xa9/ or $$tagInfo{IText}) { 2592 9351 # parse international text to extract all languages 2593 9352 my $pos = 0; 9353 if ($$tagInfo{Format}) { 9354 $et->FoundTag($tagInfo, ReadValue(\$val, 0, $$tagInfo{Format}, undef, length($val))); 9355 $pos = $size; 9356 } 2594 9357 for (;;) { 2595 last if $pos + 4 > $size; 2596 my ($len, $lang) = unpack("x${pos}nn", $val); 2597 $pos += 4; 2598 # according to the QuickTime spec (ref 12), $len should include 2599 # 4 bytes for length and type words, but nobody (including 2600 # Apple, Pentax and Kodak) seems to add these in, so try 2601 # to allow for either 2602 if ($pos + $len > $size) { 2603 $len -= 4; 2604 last if $pos + $len > $size or $len < 0; 9358 my ($len, $lang); 9359 if ($$tagInfo{IText} and $$tagInfo{IText} == 6) { 9360 last if $pos + 6 > $size; 9361 $pos += 4; 9362 $lang = unpack("x${pos}n", $val); 9363 $pos += 2; 9364 $len = $size - $pos; 9365 } else { 9366 last if $pos + 4 > $size; 9367 ($len, $lang) = unpack("x${pos}nn", $val); 9368 $pos += 4; 9369 # according to the QuickTime spec (ref 12), $len should include 9370 # 4 bytes for length and type words, but nobody (including 9371 # Apple, Pentax and Kodak) seems to add these in, so try 9372 # to allow for either 9373 if ($pos + $len > $size) { 9374 $len -= 4; 9375 last if $pos + $len > $size or $len < 0; 9376 } 2605 9377 } 2606 9378 # ignore any empty entries (or null padding) after the first … … 2608 9380 my $str = substr($val, $pos, $len); 2609 9381 my $langInfo; 2610 if ( $lang < 0x400) {9382 if (($lang < 0x400 or $lang == 0x7fff) and $str !~ /^\xfe\xff/) { 2611 9383 # this is a Macintosh language code 2612 9384 # a language code of 0 is Macintosh english, so treat as default 2613 if ($lang) { 2614 # use Font.pm to look up language string 2615 require Image::ExifTool::Font; 2616 $lang = $Image::ExifTool::Font::ttLang{Macintosh}{$lang}; 9385 if ($lang) { 9386 if ($lang == 0x7fff) { 9387 # technically, ISO 639-2 doesn't have a 2-character 9388 # equivalent for 'und', but use 'un' anyway 9389 $lang = 'un'; 9390 } else { 9391 # use Font.pm to look up language string 9392 require Image::ExifTool::Font; 9393 $lang = $Image::ExifTool::Font::ttLang{Macintosh}{$lang}; 9394 } 2617 9395 } 2618 # the spec says only "Macintosh text encoding", so2619 # I can only assume that it is the most common one2620 $str = $e xifTool->Decode($str, 'MacRoman');9396 # the spec says only "Macintosh text encoding", but 9397 # allow this to be configured by the user 9398 $str = $et->Decode($str, $charsetQuickTime); 2621 9399 } else { 2622 9400 # convert language code to ASCII (ignore read-only bit) … … 2624 9402 # may be either UTF-8 or UTF-16BE 2625 9403 my $enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8'; 2626 $str = $e xifTool->Decode($str, $enc);9404 $str = $et->Decode($str, $enc); 2627 9405 } 2628 $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $lang) if $lang; 2629 $exifTool->FoundTag($langInfo || $tagInfo, $str); 9406 $str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags) 9407 $langInfo = GetLangInfoQT($et, $tagInfo, $lang) if $lang; 9408 $et->FoundTag($langInfo || $tagInfo, $str); 2630 9409 $pos += $len; 2631 9410 } 2632 9411 } else { 2633 if ($$tagInfo{Format}) { 2634 $val = ReadValue(\$val, 0, $$tagInfo{Format}, $$tagInfo{Count}, length($val)); 9412 my $format = $$tagInfo{Format}; 9413 if ($format) { 9414 $val = ReadValue(\$val, 0, $format, $$tagInfo{Count}, length($val)); 2635 9415 } 2636 $exifTool->FoundTag($tagInfo, $val); 9416 my $oldBase; 9417 if ($$tagInfo{SetBase}) { 9418 $oldBase = $$et{BASE}; 9419 $$et{BASE} = $dataPos; 9420 } 9421 my $key = $et->FoundTag($tagInfo, $val); 9422 $$et{BASE} = $oldBase if defined $oldBase; 9423 # decode if necessary (NOTE: must be done after RawConv) 9424 if (defined $key and (not $format or $format =~ /^string/) and 9425 not $$tagInfo{Unknown} and not $$tagInfo{ValueConv} and 9426 not $$tagInfo{Binary} and defined $$et{VALUE}{$key} and not ref $val) 9427 { 9428 my $vp = \$$et{VALUE}{$key}; 9429 if (not ref $$vp and length($$vp) <= 65536 and $$vp =~ /[\x80-\xff]/) { 9430 # the encoding of this is not specified, so use CharsetQuickTime 9431 # unless the string is valid UTF-8 9432 require Image::ExifTool::XMP; 9433 my $enc = Image::ExifTool::XMP::IsUTF8($vp) > 0 ? 'UTF8' : $charsetQuickTime; 9434 $$vp = $et->Decode($$vp, $enc); 9435 } 9436 } 2637 9437 } 2638 9438 } 2639 9439 } else { 2640 $raf->Seek($size, 1) or $exifTool->Warn("Truncated '$tag' data"), last; 9440 $et->VerboseInfo($tag, $tagInfo, 9441 Size => $size, 9442 Extra => sprintf(' at offset 0x%.4x', $raf->Tell()), 9443 ) if $verbose; 9444 if ($size and (not $raf->Seek($size-1, 1) or $raf->Read($buff, 1) != 1)) { 9445 my $t = PrintableTagID($tag,2); 9446 $et->Warn("Truncated '${t}' data"); 9447 last; 9448 } 2641 9449 } 9450 $dataPos += $size + 8; # point to start of next atom data 9451 last if $dirEnd and $dataPos >= $dirEnd; # (note: ignores last value if 0 bytes) 2642 9452 $raf->Read($buff, 8) == 8 or last; 2643 $dataPos += $size + 8;2644 9453 ($size, $tag) = unpack('Na4', $buff); 9454 ++$index if defined $index; 2645 9455 } 9456 # fill in missing defaults for alternate language tags 9457 # (the first language is taken as the default) 9458 if ($doDefaultLang and $$et{QTLang}) { 9459 QTLang: foreach $tag (@{$$et{QTLang}}) { 9460 next unless defined $$et{VALUE}{$tag}; 9461 my $langInfo = $$et{TAG_INFO}{$tag} or next; 9462 my $tagInfo = $$langInfo{SrcTagInfo} or next; 9463 my $infoHash = $$et{TAG_INFO}; 9464 my $name = $$tagInfo{Name}; 9465 # loop through all instances of this tag name and generate the default-language 9466 # version only if we don't already have a QuickTime tag with this name 9467 my ($i, $key); 9468 for ($i=0, $key=$name; $$infoHash{$key}; ++$i, $key="$name ($i)") { 9469 next QTLang if $et->GetGroup($key, 0) eq 'QuickTime'; 9470 } 9471 $et->FoundTag($tagInfo, $$et{VALUE}{$tag}); 9472 } 9473 delete $$et{QTLang}; 9474 } 9475 # process item information now that we are done processing its 'meta' container 9476 HandleItemInfo($et) if $topLevel or $dirID eq 'meta'; 9477 9478 ScanMediaData($et) if $ee and $topLevel; # brute force scan for metadata embedded in media data 9479 9480 # restore any changed options 9481 $et->Options($_ => $saveOptions{$_}) foreach keys %saveOptions; 2646 9482 return 1; 2647 9483 } … … 2653 9489 sub ProcessQTIF($$) 2654 9490 { 2655 my ($e xifTool, $dirInfo) = @_;9491 my ($et, $dirInfo) = @_; 2656 9492 my $table = GetTagTable('Image::ExifTool::QuickTime::ImageFile'); 2657 return ProcessMOV($e xifTool, $dirInfo, $table);9493 return ProcessMOV($et, $dirInfo, $table); 2658 9494 } 2659 9495 … … 2673 9509 2674 9510 This module contains routines required by Image::ExifTool to extract 2675 information from QuickTime and MP4 video, and M4A audiofiles.9511 information from QuickTime and MP4 video, M4A audio, and HEIC image files. 2676 9512 2677 9513 =head1 AUTHOR 2678 9514 2679 Copyright 2003-20 11, Phil Harvey (phil at owl.phy.queensu.ca)9515 Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com) 2680 9516 2681 9517 This library is free software; you can redistribute it and/or modify it
Note:
See TracChangeset
for help on using the changeset viewer.