1#------------------------------------------------------------------------------ 2# File: QuickTime.pm 3# 4# Description: Read QuickTime and MP4 meta information 5# 6# Revisions: 10/04/2005 - P. Harvey Created 7# 12/19/2005 - P. Harvey Added MP4 support 8# 09/22/2006 - P. Harvey Added M4A support 9# 07/27/2010 - P. Harvey Updated to 2010-05-03 QuickTime spec 10# 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 40#------------------------------------------------------------------------------ 41 42package Image::ExifTool::QuickTime; 43 44use strict; 45use vars qw($VERSION $AUTOLOAD %stringEncoding); 46use Image::ExifTool qw(:DataAccess :Utils); 47use Image::ExifTool::Exif; 48use Image::ExifTool::GPS; 49 50$VERSION = '2.68'; 51 52sub ProcessMOV($$;$); 53sub ProcessKeys($$$); 54sub ProcessMetaKeys($$$); 55sub ProcessMetaData($$$); 56sub ProcessEncodingParams($$$); 57sub ProcessSampleDesc($$$); 58sub ProcessHybrid($$$); 59sub ProcessRights($$$); 60# ++vvvvvvvvvvvv++ (in QuickTimeStream.pl) 61sub Process_mebx($$$); 62sub Process_3gf($$$); 63sub Process_gps0($$$); 64sub Process_gsen($$$); 65sub ProcessRIFFTrailer($$$); 66sub ProcessTTAD($$$); 67sub ProcessNMEA($$$); 68sub ProcessGPSLog($$$); 69sub SaveMetaKeys($$$); 70# ++^^^^^^^^^^^^++ 71sub ParseItemLocation($$); 72sub ParseContentDescribes($$); 73sub ParseItemInfoEntry($$); 74sub ParseItemPropAssoc($$); 75sub FixWrongFormat($); 76sub GetMatrixStructure($$); 77sub ConvertISO6709($); 78sub ConvInvISO6709($); 79sub ConvertChapterList($); 80sub PrintChapter($); 81sub PrintGPSCoordinates($); 82sub PrintInvGPSCoordinates($); 83sub UnpackLang($;$); 84sub WriteKeys($$$); 85sub WriteQuickTime($$$); 86sub WriteMOV($$); 87sub GetLangInfo($$); 88sub CheckQTValue($$$); 89 90# MIME types for all entries in the ftypLookup with file extensions 91# (defaults to 'video/mp4' if not found in this lookup) 92my %mimeLookup = ( 93 '3G2' => 'video/3gpp2', 94 '3GP' => 'video/3gpp', 95 AAX => 'audio/vnd.audible.aax', 96 DVB => 'video/vnd.dvb.file', 97 F4A => 'audio/mp4', 98 F4B => 'audio/mp4', 99 JP2 => 'image/jp2', 100 JPM => 'image/jpm', 101 JPX => 'image/jpx', 102 M4A => 'audio/mp4', 103 M4B => 'audio/mp4', 104 M4P => 'audio/mp4', 105 M4V => 'video/x-m4v', 106 MOV => 'video/quicktime', 107 MQV => 'video/quicktime', 108 HEIC => 'image/heic', 109 HEVC => 'image/heic-sequence', 110 HEICS=> 'image/heic-sequence', 111 HEIF => 'image/heif', 112 HEIFS=> 'image/heif-sequence', 113 AVIF => 'image/avif', #PH (NC) 114 CRX => 'video/x-canon-crx', # (will get overridden) 115); 116 117# look up file type from ftyp atom type, with MIME type in comment if known 118# (ref http://www.ftyps.com/) 119my %ftypLookup = ( 120 '3g2a' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-0 V1.0', # video/3gpp2 121 '3g2b' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-A V1.0.0', # video/3gpp2 122 '3g2c' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-B v1.0', # video/3gpp2 123 '3ge6' => '3GPP (.3GP) Release 6 MBMS Extended Presentations', # video/3gpp 124 '3ge7' => '3GPP (.3GP) Release 7 MBMS Extended Presentations', # video/3gpp 125 '3gg6' => '3GPP Release 6 General Profile', # video/3gpp 126 '3gp1' => '3GPP Media (.3GP) Release 1 (probably non-existent)', # video/3gpp 127 '3gp2' => '3GPP Media (.3GP) Release 2 (probably non-existent)', # video/3gpp 128 '3gp3' => '3GPP Media (.3GP) Release 3 (probably non-existent)', # video/3gpp 129 '3gp4' => '3GPP Media (.3GP) Release 4', # video/3gpp 130 '3gp5' => '3GPP Media (.3GP) Release 5', # video/3gpp 131 '3gp6' => '3GPP Media (.3GP) Release 6 Basic Profile', # video/3gpp 132 '3gp6' => '3GPP Media (.3GP) Release 6 Progressive Download', # video/3gpp 133 '3gp6' => '3GPP Media (.3GP) Release 6 Streaming Servers', # video/3gpp 134 '3gs7' => '3GPP Media (.3GP) Release 7 Streaming Servers', # video/3gpp 135 'aax ' => 'Audible Enhanced Audiobook (.AAX)', #PH 136 'avc1' => 'MP4 Base w/ AVC ext [ISO 14496-12:2005]', # video/mp4 137 'CAEP' => 'Canon Digital Camera', 138 'caqv' => 'Casio Digital Camera', 139 'CDes' => 'Convergent Design', 140 'da0a' => 'DMB MAF w/ MPEG Layer II aud, MOT slides, DLS, JPG/PNG/MNG images', 141 'da0b' => 'DMB MAF, extending DA0A, with 3GPP timed text, DID, TVA, REL, IPMP', 142 'da1a' => 'DMB MAF audio with ER-BSAC audio, JPG/PNG/MNG images', 143 'da1b' => 'DMB MAF, extending da1a, with 3GPP timed text, DID, TVA, REL, IPMP', 144 'da2a' => 'DMB MAF aud w/ HE-AAC v2 aud, MOT slides, DLS, JPG/PNG/MNG images', 145 'da2b' => 'DMB MAF, extending da2a, with 3GPP timed text, DID, TVA, REL, IPMP', 146 'da3a' => 'DMB MAF aud with HE-AAC aud, JPG/PNG/MNG images', 147 'da3b' => 'DMB MAF, extending da3a w/ BIFS, 3GPP timed text, DID, TVA, REL, IPMP', 148 'dmb1' => 'DMB MAF supporting all the components defined in the specification', 149 'dmpf' => 'Digital Media Project', # various 150 'drc1' => 'Dirac (wavelet compression), encapsulated in ISO base media (MP4)', 151 'dv1a' => 'DMB MAF vid w/ AVC vid, ER-BSAC aud, BIFS, JPG/PNG/MNG images, TS', 152 'dv1b' => 'DMB MAF, extending dv1a, with 3GPP timed text, DID, TVA, REL, IPMP', 153 'dv2a' => 'DMB MAF vid w/ AVC vid, HE-AAC v2 aud, BIFS, JPG/PNG/MNG images, TS', 154 'dv2b' => 'DMB MAF, extending dv2a, with 3GPP timed text, DID, TVA, REL, IPMP', 155 'dv3a' => 'DMB MAF vid w/ AVC vid, HE-AAC aud, BIFS, JPG/PNG/MNG images, TS', 156 'dv3b' => 'DMB MAF, extending dv3a, with 3GPP timed text, DID, TVA, REL, IPMP', 157 'dvr1' => 'DVB (.DVB) over RTP', # video/vnd.dvb.file 158 'dvt1' => 'DVB (.DVB) over MPEG-2 Transport Stream', # video/vnd.dvb.file 159 'F4A ' => 'Audio for Adobe Flash Player 9+ (.F4A)', # audio/mp4 160 'F4B ' => 'Audio Book for Adobe Flash Player 9+ (.F4B)', # audio/mp4 161 'F4P ' => 'Protected Video for Adobe Flash Player 9+ (.F4P)', # video/mp4 162 'F4V ' => 'Video for Adobe Flash Player 9+ (.F4V)', # video/mp4 163 'isc2' => 'ISMACryp 2.0 Encrypted File', # ?/enc-isoff-generic 164 'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4 (or audio) 165 'iso3' => 'MP4 Base Media v3', # video/mp4 (or audio) 166 'iso4' => 'MP4 Base Media v4', # video/mp4 (or audio) 167 'iso5' => 'MP4 Base Media v5', # video/mp4 (or audio) 168 'iso6' => 'MP4 Base Media v6', # video/mp4 (or audio) 169 'iso7' => 'MP4 Base Media v7', # video/mp4 (or audio) 170 'iso8' => 'MP4 Base Media v8', # video/mp4 (or audio) 171 'iso9' => 'MP4 Base Media v9', # video/mp4 (or audio) 172 'isom' => 'MP4 Base Media v1 [IS0 14496-12:2003]', # video/mp4 (or audio) 173 'JP2 ' => 'JPEG 2000 Image (.JP2) [ISO 15444-1 ?]', # image/jp2 174 'JP20' => 'Unknown, from GPAC samples (prob non-existent)', 175 'jpm ' => 'JPEG 2000 Compound Image (.JPM) [ISO 15444-6]', # image/jpm 176 'jpx ' => 'JPEG 2000 with extensions (.JPX) [ISO 15444-2]', # image/jpx 177 'KDDI' => '3GPP2 EZmovie for KDDI 3G cellphones', # video/3gpp2 178 #LCAG => (found in CompatibleBrands of Leica MOV videos) 179 'M4A ' => 'Apple iTunes AAC-LC (.M4A) Audio', # audio/x-m4a 180 'M4B ' => 'Apple iTunes AAC-LC (.M4B) Audio Book', # audio/mp4 181 'M4P ' => 'Apple iTunes AAC-LC (.M4P) AES Protected Audio', # audio/mp4 182 'M4V ' => 'Apple iTunes Video (.M4V) Video', # video/x-m4v 183 'M4VH' => 'Apple TV (.M4V)', # video/x-m4v 184 'M4VP' => 'Apple iPhone (.M4V)', # video/x-m4v 185 'mj2s' => 'Motion JPEG 2000 [ISO 15444-3] Simple Profile', # video/mj2 186 'mjp2' => 'Motion JPEG 2000 [ISO 15444-3] General Profile', # video/mj2 187 'mmp4' => 'MPEG-4/3GPP Mobile Profile (.MP4/3GP) (for NTT)', # video/mp4 188 'mp21' => 'MPEG-21 [ISO/IEC 21000-9]', # various 189 'mp41' => 'MP4 v1 [ISO 14496-1:ch13]', # video/mp4 190 'mp42' => 'MP4 v2 [ISO 14496-14]', # video/mp4 191 'mp71' => 'MP4 w/ MPEG-7 Metadata [per ISO 14496-12]', # various 192 'MPPI' => 'Photo Player, MAF [ISO/IEC 23000-3]', # various 193 'mqt ' => 'Sony / Mobile QuickTime (.MQV) US Patent 7,477,830 (Sony Corp)', # video/quicktime 194 'MSNV' => 'MPEG-4 (.MP4) for SonyPSP', # audio/mp4 195 'NDAS' => 'MP4 v2 [ISO 14496-14] Nero Digital AAC Audio', # audio/mp4 196 'NDSC' => 'MPEG-4 (.MP4) Nero Cinema Profile', # video/mp4 197 'NDSH' => 'MPEG-4 (.MP4) Nero HDTV Profile', # video/mp4 198 'NDSM' => 'MPEG-4 (.MP4) Nero Mobile Profile', # video/mp4 199 'NDSP' => 'MPEG-4 (.MP4) Nero Portable Profile', # video/mp4 200 'NDSS' => 'MPEG-4 (.MP4) Nero Standard Profile', # video/mp4 201 'NDXC' => 'H.264/MPEG-4 AVC (.MP4) Nero Cinema Profile', # video/mp4 202 'NDXH' => 'H.264/MPEG-4 AVC (.MP4) Nero HDTV Profile', # video/mp4 203 'NDXM' => 'H.264/MPEG-4 AVC (.MP4) Nero Mobile Profile', # video/mp4 204 'NDXP' => 'H.264/MPEG-4 AVC (.MP4) Nero Portable Profile', # video/mp4 205 'NDXS' => 'H.264/MPEG-4 AVC (.MP4) Nero Standard Profile', # video/mp4 206 'odcf' => 'OMA DCF DRM Format 2.0 (OMA-TS-DRM-DCF-V2_0-20060303-A)', # various 207 'opf2' => 'OMA PDCF DRM Format 2.1 (OMA-TS-DRM-DCF-V2_1-20070724-C)', 208 'opx2' => 'OMA PDCF DRM + XBS extensions (OMA-TS-DRM_XBS-V1_0-20070529-C)', 209 'pana' => 'Panasonic Digital Camera', 210 'qt ' => 'Apple QuickTime (.MOV/QT)', # video/quicktime 211 'ROSS' => 'Ross Video', 212 'sdv ' => 'SD Memory Card Video', # various? 213 'ssc1' => 'Samsung stereoscopic, single stream', 214 'ssc2' => 'Samsung stereoscopic, dual stream', 215 'XAVC' => 'Sony XAVC', #PH 216 'heic' => 'High Efficiency Image Format HEVC still image (.HEIC)', # image/heic 217 'hevc' => 'High Efficiency Image Format HEVC sequence (.HEICS)', # image/heic-sequence 218 'mif1' => 'High Efficiency Image Format still image (.HEIF)', # image/heif 219 'msf1' => 'High Efficiency Image Format sequence (.HEIFS)', # image/heif-sequence 220 'heix' => 'High Efficiency Image Format still image (.HEIF)', # image/heif (ref PH, Canon 1DXmkIII) 221 'avif' => 'AV1 Image File Format (.AVIF)', # image/avif 222 'crx ' => 'Canon Raw (.CRX)', #PH (CR3 or CRM; use Canon CompressorVersion to decide) 223); 224 225# information for int32u date/time tags (time zero is Jan 1, 1904) 226my %timeInfo = ( 227 Notes => 'converted from UTC to local time if the QuickTimeUTC option is set', 228 Shift => 'Time', 229 Writable => 1, 230 Permanent => 1, 231 DelValue => 0, 232 # It is not uncommon for brain-dead software to use the wrong time zero, it should be 233 # Jan 1, 1904, so assume a time zero of Jan 1, 1970 if the date is before this 234 # Note: This value will be in UTC if generated by a system that is aware of the time zone 235 # (also note: this code is duplicated for the CreateDate tag) 236 RawConv => q{ 237 my $offset = (66 * 365 + 17) * 24 * 3600; 238 return $val - $offset if $val >= $offset or $$self{OPTIONS}{QuickTimeUTC}; 239 if ($val and not $$self{IsWriting}) { 240 $self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1); 241 } 242 return $val; 243 }, 244 RawConvInv => q{ 245 if ($$self{FileType} eq 'CR3' and not $self->Options('QuickTimeUTC')) { 246 # convert to UTC 247 my $offset = (66 * 365 + 17) * 24 * 3600; 248 $val = ConvertUnixTime($val - $offset); 249 $val = GetUnixTime($val, 1) + $offset; 250 } 251 return $val; 252 }, 253 # (all CR3 files store UTC times - PH) 254 ValueConv => 'ConvertUnixTime($val, $self->Options("QuickTimeUTC") || $$self{FileType} eq "CR3")', 255 ValueConvInv => q{ 256 $val = GetUnixTime($val, $self->Options("QuickTimeUTC")); 257 return undef unless defined $val; 258 return $val + (66 * 365 + 17) * 24 * 3600; 259 }, 260 PrintConv => '$self->ConvertDateTime($val)', 261 PrintConvInv => '$self->InverseDateTime($val)', 262 # (can't put Groups here because they aren't constant!) 263); 264# information for duration tags 265my %durationInfo = ( 266 ValueConv => '$$self{TimeScale} ? $val / $$self{TimeScale} : $val', 267 PrintConv => '$$self{TimeScale} ? ConvertDuration($val) : $val', 268); 269# handle unknown tags 270my %unknownInfo = ( 271 Unknown => 1, 272 ValueConv => '$val =~ /^([\x20-\x7e]*)\0*$/ ? $1 : \$val', 273); 274 275# multi-language text with 6-byte header 276my %langText = ( IText => 6 ); 277 278# parsing for most of the 3gp udta language text boxes 279my %langText3gp = ( 280 Notes => 'used in 3gp videos', 281 Avoid => 1, 282 IText => 6, 283); 284 285# 4-character Vendor ID codes (ref PH) 286my %vendorID = ( 287 appl => 'Apple', 288 fe20 => 'Olympus (fe20)', # (FE200) 289 FFMP => 'FFmpeg', 290 'GIC '=> 'General Imaging Co.', 291 kdak => 'Kodak', 292 KMPI => 'Konica-Minolta', 293 leic => 'Leica', 294 mino => 'Minolta', 295 niko => 'Nikon', 296 NIKO => 'Nikon', 297 olym => 'Olympus', 298 pana => 'Panasonic', 299 pent => 'Pentax', 300 pr01 => 'Olympus (pr01)', # (FE100,FE110,FE115) 301 sany => 'Sanyo', 302 'SMI '=> 'Sorenson Media Inc.', 303 ZORA => 'Zoran Corporation', 304 'AR.D'=> 'Parrot AR.Drone', 305 ' KD '=> 'Kodak', # (FZ201) 306); 307 308# QuickTime data atom encodings for string types (ref 12) 309%stringEncoding = ( 310 1 => 'UTF8', 311 2 => 'UTF16', 312 3 => 'ShiftJIS', 313 4 => 'UTF8', 314 5 => 'UTF16', 315); 316 317my %graphicsMode = ( 318 # (ref http://homepage.mac.com/vanhoek/MovieGuts%20docs/64.html) 319 0x00 => 'srcCopy', 320 0x01 => 'srcOr', 321 0x02 => 'srcXor', 322 0x03 => 'srcBic', 323 0x04 => 'notSrcCopy', 324 0x05 => 'notSrcOr', 325 0x06 => 'notSrcXor', 326 0x07 => 'notSrcBic', 327 0x08 => 'patCopy', 328 0x09 => 'patOr', 329 0x0a => 'patXor', 330 0x0b => 'patBic', 331 0x0c => 'notPatCopy', 332 0x0d => 'notPatOr', 333 0x0e => 'notPatXor', 334 0x0f => 'notPatBic', 335 0x20 => 'blend', 336 0x21 => 'addPin', 337 0x22 => 'addOver', 338 0x23 => 'subPin', 339 0x24 => 'transparent', 340 0x25 => 'addMax', 341 0x26 => 'subOver', 342 0x27 => 'addMin', 343 0x31 => 'grayishTextOr', 344 0x32 => 'hilite', 345 0x40 => 'ditherCopy', 346 # the following ref ISO/IEC 15444-3 347 0x100 => 'Alpha', 348 0x101 => 'White Alpha', 349 0x102 => 'Pre-multiplied Black Alpha', 350 0x110 => 'Component Alpha', 351); 352 353my %channelLabel = ( 354 0xFFFFFFFF => 'Unknown', 355 0 => 'Unused', 356 100 => 'UseCoordinates', 357 1 => 'Left', 358 2 => 'Right', 359 3 => 'Center', 360 4 => 'LFEScreen', 361 5 => 'LeftSurround', 362 6 => 'RightSurround', 363 7 => 'LeftCenter', 364 8 => 'RightCenter', 365 9 => 'CenterSurround', 366 10 => 'LeftSurroundDirect', 367 11 => 'RightSurroundDirect', 368 12 => 'TopCenterSurround', 369 13 => 'VerticalHeightLeft', 370 14 => 'VerticalHeightCenter', 371 15 => 'VerticalHeightRight', 372 16 => 'TopBackLeft', 373 17 => 'TopBackCenter', 374 18 => 'TopBackRight', 375 33 => 'RearSurroundLeft', 376 34 => 'RearSurroundRight', 377 35 => 'LeftWide', 378 36 => 'RightWide', 379 37 => 'LFE2', 380 38 => 'LeftTotal', 381 39 => 'RightTotal', 382 40 => 'HearingImpaired', 383 41 => 'Narration', 384 42 => 'Mono', 385 43 => 'DialogCentricMix', 386 44 => 'CenterSurroundDirect', 387 45 => 'Haptic', 388 200 => 'Ambisonic_W', 389 201 => 'Ambisonic_X', 390 202 => 'Ambisonic_Y', 391 203 => 'Ambisonic_Z', 392 204 => 'MS_Mid', 393 205 => 'MS_Side', 394 206 => 'XY_X', 395 207 => 'XY_Y', 396 301 => 'HeadphonesLeft', 397 302 => 'HeadphonesRight', 398 304 => 'ClickTrack', 399 305 => 'ForeignLanguage', 400 400 => 'Discrete', 401 0x10000 => 'Discrete_0', 402 0x10001 => 'Discrete_1', 403 0x10002 => 'Discrete_2', 404 0x10003 => 'Discrete_3', 405 0x10004 => 'Discrete_4', 406 0x10005 => 'Discrete_5', 407 0x10006 => 'Discrete_6', 408 0x10007 => 'Discrete_7', 409 0x10008 => 'Discrete_8', 410 0x10009 => 'Discrete_9', 411 0x1000a => 'Discrete_10', 412 0x1000b => 'Discrete_11', 413 0x1000c => 'Discrete_12', 414 0x1000d => 'Discrete_13', 415 0x1000e => 'Discrete_14', 416 0x1000f => 'Discrete_15', 417 0x1ffff => 'Discrete_65535', 418); 419 420# properties which don't get inherited from the parent 421my %dontInherit = ( 422 ispe => 1, # size of parent may be different 423 hvcC => 1, # (likely redundant) 424); 425 426# tags that may be duplicated and directories that may contain duplicate tags 427# (used only to avoid warnings when Validate-ing) 428my %dupTagOK = ( mdat => 1, trak => 1, free => 1, infe => 1, sgpd => 1, dimg => 1, CCDT => 1, 429 sbgp => 1, csgm => 1, uuid => 1, cdsc => 1, maxr => 1, '----' => 1 ); 430my %dupDirOK = ( ipco => 1, '----' => 1 ); 431 432# the usual atoms required to decode timed metadata with the ExtractEmbedded option 433my %eeStd = ( stco => 'stbl', co64 => 'stbl', stsz => 'stbl', stz2 => 'stbl', 434 stsc => 'stbl', stts => 'stbl' ); 435 436# boxes and their containers for the various handler types that we want to save 437# when the ExtractEmbedded is enabled (currently only the 'gps ' container name is 438# used, but others have been checked against all available sample files and may be 439# useful in the future if the names are used for different boxes on other locations) 440my %eeBox = ( 441 # (note: vide is only processed if specific atoms exist in the VideoSampleDesc) 442 vide => { %eeStd, 443 JPEG => 'stsd', 444 }, 445 text => { %eeStd }, 446 meta => { %eeStd }, 447 sbtl => { %eeStd }, 448 data => { %eeStd }, 449 camm => { %eeStd }, # (Insta360) 450 ctbx => { %eeStd }, # (GM cars) 451 '' => { 'gps ' => 'moov', 'GPS ' => 'main' }, # (no handler -- in top level 'moov' box, and main) 452); 453# boxes to save when ExtractEmbedded is set to 2 or higher 454my %eeBox2 = ( 455 vide => { avcC => 'stsd' }, # (parses H264 video stream) 456); 457 458# QuickTime atoms 459%Image::ExifTool::QuickTime::Main = ( 460 PROCESS_PROC => \&ProcessMOV, 461 WRITE_PROC => \&WriteQuickTime, # (only needs to be defined for directories to process when writing) 462 GROUPS => { 2 => 'Video' }, 463 meta => { # 'meta' is found here in my Sony ILCE-7S MP4 sample - PH 464 Name => 'Meta', 465 SubDirectory => { 466 TagTable => 'Image::ExifTool::QuickTime::Meta', 467 Start => 4, # skip 4-byte version number header 468 }, 469 }, 470 meco => { #ISO14496-12:2015 471 Name => 'OtherMeta', 472 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' }, 473 }, 474 free => [ 475 { 476 Name => 'KodakFree', 477 # (found in Kodak M5370 MP4 videos) 478 Condition => '$$valPt =~ /^\0\0\0.Seri/s', 479 SubDirectory => { TagTable => 'Image::ExifTool::Kodak::Free' }, 480 },{ 481 Name => 'Pittasoft', 482 # (Pittasoft Blackview dashcam MP4 videos) 483 Condition => '$$valPt =~ /^\0\0..(cprt|sttm|ptnm|ptrh|thum|gps |3gf )/s', 484 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' }, 485 },{ 486 Unknown => 1, 487 Binary => 1, 488 }, 489 # (also Samsung WB750 uncompressed thumbnail data starting with "SDIC\0") 490 ], 491 # fre1 - 4 bytes: "june" (Kodak PixPro SP360) 492 frea => { 493 Name => 'Kodak_frea', 494 SubDirectory => { TagTable => 'Image::ExifTool::Kodak::frea' }, 495 }, 496 skip => [ 497 { 498 Name => 'CanonSkip', 499 Condition => '$$valPt =~ /^\0.{3}(CNDB|CNCV|CNMN|CNFV|CNTH|CNDM)/s', 500 SubDirectory => { TagTable => 'Image::ExifTool::Canon::Skip' }, 501 }, 502 { 503 Name => 'PreviewImage', # (found in DuDuBell M1 dashcam MOV files) 504 Groups => { 2 => 'Preview' }, 505 Condition => '$$valPt =~ /^.{12}\xff\xd8\xff/', 506 Binary => 1, 507 RawConv => q{ 508 my $len = Get32u(\$val, 8); 509 return undef unless length($val) >= $len + 12; 510 return substr($val, 12, $len); 511 }, 512 }, 513 { Name => 'Skip', Unknown => 1, Binary => 1 }, 514 ], 515 wide => { Unknown => 1, Binary => 1 }, 516 ftyp => { #MP4 517 Name => 'FileType', 518 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FileType' }, 519 }, 520 pnot => { 521 Name => 'Preview', 522 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Preview' }, 523 }, 524 PICT => { 525 Name => 'PreviewPICT', 526 Groups => { 2 => 'Preview' }, 527 Binary => 1, 528 }, 529 pict => { #8 530 Name => 'PreviewPICT', 531 Groups => { 2 => 'Preview' }, 532 Binary => 1, 533 }, 534 # (note that moov is present for an HEIF sequence) 535 moov => { 536 Name => 'Movie', 537 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Movie' }, 538 }, 539 moof => { 540 Name => 'MovieFragment', 541 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieFragment' }, 542 }, 543 # mfra - movie fragment random access: contains tfra (track fragment random access), and 544 # mfro (movie fragment random access offset) (ref 5) 545 mdat => { Name => 'MediaData', Unknown => 1, Binary => 1 }, 546 'mdat-size' => { 547 Name => 'MediaDataSize', 548 Notes => q{ 549 not a real tag ID, this tag represents the size of the 'mdat' data in bytes 550 and is used in the AvgBitrate calculation 551 }, 552 }, 553 'mdat-offset' => 'MediaDataOffset', 554 junk => { Unknown => 1, Binary => 1 }, #8 555 uuid => [ 556 { #9 (MP4 files) 557 Name => 'XMP', 558 # *** this is where ExifTool writes XMP in MP4 videos (as per XMP spec) *** 559 Condition => '$$valPt=~/^\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac/', 560 WriteGroup => 'XMP', # (write main XMP tags here) 561 SubDirectory => { 562 TagTable => 'Image::ExifTool::XMP::Main', 563 Start => 16, 564 }, 565 }, 566 { #11 (MP4 files) 567 Name => 'UUID-PROF', 568 Condition => '$$valPt=~/^PROF!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/', 569 SubDirectory => { 570 TagTable => 'Image::ExifTool::QuickTime::Profile', 571 Start => 24, # uid(16) + version(1) + flags(3) + count(4) 572 }, 573 }, 574 { #PH (Flip MP4 files) 575 Name => 'UUID-Flip', 576 Condition => '$$valPt=~/^\x4a\xb0\x3b\x0f\x61\x8d\x40\x75\x82\xb2\xd9\xfa\xce\xd3\x5f\xf5/', 577 SubDirectory => { 578 TagTable => 'Image::ExifTool::QuickTime::Flip', 579 Start => 16, 580 }, 581 }, 582 # "\x98\x7f\xa3\xdf\x2a\x85\x43\xc0\x8f\x8f\xd9\x7c\x47\x1e\x8e\xea" - unknown data in Flip videos 583 { #PH (Canon CR3) 584 Name => 'UUID-Canon2', 585 WriteLast => 1, # MUST come after mdat or DPP will drop mdat when writing! 586 Condition => '$$valPt=~/^\x21\x0f\x16\x87\x91\x49\x11\xe4\x81\x11\x00\x24\x21\x31\xfc\xe4/', 587 SubDirectory => { 588 TagTable => 'Image::ExifTool::Canon::uuid2', 589 Start => 16, 590 }, 591 }, 592 { # (ref https://github.com/JamesHeinrich/getID3/blob/master/getid3/module.audio-video.quicktime.php) 593 Name => 'SensorData', # sensor data for the 360Fly 594 Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/ and $$self{OPTIONS}{ExtractEmbedded}', 595 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Tags360Fly' }, 596 }, 597 { 598 Name => 'SensorData', 599 Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/', 600 Notes => 'raw 360Fly sensor data without ExtractEmbedded option', 601 RawConv => q{ 602 $self->WarnOnce('Use the ExtractEmbedded option to decode timed SensorData',3); 603 return \$val; 604 }, 605 }, 606 { #PH (Canon CR3) 607 Name => 'PreviewImage', 608 Condition => '$$valPt=~/^\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16/', 609 Groups => { 2 => 'Preview' }, 610 # 0x00 - undef[16]: UUID 611 # 0x10 - int32u[2]: "0 1" (version and/or item count?) 612 # 0x18 - int32u: PRVW atom size 613 # 0x20 - int32u: 'PRVW' 614 # 0x30 - int32u: 0 615 # 0x34 - int16u: 1 616 # 0x36 - int16u: image width 617 # 0x38 - int16u: image height 618 # 0x3a - int16u: 1 619 # 0x3c - int32u: preview length 620 RawConv => '$val = substr($val, 0x30); $self->ValidateImage(\$val, $tag)', 621 }, 622 { #8 623 Name => 'UUID-Unknown', 624 %unknownInfo, 625 }, 626 ], 627 _htc => { 628 Name => 'HTCInfo', 629 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HTCInfo' }, 630 }, 631 udta => { 632 Name => 'UserData', 633 SubDirectory => { TagTable => 'Image::ExifTool::FLIR::UserData' }, 634 }, 635 thum => { #PH 636 Name => 'ThumbnailImage', 637 Groups => { 2 => 'Preview' }, 638 Binary => 1, 639 }, 640 'thm ' => { #PH (70mai A800) 641 Name => 'ThumbnailImage', 642 Groups => { 2 => 'Preview' }, 643 Binary => 1, 644 }, 645 ardt => { #PH 646 Name => 'ARDroneFile', 647 ValueConv => 'length($val) > 4 ? substr($val,4) : $val', # remove length 648 }, 649 prrt => { #PH 650 Name => 'ARDroneTelemetry', 651 Notes => q{ 652 telemetry information for each video frame: status1, status2, time, pitch, 653 roll, yaw, speed, altitude 654 }, 655 ValueConv => q{ 656 my $size = length $val; 657 return \$val if $size < 12 or not $$self{OPTIONS}{Binary}; 658 my $len = Get16u(\$val, 2); 659 my $str = ''; 660 SetByteOrder('II'); 661 my $pos = 12; 662 while ($pos + $len <= $size) { 663 my $s1 = Get16u(\$val, $pos); 664 # s2: 7=take-off?, 3=moving, 4=hovering, 9=landing?, 2=landed 665 my $s2 = Get16u(\$val, $pos + 2); 666 $str .= "$s1 $s2"; 667 my $num = int(($len-4)/4); 668 my ($i, $v); 669 for ($i=0; $i<$num; ++$i) { 670 my $pt = $pos + 4 + $i * 4; 671 if ($i > 0 && $i < 4) { 672 $v = GetFloat(\$val, $pt); # pitch/roll/yaw 673 } else { 674 $v = Get32u(\$val, $pt); 675 # convert time to sec, and speed(NC)/altitude to metres 676 $v /= 1000 if $i <= 5; 677 } 678 $str .= " $v"; 679 } 680 $str .= "\n"; 681 $pos += $len; 682 } 683 SetByteOrder('MM'); 684 return \$str; 685 }, 686 }, 687 udat => { #PH (GPS NMEA-format log written by Datakam Player software) 688 Name => 'GPSLog', 689 Binary => 1, # (actually ASCII, but very lengthy) 690 Notes => 'parsed to extract GPS separately when ExtractEmbedded is used', 691 RawConv => q{ 692 $val =~ s/\0+$//; # remove trailing nulls 693 if (length $val and $$self{OPTIONS}{ExtractEmbedded}) { 694 my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); 695 Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl); 696 } 697 return $val; 698 }, 699 }, 700 # meta - proprietary XML information written by some Flip cameras - PH 701 # beam - 16 bytes found in an iPhone video 702 IDIT => { #PH (written by DuDuBell M1, VSYS M6L dashcams) 703 Name => 'DateTimeOriginal', 704 Description => 'Date/Time Original', 705 Groups => { 2 => 'Time' }, 706 Format => 'string', # (removes trailing "\0") 707 Shift => 'Time', 708 Writable => 1, 709 Permanent => 1, 710 DelValue => '0000-00-00T00:00:00+0000', 711 ValueConv => '$val=~tr/-/:/; $val', 712 ValueConvInv => '$val=~s/(\d+):(\d+):/$1-$2-/; $val', 713 PrintConv => '$self->ConvertDateTime($val)', 714 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 715 }, 716 gps0 => { #PH (DuDuBell M1, VSYS M6L) 717 Name => 'GPSTrack', 718 SubDirectory => { 719 TagTable => 'Image::ExifTool::QuickTime::Stream', 720 ProcessProc => \&Process_gps0, 721 }, 722 }, 723 gsen => { #PH (DuDuBell M1, VSYS M6L) 724 Name => 'GSensor', 725 SubDirectory => { 726 TagTable => 'Image::ExifTool::QuickTime::Stream', 727 ProcessProc => \&Process_gsen, 728 }, 729 }, 730 # gpsa - seen hex "01 20 00 00" (DuDuBell M1, VSYS M6L) 731 # gsea - 20 bytes hex "05 00's..." (DuDuBell M1) "05 08 02 01 ..." (VSYS M6L) 732 'GPS ' => { # GPS data written by 70mai dashcam (parsed in QuickTimeStream.pl) 733 Name => 'GPSDataList2', 734 Unknown => 1, 735 Binary => 1, 736 }, 737 sefd => { 738 Name => 'SamsungTrailer', 739 SubDirectory => { TagTable => 'Image::ExifTool::Samsung::Trailer' }, 740 }, 741); 742 743# MPEG-4 'ftyp' atom 744# (ref http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html) 745%Image::ExifTool::QuickTime::FileType = ( 746 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 747 GROUPS => { 2 => 'Video' }, 748 FORMAT => 'int32u', 749 0 => { 750 Name => 'MajorBrand', 751 Format => 'undef[4]', 752 PrintConv => \%ftypLookup, 753 }, 754 1 => { 755 Name => 'MinorVersion', 756 Format => 'undef[4]', 757 ValueConv => 'sprintf("%x.%x.%x", unpack("nCC", $val))', 758 }, 759 2 => { 760 Name => 'CompatibleBrands', 761 Format => 'undef[$size-8]', 762 # ignore any entry with a null, and return others as a list 763 ValueConv => 'my @a=($val=~/.{4}/sg); @a=grep(!/\0/,@a); \@a', 764 }, 765); 766 767# proprietary HTC atom (HTC One MP4 video) 768%Image::ExifTool::QuickTime::HTCInfo = ( 769 PROCESS_PROC => \&ProcessMOV, 770 GROUPS => { 2 => 'Video' }, 771 NOTES => 'Tags written by some HTC camera phones.', 772 slmt => { 773 Name => 'Unknown_slmt', 774 Unknown => 1, 775 Format => 'int32u', # (observed values: 4) 776 }, 777); 778 779# atoms used in QTIF files 780%Image::ExifTool::QuickTime::ImageFile = ( 781 PROCESS_PROC => \&ProcessMOV, 782 GROUPS => { 2 => 'Image' }, 783 NOTES => 'Tags used in QTIF QuickTime Image Files.', 784 idsc => { 785 Name => 'ImageDescription', 786 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ImageDesc' }, 787 }, 788 idat => { 789 Name => 'ImageData', 790 Binary => 1, 791 }, 792 iicc => { 793 Name => 'ICC_Profile', 794 SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' }, 795 }, 796); 797 798# image description data block 799%Image::ExifTool::QuickTime::ImageDesc = ( 800 PROCESS_PROC => \&ProcessHybrid, 801 VARS => { ID_LABEL => 'ID/Index' }, 802 GROUPS => { 2 => 'Image' }, 803 FORMAT => 'int16u', 804 2 => { 805 Name => 'CompressorID', 806 Format => 'string[4]', 807# not very useful since this isn't a complete list and name is given below 808# # ref http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html 809# PrintConv => { 810# cvid => 'Cinepak', 811# jpeg => 'JPEG', 812# 'smc '=> 'Graphics', 813# 'rle '=> 'Animation', 814# rpza => 'Apple Video', 815# kpcd => 'Kodak Photo CD', 816# 'png '=> 'Portable Network Graphics', 817# mjpa => 'Motion-JPEG (format A)', 818# mjpb => 'Motion-JPEG (format B)', 819# SVQ1 => 'Sorenson video, version 1', 820# SVQ3 => 'Sorenson video, version 3', 821# mp4v => 'MPEG-4 video', 822# 'dvc '=> 'NTSC DV-25 video', 823# dvcp => 'PAL DV-25 video', 824# 'gif '=> 'Compuserve Graphics Interchange Format', 825# h263 => 'H.263 video', 826# tiff => 'Tagged Image File Format', 827# 'raw '=> 'Uncompressed RGB', 828# '2vuY'=> "Uncompressed Y'CbCr, 3x8-bit 4:2:2 (2vuY)", 829# 'yuv2'=> "Uncompressed Y'CbCr, 3x8-bit 4:2:2 (yuv2)", 830# v308 => "Uncompressed Y'CbCr, 8-bit 4:4:4", 831# v408 => "Uncompressed Y'CbCr, 8-bit 4:4:4:4", 832# v216 => "Uncompressed Y'CbCr, 10, 12, 14, or 16-bit 4:2:2", 833# v410 => "Uncompressed Y'CbCr, 10-bit 4:4:4", 834# v210 => "Uncompressed Y'CbCr, 10-bit 4:2:2", 835# hvc1 => 'HEVC', #PH 836# }, 837 }, 838 10 => { 839 Name => 'VendorID', 840 Format => 'string[4]', 841 RawConv => 'length $val ? $val : undef', 842 PrintConv => \%vendorID, 843 SeparateTable => 'VendorID', 844 }, 845 # 14 - ("Quality" in QuickTime docs) ?? 846 16 => 'SourceImageWidth', 847 17 => 'SourceImageHeight', 848 18 => { Name => 'XResolution', Format => 'fixed32u' }, 849 20 => { Name => 'YResolution', Format => 'fixed32u' }, 850 # 24 => 'FrameCount', # always 1 (what good is this?) 851 25 => { 852 Name => 'CompressorName', 853 Format => 'string[32]', 854 # (sometimes this is a Pascal string, and sometimes it is a C string) 855 RawConv => q{ 856 $val=substr($val,1,ord($1)) if $val=~/^([\0-\x1f])/ and ord($1)<length($val); 857 length $val ? $val : undef; 858 }, 859 }, 860 41 => 'BitDepth', 861# 862# Observed offsets for child atoms of various CompressorID types: 863# 864# CompressorID Offset Child atoms 865# ----------- ------ ---------------- 866# avc1 86 avcC, btrt, colr, pasp, fiel, clap, svcC 867# mp4v 86 esds, pasp 868# s263 86 d263 869# 870 btrt => { 871 Name => 'BitrateInfo', 872 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Bitrate' }, 873 }, 874 # Reference for fiel, colr, pasp, clap: 875 # https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9 876 fiel => { 877 Name => 'VideoFieldOrder', 878 ValueConv => 'join(" ", unpack("C*",$val))', 879 PrintConv => [{ 880 1 => 'Progressive', 881 2 => '2:1 Interlaced', 882 }], 883 }, 884 colr => { 885 Name => 'ColorRepresentation', 886 ValueConv => 'join(" ", substr($val,0,4), unpack("x4n*",$val))', 887 }, 888 pasp => { 889 Name => 'PixelAspectRatio', 890 ValueConv => 'join(":", unpack("N*",$val))', 891 }, 892 clap => { 893 Name => 'CleanAperture', 894 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::CleanAperture' }, 895 }, 896 avcC => { 897 # (see http://thompsonng.blogspot.ca/2010/11/mp4-file-format-part-2.html) 898 Name => 'AVCConfiguration', 899 Unknown => 1, 900 Binary => 1, 901 }, 902 JPEG => { # (found in CR3 images; used as a flag to identify JpgFromRaw 'vide' stream) 903 Name => 'JPEGInfo', 904 # (4 bytes all zero) 905 Unknown => 1, 906 Binary => 1, 907 }, 908 # hvcC - HEVC configuration 909 # svcC - 7 bytes: 00 00 00 00 ff e0 00 910 # esds - elementary stream descriptor 911 # d263 912 gama => { Name => 'Gamma', Format => 'fixed32u' }, 913 # mjqt - default quantization table for MJPEG 914 # mjht - default Huffman table for MJPEG 915 # csgm ? (seen in hevc video) 916 CMP1 => { # Canon CR3 917 Name => 'CMP1', 918 SubDirectory => { TagTable => 'Image::ExifTool::Canon::CMP1' }, 919 }, 920 CDI1 => { # Canon CR3 921 Name => 'CDI1', 922 SubDirectory => { 923 TagTable => 'Image::ExifTool::Canon::CDI1', 924 Start => 4, 925 }, 926 }, 927 # JPEG - 4 bytes all 0 (Canon CR3) 928 # free - (Canon CR3) 929# 930# spherical video v2 stuff (untested) 931# 932 st3d => { 933 Name => 'Stereoscopic3D', 934 Format => 'int8u', 935 ValueConv => '$val =~ s/.* //; $val', # (remove leading version/flags bytes?) 936 PrintConv => { 937 0 => 'Monoscopic', 938 1 => 'Stereoscopic Top-Bottom', 939 2 => 'Stereoscopic Left-Right', 940 3 => 'Stereoscopic Stereo-Custom', # (provisional in spec as of 2017-10-10) 941 }, 942 }, 943 sv3d => { 944 Name => 'SphericalVideo', 945 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::sv3d' }, 946 }, 947); 948 949# 'sv3d' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 950%Image::ExifTool::QuickTime::sv3d = ( 951 PROCESS_PROC => \&ProcessMOV, 952 GROUPS => { 2 => 'Video' }, 953 NOTES => q{ 954 Tags defined by the Spherical Video V2 specification. See 955 L<https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md> 956 for the specification. 957 }, 958 svhd => { 959 Name => 'MetadataSource', 960 Format => 'undef', 961 ValueConv => '$val=~tr/\0//d; $val', # (remove version/flags? and terminator?) 962 }, 963 proj => { 964 Name => 'Projection', 965 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::proj' }, 966 }, 967); 968 969# 'proj' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 970%Image::ExifTool::QuickTime::proj = ( 971 PROCESS_PROC => \&ProcessMOV, 972 GROUPS => { 2 => 'Video' }, 973 prhd => { 974 Name => 'ProjectionHeader', 975 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::prhd' }, 976 }, 977 cbmp => { 978 Name => 'CubemapProj', 979 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::cbmp' }, 980 }, 981 equi => { 982 Name => 'EquirectangularProj', 983 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::equi' }, 984 }, 985 # mshp - MeshProjection (P.I.T.A. to decode, for not much reward, see ref) 986); 987 988# 'prhd' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 989%Image::ExifTool::QuickTime::prhd = ( 990 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 991 GROUPS => { 2 => 'Video' }, 992 FORMAT => 'fixed32s', 993 # 0 - version (high 8 bits) / flags (low 24 bits) 994 1 => 'PoseYawDegrees', 995 2 => 'PosePitchDegrees', 996 3 => 'PoseRollDegrees', 997); 998 999# 'cbmp' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 1000%Image::ExifTool::QuickTime::cbmp = ( 1001 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1002 GROUPS => { 2 => 'Video' }, 1003 FORMAT => 'int32u', 1004 # 0 - version (high 8 bits) / flags (low 24 bits) 1005 1 => 'Layout', 1006 2 => 'Padding', 1007); 1008 1009# 'equi' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 1010%Image::ExifTool::QuickTime::equi = ( 1011 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1012 GROUPS => { 2 => 'Video' }, 1013 FORMAT => 'int32u', # (actually 0.32 fixed point) 1014 # 0 - version (high 8 bits) / flags (low 24 bits) 1015 1 => { Name => 'ProjectionBoundsTop', ValueConv => '$val / 4294967296' }, 1016 2 => { Name => 'ProjectionBoundsBottom',ValueConv => '$val / 4294967296' }, 1017 3 => { Name => 'ProjectionBoundsLeft', ValueConv => '$val / 4294967296' }, 1018 4 => { Name => 'ProjectionBoundsRight', ValueConv => '$val / 4294967296' }, 1019); 1020 1021# 'btrt' atom information (ref http://lists.freedesktop.org/archives/gstreamer-commits/2011-October/054459.html) 1022%Image::ExifTool::QuickTime::Bitrate = ( 1023 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1024 GROUPS => { 2 => 'Video' }, 1025 FORMAT => 'int32u', 1026 PRIORITY => 0, # often filled with zeros 1027 0 => 'BufferSize', 1028 1 => 'MaxBitrate', 1029 2 => 'AverageBitrate', 1030); 1031 1032# 'clap' atom information (ref https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9) 1033%Image::ExifTool::QuickTime::CleanAperture = ( 1034 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1035 GROUPS => { 2 => 'Video' }, 1036 FORMAT => 'rational64s', 1037 0 => 'CleanApertureWidth', 1038 1 => 'CleanApertureHeight', 1039 2 => 'CleanApertureOffsetX', 1040 3 => 'CleanApertureOffsetY', 1041); 1042 1043# preview data block 1044%Image::ExifTool::QuickTime::Preview = ( 1045 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1046 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1047 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 1048 GROUPS => { 2 => 'Image' }, 1049 FORMAT => 'int16u', 1050 0 => { 1051 Name => 'PreviewDate', 1052 Format => 'int32u', 1053 Groups => { 2 => 'Time' }, 1054 %timeInfo, 1055 }, 1056 2 => 'PreviewVersion', 1057 3 => { 1058 Name => 'PreviewAtomType', 1059 Format => 'string[4]', 1060 }, 1061 5 => 'PreviewAtomIndex', 1062); 1063 1064# movie atoms 1065%Image::ExifTool::QuickTime::Movie = ( 1066 PROCESS_PROC => \&ProcessMOV, 1067 WRITE_PROC => \&WriteQuickTime, 1068 GROUPS => { 2 => 'Video' }, 1069 mvhd => { 1070 Name => 'MovieHeader', 1071 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieHeader' }, 1072 }, 1073 trak => { 1074 Name => 'Track', 1075 CanCreate => 0, # don't create this atom 1076 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' }, 1077 }, 1078 udta => { 1079 Name => 'UserData', 1080 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::UserData' }, 1081 }, 1082 meta => { # 'meta' is found here in my EX-F1 MOV sample - PH 1083 Name => 'Meta', 1084 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 1085 }, 1086 iods => { 1087 Name => 'InitialObjectDescriptor', 1088 Flags => ['Binary','Unknown'], 1089 }, 1090 uuid => [ 1091 { #11 (MP4 files) (also found in QuickTime::Track) 1092 Name => 'UUID-USMT', 1093 Condition => '$$valPt=~/^USMT!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/', 1094 SubDirectory => { 1095 TagTable => 'Image::ExifTool::QuickTime::UserMedia', 1096 Start => 16, 1097 }, 1098 }, 1099 { #PH (Canon SX280) 1100 Name => 'UUID-Canon', 1101 Condition => '$$valPt=~/^\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48/', 1102 SubDirectory => { 1103 TagTable => 'Image::ExifTool::Canon::uuid', 1104 Start => 16, 1105 }, 1106 }, 1107 { 1108 Name => 'UUID-Unknown', 1109 %unknownInfo, 1110 }, 1111 ], 1112 cmov => { 1113 Name => 'CompressedMovie', 1114 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::CMovie' }, 1115 }, 1116 htka => { # (written by HTC One M8 in slow-motion 1280x720 video - PH) 1117 Name => 'HTCTrack', 1118 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' }, 1119 }, 1120 'gps ' => { # GPS data written by Novatek cameras (parsed in QuickTimeStream.pl) 1121 Name => 'GPSDataList', 1122 Unknown => 1, 1123 Binary => 1, 1124 }, 1125 meco => { #ISO14496-12:2015 1126 Name => 'OtherMeta', 1127 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' }, 1128 }, 1129 # prfl - Profile (ref 12) 1130 # clip - clipping --> contains crgn (clip region) (ref 12) 1131 # mvex - movie extends --> contains mehd (movie extends header), trex (track extends) (ref 14) 1132 # ICAT - 4 bytes: "6350" (Nikon CoolPix S6900), "6500" (Panasonic FT7) 1133); 1134 1135# (ref CFFMediaFormat-2_1.pdf) 1136%Image::ExifTool::QuickTime::MovieFragment = ( 1137 PROCESS_PROC => \&ProcessMOV, 1138 WRITE_PROC => \&WriteQuickTime, 1139 GROUPS => { 2 => 'Video' }, 1140 mfhd => { 1141 Name => 'MovieFragmentHeader', 1142 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieFragHdr' }, 1143 }, 1144 traf => { 1145 Name => 'TrackFragment', 1146 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackFragment' }, 1147 }, 1148 meta => { #ISO14496-12:2015 1149 Name => 'Meta', 1150 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 1151 }, 1152); 1153 1154# (ref CFFMediaFormat-2_1.pdf) 1155%Image::ExifTool::QuickTime::MovieFragHdr = ( 1156 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1157 GROUPS => { 2 => 'Video' }, 1158 FORMAT => 'int32u', 1159 1 => 'MovieFragmentSequence', 1160); 1161 1162# (ref CFFMediaFormat-2_1.pdf) 1163%Image::ExifTool::QuickTime::TrackFragment = ( 1164 PROCESS_PROC => \&ProcessMOV, 1165 WRITE_PROC => \&WriteQuickTime, 1166 GROUPS => { 2 => 'Video' }, 1167 meta => { #ISO14496-12:2015 1168 Name => 'Meta', 1169 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 1170 }, 1171 # tfhd - track fragment header 1172 # edts - edits --> contains elst (edit list) (ref PH) 1173 # tfdt - track fragment base media decode time 1174 # trik - trick play box 1175 # trun - track fragment run box 1176 # avcn - AVC NAL unit storage box 1177 # secn - sample encryption box 1178 # saio - sample auxiliary information offsets box 1179 # sbgp - sample to group box 1180 # sgpd - sample group description box 1181 # sdtp - independent and disposable samples (ref 5) 1182 # subs - sub-sample information (ref 5) 1183); 1184 1185# movie header data block 1186%Image::ExifTool::QuickTime::MovieHeader = ( 1187 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1188 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1189 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 1190 GROUPS => { 2 => 'Video' }, 1191 FORMAT => 'int32u', 1192 DATAMEMBER => [ 0, 1, 2, 3, 4 ], 1193 0 => { 1194 Name => 'MovieHeaderVersion', 1195 Format => 'int8u', 1196 RawConv => '$$self{MovieHeaderVersion} = $val', 1197 }, 1198 1 => { 1199 Name => 'CreateDate', 1200 Groups => { 2 => 'Time' }, 1201 %timeInfo, 1202 RawConv => q{ 1203 my $offset = (66 * 365 + 17) * 24 * 3600; 1204 if ($val >= $offset or $$self{OPTIONS}{QuickTimeUTC}) { 1205 $val -= $offset; 1206 } elsif ($val and not $$self{IsWriting}) { 1207 $self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1); 1208 } 1209 return $$self{CreateDate} = $val; 1210 }, 1211 # this is int64u if MovieHeaderVersion == 1 (ref 13) 1212 Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4', 1213 }, 1214 2 => { 1215 Name => 'ModifyDate', 1216 Groups => { 2 => 'Time' }, 1217 %timeInfo, 1218 # this is int64u if MovieHeaderVersion == 1 (ref 13) 1219 Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4', 1220 }, 1221 3 => { 1222 Name => 'TimeScale', 1223 RawConv => '$$self{TimeScale} = $val', 1224 }, 1225 4 => { 1226 Name => 'Duration', 1227 %durationInfo, 1228 # this is int64u if MovieHeaderVersion == 1 (ref 13) 1229 Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4', 1230 }, 1231 5 => { 1232 Name => 'PreferredRate', 1233 ValueConv => '$val / 0x10000', 1234 }, 1235 6 => { 1236 Name => 'PreferredVolume', 1237 Format => 'int16u', 1238 ValueConv => '$val / 256', 1239 PrintConv => 'sprintf("%.2f%%", $val * 100)', 1240 }, 1241 9 => { 1242 Name => 'MatrixStructure', 1243 Format => 'fixed32s[9]', 1244 # (the right column is fixed 2.30 instead of 16.16) 1245 ValueConv => q{ 1246 my @a = split ' ',$val; 1247 $_ /= 0x4000 foreach @a[2,5,8]; 1248 return "@a"; 1249 }, 1250 }, 1251 18 => { Name => 'PreviewTime', %durationInfo }, 1252 19 => { Name => 'PreviewDuration', %durationInfo }, 1253 20 => { Name => 'PosterTime', %durationInfo }, 1254 21 => { Name => 'SelectionTime', %durationInfo }, 1255 22 => { Name => 'SelectionDuration',%durationInfo }, 1256 23 => { Name => 'CurrentTime', %durationInfo }, 1257 24 => 'NextTrackID', 1258); 1259 1260# track atoms 1261%Image::ExifTool::QuickTime::Track = ( 1262 PROCESS_PROC => \&ProcessMOV, 1263 WRITE_PROC => \&WriteQuickTime, 1264 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 1265 tkhd => { 1266 Name => 'TrackHeader', 1267 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackHeader' }, 1268 }, 1269 udta => { 1270 Name => 'UserData', 1271 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::UserData' }, 1272 }, 1273 mdia => { #MP4 1274 Name => 'Media', 1275 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Media' }, 1276 }, 1277 meta => { #PH (MOV) 1278 Name => 'Meta', 1279 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 1280 }, 1281 tref => { 1282 Name => 'TrackRef', 1283 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackRef' }, 1284 }, 1285 tapt => { 1286 Name => 'TrackAperture', 1287 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackAperture' }, 1288 }, 1289 uuid => [ 1290 { #11 (MP4 files) (also found in QuickTime::Movie) 1291 Name => 'UUID-USMT', 1292 Condition => '$$valPt=~/^USMT!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/', 1293 SubDirectory => { 1294 TagTable => 'Image::ExifTool::QuickTime::UserMedia', 1295 Start => 16, 1296 }, 1297 }, 1298 { #https://github.com/google/spatial-media/blob/master/docs/spherical-video-rfc.md 1299 Name => 'SphericalVideoXML', 1300 Condition => '$$valPt=~/^\xff\xcc\x82\x63\xf8\x55\x4a\x93\x88\x14\x58\x7a\x02\x52\x1f\xdd/', 1301 WriteGroup => 'GSpherical', # write only GSpherical XMP tags here 1302 HandlerType => 'vide', # only write in video tracks 1303 SubDirectory => { 1304 TagTable => 'Image::ExifTool::XMP::Main', 1305 Start => 16, 1306 WriteProc => 'Image::ExifTool::XMP::WriteGSpherical', 1307 }, 1308 }, 1309 { 1310 Name => 'UUID-Unknown', 1311 %unknownInfo, 1312 }, 1313 ], 1314 meco => { #ISO14492-12:2015 pg 83 1315 Name => 'OtherMeta', 1316 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' }, 1317 }, 1318 # edts - edits --> contains elst (edit list) 1319 # clip - clipping --> contains crgn (clip region) 1320 # matt - track matt --> contains kmat (compressed matt) 1321 # load - track loading settings 1322 # imap - track input map --> contains ' in' --> contains ' ty', obid 1323 # prfl - Profile (ref 12) 1324); 1325 1326# track header data block 1327%Image::ExifTool::QuickTime::TrackHeader = ( 1328 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1329 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1330 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 1331 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 1332 FORMAT => 'int32u', 1333 DATAMEMBER => [ 0, 1, 2, 5, 7 ], 1334 0 => { 1335 Name => 'TrackHeaderVersion', 1336 Format => 'int8u', 1337 Priority => 0, 1338 RawConv => '$$self{TrackHeaderVersion} = $val', 1339 }, 1340 1 => { 1341 Name => 'TrackCreateDate', 1342 Priority => 0, 1343 Groups => { 2 => 'Time' }, 1344 %timeInfo, 1345 # this is int64u if TrackHeaderVersion == 1 (ref 13) 1346 Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4', 1347 }, 1348 2 => { 1349 Name => 'TrackModifyDate', 1350 Priority => 0, 1351 Groups => { 2 => 'Time' }, 1352 %timeInfo, 1353 # this is int64u if TrackHeaderVersion == 1 (ref 13) 1354 Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4', 1355 }, 1356 3 => { 1357 Name => 'TrackID', 1358 Priority => 0, 1359 }, 1360 5 => { 1361 Name => 'TrackDuration', 1362 Priority => 0, 1363 %durationInfo, 1364 # this is int64u if TrackHeaderVersion == 1 (ref 13) 1365 Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4', 1366 }, 1367 7 => { # (used only for writing MatrixStructure) 1368 Name => 'ImageSizeLookahead', 1369 Hidden => 1, 1370 Format => 'int32u[14]', 1371 RawConv => '$$self{ImageSizeLookahead} = $val; undef', 1372 }, 1373 8 => { 1374 Name => 'TrackLayer', 1375 Format => 'int16u', 1376 Priority => 0, 1377 }, 1378 9 => { 1379 Name => 'TrackVolume', 1380 Format => 'int16u', 1381 Priority => 0, 1382 ValueConv => '$val / 256', 1383 PrintConv => 'sprintf("%.2f%%", $val * 100)', 1384 }, 1385 10 => { 1386 Name => 'MatrixStructure', 1387 Format => 'fixed32s[9]', 1388 Notes => 'writable for the video track via the Composite Rotation tag', 1389 Writable => 1, 1390 Protected => 1, 1391 Permanent => 1, 1392 # only set rotation if image size is non-zero 1393 RawConvInv => \&GetMatrixStructure, 1394 # (the right column is fixed 2.30 instead of 16.16) 1395 ValueConv => q{ 1396 my @a = split ' ',$val; 1397 $_ /= 0x4000 foreach @a[2,5,8]; 1398 return "@a"; 1399 }, 1400 ValueConvInv => q{ 1401 my @a = split ' ',$val; 1402 $_ *= 0x4000 foreach @a[2,5,8]; 1403 return "@a"; 1404 }, 1405 }, 1406 19 => { 1407 Name => 'ImageWidth', 1408 Priority => 0, 1409 RawConv => \&FixWrongFormat, 1410 }, 1411 20 => { 1412 Name => 'ImageHeight', 1413 Priority => 0, 1414 RawConv => \&FixWrongFormat, 1415 }, 1416); 1417 1418# user data atoms 1419%Image::ExifTool::QuickTime::UserData = ( 1420 PROCESS_PROC => \&ProcessMOV, 1421 WRITE_PROC => \&WriteQuickTime, 1422 CHECK_PROC => \&CheckQTValue, 1423 GROUPS => { 1 => 'UserData', 2 => 'Video' }, 1424 WRITABLE => 1, 1425 PREFERRED => 1, # (preferred over Keys tags when writing) 1426 FORMAT => 'string', 1427 WRITE_GROUP => 'UserData', 1428 LANG_INFO => \&GetLangInfo, 1429 NOTES => q{ 1430 Tag ID's beginning with the copyright symbol (hex 0xa9) are multi-language 1431 text. Alternate language tags are accessed by adding a dash followed by a 1432 3-character ISO 639-2 language code to the tag name. ExifTool will extract 1433 any multi-language user data tags found, even if they aren't in this table. 1434 Note when creating new tags, 1435 L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags are 1436 preferred over these, so to create the tag when a same-named ItemList tag 1437 exists, either "UserData" must be specified (eg. C<-UserData:Artist=Monet> 1438 on the command line), or the PREFERRED level must be changed via 1439 L<the config file|../config.html#PREF>. 1440 }, 1441 "\xa9cpy" => { Name => 'Copyright', Groups => { 2 => 'Author' } }, 1442 "\xa9day" => { 1443 Name => 'ContentCreateDate', 1444 Groups => { 2 => 'Time' }, 1445 Shift => 'Time', 1446 # handle values in the form "2010-02-12T13:27:14-0800" (written by Apple iPhone) 1447 ValueConv => q{ 1448 require Image::ExifTool::XMP; 1449 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 1450 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 1451 return $val; 1452 }, 1453 ValueConvInv => q{ 1454 require Image::ExifTool::XMP; 1455 my $tmp = Image::ExifTool::XMP::FormatXMPDate($val); 1456 ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon 1457 return $val; 1458 }, 1459 PrintConv => '$self->ConvertDateTime($val)', 1460 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 1461 }, 1462 "\xa9ART" => 'Artist', #PH (iTunes 8.0.2) 1463 "\xa9alb" => 'Album', #PH (iTunes 8.0.2) 1464 "\xa9arg" => 'Arranger', #12 1465 "\xa9ark" => 'ArrangerKeywords', #12 1466 "\xa9cmt" => 'Comment', #PH (iTunes 8.0.2) 1467 "\xa9cok" => 'ComposerKeywords', #12 1468 "\xa9com" => 'Composer', #12 1469 "\xa9dir" => 'Director', #12 1470 "\xa9ed1" => 'Edit1', 1471 "\xa9ed2" => 'Edit2', 1472 "\xa9ed3" => 'Edit3', 1473 "\xa9ed4" => 'Edit4', 1474 "\xa9ed5" => 'Edit5', 1475 "\xa9ed6" => 'Edit6', 1476 "\xa9ed7" => 'Edit7', 1477 "\xa9ed8" => 'Edit8', 1478 "\xa9ed9" => 'Edit9', 1479 "\xa9fmt" => 'Format', 1480 "\xa9gen" => 'Genre', #PH (iTunes 8.0.2) 1481 "\xa9grp" => 'Grouping', #PH (NC) 1482 "\xa9inf" => 'Information', 1483 "\xa9isr" => 'ISRCCode', #12 1484 "\xa9lab" => 'RecordLabelName', #12 1485 "\xa9lal" => 'RecordLabelURL', #12 1486 "\xa9lyr" => 'Lyrics', #PH (NC) 1487 "\xa9mak" => 'Make', #12 1488 "\xa9mal" => 'MakerURL', #12 1489 "\xa9mod" => 'Model', #PH 1490 "\xa9nam" => 'Title', #12 1491 "\xa9pdk" => 'ProducerKeywords', #12 1492 "\xa9phg" => 'RecordingCopyright', #12 1493 "\xa9prd" => 'Producer', 1494 "\xa9prf" => 'Performers', 1495 "\xa9prk" => 'PerformerKeywords', #12 1496 "\xa9prl" => 'PerformerURL', 1497 "\xa9req" => 'Requirements', 1498 "\xa9snk" => 'SubtitleKeywords', #12 1499 "\xa9snm" => 'Subtitle', #12 1500 "\xa9src" => 'SourceCredits', #12 1501 "\xa9swf" => 'SongWriter', #12 1502 "\xa9swk" => 'SongWriterKeywords', #12 1503 "\xa9swr" => 'SoftwareVersion', #12 1504 "\xa9too" => 'Encoder', #PH (NC) 1505 "\xa9trk" => 'Track', #PH (NC) 1506 "\xa9wrt" => { Name => 'Composer', Avoid => 1 }, # ("\xa9com" is preferred in UserData) 1507 "\xa9xyz" => { #PH (iPhone 3GS) 1508 Name => 'GPSCoordinates', 1509 Groups => { 2 => 'Location' }, 1510 ValueConv => \&ConvertISO6709, 1511 ValueConvInv => \&ConvInvISO6709, 1512 PrintConv => \&PrintGPSCoordinates, 1513 PrintConvInv => \&PrintInvGPSCoordinates, 1514 }, 1515 # \xa9 tags written by DJI Phantom 3: (ref PH) 1516 "\xa9xsp" => 'SpeedX', #PH (guess) 1517 "\xa9ysp" => 'SpeedY', #PH (guess) 1518 "\xa9zsp" => 'SpeedZ', #PH (guess) 1519 "\xa9fpt" => 'Pitch', #PH 1520 "\xa9fyw" => 'Yaw', #PH 1521 "\xa9frl" => 'Roll', #PH 1522 "\xa9gpt" => 'CameraPitch', #PH 1523 "\xa9gyw" => 'CameraYaw', #PH 1524 "\xa9grl" => 'CameraRoll', #PH 1525 "\xa9enc" => 'EncoderID', #PH (forum9271) 1526 # and the following entries don't have the proper 4-byte header for \xa9 tags: 1527 "\xa9dji" => { Name => 'UserData_dji', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 }, 1528 "\xa9res" => { Name => 'UserData_res', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 }, 1529 "\xa9uid" => { Name => 'UserData_uid', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 }, 1530 "\xa9mdl" => { 1531 Name => 'Model', 1532 Notes => 'non-standard-format DJI tag', 1533 Format => 'string', 1534 Avoid => 1, 1535 }, 1536 # end DJI tags 1537 name => 'Name', 1538 WLOC => { 1539 Name => 'WindowLocation', 1540 Format => 'int16u', 1541 }, 1542 LOOP => { 1543 Name => 'LoopStyle', 1544 Format => 'int32u', 1545 PrintConv => { 1546 1 => 'Normal', 1547 2 => 'Palindromic', 1548 }, 1549 }, 1550 SelO => { 1551 Name => 'PlaySelection', 1552 Format => 'int8u', 1553 }, 1554 AllF => { 1555 Name => 'PlayAllFrames', 1556 Format => 'int8u', 1557 }, 1558 meta => { 1559 Name => 'Meta', 1560 SubDirectory => { 1561 TagTable => 'Image::ExifTool::QuickTime::Meta', 1562 Start => 4, # must skip 4-byte version number header 1563 }, 1564 }, 1565 'ptv '=> { 1566 Name => 'PrintToVideo', 1567 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Video' }, 1568 }, 1569 hnti => { 1570 Name => 'HintInfo', 1571 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintInfo' }, 1572 }, 1573 hinf => { 1574 Name => 'HintTrackInfo', 1575 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintTrackInfo' }, 1576 }, 1577 hinv => 'HintVersion', #PH (guess) 1578 XMP_ => { #PH (Adobe CS3 Bridge) 1579 Name => 'XMP', 1580 WriteGroup => 'XMP', # (write main tags here) 1581 # *** this is where ExifTool writes XMP in MOV videos (as per XMP spec) *** 1582 SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' }, 1583 }, 1584 # the following are 3gp tags, references: 1585 # http://atomicparsley.sourceforge.net 1586 # http://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/TSGS4_25/Docs/ 1587 # (note that all %langText3gp tags are Avoid => 1) 1588 cprt => { Name => 'Copyright', %langText3gp, Groups => { 2 => 'Author' } }, 1589 auth => { Name => 'Author', %langText3gp, Groups => { 2 => 'Author' } }, 1590 titl => { Name => 'Title', %langText3gp }, 1591 dscp => { Name => 'Description',%langText3gp }, 1592 perf => { Name => 'Performer', %langText3gp }, 1593 gnre => { Name => 'Genre', %langText3gp }, 1594 albm => { Name => 'Album', %langText3gp }, 1595 coll => { Name => 'CollectionName', %langText3gp }, #17 1596 rtng => { 1597 Name => 'Rating', 1598 Writable => 'undef', 1599 Avoid => 1, 1600 # (4-byte flags, 4-char entity, 4-char criteria, 2-byte lang, string) 1601 IText => 14, # (14 bytes before string) 1602 Notes => 'string in the form "Entity=XXXX Criteria=XXXX XXXXX", used in 3gp videos', 1603 ValueConv => '$val=~s/^(.{4})(.{4})/Entity=$1 Criteria=$2 /i; $val', 1604 ValueConvInv => '$val=~s/Entity=(.{4}) Criteria=(.{4}) ?/$1$2/i; $val', 1605 }, 1606 clsf => { 1607 Name => 'Classification', 1608 Writable => 'undef', 1609 Avoid => 1, 1610 # (4-byte flags, 4-char entity, 2-byte index, 2-byte lang, string) 1611 IText => 12, 1612 Notes => 'string in the form "Entity=XXXX Index=### XXXXX", used in 3gp videos', 1613 ValueConv => '$val=~s/^(.{4})(.{2})/"Entity=$1 Index=".unpack("n",$2)." "/ie; $val', 1614 ValueConvInv => '$val=~s/Entity=(.{4}) Index=(\d+) ?/$1.pack("n",$2)/ie; $val', 1615 }, 1616 kywd => { 1617 Name => 'Keywords', 1618 # (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings, ref 17) 1619 # (but I have also seen a simple string written by iPhone, so don't make writable yet) 1620 Notes => "not writable because Apple doesn't follow the 3gp specification", 1621 RawConv => q{ 1622 my $sep = $self->Options('ListSep'); 1623 return join($sep, split /\0+/, $val) unless $val =~ /^\0/; # (iPhone) 1624 return '<err>' unless length $val >= 7; 1625 my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4)); 1626 $lang = $lang ? "($lang) " : ''; 1627 my $num = Get8u(\$val, 6); 1628 my ($i, @vals); 1629 my $pos = 7; 1630 for ($i=0; $i<$num; ++$i) { 1631 last if $pos >= length $val; 1632 my $len = Get8u(\$val, $pos++); 1633 last if $pos + $len > length $val; 1634 my $v = substr($val, $pos, $len); 1635 $v = $self->Decode($v, 'UCS2') if $v =~ /^\xfe\xff/; 1636 push @vals, $v; 1637 $pos += $len; 1638 } 1639 return $lang . join($sep, @vals); 1640 }, 1641 }, 1642 loci => { 1643 Name => 'LocationInformation', 1644 Groups => { 2 => 'Location' }, 1645 Writable => 'undef', 1646 IText => 6, 1647 Avoid => 1, 1648 NoDecode => 1, # (we'll decode the data ourself) 1649 Notes => q{ 1650 string in the form "XXXXX Role=XXX Lat=XXX Lon=XXX Alt=XXX Body=XXX 1651 Notes=XXX", used in 3gp videos 1652 }, 1653 # (4-byte flags, 2-byte lang, location string, 1-byte role, 4-byte fixed longitude, 1654 # 4-byte fixed latitude, 4-byte fixed altitude, body string, notes string) 1655 RawConv => q{ 1656 my $str; 1657 if ($val =~ /^\xfe\xff/) { 1658 $val =~ s/^(\xfe\xff(.{2})*?)\0\0//s or return '<err>'; 1659 $str = $self->Decode($1, 'UCS2'); 1660 } else { 1661 $val =~ s/^(.*?)\0//s or return '<err>'; 1662 $str = $self->Decode($1, 'UTF8'); 1663 } 1664 $str = '(none)' unless length $str; 1665 return '<err>' if length $val < 13; 1666 my $role = Get8u(\$val, 0); 1667 my $lon = GetFixed32s(\$val, 1); 1668 my $lat = GetFixed32s(\$val, 5); 1669 my $alt = GetFixed32s(\$val, 9); 1670 my $roleStr = {0=>'shooting',1=>'real',2=>'fictional',3=>'reserved'}->{$role}; 1671 $str .= ' Role=' . ($roleStr || "unknown($role)"); 1672 $str .= sprintf(' Lat=%.5f Lon=%.5f Alt=%.2f', $lat, $lon, $alt); 1673 $val = substr($val, 13); 1674 if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) { 1675 $str .= ' Body=' . $self->Decode($1, 'UCS2'); 1676 } elsif ($val =~ s/^(.*?)\0//s) { 1677 $str .= ' Body=' . $self->Decode($1, 'UTF8'); 1678 } 1679 if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) { 1680 $str .= ' Notes=' . $self->Decode($1, 'UCS2'); 1681 } elsif ($val =~ s/^(.*?)\0//s) { 1682 $str .= ' Notes=' . $self->Decode($1, 'UTF8'); 1683 } 1684 return $str; 1685 }, 1686 RawConvInv => q{ 1687 my ($role, $lat, $lon, $alt, $body, $note); 1688 $lat = $1 if $val =~ s/ Lat=([-+]?[.\d]+)//i; 1689 $lon = $1 if $val =~ s/ Lon=([-+]?[.\d]+)//i; 1690 $alt = $1 if $val =~ s/ Alt=([-+]?[.\d]+)//i; 1691 $note = $val =~ s/ Notes=(.*)//i ? $1 : ''; 1692 $body = $val =~ s/ Body=(.*)//i ? $1 : ''; 1693 $role = $val =~ s/ Role=(.*)//i ? $1 : ''; 1694 $val = '' if $val eq '(none)'; 1695 $role = {shooting=>0,real=>1,fictional=>2}->{lc $role} || 0; 1696 return $self->Encode($val, 'UTF8') . "\0" . Set8u($role) . 1697 SetFixed32s(defined $lon ? $lon : 999) . 1698 SetFixed32s(defined $lat ? $lat : 999) . 1699 SetFixed32s(defined $alt ? $alt : 0) . 1700 $self->Encode($body) . "\0" . 1701 $self->Encode($note) . "\0"; 1702 }, 1703 }, 1704 yrrc => { 1705 Name => 'Year', 1706 Writable => 'undef', 1707 Groups => { 2 => 'Time' }, 1708 Avoid => 1, 1709 Notes => 'used in 3gp videos', 1710 ValueConv => 'length($val) >= 6 ? unpack("x4n",$val) : "<err>"', 1711 ValueConvInv => 'pack("Nn",0,$val)', 1712 }, 1713 urat => { #17 1714 Name => 'UserRating', 1715 Writable => 'undef', 1716 Notes => 'used in 3gp videos', 1717 Avoid => 1, 1718 ValueConv => q{ 1719 return '<err>' unless length $val >= 8; 1720 unpack('x7C', $val); 1721 }, 1722 ValueConvInv => 'pack("N2",0,$val)', 1723 }, 1724 # tsel - TrackSelection (ref 17) 1725 # Apple tags (ref 16[dead] -- see ref 25 instead) 1726 angl => { Name => 'CameraAngle', Format => 'string' }, # (NC) 1727 clfn => { Name => 'ClipFileName', Format => 'string' }, # (NC) 1728 clid => { Name => 'ClipID', Format => 'string' }, # (NC) 1729 cmid => { Name => 'CameraID', Format => 'string' }, # (NC) 1730 cmnm => { # (NC) 1731 Name => 'Model', 1732 Description => 'Camera Model Name', 1733 Avoid => 1, 1734 Format => 'string', # (necessary to remove the trailing NULL) 1735 }, 1736 date => { 1737 Name => 'DateTimeOriginal', 1738 Description => 'Date/Time Original', 1739 Groups => { 2 => 'Time' }, 1740 Notes => q{ 1741 Apple Photos has been reported to show a crazy date/time for some MP4 files 1742 containing this tag, but perhaps only if it is missing a time zone 1743 }, #forum10690/11125 1744 Shift => 'Time', 1745 ValueConv => q{ 1746 require Image::ExifTool::XMP; 1747 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 1748 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 1749 return $val; 1750 }, 1751 ValueConvInv => q{ 1752 require Image::ExifTool::XMP; 1753 $val = Image::ExifTool::XMP::FormatXMPDate($val); 1754 $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon 1755 return $val; 1756 }, 1757 PrintConv => '$self->ConvertDateTime($val)', 1758 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 1759 }, 1760 manu => { # (SX280) 1761 Name => 'Make', 1762 Avoid => 1, 1763 # (with Canon there are 6 unknown bytes before the model: "\0\0\0\0\x15\xc7") 1764 RawConv => '$val=~s/^\0{4}..//s; $val=~s/\0.*//; $val', 1765 }, 1766 modl => { # (Samsung GT-S8530, Canon SX280) 1767 Name => 'Model', 1768 Description => 'Camera Model Name', 1769 Avoid => 1, 1770 # (with Canon there are 6 unknown bytes before the model: "\0\0\0\0\x15\xc7") 1771 RawConv => '$val=~s/^\0{4}..//s; $val=~s/\0.*//; $val', 1772 }, 1773 reel => { Name => 'ReelName', Format => 'string' }, # (NC) 1774 scen => { Name => 'Scene', Format => 'string' }, # (NC) 1775 shot => { Name => 'ShotName', Format => 'string' }, # (NC) 1776 slno => { Name => 'SerialNumber', Format => 'string' }, # (NC) 1777 apmd => { Name => 'ApertureMode', Format => 'undef' }, #20 1778 kgtt => { #http://lists.ffmpeg.org/pipermail/ffmpeg-devel-irc/2012-June/000707.html 1779 # 'TrackType' will expand to 'Track#Type' when found inside a track 1780 Name => 'TrackType', 1781 # set flag to process this as international text 1782 # even though the tag ID doesn't start with 0xa9 1783 IText => 4, # IText with 4-byte header 1784 }, 1785 chpl => { # (Nero chapter list) 1786 Name => 'ChapterList', 1787 ValueConv => \&ConvertChapterList, 1788 PrintConv => \&PrintChapter, 1789 }, 1790 # ndrm - 7 bytes (0 0 0 1 0 0 0) Nero Digital Rights Management? (PH) 1791 # other non-Apple tags (ref 16) 1792 # hpix - HipixRichPicture (ref 16, HIPIX) 1793 # strk - sub-track information (ref 16, ISO) 1794# 1795# Manufacturer-specific metadata 1796# 1797 TAGS => [ #PH 1798 # these tags were initially discovered in a Pentax movie, 1799 # but similar information is found in videos from other manufacturers 1800 { 1801 Name => 'FujiFilmTags', 1802 Condition => '$$valPt =~ /^FUJIFILM DIGITAL CAMERA\0/', 1803 SubDirectory => { 1804 TagTable => 'Image::ExifTool::FujiFilm::MOV', 1805 ByteOrder => 'LittleEndian', 1806 }, 1807 }, 1808 { 1809 Name => 'KodakTags', 1810 Condition => '$$valPt =~ /^EASTMAN KODAK COMPANY/', 1811 SubDirectory => { 1812 TagTable => 'Image::ExifTool::Kodak::MOV', 1813 ByteOrder => 'LittleEndian', 1814 }, 1815 }, 1816 { 1817 Name => 'KonicaMinoltaTags', 1818 Condition => '$$valPt =~ /^KONICA MINOLTA DIGITAL CAMERA/', 1819 SubDirectory => { 1820 TagTable => 'Image::ExifTool::Minolta::MOV1', 1821 ByteOrder => 'LittleEndian', 1822 }, 1823 }, 1824 { 1825 Name => 'MinoltaTags', 1826 Condition => '$$valPt =~ /^MINOLTA DIGITAL CAMERA/', 1827 SubDirectory => { 1828 TagTable => 'Image::ExifTool::Minolta::MOV2', 1829 ByteOrder => 'LittleEndian', 1830 }, 1831 }, 1832 { 1833 Name => 'NikonTags', 1834 Condition => '$$valPt =~ /^NIKON DIGITAL CAMERA\0/', 1835 SubDirectory => { 1836 TagTable => 'Image::ExifTool::Nikon::MOV', 1837 ByteOrder => 'LittleEndian', 1838 }, 1839 }, 1840 { 1841 Name => 'OlympusTags1', 1842 Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA\0.{9}\x01\0/s', 1843 SubDirectory => { 1844 TagTable => 'Image::ExifTool::Olympus::MOV1', 1845 ByteOrder => 'LittleEndian', 1846 }, 1847 }, 1848 { 1849 Name => 'OlympusTags2', 1850 Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA(?!\0.{21}\x0a\0{3})/s', 1851 SubDirectory => { 1852 TagTable => 'Image::ExifTool::Olympus::MOV2', 1853 ByteOrder => 'LittleEndian', 1854 }, 1855 }, 1856 { 1857 Name => 'OlympusTags3', 1858 Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA\0/', 1859 SubDirectory => { 1860 TagTable => 'Image::ExifTool::Olympus::MP4', 1861 ByteOrder => 'LittleEndian', 1862 }, 1863 }, 1864 { 1865 Name => 'OlympusTags4', 1866 Condition => '$$valPt =~ /^.{16}OLYM\0/s', 1867 SubDirectory => { 1868 TagTable => 'Image::ExifTool::Olympus::MOV3', 1869 Start => 12, 1870 }, 1871 }, 1872 { 1873 Name => 'PentaxTags', 1874 Condition => '$$valPt =~ /^PENTAX DIGITAL CAMERA\0/', 1875 SubDirectory => { 1876 TagTable => 'Image::ExifTool::Pentax::MOV', 1877 ByteOrder => 'LittleEndian', 1878 }, 1879 }, 1880 { 1881 Name => 'SamsungTags', 1882 Condition => '$$valPt =~ /^SAMSUNG DIGITAL CAMERA\0/', 1883 SubDirectory => { 1884 TagTable => 'Image::ExifTool::Samsung::MP4', 1885 ByteOrder => 'LittleEndian', 1886 }, 1887 }, 1888 { 1889 Name => 'SanyoMOV', 1890 Condition => q{ 1891 $$valPt =~ /^SANYO DIGITAL CAMERA\0/ and 1892 $self->{VALUE}->{FileType} eq "MOV" 1893 }, 1894 SubDirectory => { 1895 TagTable => 'Image::ExifTool::Sanyo::MOV', 1896 ByteOrder => 'LittleEndian', 1897 }, 1898 }, 1899 { 1900 Name => 'SanyoMP4', 1901 Condition => q{ 1902 $$valPt =~ /^SANYO DIGITAL CAMERA\0/ and 1903 $self->{VALUE}->{FileType} eq "MP4" 1904 }, 1905 SubDirectory => { 1906 TagTable => 'Image::ExifTool::Sanyo::MP4', 1907 ByteOrder => 'LittleEndian', 1908 }, 1909 }, 1910 { 1911 Name => 'UnknownTags', 1912 Unknown => 1, 1913 Binary => 1 1914 }, 1915 ], 1916 # ---- Canon ---- 1917 CNCV => { Name => 'CompressorVersion', Format => 'string' }, #PH (5D Mark II) 1918 CNMN => { 1919 Name => 'Model', #PH (EOS 550D) 1920 Description => 'Camera Model Name', 1921 Avoid => 1, 1922 Format => 'string', # (necessary to remove the trailing NULL) 1923 }, 1924 CNFV => { Name => 'FirmwareVersion', Format => 'string' }, #PH (EOS 550D) 1925 CNTH => { #PH (PowerShot S95) 1926 Name => 'CanonCNTH', 1927 SubDirectory => { TagTable => 'Image::ExifTool::Canon::CNTH' }, 1928 }, 1929 CNOP => { #PH (7DmkII) 1930 Name => 'CanonCNOP', 1931 SubDirectory => { TagTable => 'Image::ExifTool::Canon::CNOP' }, 1932 }, 1933 # CNDB - 2112 bytes (550D) 1934 # CNDM - 4 bytes - 0xff,0xd8,0xff,0xd9 (S95) 1935 # CNDG - 10232 bytes, mostly zeros (N100) 1936 # ---- Casio ---- 1937 QVMI => { #PH 1938 Name => 'CasioQVMI', 1939 # Casio stores standard EXIF-format information in MOV videos (eg. EX-S880) 1940 SubDirectory => { 1941 TagTable => 'Image::ExifTool::Exif::Main', 1942 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 1943 DirName => 'IFD0', 1944 Multi => 0, # (no NextIFD pointer) 1945 Start => 10, 1946 ByteOrder => 'BigEndian', 1947 }, 1948 }, 1949 # ---- FujiFilm ---- 1950 FFMV => { #PH (FinePix HS20EXR) 1951 Name => 'FujiFilmFFMV', 1952 SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::FFMV' }, 1953 }, 1954 MVTG => { #PH (FinePix HS20EXR) 1955 Name => 'FujiFilmMVTG', 1956 SubDirectory => { 1957 TagTable => 'Image::ExifTool::Exif::Main', 1958 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 1959 DirName => 'IFD0', 1960 Start => 16, 1961 Base => '$start', 1962 ByteOrder => 'LittleEndian', 1963 }, 1964 }, 1965 # ---- Garmin ---- (ref PH) 1966 uuid => [{ 1967 Name => 'GarminSoftware', # (NC) 1968 Condition => '$$valPt =~ /^VIRBactioncamera/', 1969 RawConv => 'substr($val, 16)', 1970 RawConvInv => '"VIRBactioncamera$val"', 1971 },{ 1972 # 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) 1973 Name => 'UUID-Unknown', 1974 Writable => 0, 1975 %unknownInfo, 1976 }], 1977 pmcc => { 1978 Name => 'GarminSettings', 1979 ValueConv => 'substr($val, 4)', 1980 ValueConvInv => '"\0\0\0\x01$val"', 1981 }, 1982 # hmtp - "\0\0\0\x01" followed by 408 bytes of zero 1983 # vrin - "\0\0\0\x01" followed by 8 bytes of zero 1984 # ---- GoPro ---- (ref PH) 1985 GoPr => 'GoProType', # (Hero3+) 1986 FIRM => { Name => 'FirmwareVersion', Avoid => 1 }, # (Hero4) 1987 LENS => 'LensSerialNumber', # (Hero4) 1988 CAME => { # (Hero4) 1989 Name => 'SerialNumberHash', 1990 Description => 'Camera Serial Number Hash', 1991 ValueConv => 'unpack("H*",$val)', 1992 ValueConvInv => 'pack("H*",$val)', 1993 }, 1994 # SETT? 12 bytes (Hero4) 1995 # MUID? 32 bytes (Hero4, starts with serial number hash) 1996 # HMMT? 404 bytes (Hero4, all zero) 1997 # BCID? 26 bytes (Hero5, all zero), 36 bytes GoPro Max 1998 # GUMI? 16 bytes (Hero5) 1999 "FOV\0" => 'FieldOfView', #forum8938 (Hero2) seen: "Wide" 2000 GPMF => { 2001 Name => 'GoProGPMF', 2002 SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' }, 2003 }, 2004 # free (all zero) 2005 "\xa9TSC" => 'StartTimeScale', # (Hero6) 2006 "\xa9TSZ" => 'StartTimeSampleSize', # (Hero6) 2007 "\xa9TIM" => 'StartTimecode', #PH (NC) 2008 # --- HTC ---- 2009 htcb => { 2010 Name => 'HTCBinary', 2011 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HTCBinary' }, 2012 }, 2013 # ---- Kodak ---- 2014 DcMD => { 2015 Name => 'KodakDcMD', 2016 SubDirectory => { TagTable => 'Image::ExifTool::Kodak::DcMD' }, 2017 }, 2018 SNum => { Name => 'SerialNumber', Avoid => 1, Groups => { 2 => 'Camera' } }, 2019 ptch => { Name => 'Pitch', Format => 'rational64s', Avoid => 1 }, # Units?? 2020 _yaw => { Name => 'Yaw', Format => 'rational64s', Avoid => 1 }, # Units?? 2021 roll => { Name => 'Roll', Format => 'rational64s', Avoid => 1 }, # Units?? 2022 _cx_ => { Name => 'CX', Format => 'rational64s', Unknown => 1 }, 2023 _cy_ => { Name => 'CY', Format => 'rational64s', Unknown => 1 }, 2024 rads => { Name => 'Rads', Format => 'rational64s', Unknown => 1 }, 2025 lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess) 2026 Lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess) 2027 pose => { Name => 'pose', SubDirectory => { TagTable => 'Image::ExifTool::Kodak::pose' } }, 2028 # AMBA => Ambarella AVC atom (unknown data written by Kodak Playsport video cam) 2029 # tmlp - 1 byte: 0 (PixPro SP360/4KVR360) 2030 # pivi - 72 bytes (PixPro SP360) 2031 # pive - 12 bytes (PixPro SP360) 2032 # loop - 4 bytes: 0 0 0 0 (PixPro 4KVR360) 2033 # m cm - 2 bytes: 0 0 (PixPro 4KVR360) 2034 # m ev - 2 bytes: 0 0 (PixPro SP360/4KVR360) (exposure comp?) 2035 # m vr - 2 bytes: 0 1 (PixPro 4KVR360) (virtual reality?) 2036 # m wb - 4 bytes: 0 0 0 0 (PixPro SP360/4KVR360) (white balance?) 2037 # mclr - 4 bytes: 0 0 0 0 (PixPro SP360/4KVR360) 2038 # mmtr - 4 bytes: 0,6 0 0 0 (PixPro SP360/4KVR360) 2039 # mflr - 4 bytes: 0 0 0 0 (PixPro SP360) 2040 # lvlm - 24 bytes (PixPro SP360) 2041 # Lvlm - 24 bytes (PixPro 4KVR360) 2042 # ufdm - 4 bytes: 0 0 0 1 (PixPro SP360) 2043 # mtdt - 1 byte: 0 (PixPro SP360/4KVR360) 2044 # gdta - 75240 bytes (PixPro SP360) 2045 # EIS1 - 4 bytes: 03 07 00 00 (PixPro 4KVR360) 2046 # EIS2 - 4 bytes: 04 97 00 00 (PixPro 4KVR360) 2047 # ---- LG ---- 2048 adzc => { Name => 'Unknown_adzc', Unknown => 1, Hidden => 1, %langText }, # "false\0/","true\0/" 2049 adze => { Name => 'Unknown_adze', Unknown => 1, Hidden => 1, %langText }, # "false\0/" 2050 adzm => { Name => 'Unknown_adzm', Unknown => 1, Hidden => 1, %langText }, # "\x0e\x04/","\x10\x06" 2051 # ---- Microsoft ---- 2052 Xtra => { #PH (microsoft) 2053 Name => 'MicrosoftXtra', 2054 WriteGroup => 'Microsoft', 2055 SubDirectory => { 2056 DirName => 'Microsoft', 2057 TagTable => 'Image::ExifTool::Microsoft::Xtra', 2058 }, 2059 }, 2060 # ---- Minolta ---- 2061 MMA0 => { #PH (DiMage 7Hi) 2062 Name => 'MinoltaMMA0', 2063 SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' }, 2064 }, 2065 MMA1 => { #PH (Dimage A2) 2066 Name => 'MinoltaMMA1', 2067 SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' }, 2068 }, 2069 # ---- Nikon ---- 2070 NCDT => { #PH 2071 Name => 'NikonNCDT', 2072 SubDirectory => { TagTable => 'Image::ExifTool::Nikon::NCDT' }, 2073 }, 2074 # ---- Olympus ---- 2075 scrn => { #PH (TG-810) 2076 Name => 'OlympusPreview', 2077 Condition => '$$valPt =~ /^.{4}\xff\xd8\xff\xdb/s', 2078 SubDirectory => { TagTable => 'Image::ExifTool::Olympus::scrn' }, 2079 }, 2080 # ---- Panasonic/Leica ---- 2081 PANA => { #PH 2082 Name => 'PanasonicPANA', 2083 SubDirectory => { TagTable => 'Image::ExifTool::Panasonic::PANA' }, 2084 }, 2085 LEIC => { #PH 2086 Name => 'LeicaLEIC', 2087 SubDirectory => { TagTable => 'Image::ExifTool::Panasonic::PANA' }, 2088 }, 2089 # ---- Pentax ---- 2090 thmb => [ # (apparently defined by 3gpp, ref 16) 2091 { #PH (Pentax Q) 2092 Name => 'MakerNotePentax5a', 2093 Condition => '$$valPt =~ /^PENTAX \0II/', 2094 SubDirectory => { 2095 TagTable => 'Image::ExifTool::Pentax::Main', 2096 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 2097 Start => 10, 2098 Base => '$start - 10', 2099 ByteOrder => 'LittleEndian', 2100 }, 2101 },{ #PH (TG-810) 2102 Name => 'OlympusThumbnail', 2103 Condition => '$$valPt =~ /^.{4}\xff\xd8\xff\xdb/s', 2104 SubDirectory => { TagTable => 'Image::ExifTool::Olympus::thmb' }, 2105 },{ #17 (format is in bytes 3-7) 2106 Name => 'ThumbnailImage', 2107 Condition => '$$valPt =~ /^.{8}\xff\xd8\xff[\xdb\xe0]/s', 2108 Groups => { 2 => 'Preview' }, 2109 RawConv => 'substr($val, 8)', 2110 Binary => 1, 2111 },{ #17 (format is in bytes 3-7) 2112 Name => 'ThumbnailPNG', 2113 Condition => '$$valPt =~ /^.{8}\x89PNG\r\n\x1a\n/s', 2114 Groups => { 2 => 'Preview' }, 2115 RawConv => 'substr($val, 8)', 2116 Binary => 1, 2117 },{ 2118 Name => 'UnknownThumbnail', 2119 Groups => { 2 => 'Preview' }, 2120 Binary => 1, 2121 }, 2122 ], 2123 PENT => { #PH 2124 Name => 'PentaxPENT', 2125 SubDirectory => { 2126 TagTable => 'Image::ExifTool::Pentax::PENT', 2127 ByteOrder => 'LittleEndian', 2128 }, 2129 }, 2130 PXTH => { #PH (Pentax K-01) 2131 Name => 'PentaxPreview', 2132 SubDirectory => { TagTable => 'Image::ExifTool::Pentax::PXTH' }, 2133 }, 2134 PXMN => [{ #PH (Pentax K-01) 2135 Name => 'MakerNotePentax5b', 2136 Condition => '$$valPt =~ /^PENTAX \0MM/', 2137 SubDirectory => { 2138 TagTable => 'Image::ExifTool::Pentax::Main', 2139 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 2140 Start => 10, 2141 Base => '$start - 10', 2142 ByteOrder => 'BigEndian', 2143 }, 2144 },{ #PH (Pentax 645Z) 2145 Name => 'MakerNotePentax5c', 2146 Condition => '$$valPt =~ /^PENTAX \0II/', 2147 SubDirectory => { 2148 TagTable => 'Image::ExifTool::Pentax::Main', 2149 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 2150 Start => 10, 2151 Base => '$start - 10', 2152 ByteOrder => 'LittleEndian', 2153 }, 2154 },{ 2155 Name => 'MakerNotePentaxUnknown', 2156 Binary => 1, 2157 }], 2158 # ---- Ricoh ---- 2159 RTHU => { #PH (GR) 2160 Name => 'PreviewImage', 2161 Groups => { 2 => 'Preview' }, 2162 RawConv => '$self->ValidateImage(\$val, $tag)', 2163 }, 2164 RMKN => { #PH (GR) 2165 Name => 'RicohRMKN', 2166 SubDirectory => { 2167 TagTable => 'Image::ExifTool::Exif::Main', 2168 ProcessProc => \&Image::ExifTool::ProcessTIFF, # (because ProcessMOV is default) 2169 }, 2170 }, 2171 '@mak' => { Name => 'Make', Avoid => 1 }, 2172 '@mod' => { Name => 'Model', Avoid => 1 }, 2173 '@swr' => { Name => 'SoftwareVersion', Avoid => 1 }, 2174 '@day' => { 2175 Name => 'ContentCreateDate', 2176 Notes => q{ 2177 some stupid Ricoh programmer used the '@' symbol instead of the copyright 2178 symbol in these tag ID's for the Ricoh Theta Z1 and maybe other models 2179 }, 2180 Groups => { 2 => 'Time' }, 2181 Shift => 'Time', 2182 Avoid => 1, 2183 # handle values in the form "2010-02-12T13:27:14-0800" 2184 ValueConv => q{ 2185 require Image::ExifTool::XMP; 2186 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 2187 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 2188 return $val; 2189 }, 2190 ValueConvInv => q{ 2191 require Image::ExifTool::XMP; 2192 my $tmp = Image::ExifTool::XMP::FormatXMPDate($val); 2193 ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon 2194 return $val; 2195 }, 2196 PrintConv => '$self->ConvertDateTime($val)', 2197 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 2198 }, 2199 '@xyz' => { #PH (iPhone 3GS) 2200 Name => 'GPSCoordinates', 2201 Groups => { 2 => 'Location' }, 2202 Avoid => 1, 2203 ValueConv => \&ConvertISO6709, 2204 ValueConvInv => \&ConvInvISO6709, 2205 PrintConv => \&PrintGPSCoordinates, 2206 PrintConvInv => \&PrintInvGPSCoordinates, 2207 }, 2208 # RDT1 - pairs of int32u_BE, starting at byte 8: "458275 471846" 2209 # RDT2 - pairs of int32u_BE, starting at byte 8: "472276 468526" 2210 # RDT3 - pairs of int32u_BE, starting at byte 8: "876603 482191" 2211 # RDT4 - pairs of int32u_BE, starting at byte 8: "1955 484612" 2212 # RDT6 - empty 2213 # RDT7 - empty 2214 # RDT8 - empty 2215 # RDT9 - only 16-byte header? 2216 # the boxes below all have a similar header (little-endian): 2217 # 0 int32u - number of records 2218 # 4 ? - "1e 00" 2219 # 6 int16u - record length in bytes 2220 # 8 ? - "23 01 00 00 00 00 00 00" 2221 # 16 - start of records (each record ends in an int64u timestamp in ns) 2222 # RDTA - float[4],ts: "-0.31289672 -0.2245330 11.303817 0 775.780" 2223 # RDTB - float[4],ts: "-0.04841613 -0.2166595 0.0724792 0 775.780" 2224 # RDTC - float[4],ts: "27.60925 -27.10037 -13.27285 0 775.829" 2225 # RDTD - int16s[3],ts: "353 -914 16354 0 775.829" 2226 # RDTG - ts: "775.825" 2227 # RDTI - float[4],ts: "0.00165951 0.005770059 0.06838259 0.1744695 775.862" 2228 # ---- Samsung ---- 2229 vndr => 'Vendor', #PH (Samsung PL70) 2230 SDLN => 'PlayMode', #PH (NC, Samsung ST80 "SEQ_PLAY") 2231 INFO => { 2232 Name => 'SamsungINFO', 2233 SubDirectory => { TagTable => 'Image::ExifTool::Samsung::INFO' }, 2234 }, 2235 '@sec' => { #PH (Samsung WB30F) 2236 Name => 'SamsungSec', 2237 SubDirectory => { TagTable => 'Image::ExifTool::Samsung::sec' }, 2238 }, 2239 'smta' => { #PH (Samsung SM-C101) 2240 Name => 'SamsungSmta', 2241 SubDirectory => { 2242 TagTable => 'Image::ExifTool::Samsung::smta', 2243 Start => 4, 2244 }, 2245 }, 2246 cver => 'CodeVersion', #PH (guess, Samsung MV900F) 2247 # ducp - 4 bytes all zero (Samsung ST96,WB750), 52 bytes all zero (Samsung WB30F) 2248 # edli - 52 bytes all zero (Samsung WB30F) 2249 # @etc - 4 bytes all zero (Samsung WB30F) 2250 # saut - 4 bytes all zero (Samsung SM-N900T) 2251 # smrd - string "TRUEBLUE" (Samsung SM-C101) 2252 # ---- TomTom Bandit Action Cam ---- 2253 TTMD => { 2254 Name => 'TomTomMetaData', 2255 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TomTom' }, 2256 }, 2257 # ---- Samsung Gear 360 ---- 2258 vrot => { 2259 Name => 'AccelerometerData', 2260 Notes => q{ 2261 accelerometer readings for each frame of the video, expressed as sets of 2262 yaw, pitch and roll angles in degrees 2263 }, 2264 Format => 'rational64s', 2265 ValueConv => '$val =~ s/^-?\d+ //; \$val', # (ignore leading version/size words) 2266 }, 2267 # m360 - 8 bytes "0 0 0 0 0 0 0 1" 2268 # opax - 164 bytes unknown (center and affine arrays? ref 26) 2269 # opai - 32 bytes (maybe contains a serial number starting at byte 16? - PH) (rgb gains, degamma, gamma? ref 26) 2270 # intv - 16 bytes all zero 2271 # ---- Xaiomi ---- 2272 mcvr => { 2273 Name => 'PreviewImage', 2274 Groups => { 2 => 'Preview' }, 2275 Binary => 1, 2276 }, 2277 # ---- Unknown ---- 2278 # CDET - 128 bytes (unknown origin) 2279 # mtyp - 4 bytes all zero (some drone video) 2280 # kgrf - 8 bytes all zero ? (in udta inside trak atom) 2281 # kgcg - 128 bytes 0's and 1's 2282 # kgsi - 4 bytes "00 00 00 80" 2283 # FIEL - 18 bytes "FIEL\0\x01\0\0\0..." 2284# 2285# other 3rd-party tags 2286# (ref http://code.google.com/p/mp4parser/source/browse/trunk/isoparser/src/main/resources/isoparser-default.properties?r=814) 2287# 2288 ccid => 'ContentID', 2289 icnu => 'IconURI', 2290 infu => 'InfoURL', 2291 cdis => 'ContentDistributorID', 2292 albr => { Name => 'AlbumArtist', Groups => { 2 => 'Author' } }, 2293 cvru => 'CoverURI', 2294 lrcu => 'LyricsURI', 2295 2296 tags => { # found in Audible .m4b audio books (ref PH) 2297 Name => 'Audible_tags', 2298 SubDirectory => { TagTable => 'Image::ExifTool::Audible::tags' }, 2299 }, 2300); 2301 2302# Unknown information stored in HTC One (M8) videos - PH 2303%Image::ExifTool::QuickTime::HTCBinary = ( 2304 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2305 GROUPS => { 0 => 'MakerNotes', 1 => 'HTC', 2 => 'Video' }, 2306 TAG_PREFIX => 'HTCBinary', 2307 FORMAT => 'int32u', 2308 FIRST_ENTRY => 0, 2309 # 0 - values: 1 2310 # 1 - values: 0 2311 # 2 - values: 0 2312 # 3 - values: FileSize minus 12 (why?) 2313 # 4 - values: 12 2314); 2315 2316# TomTom Bandit Action Cam metadata (ref PH) 2317%Image::ExifTool::QuickTime::TomTom = ( 2318 PROCESS_PROC => \&ProcessMOV, 2319 GROUPS => { 2 => 'Video' }, 2320 NOTES => 'Tags found in TomTom Bandit Action Cam MP4 videos.', 2321 TTAD => { 2322 Name => 'TomTomAD', 2323 SubDirectory => { 2324 TagTable => 'Image::ExifTool::QuickTime::Stream', 2325 ProcessProc => \&Image::ExifTool::QuickTime::ProcessTTAD, 2326 }, 2327 }, 2328 TTHL => { Name => 'TomTomHL', Binary => 1, Unknown => 1 }, # (mostly zeros) 2329 # (TTID values are different for each video) 2330 TTID => { Name => 'TomTomID', ValueConv => 'unpack("x4H*",$val)' }, 2331 TTVI => { Name => 'TomTomVI', Format => 'int32u', Unknown => 1 }, # seen: "0 1 61 508 508" 2332 # TTVD seen: "normal 720p 60fps 60fps 16/9 wide 1x" 2333 TTVD => { Name => 'TomTomVD', ValueConv => 'my @a = ($val =~ /[\x20-\x7f]+/g); "@a"' }, 2334); 2335 2336# User-specific media data atoms (ref 11) 2337%Image::ExifTool::QuickTime::UserMedia = ( 2338 PROCESS_PROC => \&ProcessMOV, 2339 GROUPS => { 2 => 'Video' }, 2340 MTDT => { 2341 Name => 'MetaData', 2342 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MetaData' }, 2343 }, 2344); 2345 2346# User-specific media data atoms (ref 11) 2347%Image::ExifTool::QuickTime::MetaData = ( 2348 PROCESS_PROC => \&ProcessMetaData, 2349 GROUPS => { 2 => 'Video' }, 2350 TAG_PREFIX => 'MetaData', 2351 0x01 => 'Title', 2352 0x03 => { 2353 Name => 'ProductionDate', 2354 Groups => { 2 => 'Time' }, 2355 Shift => 'Time', 2356 Writable => 1, 2357 Permanent => 1, 2358 DelValue => '0000/00/00 00:00:00', 2359 # translate from format "YYYY/mm/dd HH:MM:SS" 2360 ValueConv => '$val=~tr{/}{:}; $val', 2361 ValueConvInv => '$val=~s[^(\d{4}):(\d{2}):][$1/$2/]; $val', 2362 PrintConv => '$self->ConvertDateTime($val)', 2363 PrintConvInv => '$self->InverseDateTime($val)', 2364 }, 2365 0x04 => 'Software', 2366 0x05 => 'Product', 2367 0x0a => { 2368 Name => 'TrackProperty', 2369 RawConv => 'my @a=unpack("Nnn",$val); "@a"', 2370 PrintConv => [ 2371 { 0 => 'No presentation', BITMASK => { 0 => 'Main track' } }, 2372 { 0 => 'No attributes', BITMASK => { 15 => 'Read only' } }, 2373 '"Priority $val"', 2374 ], 2375 }, 2376 0x0b => { 2377 Name => 'TimeZone', 2378 Groups => { 2 => 'Time' }, 2379 Writable => 1, 2380 Permanent => 1, 2381 DelValue => 0, 2382 RawConv => 'Get16s(\$val,0)', 2383 RawConvInv => 'Set16s($val)', 2384 PrintConv => 'TimeZoneString($val)', 2385 PrintConvInv => q{ 2386 return undef unless $val =~ /^([-+])(\d{1,2}):?(\d{2})$/' 2387 my $tzmin = $2 * 60 + $3; 2388 $tzmin = -$tzmin if $1 eq '-'; 2389 return $tzmin; 2390 } 2391 }, 2392 0x0c => { 2393 Name => 'ModifyDate', 2394 Groups => { 2 => 'Time' }, 2395 Shift => 'Time', 2396 Writable => 1, 2397 Permanent => 1, 2398 DelValue => '0000/00/00 00:00:00', 2399 # translate from format "YYYY/mm/dd HH:MM:SS" 2400 ValueConv => '$val=~tr{/}{:}; $val', 2401 ValueConvInv => '$val=~s[^(\d{4}):(\d{2}):][$1/$2/]; $val', 2402 PrintConv => '$self->ConvertDateTime($val)', 2403 PrintConvInv => '$self->InverseDateTime($val)', 2404 }, 2405); 2406 2407# compressed movie atoms (ref http://wiki.multimedia.cx/index.php?title=QuickTime_container#cmov) 2408%Image::ExifTool::QuickTime::CMovie = ( 2409 PROCESS_PROC => \&ProcessMOV, 2410 GROUPS => { 2 => 'Video' }, 2411 dcom => 'Compression', 2412 # cmvd - compressed moov atom data 2413); 2414 2415# Profile atoms (ref 11) 2416%Image::ExifTool::QuickTime::Profile = ( 2417 PROCESS_PROC => \&ProcessMOV, 2418 GROUPS => { 2 => 'Video' }, 2419 FPRF => { 2420 Name => 'FileGlobalProfile', 2421 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FileProf' }, 2422 }, 2423 APRF => { 2424 Name => 'AudioProfile', 2425 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AudioProf' }, 2426 }, 2427 VPRF => { 2428 Name => 'VideoProfile', 2429 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::VideoProf' }, 2430 }, 2431 OLYM => { #PH 2432 Name => 'OlympusOLYM', 2433 SubDirectory => { 2434 TagTable => 'Image::ExifTool::Olympus::OLYM', 2435 ByteOrder => 'BigEndian', 2436 }, 2437 }, 2438); 2439 2440# FPRF atom information (ref 11) 2441%Image::ExifTool::QuickTime::FileProf = ( 2442 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2443 GROUPS => { 2 => 'Video' }, 2444 FORMAT => 'int32u', 2445 0 => { Name => 'FileProfileVersion', Unknown => 1 }, # unknown = uninteresting 2446 1 => { 2447 Name => 'FileFunctionFlags', 2448 PrintConv => { BITMASK => { 2449 28 => 'Fragmented', 2450 29 => 'Additional tracks', 2451 30 => 'Edited', # (main AV track is edited) 2452 }}, 2453 }, 2454 # 2 - reserved 2455); 2456 2457# APRF atom information (ref 11) 2458%Image::ExifTool::QuickTime::AudioProf = ( 2459 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2460 GROUPS => { 2 => 'Audio' }, 2461 FORMAT => 'int32u', 2462 0 => { Name => 'AudioProfileVersion', Unknown => 1 }, 2463 1 => 'AudioTrackID', 2464 2 => { 2465 Name => 'AudioCodec', 2466 Format => 'undef[4]', 2467 }, 2468 3 => { 2469 Name => 'AudioCodecInfo', 2470 Unknown => 1, 2471 PrintConv => 'sprintf("0x%.4x", $val)', 2472 }, 2473 4 => { 2474 Name => 'AudioAttributes', 2475 PrintConv => { BITMASK => { 2476 0 => 'Encrypted', 2477 1 => 'Variable bitrate', 2478 2 => 'Dual mono', 2479 }}, 2480 }, 2481 5 => { 2482 Name => 'AudioAvgBitrate', 2483 ValueConv => '$val * 1000', 2484 PrintConv => 'ConvertBitrate($val)', 2485 }, 2486 6 => { 2487 Name => 'AudioMaxBitrate', 2488 ValueConv => '$val * 1000', 2489 PrintConv => 'ConvertBitrate($val)', 2490 }, 2491 7 => 'AudioSampleRate', 2492 8 => 'AudioChannels', 2493); 2494 2495# VPRF atom information (ref 11) 2496%Image::ExifTool::QuickTime::VideoProf = ( 2497 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2498 GROUPS => { 2 => 'Video' }, 2499 FORMAT => 'int32u', 2500 0 => { Name => 'VideoProfileVersion', Unknown => 1 }, 2501 1 => 'VideoTrackID', 2502 2 => { 2503 Name => 'VideoCodec', 2504 Format => 'undef[4]', 2505 }, 2506 3 => { 2507 Name => 'VideoCodecInfo', 2508 Unknown => 1, 2509 PrintConv => 'sprintf("0x%.4x", $val)', 2510 }, 2511 4 => { 2512 Name => 'VideoAttributes', 2513 PrintConv => { BITMASK => { 2514 0 => 'Encrypted', 2515 1 => 'Variable bitrate', 2516 2 => 'Variable frame rate', 2517 3 => 'Interlaced', 2518 }}, 2519 }, 2520 5 => { 2521 Name => 'VideoAvgBitrate', 2522 ValueConv => '$val * 1000', 2523 PrintConv => 'ConvertBitrate($val)', 2524 }, 2525 6 => { 2526 Name => 'VideoMaxBitrate', 2527 ValueConv => '$val * 1000', 2528 PrintConv => 'ConvertBitrate($val)', 2529 }, 2530 7 => { 2531 Name => 'VideoAvgFrameRate', 2532 Format => 'fixed32u', 2533 PrintConv => 'int($val * 1000 + 0.5) / 1000', 2534 }, 2535 8 => { 2536 Name => 'VideoMaxFrameRate', 2537 Format => 'fixed32u', 2538 PrintConv => 'int($val * 1000 + 0.5) / 1000', 2539 }, 2540 9 => { 2541 Name => 'VideoSize', 2542 Format => 'int16u[2]', 2543 PrintConv => '$val=~tr/ /x/; $val', 2544 }, 2545 10 => { 2546 Name => 'PixelAspectRatio', 2547 Format => 'int16u[2]', 2548 PrintConv => '$val=~tr/ /:/; $val', 2549 }, 2550); 2551 2552# meta atoms 2553%Image::ExifTool::QuickTime::Meta = ( 2554 PROCESS_PROC => \&ProcessMOV, 2555 WRITE_PROC => \&WriteQuickTime, 2556 GROUPS => { 1 => 'Meta', 2 => 'Video' }, 2557 ilst => { 2558 Name => 'ItemList', 2559 SubDirectory => { 2560 TagTable => 'Image::ExifTool::QuickTime::ItemList', 2561 HasData => 1, # process atoms as containers with 'data' elements 2562 }, 2563 }, 2564 # MP4 tags (ref 5) 2565 hdlr => { 2566 Name => 'Handler', 2567 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' }, 2568 }, 2569 dinf => { 2570 Name => 'DataInfo', # (don't change this name -- used to recognize directory when writing) 2571 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' }, 2572 }, 2573 ipmc => { 2574 Name => 'IPMPControl', 2575 Flags => ['Binary','Unknown'], 2576 }, 2577 iloc => { 2578 Name => 'ItemLocation', 2579 RawConv => \&ParseItemLocation, 2580 WriteHook => \&ParseItemLocation, 2581 Notes => 'parsed, but not extracted as a tag', 2582 }, 2583 ipro => { 2584 Name => 'ItemProtection', 2585 Flags => ['Binary','Unknown'], 2586 }, 2587 iinf => [{ 2588 Name => 'ItemInformation', 2589 Condition => '$$valPt =~ /^\0/', # (check for version 0) 2590 SubDirectory => { 2591 TagTable => 'Image::ExifTool::QuickTime::ItemInfo', 2592 Start => 6, # (4-byte version/flags + 2-byte count) 2593 }, 2594 },{ 2595 Name => 'ItemInformation', 2596 SubDirectory => { 2597 TagTable => 'Image::ExifTool::QuickTime::ItemInfo', 2598 Start => 8, # (4-byte version/flags + 4-byte count) 2599 }, 2600 }], 2601 'xml ' => { 2602 Name => 'XML', 2603 Flags => [ 'Binary', 'Protected' ], 2604 SubDirectory => { 2605 TagTable => 'Image::ExifTool::XMP::XML', 2606 IgnoreProp => { NonRealTimeMeta => 1 }, # ignore container for Sony 'nrtm' 2607 }, 2608 }, 2609 'keys' => { 2610 Name => 'Keys', 2611 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Keys' }, 2612 }, 2613 bxml => { 2614 Name => 'BinaryXML', 2615 Flags => ['Binary','Unknown'], 2616 }, 2617 pitm => [{ 2618 Name => 'PrimaryItemReference', 2619 Condition => '$$valPt =~ /^\0/', # (version 0?) 2620 RawConv => '$$self{PrimaryItem} = unpack("x4n",$val)', 2621 WriteHook => sub { my ($val,$et) = @_; $$et{PrimaryItem} = unpack("x4n",$val); }, 2622 },{ 2623 Name => 'PrimaryItemReference', 2624 RawConv => '$$self{PrimaryItem} = unpack("x4N",$val)', 2625 WriteHook => sub { my ($val,$et) = @_; $$et{PrimaryItem} = unpack("x4N",$val); }, 2626 }], 2627 free => { #PH 2628 Name => 'Free', 2629 Flags => ['Binary','Unknown'], 2630 }, 2631 iprp => { 2632 Name => 'ItemProperties', 2633 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemProp' }, 2634 }, 2635 iref => { 2636 Name => 'ItemReference', 2637 # the version is needed to parse some of the item references 2638 Condition => '$$self{ItemRefVersion} = ord($$valPt); 1', 2639 SubDirectory => { 2640 TagTable => 'Image::ExifTool::QuickTime::ItemRef', 2641 Start => 4, 2642 }, 2643 }, 2644 idat => { 2645 Name => 'MetaImageSize', #PH (NC) 2646 Format => 'int16u', 2647 # (don't know what the first two numbers are for) 2648 PrintConv => '$val =~ s/^(\d+) (\d+) (\d+) (\d+)/${3}x$4/; $val', 2649 }, 2650 uuid => [ 2651 { #PH (Canon R5/R6 HIF) 2652 Name => 'MetaVersion', # (NC) 2653 Condition => '$$valPt=~/^\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48/', 2654 RawConv => 'substr($val, 0x14)', 2655 }, 2656 { 2657 Name => 'UUID-Unknown', 2658 %unknownInfo, 2659 }, 2660 ], 2661); 2662 2663# additional metadata container (ref ISO14496-12:2015) 2664%Image::ExifTool::QuickTime::OtherMeta = ( 2665 PROCESS_PROC => \&ProcessMOV, 2666 WRITE_PROC => \&WriteQuickTime, 2667 GROUPS => { 2 => 'Video' }, 2668 mere => { 2669 Name => 'MetaRelation', 2670 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MetaRelation' }, 2671 }, 2672 meta => { 2673 Name => 'Meta', 2674 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 2675 }, 2676); 2677 2678# metabox relation (ref ISO14496-12:2015) 2679%Image::ExifTool::QuickTime::MetaRelation = ( 2680 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2681 GROUPS => { 2 => 'Video' }, 2682 FORMAT => 'int32u', 2683 # 0 => 'MetaRelationVersion', 2684 # 1 => 'FirstMetaboxHandlerType', 2685 # 2 => 'FirstMetaboxHandlerType', 2686 # 3 => { Name => 'MetaboxRelation', Format => 'int8u' }, 2687); 2688 2689%Image::ExifTool::QuickTime::ItemProp = ( 2690 PROCESS_PROC => \&ProcessMOV, 2691 WRITE_PROC => \&WriteQuickTime, 2692 GROUPS => { 2 => 'Image' }, 2693 ipco => { 2694 Name => 'ItemPropertyContainer', 2695 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemPropCont' }, 2696 }, 2697 ipma => { 2698 Name => 'ItemPropertyAssociation', 2699 RawConv => \&ParseItemPropAssoc, 2700 WriteHook => \&ParseItemPropAssoc, 2701 Notes => 'parsed, but not extracted as a tag', 2702 }, 2703); 2704 2705%Image::ExifTool::QuickTime::ItemPropCont = ( 2706 PROCESS_PROC => \&ProcessMOV, 2707 WRITE_PROC => \&WriteQuickTime, 2708 PERMANENT => 1, # (can't be deleted) 2709 GROUPS => { 2 => 'Image' }, 2710 VARS => { START_INDEX => 1 }, # show verbose indices starting at 1 2711 colr => [{ 2712 Name => 'ICC_Profile', 2713 Condition => '$$valPt =~ /^(prof|rICC)/', 2714 Permanent => 0, # (in QuickTime, this writes a zero-length box instead of deleting) 2715 SubDirectory => { 2716 TagTable => 'Image::ExifTool::ICC_Profile::Main', 2717 Start => 4, 2718 }, 2719 },{ 2720 Name => 'ColorRepresentation', 2721 ValueConv => 'join(" ", substr($val,0,4), unpack("x4n*",$val))', 2722 }], 2723 irot => { 2724 Name => 'Rotation', 2725 Format => 'int8u', 2726 Writable => 'int8u', 2727 Protected => 1, 2728 ValueConv => '$val * 90', 2729 ValueConvInv => 'int($val / 90 + 0.5)', 2730 }, 2731 ispe => { 2732 Name => 'ImageSpatialExtent', 2733 Condition => '$$valPt =~ /^\0{4}/', # (version/flags == 0/0) 2734 RawConv => q{ 2735 my @dim = unpack("x4N*", $val); 2736 return undef if @dim < 2; 2737 unless ($$self{DOC_NUM}) { 2738 $self->FoundTag(ImageWidth => $dim[0]); 2739 $self->FoundTag(ImageHeight => $dim[1]); 2740 } 2741 return join ' ', @dim; 2742 }, 2743 PrintConv => '$val =~ tr/ /x/; $val', 2744 }, 2745 pixi => { 2746 Name => 'ImagePixelDepth', 2747 Condition => '$$valPt =~ /^\0{4}./s', # (version/flags == 0/0 and count) 2748 RawConv => 'join " ", unpack("x5C*", $val)', 2749 }, 2750 auxC => { 2751 Name => 'AuxiliaryImageType', 2752 Format => 'undef', 2753 RawConv => '$val = substr($val, 4); $val =~ s/\0.*//s; $val', 2754 }, 2755 pasp => { 2756 Name => 'PixelAspectRatio', 2757 Format => 'int32u', 2758 Writable => 'int32u', 2759 Protected => 1, 2760 }, 2761 rloc => { 2762 Name => 'RelativeLocation', 2763 Format => 'int32u', 2764 RawConv => '$val =~ s/^\S+\s+//; $val', # remove version/flags 2765 }, 2766 clap => { 2767 Name => 'CleanAperture', 2768 Format => 'rational64s', 2769 Notes => '4 numbers: width, height, left and top', 2770 }, 2771 hvcC => { 2772 Name => 'HEVCConfiguration', 2773 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HEVCConfig' }, 2774 }, 2775 av1C => { 2776 Name => 'AV1Configuration', 2777 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AV1Config' }, 2778 }, 2779); 2780 2781# HEVC configuration (ref https://github.com/MPEGGroup/isobmff/blob/master/IsoLib/libisomediafile/src/HEVCConfigAtom.c) 2782%Image::ExifTool::QuickTime::HEVCConfig = ( 2783 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2784 GROUPS => { 2 => 'Video' }, 2785 FIRST_ENTRY => 0, 2786 0 => 'HEVCConfigurationVersion', 2787 1 => { 2788 Name => 'GeneralProfileSpace', 2789 Mask => 0xc0, 2790 PrintConv => { 0 => 'Conforming' }, 2791 }, 2792 1.1 => { 2793 Name => 'GeneralTierFlag', 2794 Mask => 0x20, 2795 PrintConv => { 2796 0 => 'Main Tier', 2797 1 => 'High Tier', 2798 }, 2799 }, 2800 1.2 => { 2801 Name => 'GeneralProfileIDC', 2802 Mask => 0x1f, 2803 PrintConv => { 2804 0 => 'No Profile', 2805 1 => 'Main', 2806 2 => 'Main 10', 2807 3 => 'Main Still Picture', 2808 4 => 'Format Range Extensions', 2809 5 => 'High Throughput', 2810 6 => 'Multiview Main', 2811 7 => 'Scalable Main', 2812 8 => '3D Main', 2813 9 => 'Screen Content Coding Extensions', 2814 10 => 'Scalable Format Range Extensions', 2815 11 => 'High Throughput Screen Content Coding Extensions', 2816 }, 2817 }, 2818 2 => { 2819 Name => 'GenProfileCompatibilityFlags', 2820 Format => 'int32u', 2821 PrintConv => { BITMASK => { 2822 31 => 'No Profile', # (bit 0 in stream) 2823 30 => 'Main', # (bit 1 in stream) 2824 29 => 'Main 10', # (bit 2 in stream) 2825 28 => 'Main Still Picture', # (bit 3 in stream) 2826 27 => 'Format Range Extensions',# (...) 2827 26 => 'High Throughput', 2828 25 => 'Multiview Main', 2829 24 => 'Scalable Main', 2830 23 => '3D Main', 2831 22 => 'Screen Content Coding Extensions', 2832 21 => 'Scalable Format Range Extensions', 2833 20 => 'High Throughput Screen Content Coding Extensions', 2834 }}, 2835 }, 2836 6 => { 2837 Name => 'ConstraintIndicatorFlags', 2838 Format => 'int8u[6]', 2839 }, 2840 12 => { 2841 Name => 'GeneralLevelIDC', 2842 PrintConv => 'sprintf("%d (level %.1f)", $val, $val/30)', 2843 }, 2844 13 => { 2845 Name => 'MinSpatialSegmentationIDC', 2846 Format => 'int16u', 2847 Mask => 0x0fff, 2848 }, 2849 15 => { 2850 Name => 'ParallelismType', 2851 Mask => 0x03, 2852 }, 2853 16 => { 2854 Name => 'ChromaFormat', 2855 Mask => 0x03, 2856 PrintConv => { 2857 0 => 'Monochrome', 2858 1 => '4:2:0', 2859 2 => '4:2:2', 2860 3 => '4:4:4', 2861 }, 2862 }, 2863 17 => { 2864 Name => 'BitDepthLuma', 2865 Mask => 0x07, 2866 ValueConv => '$val + 8', 2867 }, 2868 18 => { 2869 Name => 'BitDepthChroma', 2870 Mask => 0x07, 2871 ValueConv => '$val + 8', 2872 }, 2873 19 => { 2874 Name => 'AverageFrameRate', 2875 Format => 'int16u', 2876 ValueConv => '$val / 256', 2877 }, 2878 21 => { 2879 Name => 'ConstantFrameRate', 2880 Mask => 0xc0, 2881 PrintConv => { 2882 0 => 'Unknown', 2883 1 => 'Constant Frame Rate', 2884 2 => 'Each Temporal Layer is Constant Frame Rate', 2885 }, 2886 }, 2887 21.1 => { 2888 Name => 'NumTemporalLayers', 2889 Mask => 0x38, 2890 }, 2891 21.2 => { 2892 Name => 'TemporalIDNested', 2893 Mask => 0x04, 2894 PrintConv => { 0 => 'No', 1 => 'Yes' }, 2895 }, 2896 #21.3 => { 2897 # Name => 'NALUnitLengthSize', 2898 # Mask => 0x03, 2899 # ValueConv => '$val + 1', 2900 # PrintConv => { 1 => '8-bit', 2 => '16-bit', 4 => '32-bit' }, 2901 #}, 2902 #22 => 'NumberOfNALUnitArrays', 2903 # (don't decode the NAL unit arrays) 2904); 2905 2906# HEVC configuration (ref https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox) 2907%Image::ExifTool::QuickTime::AV1Config = ( 2908 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2909 GROUPS => { 2 => 'Video' }, 2910 FIRST_ENTRY => 0, 2911 0 => { 2912 Name => 'AV1ConfigurationVersion', 2913 Mask => 0x7f, 2914 }, 2915 1.0 => { 2916 Name => 'SeqProfile', 2917 Mask => 0xe0, 2918 Unknown => 1, 2919 }, 2920 1.1 => { 2921 Name => 'SeqLevelIdx0', 2922 Mask => 0x1f, 2923 Unknown => 1, 2924 }, 2925 2.0 => { 2926 Name => 'SeqTier0', 2927 Mask => 0x80, 2928 Unknown => 1, 2929 }, 2930 2.1 => { 2931 Name => 'HighBitDepth', 2932 Mask => 0x40, 2933 Unknown => 1, 2934 }, 2935 2.2 => { 2936 Name => 'TwelveBit', 2937 Mask => 0x20, 2938 Unknown => 1, 2939 }, 2940 2.3 => { 2941 Name => 'ChromaFormat', # (Monochrome+SubSamplingX+SubSamplingY) 2942 Notes => 'bits: 0x04 = Monochrome, 0x02 = SubSamplingX, 0x01 = SubSamplingY', 2943 Mask => 0x1c, 2944 PrintConv => { 2945 0x00 => 'YUV 4:4:4', 2946 0x02 => 'YUV 4:2:2', 2947 0x03 => 'YUV 4:2:0', 2948 0x07 => 'Monochrome 4:0:0', 2949 }, 2950 }, 2951 2.4 => { 2952 Name => 'ChromaSamplePosition', 2953 Mask => 0x03, 2954 PrintConv => { 2955 0 => 'Unknown', 2956 1 => 'Vertical', 2957 2 => 'Colocated', 2958 3 => '(reserved)', 2959 }, 2960 }, 2961 3 => { 2962 Name => 'InitialDelaySamples', 2963 RawConv => '$val & 0x10 ? undef : ($val & 0x0f) + 1', 2964 Unknown => 1, 2965 }, 2966); 2967 2968%Image::ExifTool::QuickTime::ItemRef = ( 2969 PROCESS_PROC => \&ProcessMOV, 2970 WRITE_PROC => \&WriteQuickTime, 2971 GROUPS => { 2 => 'Image' }, 2972 # (Note: ExifTool's ItemRefVersion may be used to test the iref version number) 2973 NOTES => q{ 2974 The Item reference entries listed in the table below contain information about 2975 the associations between items in the file. This information is used by 2976 ExifTool, but these entries are not extracted as tags. 2977 }, 2978 dimg => { Name => 'DerivedImageRef', RawConv => 'undef' }, 2979 thmb => { Name => 'ThumbnailRef', RawConv => 'undef' }, 2980 auxl => { Name => 'AuxiliaryImageRef', RawConv => 'undef' }, 2981 cdsc => { 2982 Name => 'ContentDescribes', 2983 RawConv => \&ParseContentDescribes, 2984 WriteHook => \&ParseContentDescribes, 2985 }, 2986); 2987 2988%Image::ExifTool::QuickTime::ItemInfo = ( 2989 PROCESS_PROC => \&ProcessMOV, 2990 WRITE_PROC => \&WriteQuickTime, 2991 GROUPS => { 2 => 'Image' }, 2992 # avc1 - AVC image 2993 # hvc1 - HEVC image 2994 # lhv1 - L-HEVC image 2995 # infe - ItemInformationEntry 2996 # infe types: avc1,hvc1,lhv1,Exif,xml1,iovl(overlay image),grid,mime,hvt1(tile image) 2997 infe => { 2998 Name => 'ItemInfoEntry', 2999 RawConv => \&ParseItemInfoEntry, 3000 WriteHook => \&ParseItemInfoEntry, 3001 Notes => 'parsed, but not extracted as a tag', 3002 }, 3003); 3004 3005# track reference atoms 3006%Image::ExifTool::QuickTime::TrackRef = ( 3007 PROCESS_PROC => \&ProcessMOV, 3008 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 3009 chap => { Name => 'ChapterListTrackID', Format => 'int32u' }, 3010 tmcd => { Name => 'TimeCode', Format => 'int32u' }, 3011 mpod => { #PH (FLIR MP4) 3012 Name => 'ElementaryStreamTrack', 3013 Format => 'int32u', 3014 ValueConv => '$val =~ s/^1 //; $val', # (why 2 numbers? -- ignore the first if "1") 3015 }, 3016 # also: sync, scpt, ssrc, iTunesInfo 3017 cdsc => { 3018 Name => 'ContentDescribes', 3019 Format => 'int32u', 3020 PrintConv => '"Track $val"', 3021 }, 3022 # cdep (Structural Dependency QT tag?) 3023); 3024 3025# track aperture mode dimensions atoms 3026# (ref https://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap2/qtff2.html) 3027%Image::ExifTool::QuickTime::TrackAperture = ( 3028 PROCESS_PROC => \&ProcessMOV, 3029 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 3030 clef => { 3031 Name => 'CleanApertureDimensions', 3032 Format => 'fixed32u', 3033 Count => 3, 3034 ValueConv => '$val =~ s/^.*? //; $val', # remove flags word 3035 PrintConv => '$val =~ tr/ /x/; $val', 3036 }, 3037 prof => { 3038 Name => 'ProductionApertureDimensions', 3039 Format => 'fixed32u', 3040 Count => 3, 3041 ValueConv => '$val =~ s/^.*? //; $val', 3042 PrintConv => '$val =~ tr/ /x/; $val', 3043 }, 3044 enof => { 3045 Name => 'EncodedPixelsDimensions', 3046 Format => 'fixed32u', 3047 Count => 3, 3048 ValueConv => '$val =~ s/^.*? //; $val', 3049 PrintConv => '$val =~ tr/ /x/; $val', 3050 }, 3051); 3052 3053# item list atoms 3054# -> these atoms are unique, and contain one or more 'data' atoms 3055%Image::ExifTool::QuickTime::ItemList = ( 3056 PROCESS_PROC => \&ProcessMOV, 3057 WRITE_PROC => \&WriteQuickTime, 3058 CHECK_PROC => \&CheckQTValue, 3059 WRITABLE => 1, 3060 PREFERRED => 2, # (preferred over UserData and Keys tags when writing) 3061 FORMAT => 'string', 3062 GROUPS => { 1 => 'ItemList', 2 => 'Audio' }, 3063 WRITE_GROUP => 'ItemList', 3064 LANG_INFO => \&GetLangInfo, 3065 NOTES => q{ 3066 This is the preferred location for creating new QuickTime tags. Tags in 3067 this table support alternate languages which are accessed by adding a 3068 3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2 3069 country code to the tag name (eg. "ItemList:Title-fra" or 3070 "ItemList::Title-fra-FR"). When creating a new Meta box to contain the 3071 ItemList directory, by default ExifTool adds an 'mdir' (Metadata) Handler 3072 box because Apple software may ignore ItemList tags otherwise, but the API 3073 L<QuickTimeHandler|../ExifTool.html#QuickTimeHandler> option may be set to 0 to avoid this. 3074 }, 3075 # in this table, binary 1 and 2-byte "data"-type tags are interpreted as 3076 # int8u and int16u. Multi-byte binary "data" tags are extracted as binary data. 3077 # (Note that the Preferred property is set to 0 for some tags to prevent them 3078 # from being created when a same-named tag already exists in the table) 3079 "\xa9ART" => 'Artist', 3080 "\xa9alb" => 'Album', 3081 "\xa9aut" => { Name => 'Author', Avoid => 1, Groups => { 2 => 'Author' } }, #forum10091 ('auth' is preferred) 3082 "\xa9cmt" => 'Comment', 3083 "\xa9com" => { Name => 'Composer', Avoid => 1, }, # ("\xa9wrt" is preferred in ItemList) 3084 "\xa9day" => { 3085 Name => 'ContentCreateDate', 3086 Groups => { 2 => 'Time' }, 3087 Shift => 'Time', 3088 # handle values in the form "2010-02-12T13:27:14-0800" 3089 ValueConv => q{ 3090 require Image::ExifTool::XMP; 3091 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 3092 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 3093 return $val; 3094 }, 3095 ValueConvInv => q{ 3096 require Image::ExifTool::XMP; 3097 $val = Image::ExifTool::XMP::FormatXMPDate($val); 3098 $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon 3099 return $val; 3100 }, 3101 PrintConv => '$self->ConvertDateTime($val)', 3102 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 3103 }, 3104 "\xa9des" => 'Description', #4 3105 "\xa9enc" => 'EncodedBy', #10 3106 "\xa9gen" => 'Genre', 3107 "\xa9grp" => 'Grouping', 3108 "\xa9lyr" => 'Lyrics', 3109 "\xa9nam" => 'Title', 3110 "\xa9too" => 'Encoder', 3111 "\xa9trk" => 'Track', 3112 "\xa9wrt" => 'Composer', 3113# 3114# the following tags written by AtomicParsley 0.9.6 3115# (ref https://exiftool.org/forum/index.php?topic=11455.0) 3116# 3117 "\xa9st3" => 'Subtitle', 3118 "\xa9con" => 'Conductor', 3119 "\xa9sol" => 'Soloist', 3120 "\xa9arg" => 'Arranger', 3121 "\xa9ope" => 'OriginalArtist', 3122 "\xa9dir" => 'Director', 3123 "\xa9ard" => 'ArtDirector', 3124 "\xa9sne" => 'SoundEngineer', 3125 "\xa9prd" => 'Producer', 3126 "\xa9xpd" => 'ExecutiveProducer', 3127 sdes => 'StoreDescription', 3128# 3129 '----' => { 3130 Name => 'iTunesInfo', 3131 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::iTunesInfo' }, 3132 }, 3133 aART => { Name => 'AlbumArtist', Groups => { 2 => 'Author' } }, 3134 covr => { Name => 'CoverArt', Groups => { 2 => 'Preview' } }, 3135 cpil => { #10 3136 Name => 'Compilation', 3137 Format => 'int8u', #27 (ref 23 contradicts what AtomicParsley actually writes, which is int8s) 3138 Writable => 'int8s', 3139 PrintConv => { 0 => 'No', 1 => 'Yes' }, 3140 }, 3141 disk => { 3142 Name => 'DiskNumber', 3143 Format => 'undef', # (necessary to prevent decoding as string!) 3144 ValueConv => q{ 3145 return \$val unless length($val) >= 6; 3146 my @a = unpack 'x2nn', $val; 3147 return $a[1] ? join(' of ', @a) : $a[0]; 3148 }, 3149 ValueConvInv => q{ 3150 my @a = $val =~ /\d+/g; 3151 return undef if @a == 0 or @a > 2; 3152 push @a, 0 if @a == 1; 3153 return pack('n3', 0, @a); 3154 }, 3155 }, 3156 pgap => { #10 3157 Name => 'PlayGap', 3158 Format => 'int8u', #23 3159 Writable => 'int8s', #27 3160 PrintConv => { 3161 0 => 'Insert Gap', 3162 1 => 'No Gap', 3163 }, 3164 }, 3165 tmpo => { 3166 Name => 'BeatsPerMinute', 3167 # marked as boolean but really int16u in my sample 3168 # (but written as int16s by iTunes and AtomicParsley, ref forum11506) 3169 Format => 'int16u', 3170 Writable => 'int16s', 3171 }, 3172 trkn => { 3173 Name => 'TrackNumber', 3174 Format => 'undef', # (necessary to prevent decoding as string!) 3175 ValueConv => q{ 3176 return \$val unless length($val) >= 6; 3177 my @a = unpack 'x2nn', $val; 3178 return $a[1] ? join(' of ', @a) : $a[0]; 3179 }, 3180 # (see forum11501 for discussion about the format used) 3181 ValueConvInv => q{ 3182 my @a = $val =~ /\d+/g; 3183 return undef if @a == 0 or @a > 2; 3184 push @a, 0 if @a == 1; 3185 return pack('n4', 0, @a, 0); 3186 }, 3187 }, 3188# 3189# Note: it is possible that the tags below are not being decoded properly 3190# because I don't have samples to verify many of these - PH 3191# 3192 akID => { #10 3193 Name => 'AppleStoreAccountType', 3194 Format => 'int8u', #24 3195 Writable => 'int8s', #27 3196 PrintConv => { 3197 0 => 'iTunes', 3198 1 => 'AOL', 3199 }, 3200 }, 3201 albm => { Name => 'Album', Avoid => 1 }, #(ffmpeg source) 3202 apID => 'AppleStoreAccount', 3203 atID => { #10 (or TV series) 3204 Name => 'AlbumTitleID', 3205 Format => 'int32u', 3206 Writable => 'int32s', #27 3207 }, 3208 auth => { Name => 'Author', Groups => { 2 => 'Author' } }, 3209 catg => 'Category', #7 3210 cnID => { #10 3211 Name => 'AppleStoreCatalogID', 3212 Format => 'int32u', 3213 Writable => 'int32s', #27 3214 }, 3215 cprt => { Name => 'Copyright', Groups => { 2 => 'Author' } }, 3216 dscp => { Name => 'Description', Avoid => 1 }, 3217 desc => { Name => 'Description', Avoid => 1 }, #7 3218 gnre => { #10 3219 Name => 'Genre', 3220 Avoid => 1, 3221 # (Note: see https://exiftool.org/forum/index.php?topic=11537.0) 3222 Format => 'undef', 3223 ValueConv => 'unpack("n",$val)', 3224 ValueConvInv => '$val =~ /^\d+$/ ? pack("n",$val) : undef', 3225 PrintConv => q{ 3226 return $val unless $val =~ /^\d+$/; 3227 require Image::ExifTool::ID3; 3228 Image::ExifTool::ID3::PrintGenre($val - 1); # note the "- 1" 3229 }, 3230 PrintConvInv => q{ 3231 return $val if $val =~ /^[0-9]+$/; 3232 require Image::ExifTool::ID3; 3233 my $id = Image::ExifTool::ID3::GetGenreID($val); 3234 return unless defined $id and $id =~ /^\d+$/; 3235 return $id + 1; 3236 }, 3237 }, 3238 egid => 'EpisodeGlobalUniqueID', #7 3239 geID => { #10 3240 Name => 'GenreID', 3241 Format => 'int32u', 3242 Writable => 'int32s', #27 3243 SeparateTable => 1, 3244 # the following lookup is based on http://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/genres 3245 # (see scripts/parse_genre to parse genre JSON file from above) 3246 PrintConv => { #21/PH 3247 2 => 'Music|Blues', 3248 3 => 'Music|Comedy', 3249 4 => "Music|Children's Music", 3250 5 => 'Music|Classical', 3251 6 => 'Music|Country', 3252 7 => 'Music|Electronic', 3253 8 => 'Music|Holiday', 3254 9 => 'Music|Classical|Opera', 3255 10 => 'Music|Singer/Songwriter', 3256 11 => 'Music|Jazz', 3257 12 => 'Music|Latino', 3258 13 => 'Music|New Age', 3259 14 => 'Music|Pop', 3260 15 => 'Music|R&B/Soul', 3261 16 => 'Music|Soundtrack', 3262 17 => 'Music|Dance', 3263 18 => 'Music|Hip-Hop/Rap', 3264 19 => 'Music|World', 3265 20 => 'Music|Alternative', 3266 21 => 'Music|Rock', 3267 22 => 'Music|Christian & Gospel', 3268 23 => 'Music|Vocal', 3269 24 => 'Music|Reggae', 3270 25 => 'Music|Easy Listening', 3271 26 => 'Podcasts', 3272 27 => 'Music|J-Pop', 3273 28 => 'Music|Enka', 3274 29 => 'Music|Anime', 3275 30 => 'Music|Kayokyoku', 3276 31 => 'Music Videos', 3277 32 => 'TV Shows', 3278 33 => 'Movies', 3279 34 => 'Music', 3280 35 => 'iPod Games', 3281 36 => 'App Store', 3282 37 => 'Tones', 3283 38 => 'Books', 3284 39 => 'Mac App Store', 3285 40 => 'Textbooks', 3286 50 => 'Music|Fitness & Workout', 3287 51 => 'Music|Pop|K-Pop', 3288 52 => 'Music|Karaoke', 3289 53 => 'Music|Instrumental', 3290 74 => 'Audiobooks|News', 3291 75 => 'Audiobooks|Programs & Performances', 3292 500 => 'Fitness Music', 3293 501 => 'Fitness Music|Pop', 3294 502 => 'Fitness Music|Dance', 3295 503 => 'Fitness Music|Hip-Hop', 3296 504 => 'Fitness Music|Rock', 3297 505 => 'Fitness Music|Alt/Indie', 3298 506 => 'Fitness Music|Latino', 3299 507 => 'Fitness Music|Country', 3300 508 => 'Fitness Music|World', 3301 509 => 'Fitness Music|New Age', 3302 510 => 'Fitness Music|Classical', 3303 1001 => 'Music|Alternative|College Rock', 3304 1002 => 'Music|Alternative|Goth Rock', 3305 1003 => 'Music|Alternative|Grunge', 3306 1004 => 'Music|Alternative|Indie Rock', 3307 1005 => 'Music|Alternative|New Wave', 3308 1006 => 'Music|Alternative|Punk', 3309 1007 => 'Music|Blues|Chicago Blues', 3310 1009 => 'Music|Blues|Classic Blues', 3311 1010 => 'Music|Blues|Contemporary Blues', 3312 1011 => 'Music|Blues|Country Blues', 3313 1012 => 'Music|Blues|Delta Blues', 3314 1013 => 'Music|Blues|Electric Blues', 3315 1014 => "Music|Children's Music|Lullabies", 3316 1015 => "Music|Children's Music|Sing-Along", 3317 1016 => "Music|Children's Music|Stories", 3318 1017 => 'Music|Classical|Avant-Garde', 3319 1018 => 'Music|Classical|Baroque Era', 3320 1019 => 'Music|Classical|Chamber Music', 3321 1020 => 'Music|Classical|Chant', 3322 1021 => 'Music|Classical|Choral', 3323 1022 => 'Music|Classical|Classical Crossover', 3324 1023 => 'Music|Classical|Early Music', 3325 1024 => 'Music|Classical|Impressionist', 3326 1025 => 'Music|Classical|Medieval Era', 3327 1026 => 'Music|Classical|Minimalism', 3328 1027 => 'Music|Classical|Modern Era', 3329 1028 => 'Music|Classical|Opera', 3330 1029 => 'Music|Classical|Orchestral', 3331 1030 => 'Music|Classical|Renaissance', 3332 1031 => 'Music|Classical|Romantic Era', 3333 1032 => 'Music|Classical|Wedding Music', 3334 1033 => 'Music|Country|Alternative Country', 3335 1034 => 'Music|Country|Americana', 3336 1035 => 'Music|Country|Bluegrass', 3337 1036 => 'Music|Country|Contemporary Bluegrass', 3338 1037 => 'Music|Country|Contemporary Country', 3339 1038 => 'Music|Country|Country Gospel', 3340 1039 => 'Music|Country|Honky Tonk', 3341 1040 => 'Music|Country|Outlaw Country', 3342 1041 => 'Music|Country|Traditional Bluegrass', 3343 1042 => 'Music|Country|Traditional Country', 3344 1043 => 'Music|Country|Urban Cowboy', 3345 1044 => 'Music|Dance|Breakbeat', 3346 1045 => 'Music|Dance|Exercise', 3347 1046 => 'Music|Dance|Garage', 3348 1047 => 'Music|Dance|Hardcore', 3349 1048 => 'Music|Dance|House', 3350 1049 => "Music|Dance|Jungle/Drum'n'bass", 3351 1050 => 'Music|Dance|Techno', 3352 1051 => 'Music|Dance|Trance', 3353 1052 => 'Music|Jazz|Big Band', 3354 1053 => 'Music|Jazz|Bop', 3355 1054 => 'Music|Easy Listening|Lounge', 3356 1055 => 'Music|Easy Listening|Swing', 3357 1056 => 'Music|Electronic|Ambient', 3358 1057 => 'Music|Electronic|Downtempo', 3359 1058 => 'Music|Electronic|Electronica', 3360 1060 => 'Music|Electronic|IDM/Experimental', 3361 1061 => 'Music|Electronic|Industrial', 3362 1062 => 'Music|Singer/Songwriter|Alternative Folk', 3363 1063 => 'Music|Singer/Songwriter|Contemporary Folk', 3364 1064 => 'Music|Singer/Songwriter|Contemporary Singer/Songwriter', 3365 1065 => 'Music|Singer/Songwriter|Folk-Rock', 3366 1066 => 'Music|Singer/Songwriter|New Acoustic', 3367 1067 => 'Music|Singer/Songwriter|Traditional Folk', 3368 1068 => 'Music|Hip-Hop/Rap|Alternative Rap', 3369 1069 => 'Music|Hip-Hop/Rap|Dirty South', 3370 1070 => 'Music|Hip-Hop/Rap|East Coast Rap', 3371 1071 => 'Music|Hip-Hop/Rap|Gangsta Rap', 3372 1072 => 'Music|Hip-Hop/Rap|Hardcore Rap', 3373 1073 => 'Music|Hip-Hop/Rap|Hip-Hop', 3374 1074 => 'Music|Hip-Hop/Rap|Latin Rap', 3375 1075 => 'Music|Hip-Hop/Rap|Old School Rap', 3376 1076 => 'Music|Hip-Hop/Rap|Rap', 3377 1077 => 'Music|Hip-Hop/Rap|Underground Rap', 3378 1078 => 'Music|Hip-Hop/Rap|West Coast Rap', 3379 1079 => 'Music|Holiday|Chanukah', 3380 1080 => 'Music|Holiday|Christmas', 3381 1081 => "Music|Holiday|Christmas: Children's", 3382 1082 => 'Music|Holiday|Christmas: Classic', 3383 1083 => 'Music|Holiday|Christmas: Classical', 3384 1084 => 'Music|Holiday|Christmas: Jazz', 3385 1085 => 'Music|Holiday|Christmas: Modern', 3386 1086 => 'Music|Holiday|Christmas: Pop', 3387 1087 => 'Music|Holiday|Christmas: R&B', 3388 1088 => 'Music|Holiday|Christmas: Religious', 3389 1089 => 'Music|Holiday|Christmas: Rock', 3390 1090 => 'Music|Holiday|Easter', 3391 1091 => 'Music|Holiday|Halloween', 3392 1092 => 'Music|Holiday|Holiday: Other', 3393 1093 => 'Music|Holiday|Thanksgiving', 3394 1094 => 'Music|Christian & Gospel|CCM', 3395 1095 => 'Music|Christian & Gospel|Christian Metal', 3396 1096 => 'Music|Christian & Gospel|Christian Pop', 3397 1097 => 'Music|Christian & Gospel|Christian Rap', 3398 1098 => 'Music|Christian & Gospel|Christian Rock', 3399 1099 => 'Music|Christian & Gospel|Classic Christian', 3400 1100 => 'Music|Christian & Gospel|Contemporary Gospel', 3401 1101 => 'Music|Christian & Gospel|Gospel', 3402 1103 => 'Music|Christian & Gospel|Praise & Worship', 3403 1104 => 'Music|Christian & Gospel|Southern Gospel', 3404 1105 => 'Music|Christian & Gospel|Traditional Gospel', 3405 1106 => 'Music|Jazz|Avant-Garde Jazz', 3406 1107 => 'Music|Jazz|Contemporary Jazz', 3407 1108 => 'Music|Jazz|Crossover Jazz', 3408 1109 => 'Music|Jazz|Dixieland', 3409 1110 => 'Music|Jazz|Fusion', 3410 1111 => 'Music|Jazz|Latin Jazz', 3411 1112 => 'Music|Jazz|Mainstream Jazz', 3412 1113 => 'Music|Jazz|Ragtime', 3413 1114 => 'Music|Jazz|Smooth Jazz', 3414 1115 => 'Music|Latino|Latin Jazz', 3415 1116 => 'Music|Latino|Contemporary Latin', 3416 1117 => 'Music|Latino|Pop Latino', 3417 1118 => 'Music|Latino|Raices', # (Raíces) 3418 1119 => 'Music|Latino|Urbano latino', 3419 1120 => 'Music|Latino|Baladas y Boleros', 3420 1121 => 'Music|Latino|Rock y Alternativo', 3421 1122 => 'Music|Brazilian', 3422 1123 => 'Music|Latino|Musica Mexicana', # (Música Mexicana) 3423 1124 => 'Music|Latino|Musica tropical', # (Música tropical) 3424 1125 => 'Music|New Age|Environmental', 3425 1126 => 'Music|New Age|Healing', 3426 1127 => 'Music|New Age|Meditation', 3427 1128 => 'Music|New Age|Nature', 3428 1129 => 'Music|New Age|Relaxation', 3429 1130 => 'Music|New Age|Travel', 3430 1131 => 'Music|Pop|Adult Contemporary', 3431 1132 => 'Music|Pop|Britpop', 3432 1133 => 'Music|Pop|Pop/Rock', 3433 1134 => 'Music|Pop|Soft Rock', 3434 1135 => 'Music|Pop|Teen Pop', 3435 1136 => 'Music|R&B/Soul|Contemporary R&B', 3436 1137 => 'Music|R&B/Soul|Disco', 3437 1138 => 'Music|R&B/Soul|Doo Wop', 3438 1139 => 'Music|R&B/Soul|Funk', 3439 1140 => 'Music|R&B/Soul|Motown', 3440 1141 => 'Music|R&B/Soul|Neo-Soul', 3441 1142 => 'Music|R&B/Soul|Quiet Storm', 3442 1143 => 'Music|R&B/Soul|Soul', 3443 1144 => 'Music|Rock|Adult Alternative', 3444 1145 => 'Music|Rock|American Trad Rock', 3445 1146 => 'Music|Rock|Arena Rock', 3446 1147 => 'Music|Rock|Blues-Rock', 3447 1148 => 'Music|Rock|British Invasion', 3448 1149 => 'Music|Rock|Death Metal/Black Metal', 3449 1150 => 'Music|Rock|Glam Rock', 3450 1151 => 'Music|Rock|Hair Metal', 3451 1152 => 'Music|Rock|Hard Rock', 3452 1153 => 'Music|Rock|Metal', 3453 1154 => 'Music|Rock|Jam Bands', 3454 1155 => 'Music|Rock|Prog-Rock/Art Rock', 3455 1156 => 'Music|Rock|Psychedelic', 3456 1157 => 'Music|Rock|Rock & Roll', 3457 1158 => 'Music|Rock|Rockabilly', 3458 1159 => 'Music|Rock|Roots Rock', 3459 1160 => 'Music|Rock|Singer/Songwriter', 3460 1161 => 'Music|Rock|Southern Rock', 3461 1162 => 'Music|Rock|Surf', 3462 1163 => 'Music|Rock|Tex-Mex', 3463 1165 => 'Music|Soundtrack|Foreign Cinema', 3464 1166 => 'Music|Soundtrack|Musicals', 3465 1167 => 'Music|Comedy|Novelty', 3466 1168 => 'Music|Soundtrack|Original Score', 3467 1169 => 'Music|Soundtrack|Soundtrack', 3468 1171 => 'Music|Comedy|Standup Comedy', 3469 1172 => 'Music|Soundtrack|TV Soundtrack', 3470 1173 => 'Music|Vocal|Standards', 3471 1174 => 'Music|Vocal|Traditional Pop', 3472 1175 => 'Music|Jazz|Vocal Jazz', 3473 1176 => 'Music|Vocal|Vocal Pop', 3474 1177 => 'Music|African|Afro-Beat', 3475 1178 => 'Music|African|Afro-Pop', 3476 1179 => 'Music|World|Cajun', 3477 1180 => 'Music|World|Celtic', 3478 1181 => 'Music|World|Celtic Folk', 3479 1182 => 'Music|World|Contemporary Celtic', 3480 1183 => 'Music|Reggae|Modern Dancehall', 3481 1184 => 'Music|World|Drinking Songs', 3482 1185 => 'Music|Indian|Indian Pop', 3483 1186 => 'Music|World|Japanese Pop', 3484 1187 => 'Music|World|Klezmer', 3485 1188 => 'Music|World|Polka', 3486 1189 => 'Music|World|Traditional Celtic', 3487 1190 => 'Music|World|Worldbeat', 3488 1191 => 'Music|World|Zydeco', 3489 1192 => 'Music|Reggae|Roots Reggae', 3490 1193 => 'Music|Reggae|Dub', 3491 1194 => 'Music|Reggae|Ska', 3492 1195 => 'Music|World|Caribbean', 3493 1196 => 'Music|World|South America', 3494 1197 => 'Music|Arabic', 3495 1198 => 'Music|World|North America', 3496 1199 => 'Music|World|Hawaii', 3497 1200 => 'Music|World|Australia', 3498 1201 => 'Music|World|Japan', 3499 1202 => 'Music|World|France', 3500 1203 => 'Music|African', 3501 1204 => 'Music|World|Asia', 3502 1205 => 'Music|World|Europe', 3503 1206 => 'Music|World|South Africa', 3504 1207 => 'Music|Jazz|Hard Bop', 3505 1208 => 'Music|Jazz|Trad Jazz', 3506 1209 => 'Music|Jazz|Cool Jazz', 3507 1210 => 'Music|Blues|Acoustic Blues', 3508 1211 => 'Music|Classical|High Classical', 3509 1220 => 'Music|Brazilian|Axe', # (Axé) 3510 1221 => 'Music|Brazilian|Bossa Nova', 3511 1222 => 'Music|Brazilian|Choro', 3512 1223 => 'Music|Brazilian|Forro', # (Forró) 3513 1224 => 'Music|Brazilian|Frevo', 3514 1225 => 'Music|Brazilian|MPB', 3515 1226 => 'Music|Brazilian|Pagode', 3516 1227 => 'Music|Brazilian|Samba', 3517 1228 => 'Music|Brazilian|Sertanejo', 3518 1229 => 'Music|Brazilian|Baile Funk', 3519 1230 => 'Music|Alternative|Chinese Alt', 3520 1231 => 'Music|Alternative|Korean Indie', 3521 1232 => 'Music|Chinese', 3522 1233 => 'Music|Chinese|Chinese Classical', 3523 1234 => 'Music|Chinese|Chinese Flute', 3524 1235 => 'Music|Chinese|Chinese Opera', 3525 1236 => 'Music|Chinese|Chinese Orchestral', 3526 1237 => 'Music|Chinese|Chinese Regional Folk', 3527 1238 => 'Music|Chinese|Chinese Strings', 3528 1239 => 'Music|Chinese|Taiwanese Folk', 3529 1240 => 'Music|Chinese|Tibetan Native Music', 3530 1241 => 'Music|Hip-Hop/Rap|Chinese Hip-Hop', 3531 1242 => 'Music|Hip-Hop/Rap|Korean Hip-Hop', 3532 1243 => 'Music|Korean', 3533 1244 => 'Music|Korean|Korean Classical', 3534 1245 => 'Music|Korean|Korean Trad Song', 3535 1246 => 'Music|Korean|Korean Trad Instrumental', 3536 1247 => 'Music|Korean|Korean Trad Theater', 3537 1248 => 'Music|Rock|Chinese Rock', 3538 1249 => 'Music|Rock|Korean Rock', 3539 1250 => 'Music|Pop|C-Pop', 3540 1251 => 'Music|Pop|Cantopop/HK-Pop', 3541 1252 => 'Music|Pop|Korean Folk-Pop', 3542 1253 => 'Music|Pop|Mandopop', 3543 1254 => 'Music|Pop|Tai-Pop', 3544 1255 => 'Music|Pop|Malaysian Pop', 3545 1256 => 'Music|Pop|Pinoy Pop', 3546 1257 => 'Music|Pop|Original Pilipino Music', 3547 1258 => 'Music|Pop|Manilla Sound', 3548 1259 => 'Music|Pop|Indo Pop', 3549 1260 => 'Music|Pop|Thai Pop', 3550 1261 => 'Music|Vocal|Trot', 3551 1262 => 'Music|Indian', 3552 1263 => 'Music|Indian|Bollywood', 3553 1264 => 'Music|Indian|Regional Indian|Tamil', 3554 1265 => 'Music|Indian|Regional Indian|Telugu', 3555 1266 => 'Music|Indian|Regional Indian', 3556 1267 => 'Music|Indian|Devotional & Spiritual', 3557 1268 => 'Music|Indian|Sufi', 3558 1269 => 'Music|Indian|Indian Classical', 3559 1270 => 'Music|Russian|Russian Chanson', 3560 1271 => 'Music|World|Dini', 3561 1272 => 'Music|Turkish|Halk', 3562 1273 => 'Music|Turkish|Sanat', 3563 1274 => 'Music|World|Dangdut', 3564 1275 => 'Music|World|Indonesian Religious', 3565 1276 => 'Music|World|Calypso', 3566 1277 => 'Music|World|Soca', 3567 1278 => 'Music|Indian|Ghazals', 3568 1279 => 'Music|Indian|Indian Folk', 3569 1280 => 'Music|Turkish|Arabesque', 3570 1281 => 'Music|African|Afrikaans', 3571 1282 => 'Music|World|Farsi', 3572 1283 => 'Music|World|Israeli', 3573 1284 => 'Music|Arabic|Khaleeji', 3574 1285 => 'Music|Arabic|North African', 3575 1286 => 'Music|Arabic|Arabic Pop', 3576 1287 => 'Music|Arabic|Islamic', 3577 1288 => 'Music|Soundtrack|Sound Effects', 3578 1289 => 'Music|Folk', 3579 1290 => 'Music|Orchestral', 3580 1291 => 'Music|Marching', 3581 1293 => 'Music|Pop|Oldies', 3582 1294 => 'Music|Country|Thai Country', 3583 1295 => 'Music|World|Flamenco', 3584 1296 => 'Music|World|Tango', 3585 1297 => 'Music|World|Fado', 3586 1298 => 'Music|World|Iberia', 3587 1299 => 'Music|Russian', 3588 1300 => 'Music|Turkish', 3589 1301 => 'Podcasts|Arts', 3590 1302 => 'Podcasts|Society & Culture|Personal Journals', 3591 1303 => 'Podcasts|Comedy', 3592 1304 => 'Podcasts|Education', 3593 1305 => 'Podcasts|Kids & Family', 3594 1306 => 'Podcasts|Arts|Food', 3595 1307 => 'Podcasts|Health', 3596 1309 => 'Podcasts|TV & Film', 3597 1310 => 'Podcasts|Music', 3598 1311 => 'Podcasts|News & Politics', 3599 1314 => 'Podcasts|Religion & Spirituality', 3600 1315 => 'Podcasts|Science & Medicine', 3601 1316 => 'Podcasts|Sports & Recreation', 3602 1318 => 'Podcasts|Technology', 3603 1320 => 'Podcasts|Society & Culture|Places & Travel', 3604 1321 => 'Podcasts|Business', 3605 1323 => 'Podcasts|Games & Hobbies', 3606 1324 => 'Podcasts|Society & Culture', 3607 1325 => 'Podcasts|Government & Organizations', 3608 1337 => 'Music Videos|Classical|Piano', 3609 1401 => 'Podcasts|Arts|Literature', 3610 1402 => 'Podcasts|Arts|Design', 3611 1404 => 'Podcasts|Games & Hobbies|Video Games', 3612 1405 => 'Podcasts|Arts|Performing Arts', 3613 1406 => 'Podcasts|Arts|Visual Arts', 3614 1410 => 'Podcasts|Business|Careers', 3615 1412 => 'Podcasts|Business|Investing', 3616 1413 => 'Podcasts|Business|Management & Marketing', 3617 1415 => 'Podcasts|Education|K-12', 3618 1416 => 'Podcasts|Education|Higher Education', 3619 1417 => 'Podcasts|Health|Fitness & Nutrition', 3620 1420 => 'Podcasts|Health|Self-Help', 3621 1421 => 'Podcasts|Health|Sexuality', 3622 1438 => 'Podcasts|Religion & Spirituality|Buddhism', 3623 1439 => 'Podcasts|Religion & Spirituality|Christianity', 3624 1440 => 'Podcasts|Religion & Spirituality|Islam', 3625 1441 => 'Podcasts|Religion & Spirituality|Judaism', 3626 1443 => 'Podcasts|Society & Culture|Philosophy', 3627 1444 => 'Podcasts|Religion & Spirituality|Spirituality', 3628 1446 => 'Podcasts|Technology|Gadgets', 3629 1448 => 'Podcasts|Technology|Tech News', 3630 1450 => 'Podcasts|Technology|Podcasting', 3631 1454 => 'Podcasts|Games & Hobbies|Automotive', 3632 1455 => 'Podcasts|Games & Hobbies|Aviation', 3633 1456 => 'Podcasts|Sports & Recreation|Outdoor', 3634 1459 => 'Podcasts|Arts|Fashion & Beauty', 3635 1460 => 'Podcasts|Games & Hobbies|Hobbies', 3636 1461 => 'Podcasts|Games & Hobbies|Other Games', 3637 1462 => 'Podcasts|Society & Culture|History', 3638 1463 => 'Podcasts|Religion & Spirituality|Hinduism', 3639 1464 => 'Podcasts|Religion & Spirituality|Other', 3640 1465 => 'Podcasts|Sports & Recreation|Professional', 3641 1466 => 'Podcasts|Sports & Recreation|College & High School', 3642 1467 => 'Podcasts|Sports & Recreation|Amateur', 3643 1468 => 'Podcasts|Education|Educational Technology', 3644 1469 => 'Podcasts|Education|Language Courses', 3645 1470 => 'Podcasts|Education|Training', 3646 1471 => 'Podcasts|Business|Business News', 3647 1472 => 'Podcasts|Business|Shopping', 3648 1473 => 'Podcasts|Government & Organizations|National', 3649 1474 => 'Podcasts|Government & Organizations|Regional', 3650 1475 => 'Podcasts|Government & Organizations|Local', 3651 1476 => 'Podcasts|Government & Organizations|Non-Profit', 3652 1477 => 'Podcasts|Science & Medicine|Natural Sciences', 3653 1478 => 'Podcasts|Science & Medicine|Medicine', 3654 1479 => 'Podcasts|Science & Medicine|Social Sciences', 3655 1480 => 'Podcasts|Technology|Software How-To', 3656 1481 => 'Podcasts|Health|Alternative Health', 3657 1482 => 'Podcasts|Arts|Books', 3658 1483 => 'Podcasts|Fiction', 3659 1484 => 'Podcasts|Fiction|Drama', 3660 1485 => 'Podcasts|Fiction|Science Fiction', 3661 1486 => 'Podcasts|Fiction|Comedy Fiction', 3662 1487 => 'Podcasts|History', 3663 1488 => 'Podcasts|True Crime', 3664 1489 => 'Podcasts|News', 3665 1490 => 'Podcasts|News|Business News', 3666 1491 => 'Podcasts|Business|Management', 3667 1492 => 'Podcasts|Business|Marketing', 3668 1493 => 'Podcasts|Business|Entrepreneurship', 3669 1494 => 'Podcasts|Business|Non-Profit', 3670 1495 => 'Podcasts|Comedy|Improv', 3671 1496 => 'Podcasts|Comedy|Comedy Interviews', 3672 1497 => 'Podcasts|Comedy|Stand-Up', 3673 1498 => 'Podcasts|Education|Language Learning', 3674 1499 => 'Podcasts|Education|How To', 3675 1500 => 'Podcasts|Education|Self-Improvement', 3676 1501 => 'Podcasts|Education|Courses', 3677 1502 => 'Podcasts|Leisure', 3678 1503 => 'Podcasts|Leisure|Automotive', 3679 1504 => 'Podcasts|Leisure|Aviation', 3680 1505 => 'Podcasts|Leisure|Hobbies', 3681 1506 => 'Podcasts|Leisure|Crafts', 3682 1507 => 'Podcasts|Leisure|Games', 3683 1508 => 'Podcasts|Leisure|Home & Garden', 3684 1509 => 'Podcasts|Leisure|Video Games', 3685 1510 => 'Podcasts|Leisure|Animation & Manga', 3686 1511 => 'Podcasts|Government', 3687 1512 => 'Podcasts|Health & Fitness', 3688 1513 => 'Podcasts|Health & Fitness|Alternative Health', 3689 1514 => 'Podcasts|Health & Fitness|Fitness', 3690 1515 => 'Podcasts|Health & Fitness|Nutrition', 3691 1516 => 'Podcasts|Health & Fitness|Sexuality', 3692 1517 => 'Podcasts|Health & Fitness|Mental Health', 3693 1518 => 'Podcasts|Health & Fitness|Medicine', 3694 1519 => 'Podcasts|Kids & Family|Education for Kids', 3695 1520 => 'Podcasts|Kids & Family|Stories for Kids', 3696 1521 => 'Podcasts|Kids & Family|Parenting', 3697 1522 => 'Podcasts|Kids & Family|Pets & Animals', 3698 1523 => 'Podcasts|Music|Music Commentary', 3699 1524 => 'Podcasts|Music|Music History', 3700 1525 => 'Podcasts|Music|Music Interviews', 3701 1526 => 'Podcasts|News|Daily News', 3702 1527 => 'Podcasts|News|Politics', 3703 1528 => 'Podcasts|News|Tech News', 3704 1529 => 'Podcasts|News|Sports News', 3705 1530 => 'Podcasts|News|News Commentary', 3706 1531 => 'Podcasts|News|Entertainment News', 3707 1532 => 'Podcasts|Religion & Spirituality|Religion', 3708 1533 => 'Podcasts|Science', 3709 1534 => 'Podcasts|Science|Natural Sciences', 3710 1535 => 'Podcasts|Science|Social Sciences', 3711 1536 => 'Podcasts|Science|Mathematics', 3712 1537 => 'Podcasts|Science|Nature', 3713 1538 => 'Podcasts|Science|Astronomy', 3714 1539 => 'Podcasts|Science|Chemistry', 3715 1540 => 'Podcasts|Science|Earth Sciences', 3716 1541 => 'Podcasts|Science|Life Sciences', 3717 1542 => 'Podcasts|Science|Physics', 3718 1543 => 'Podcasts|Society & Culture|Documentary', 3719 1544 => 'Podcasts|Society & Culture|Relationships', 3720 1545 => 'Podcasts|Sports', 3721 1546 => 'Podcasts|Sports|Soccer', 3722 1547 => 'Podcasts|Sports|Football', 3723 1548 => 'Podcasts|Sports|Basketball', 3724 1549 => 'Podcasts|Sports|Baseball', 3725 1550 => 'Podcasts|Sports|Hockey', 3726 1551 => 'Podcasts|Sports|Running', 3727 1552 => 'Podcasts|Sports|Rugby', 3728 1553 => 'Podcasts|Sports|Golf', 3729 1554 => 'Podcasts|Sports|Cricket', 3730 1555 => 'Podcasts|Sports|Wrestling', 3731 1556 => 'Podcasts|Sports|Tennis', 3732 1557 => 'Podcasts|Sports|Volleyball', 3733 1558 => 'Podcasts|Sports|Swimming', 3734 1559 => 'Podcasts|Sports|Wilderness', 3735 1560 => 'Podcasts|Sports|Fantasy Sports', 3736 1561 => 'Podcasts|TV & Film|TV Reviews', 3737 1562 => 'Podcasts|TV & Film|After Shows', 3738 1563 => 'Podcasts|TV & Film|Film Reviews', 3739 1564 => 'Podcasts|TV & Film|Film History', 3740 1565 => 'Podcasts|TV & Film|Film Interviews', 3741 1602 => 'Music Videos|Blues', 3742 1603 => 'Music Videos|Comedy', 3743 1604 => "Music Videos|Children's Music", 3744 1605 => 'Music Videos|Classical', 3745 1606 => 'Music Videos|Country', 3746 1607 => 'Music Videos|Electronic', 3747 1608 => 'Music Videos|Holiday', 3748 1609 => 'Music Videos|Classical|Opera', 3749 1610 => 'Music Videos|Singer/Songwriter', 3750 1611 => 'Music Videos|Jazz', 3751 1612 => 'Music Videos|Latin', 3752 1613 => 'Music Videos|New Age', 3753 1614 => 'Music Videos|Pop', 3754 1615 => 'Music Videos|R&B/Soul', 3755 1616 => 'Music Videos|Soundtrack', 3756 1617 => 'Music Videos|Dance', 3757 1618 => 'Music Videos|Hip-Hop/Rap', 3758 1619 => 'Music Videos|World', 3759 1620 => 'Music Videos|Alternative', 3760 1621 => 'Music Videos|Rock', 3761 1622 => 'Music Videos|Christian & Gospel', 3762 1623 => 'Music Videos|Vocal', 3763 1624 => 'Music Videos|Reggae', 3764 1625 => 'Music Videos|Easy Listening', 3765 1626 => 'Music Videos|Podcasts', 3766 1627 => 'Music Videos|J-Pop', 3767 1628 => 'Music Videos|Enka', 3768 1629 => 'Music Videos|Anime', 3769 1630 => 'Music Videos|Kayokyoku', 3770 1631 => 'Music Videos|Disney', 3771 1632 => 'Music Videos|French Pop', 3772 1633 => 'Music Videos|German Pop', 3773 1634 => 'Music Videos|German Folk', 3774 1635 => 'Music Videos|Alternative|Chinese Alt', 3775 1636 => 'Music Videos|Alternative|Korean Indie', 3776 1637 => 'Music Videos|Chinese', 3777 1638 => 'Music Videos|Chinese|Chinese Classical', 3778 1639 => 'Music Videos|Chinese|Chinese Flute', 3779 1640 => 'Music Videos|Chinese|Chinese Opera', 3780 1641 => 'Music Videos|Chinese|Chinese Orchestral', 3781 1642 => 'Music Videos|Chinese|Chinese Regional Folk', 3782 1643 => 'Music Videos|Chinese|Chinese Strings', 3783 1644 => 'Music Videos|Chinese|Taiwanese Folk', 3784 1645 => 'Music Videos|Chinese|Tibetan Native Music', 3785 1646 => 'Music Videos|Hip-Hop/Rap|Chinese Hip-Hop', 3786 1647 => 'Music Videos|Hip-Hop/Rap|Korean Hip-Hop', 3787 1648 => 'Music Videos|Korean', 3788 1649 => 'Music Videos|Korean|Korean Classical', 3789 1650 => 'Music Videos|Korean|Korean Trad Song', 3790 1651 => 'Music Videos|Korean|Korean Trad Instrumental', 3791 1652 => 'Music Videos|Korean|Korean Trad Theater', 3792 1653 => 'Music Videos|Rock|Chinese Rock', 3793 1654 => 'Music Videos|Rock|Korean Rock', 3794 1655 => 'Music Videos|Pop|C-Pop', 3795 1656 => 'Music Videos|Pop|Cantopop/HK-Pop', 3796 1657 => 'Music Videos|Pop|Korean Folk-Pop', 3797 1658 => 'Music Videos|Pop|Mandopop', 3798 1659 => 'Music Videos|Pop|Tai-Pop', 3799 1660 => 'Music Videos|Pop|Malaysian Pop', 3800 1661 => 'Music Videos|Pop|Pinoy Pop', 3801 1662 => 'Music Videos|Pop|Original Pilipino Music', 3802 1663 => 'Music Videos|Pop|Manilla Sound', 3803 1664 => 'Music Videos|Pop|Indo Pop', 3804 1665 => 'Music Videos|Pop|Thai Pop', 3805 1666 => 'Music Videos|Vocal|Trot', 3806 1671 => 'Music Videos|Brazilian', 3807 1672 => 'Music Videos|Brazilian|Axe', # (Axé) 3808 1673 => 'Music Videos|Brazilian|Baile Funk', 3809 1674 => 'Music Videos|Brazilian|Bossa Nova', 3810 1675 => 'Music Videos|Brazilian|Choro', 3811 1676 => 'Music Videos|Brazilian|Forro', 3812 1677 => 'Music Videos|Brazilian|Frevo', 3813 1678 => 'Music Videos|Brazilian|MPB', 3814 1679 => 'Music Videos|Brazilian|Pagode', 3815 1680 => 'Music Videos|Brazilian|Samba', 3816 1681 => 'Music Videos|Brazilian|Sertanejo', 3817 1682 => 'Music Videos|Classical|High Classical', 3818 1683 => 'Music Videos|Fitness & Workout', 3819 1684 => 'Music Videos|Instrumental', 3820 1685 => 'Music Videos|Jazz|Big Band', 3821 1686 => 'Music Videos|Pop|K-Pop', 3822 1687 => 'Music Videos|Karaoke', 3823 1688 => 'Music Videos|Rock|Heavy Metal', 3824 1689 => 'Music Videos|Spoken Word', 3825 1690 => 'Music Videos|Indian', 3826 1691 => 'Music Videos|Indian|Bollywood', 3827 1692 => 'Music Videos|Indian|Regional Indian|Tamil', 3828 1693 => 'Music Videos|Indian|Regional Indian|Telugu', 3829 1694 => 'Music Videos|Indian|Regional Indian', 3830 1695 => 'Music Videos|Indian|Devotional & Spiritual', 3831 1696 => 'Music Videos|Indian|Sufi', 3832 1697 => 'Music Videos|Indian|Indian Classical', 3833 1698 => 'Music Videos|Russian|Russian Chanson', 3834 1699 => 'Music Videos|World|Dini', 3835 1700 => 'Music Videos|Turkish|Halk', 3836 1701 => 'Music Videos|Turkish|Sanat', 3837 1702 => 'Music Videos|World|Dangdut', 3838 1703 => 'Music Videos|World|Indonesian Religious', 3839 1704 => 'Music Videos|Indian|Indian Pop', 3840 1705 => 'Music Videos|World|Calypso', 3841 1706 => 'Music Videos|World|Soca', 3842 1707 => 'Music Videos|Indian|Ghazals', 3843 1708 => 'Music Videos|Indian|Indian Folk', 3844 1709 => 'Music Videos|Turkish|Arabesque', 3845 1710 => 'Music Videos|African|Afrikaans', 3846 1711 => 'Music Videos|World|Farsi', 3847 1712 => 'Music Videos|World|Israeli', 3848 1713 => 'Music Videos|Arabic', 3849 1714 => 'Music Videos|Arabic|Khaleeji', 3850 1715 => 'Music Videos|Arabic|North African', 3851 1716 => 'Music Videos|Arabic|Arabic Pop', 3852 1717 => 'Music Videos|Arabic|Islamic', 3853 1718 => 'Music Videos|Soundtrack|Sound Effects', 3854 1719 => 'Music Videos|Folk', 3855 1720 => 'Music Videos|Orchestral', 3856 1721 => 'Music Videos|Marching', 3857 1723 => 'Music Videos|Pop|Oldies', 3858 1724 => 'Music Videos|Country|Thai Country', 3859 1725 => 'Music Videos|World|Flamenco', 3860 1726 => 'Music Videos|World|Tango', 3861 1727 => 'Music Videos|World|Fado', 3862 1728 => 'Music Videos|World|Iberia', 3863 1729 => 'Music Videos|Russian', 3864 1730 => 'Music Videos|Turkish', 3865 1731 => 'Music Videos|Alternative|College Rock', 3866 1732 => 'Music Videos|Alternative|Goth Rock', 3867 1733 => 'Music Videos|Alternative|Grunge', 3868 1734 => 'Music Videos|Alternative|Indie Rock', 3869 1735 => 'Music Videos|Alternative|New Wave', 3870 1736 => 'Music Videos|Alternative|Punk', 3871 1737 => 'Music Videos|Blues|Acoustic Blues', 3872 1738 => 'Music Videos|Blues|Chicago Blues', 3873 1739 => 'Music Videos|Blues|Classic Blues', 3874 1740 => 'Music Videos|Blues|Contemporary Blues', 3875 1741 => 'Music Videos|Blues|Country Blues', 3876 1742 => 'Music Videos|Blues|Delta Blues', 3877 1743 => 'Music Videos|Blues|Electric Blues', 3878 1744 => "Music Videos|Children's Music|Lullabies", 3879 1745 => "Music Videos|Children's Music|Sing-Along", 3880 1746 => "Music Videos|Children's Music|Stories", 3881 1747 => 'Music Videos|Christian & Gospel|CCM', 3882 1748 => 'Music Videos|Christian & Gospel|Christian Metal', 3883 1749 => 'Music Videos|Christian & Gospel|Christian Pop', 3884 1750 => 'Music Videos|Christian & Gospel|Christian Rap', 3885 1751 => 'Music Videos|Christian & Gospel|Christian Rock', 3886 1752 => 'Music Videos|Christian & Gospel|Classic Christian', 3887 1753 => 'Music Videos|Christian & Gospel|Contemporary Gospel', 3888 1754 => 'Music Videos|Christian & Gospel|Gospel', 3889 1755 => 'Music Videos|Christian & Gospel|Praise & Worship', 3890 1756 => 'Music Videos|Christian & Gospel|Southern Gospel', 3891 1757 => 'Music Videos|Christian & Gospel|Traditional Gospel', 3892 1758 => 'Music Videos|Classical|Avant-Garde', 3893 1759 => 'Music Videos|Classical|Baroque Era', 3894 1760 => 'Music Videos|Classical|Chamber Music', 3895 1761 => 'Music Videos|Classical|Chant', 3896 1762 => 'Music Videos|Classical|Choral', 3897 1763 => 'Music Videos|Classical|Classical Crossover', 3898 1764 => 'Music Videos|Classical|Early Music', 3899 1765 => 'Music Videos|Classical|Impressionist', 3900 1766 => 'Music Videos|Classical|Medieval Era', 3901 1767 => 'Music Videos|Classical|Minimalism', 3902 1768 => 'Music Videos|Classical|Modern Era', 3903 1769 => 'Music Videos|Classical|Orchestral', 3904 1770 => 'Music Videos|Classical|Renaissance', 3905 1771 => 'Music Videos|Classical|Romantic Era', 3906 1772 => 'Music Videos|Classical|Wedding Music', 3907 1773 => 'Music Videos|Comedy|Novelty', 3908 1774 => 'Music Videos|Comedy|Standup Comedy', 3909 1775 => 'Music Videos|Country|Alternative Country', 3910 1776 => 'Music Videos|Country|Americana', 3911 1777 => 'Music Videos|Country|Bluegrass', 3912 1778 => 'Music Videos|Country|Contemporary Bluegrass', 3913 1779 => 'Music Videos|Country|Contemporary Country', 3914 1780 => 'Music Videos|Country|Country Gospel', 3915 1781 => 'Music Videos|Country|Honky Tonk', 3916 1782 => 'Music Videos|Country|Outlaw Country', 3917 1783 => 'Music Videos|Country|Traditional Bluegrass', 3918 1784 => 'Music Videos|Country|Traditional Country', 3919 1785 => 'Music Videos|Country|Urban Cowboy', 3920 1786 => 'Music Videos|Dance|Breakbeat', 3921 1787 => 'Music Videos|Dance|Exercise', 3922 1788 => 'Music Videos|Dance|Garage', 3923 1789 => 'Music Videos|Dance|Hardcore', 3924 1790 => 'Music Videos|Dance|House', 3925 1791 => "Music Videos|Dance|Jungle/Drum'n'bass", 3926 1792 => 'Music Videos|Dance|Techno', 3927 1793 => 'Music Videos|Dance|Trance', 3928 1794 => 'Music Videos|Easy Listening|Lounge', 3929 1795 => 'Music Videos|Easy Listening|Swing', 3930 1796 => 'Music Videos|Electronic|Ambient', 3931 1797 => 'Music Videos|Electronic|Downtempo', 3932 1798 => 'Music Videos|Electronic|Electronica', 3933 1799 => 'Music Videos|Electronic|IDM/Experimental', 3934 1800 => 'Music Videos|Electronic|Industrial', 3935 1801 => 'Music Videos|Hip-Hop/Rap|Alternative Rap', 3936 1802 => 'Music Videos|Hip-Hop/Rap|Dirty South', 3937 1803 => 'Music Videos|Hip-Hop/Rap|East Coast Rap', 3938 1804 => 'Music Videos|Hip-Hop/Rap|Gangsta Rap', 3939 1805 => 'Music Videos|Hip-Hop/Rap|Hardcore Rap', 3940 1806 => 'Music Videos|Hip-Hop/Rap|Hip-Hop', 3941 1807 => 'Music Videos|Hip-Hop/Rap|Latin Rap', 3942 1808 => 'Music Videos|Hip-Hop/Rap|Old School Rap', 3943 1809 => 'Music Videos|Hip-Hop/Rap|Rap', 3944 1810 => 'Music Videos|Hip-Hop/Rap|Underground Rap', 3945 1811 => 'Music Videos|Hip-Hop/Rap|West Coast Rap', 3946 1812 => 'Music Videos|Holiday|Chanukah', 3947 1813 => 'Music Videos|Holiday|Christmas', 3948 1814 => "Music Videos|Holiday|Christmas: Children's", 3949 1815 => 'Music Videos|Holiday|Christmas: Classic', 3950 1816 => 'Music Videos|Holiday|Christmas: Classical', 3951 1817 => 'Music Videos|Holiday|Christmas: Jazz', 3952 1818 => 'Music Videos|Holiday|Christmas: Modern', 3953 1819 => 'Music Videos|Holiday|Christmas: Pop', 3954 1820 => 'Music Videos|Holiday|Christmas: R&B', 3955 1821 => 'Music Videos|Holiday|Christmas: Religious', 3956 1822 => 'Music Videos|Holiday|Christmas: Rock', 3957 1823 => 'Music Videos|Holiday|Easter', 3958 1824 => 'Music Videos|Holiday|Halloween', 3959 1825 => 'Music Videos|Holiday|Thanksgiving', 3960 1826 => 'Music Videos|Jazz|Avant-Garde Jazz', 3961 1828 => 'Music Videos|Jazz|Bop', 3962 1829 => 'Music Videos|Jazz|Contemporary Jazz', 3963 1830 => 'Music Videos|Jazz|Cool Jazz', 3964 1831 => 'Music Videos|Jazz|Crossover Jazz', 3965 1832 => 'Music Videos|Jazz|Dixieland', 3966 1833 => 'Music Videos|Jazz|Fusion', 3967 1834 => 'Music Videos|Jazz|Hard Bop', 3968 1835 => 'Music Videos|Jazz|Latin Jazz', 3969 1836 => 'Music Videos|Jazz|Mainstream Jazz', 3970 1837 => 'Music Videos|Jazz|Ragtime', 3971 1838 => 'Music Videos|Jazz|Smooth Jazz', 3972 1839 => 'Music Videos|Jazz|Trad Jazz', 3973 1840 => 'Music Videos|Latin|Alternative & Rock in Spanish', 3974 1841 => 'Music Videos|Latin|Baladas y Boleros', 3975 1842 => 'Music Videos|Latin|Contemporary Latin', 3976 1843 => 'Music Videos|Latin|Latin Jazz', 3977 1844 => 'Music Videos|Latin|Latin Urban', 3978 1845 => 'Music Videos|Latin|Pop in Spanish', 3979 1846 => 'Music Videos|Latin|Raices', 3980 1847 => 'Music Videos|Latin|Musica Mexicana', # (Música Mexicana) 3981 1848 => 'Music Videos|Latin|Salsa y Tropical', 3982 1849 => 'Music Videos|New Age|Healing', 3983 1850 => 'Music Videos|New Age|Meditation', 3984 1851 => 'Music Videos|New Age|Nature', 3985 1852 => 'Music Videos|New Age|Relaxation', 3986 1853 => 'Music Videos|New Age|Travel', 3987 1854 => 'Music Videos|Pop|Adult Contemporary', 3988 1855 => 'Music Videos|Pop|Britpop', 3989 1856 => 'Music Videos|Pop|Pop/Rock', 3990 1857 => 'Music Videos|Pop|Soft Rock', 3991 1858 => 'Music Videos|Pop|Teen Pop', 3992 1859 => 'Music Videos|R&B/Soul|Contemporary R&B', 3993 1860 => 'Music Videos|R&B/Soul|Disco', 3994 1861 => 'Music Videos|R&B/Soul|Doo Wop', 3995 1862 => 'Music Videos|R&B/Soul|Funk', 3996 1863 => 'Music Videos|R&B/Soul|Motown', 3997 1864 => 'Music Videos|R&B/Soul|Neo-Soul', 3998 1865 => 'Music Videos|R&B/Soul|Soul', 3999 1866 => 'Music Videos|Reggae|Modern Dancehall', 4000 1867 => 'Music Videos|Reggae|Dub', 4001 1868 => 'Music Videos|Reggae|Roots Reggae', 4002 1869 => 'Music Videos|Reggae|Ska', 4003 1870 => 'Music Videos|Rock|Adult Alternative', 4004 1871 => 'Music Videos|Rock|American Trad Rock', 4005 1872 => 'Music Videos|Rock|Arena Rock', 4006 1873 => 'Music Videos|Rock|Blues-Rock', 4007 1874 => 'Music Videos|Rock|British Invasion', 4008 1875 => 'Music Videos|Rock|Death Metal/Black Metal', 4009 1876 => 'Music Videos|Rock|Glam Rock', 4010 1877 => 'Music Videos|Rock|Hair Metal', 4011 1878 => 'Music Videos|Rock|Hard Rock', 4012 1879 => 'Music Videos|Rock|Jam Bands', 4013 1880 => 'Music Videos|Rock|Prog-Rock/Art Rock', 4014 1881 => 'Music Videos|Rock|Psychedelic', 4015 1882 => 'Music Videos|Rock|Rock & Roll', 4016 1883 => 'Music Videos|Rock|Rockabilly', 4017 1884 => 'Music Videos|Rock|Roots Rock', 4018 1885 => 'Music Videos|Rock|Singer/Songwriter', 4019 1886 => 'Music Videos|Rock|Southern Rock', 4020 1887 => 'Music Videos|Rock|Surf', 4021 1888 => 'Music Videos|Rock|Tex-Mex', 4022 1889 => 'Music Videos|Singer/Songwriter|Alternative Folk', 4023 1890 => 'Music Videos|Singer/Songwriter|Contemporary Folk', 4024 1891 => 'Music Videos|Singer/Songwriter|Contemporary Singer/Songwriter', 4025 1892 => 'Music Videos|Singer/Songwriter|Folk-Rock', 4026 1893 => 'Music Videos|Singer/Songwriter|New Acoustic', 4027 1894 => 'Music Videos|Singer/Songwriter|Traditional Folk', 4028 1895 => 'Music Videos|Soundtrack|Foreign Cinema', 4029 1896 => 'Music Videos|Soundtrack|Musicals', 4030 1897 => 'Music Videos|Soundtrack|Original Score', 4031 1898 => 'Music Videos|Soundtrack|Soundtrack', 4032 1899 => 'Music Videos|Soundtrack|TV Soundtrack', 4033 1900 => 'Music Videos|Vocal|Standards', 4034 1901 => 'Music Videos|Vocal|Traditional Pop', 4035 1902 => 'Music Videos|Jazz|Vocal Jazz', 4036 1903 => 'Music Videos|Vocal|Vocal Pop', 4037 1904 => 'Music Videos|African', 4038 1905 => 'Music Videos|African|Afro-Beat', 4039 1906 => 'Music Videos|African|Afro-Pop', 4040 1907 => 'Music Videos|World|Asia', 4041 1908 => 'Music Videos|World|Australia', 4042 1909 => 'Music Videos|World|Cajun', 4043 1910 => 'Music Videos|World|Caribbean', 4044 1911 => 'Music Videos|World|Celtic', 4045 1912 => 'Music Videos|World|Celtic Folk', 4046 1913 => 'Music Videos|World|Contemporary Celtic', 4047 1914 => 'Music Videos|World|Europe', 4048 1915 => 'Music Videos|World|France', 4049 1916 => 'Music Videos|World|Hawaii', 4050 1917 => 'Music Videos|World|Japan', 4051 1918 => 'Music Videos|World|Klezmer', 4052 1919 => 'Music Videos|World|North America', 4053 1920 => 'Music Videos|World|Polka', 4054 1921 => 'Music Videos|World|South Africa', 4055 1922 => 'Music Videos|World|South America', 4056 1923 => 'Music Videos|World|Traditional Celtic', 4057 1924 => 'Music Videos|World|Worldbeat', 4058 1925 => 'Music Videos|World|Zydeco', 4059 1926 => 'Music Videos|Christian & Gospel', 4060 1928 => 'Music Videos|Classical|Art Song', 4061 1929 => 'Music Videos|Classical|Brass & Woodwinds', 4062 1930 => 'Music Videos|Classical|Solo Instrumental', 4063 1931 => 'Music Videos|Classical|Contemporary Era', 4064 1932 => 'Music Videos|Classical|Oratorio', 4065 1933 => 'Music Videos|Classical|Cantata', 4066 1934 => 'Music Videos|Classical|Electronic', 4067 1935 => 'Music Videos|Classical|Sacred', 4068 1936 => 'Music Videos|Classical|Guitar', 4069 1938 => 'Music Videos|Classical|Violin', 4070 1939 => 'Music Videos|Classical|Cello', 4071 1940 => 'Music Videos|Classical|Percussion', 4072 1941 => 'Music Videos|Electronic|Dubstep', 4073 1942 => 'Music Videos|Electronic|Bass', 4074 1943 => 'Music Videos|Hip-Hop/Rap|UK Hip-Hop', 4075 1944 => 'Music Videos|Reggae|Lovers Rock', 4076 1945 => 'Music Videos|Alternative|EMO', 4077 1946 => 'Music Videos|Alternative|Pop Punk', 4078 1947 => 'Music Videos|Alternative|Indie Pop', 4079 1948 => 'Music Videos|New Age|Yoga', 4080 1949 => 'Music Videos|Pop|Tribute', 4081 1950 => 'Music Videos|Pop|Shows', 4082 1951 => 'Music Videos|Cuban', 4083 1952 => 'Music Videos|Cuban|Mambo', 4084 1953 => 'Music Videos|Cuban|Chachacha', 4085 1954 => 'Music Videos|Cuban|Guajira', 4086 1955 => 'Music Videos|Cuban|Son', 4087 1956 => 'Music Videos|Cuban|Bolero', 4088 1957 => 'Music Videos|Cuban|Guaracha', 4089 1958 => 'Music Videos|Cuban|Timba', 4090 1959 => 'Music Videos|Soundtrack|Video Game', 4091 1960 => 'Music Videos|Indian|Regional Indian|Punjabi|Punjabi Pop', 4092 1961 => 'Music Videos|Indian|Regional Indian|Bengali|Rabindra Sangeet', 4093 1962 => 'Music Videos|Indian|Regional Indian|Malayalam', 4094 1963 => 'Music Videos|Indian|Regional Indian|Kannada', 4095 1964 => 'Music Videos|Indian|Regional Indian|Marathi', 4096 1965 => 'Music Videos|Indian|Regional Indian|Gujarati', 4097 1966 => 'Music Videos|Indian|Regional Indian|Assamese', 4098 1967 => 'Music Videos|Indian|Regional Indian|Bhojpuri', 4099 1968 => 'Music Videos|Indian|Regional Indian|Haryanvi', 4100 1969 => 'Music Videos|Indian|Regional Indian|Odia', 4101 1970 => 'Music Videos|Indian|Regional Indian|Rajasthani', 4102 1971 => 'Music Videos|Indian|Regional Indian|Urdu', 4103 1972 => 'Music Videos|Indian|Regional Indian|Punjabi', 4104 1973 => 'Music Videos|Indian|Regional Indian|Bengali', 4105 1974 => 'Music Videos|Indian|Indian Classical|Carnatic Classical', 4106 1975 => 'Music Videos|Indian|Indian Classical|Hindustani Classical', 4107 1976 => 'Music Videos|African|Afro House', 4108 1977 => 'Music Videos|African|Afro Soul', 4109 1978 => 'Music Videos|African|Afrobeats', 4110 1979 => 'Music Videos|African|Benga', 4111 1980 => 'Music Videos|African|Bongo-Flava', 4112 1981 => 'Music Videos|African|Coupe-Decale', 4113 1982 => 'Music Videos|African|Gqom', 4114 1983 => 'Music Videos|African|Highlife', 4115 1984 => 'Music Videos|African|Kuduro', 4116 1985 => 'Music Videos|African|Kizomba', 4117 1986 => 'Music Videos|African|Kwaito', 4118 1987 => 'Music Videos|African|Mbalax', 4119 1988 => 'Music Videos|African|Ndombolo', 4120 1989 => 'Music Videos|African|Shangaan Electro', 4121 1990 => 'Music Videos|African|Soukous', 4122 1991 => 'Music Videos|African|Taarab', 4123 1992 => 'Music Videos|African|Zouglou', 4124 1993 => 'Music Videos|Turkish|Ozgun', 4125 1994 => 'Music Videos|Turkish|Fantezi', 4126 1995 => 'Music Videos|Turkish|Religious', 4127 1996 => 'Music Videos|Pop|Turkish Pop', 4128 1997 => 'Music Videos|Rock|Turkish Rock', 4129 1998 => 'Music Videos|Alternative|Turkish Alternative', 4130 1999 => 'Music Videos|Hip-Hop/Rap|Turkish Hip-Hop/Rap', 4131 2000 => 'Music Videos|African|Maskandi', 4132 2001 => 'Music Videos|Russian|Russian Romance', 4133 2002 => 'Music Videos|Russian|Russian Bard', 4134 2003 => 'Music Videos|Russian|Russian Pop', 4135 2004 => 'Music Videos|Russian|Russian Rock', 4136 2005 => 'Music Videos|Russian|Russian Hip-Hop', 4137 2006 => 'Music Videos|Arabic|Levant', 4138 2007 => 'Music Videos|Arabic|Levant|Dabke', 4139 2008 => 'Music Videos|Arabic|Maghreb Rai', 4140 2009 => 'Music Videos|Arabic|Khaleeji|Khaleeji Jalsat', 4141 2010 => 'Music Videos|Arabic|Khaleeji|Khaleeji Shailat', 4142 2011 => 'Music Videos|Tarab', 4143 2012 => 'Music Videos|Tarab|Iraqi Tarab', 4144 2013 => 'Music Videos|Tarab|Egyptian Tarab', 4145 2014 => 'Music Videos|Tarab|Khaleeji Tarab', 4146 2015 => 'Music Videos|Pop|Levant Pop', 4147 2016 => 'Music Videos|Pop|Iraqi Pop', 4148 2017 => 'Music Videos|Pop|Egyptian Pop', 4149 2018 => 'Music Videos|Pop|Maghreb Pop', 4150 2019 => 'Music Videos|Pop|Khaleeji Pop', 4151 2020 => 'Music Videos|Hip-Hop/Rap|Levant Hip-Hop', 4152 2021 => 'Music Videos|Hip-Hop/Rap|Egyptian Hip-Hop', 4153 2022 => 'Music Videos|Hip-Hop/Rap|Maghreb Hip-Hop', 4154 2023 => 'Music Videos|Hip-Hop/Rap|Khaleeji Hip-Hop', 4155 2024 => 'Music Videos|Alternative|Indie Levant', 4156 2025 => 'Music Videos|Alternative|Indie Egyptian', 4157 2026 => 'Music Videos|Alternative|Indie Maghreb', 4158 2027 => 'Music Videos|Electronic|Levant Electronic', 4159 2028 => "Music Videos|Electronic|Electro-Cha'abi", 4160 2029 => 'Music Videos|Electronic|Maghreb Electronic', 4161 2030 => 'Music Videos|Folk|Iraqi Folk', 4162 2031 => 'Music Videos|Folk|Khaleeji Folk', 4163 2032 => 'Music Videos|Dance|Maghreb Dance', 4164 4000 => 'TV Shows|Comedy', 4165 4001 => 'TV Shows|Drama', 4166 4002 => 'TV Shows|Animation', 4167 4003 => 'TV Shows|Action & Adventure', 4168 4004 => 'TV Shows|Classics', 4169 4005 => 'TV Shows|Kids & Family', 4170 4006 => 'TV Shows|Nonfiction', 4171 4007 => 'TV Shows|Reality TV', 4172 4008 => 'TV Shows|Sci-Fi & Fantasy', 4173 4009 => 'TV Shows|Sports', 4174 4010 => 'TV Shows|Teens', 4175 4011 => 'TV Shows|Latino TV', 4176 4401 => 'Movies|Action & Adventure', 4177 4402 => 'Movies|Anime', 4178 4403 => 'Movies|Classics', 4179 4404 => 'Movies|Comedy', 4180 4405 => 'Movies|Documentary', 4181 4406 => 'Movies|Drama', 4182 4407 => 'Movies|Foreign', 4183 4408 => 'Movies|Horror', 4184 4409 => 'Movies|Independent', 4185 4410 => 'Movies|Kids & Family', 4186 4411 => 'Movies|Musicals', 4187 4412 => 'Movies|Romance', 4188 4413 => 'Movies|Sci-Fi & Fantasy', 4189 4414 => 'Movies|Short Films', 4190 4415 => 'Movies|Special Interest', 4191 4416 => 'Movies|Thriller', 4192 4417 => 'Movies|Sports', 4193 4418 => 'Movies|Western', 4194 4419 => 'Movies|Urban', 4195 4420 => 'Movies|Holiday', 4196 4421 => 'Movies|Made for TV', 4197 4422 => 'Movies|Concert Films', 4198 4423 => 'Movies|Music Documentaries', 4199 4424 => 'Movies|Music Feature Films', 4200 4425 => 'Movies|Japanese Cinema', 4201 4426 => 'Movies|Jidaigeki', 4202 4427 => 'Movies|Tokusatsu', 4203 4428 => 'Movies|Korean Cinema', 4204 4429 => 'Movies|Russian', 4205 4430 => 'Movies|Turkish', 4206 4431 => 'Movies|Bollywood', 4207 4432 => 'Movies|Regional Indian', 4208 4433 => 'Movies|Middle Eastern', 4209 4434 => 'Movies|African', 4210 6000 => 'App Store|Business', 4211 6001 => 'App Store|Weather', 4212 6002 => 'App Store|Utilities', 4213 6003 => 'App Store|Travel', 4214 6004 => 'App Store|Sports', 4215 6005 => 'App Store|Social Networking', 4216 6006 => 'App Store|Reference', 4217 6007 => 'App Store|Productivity', 4218 6008 => 'App Store|Photo & Video', 4219 6009 => 'App Store|News', 4220 6010 => 'App Store|Navigation', 4221 6011 => 'App Store|Music', 4222 6012 => 'App Store|Lifestyle', 4223 6013 => 'App Store|Health & Fitness', 4224 6014 => 'App Store|Games', 4225 6015 => 'App Store|Finance', 4226 6016 => 'App Store|Entertainment', 4227 6017 => 'App Store|Education', 4228 6018 => 'App Store|Books', 4229 6020 => 'App Store|Medical', 4230 6021 => 'App Store|Magazines & Newspapers', 4231 6022 => 'App Store|Catalogs', 4232 6023 => 'App Store|Food & Drink', 4233 6024 => 'App Store|Shopping', 4234 6025 => 'App Store|Stickers', 4235 6026 => 'App Store|Developer Tools', 4236 6027 => 'App Store|Graphics & Design', 4237 7001 => 'App Store|Games|Action', 4238 7002 => 'App Store|Games|Adventure', 4239 7003 => 'App Store|Games|Casual', 4240 7004 => 'App Store|Games|Board', 4241 7005 => 'App Store|Games|Card', 4242 7006 => 'App Store|Games|Casino', 4243 7007 => 'App Store|Games|Dice', 4244 7008 => 'App Store|Games|Educational', 4245 7009 => 'App Store|Games|Family', 4246 7011 => 'App Store|Games|Music', 4247 7012 => 'App Store|Games|Puzzle', 4248 7013 => 'App Store|Games|Racing', 4249 7014 => 'App Store|Games|Role Playing', 4250 7015 => 'App Store|Games|Simulation', 4251 7016 => 'App Store|Games|Sports', 4252 7017 => 'App Store|Games|Strategy', 4253 7018 => 'App Store|Games|Trivia', 4254 7019 => 'App Store|Games|Word', 4255 8001 => 'Tones|Ringtones|Alternative', 4256 8002 => 'Tones|Ringtones|Blues', 4257 8003 => "Tones|Ringtones|Children's Music", 4258 8004 => 'Tones|Ringtones|Classical', 4259 8005 => 'Tones|Ringtones|Comedy', 4260 8006 => 'Tones|Ringtones|Country', 4261 8007 => 'Tones|Ringtones|Dance', 4262 8008 => 'Tones|Ringtones|Electronic', 4263 8009 => 'Tones|Ringtones|Enka', 4264 8010 => 'Tones|Ringtones|French Pop', 4265 8011 => 'Tones|Ringtones|German Folk', 4266 8012 => 'Tones|Ringtones|German Pop', 4267 8013 => 'Tones|Ringtones|Hip-Hop/Rap', 4268 8014 => 'Tones|Ringtones|Holiday', 4269 8015 => 'Tones|Ringtones|Inspirational', 4270 8016 => 'Tones|Ringtones|J-Pop', 4271 8017 => 'Tones|Ringtones|Jazz', 4272 8018 => 'Tones|Ringtones|Kayokyoku', 4273 8019 => 'Tones|Ringtones|Latin', 4274 8020 => 'Tones|Ringtones|New Age', 4275 8021 => 'Tones|Ringtones|Classical|Opera', 4276 8022 => 'Tones|Ringtones|Pop', 4277 8023 => 'Tones|Ringtones|R&B/Soul', 4278 8024 => 'Tones|Ringtones|Reggae', 4279 8025 => 'Tones|Ringtones|Rock', 4280 8026 => 'Tones|Ringtones|Singer/Songwriter', 4281 8027 => 'Tones|Ringtones|Soundtrack', 4282 8028 => 'Tones|Ringtones|Spoken Word', 4283 8029 => 'Tones|Ringtones|Vocal', 4284 8030 => 'Tones|Ringtones|World', 4285 8050 => 'Tones|Alert Tones|Sound Effects', 4286 8051 => 'Tones|Alert Tones|Dialogue', 4287 8052 => 'Tones|Alert Tones|Music', 4288 8053 => 'Tones|Ringtones', 4289 8054 => 'Tones|Alert Tones', 4290 8055 => 'Tones|Ringtones|Alternative|Chinese Alt', 4291 8056 => 'Tones|Ringtones|Alternative|College Rock', 4292 8057 => 'Tones|Ringtones|Alternative|Goth Rock', 4293 8058 => 'Tones|Ringtones|Alternative|Grunge', 4294 8059 => 'Tones|Ringtones|Alternative|Indie Rock', 4295 8060 => 'Tones|Ringtones|Alternative|Korean Indie', 4296 8061 => 'Tones|Ringtones|Alternative|New Wave', 4297 8062 => 'Tones|Ringtones|Alternative|Punk', 4298 8063 => 'Tones|Ringtones|Anime', 4299 8064 => 'Tones|Ringtones|Arabic', 4300 8065 => 'Tones|Ringtones|Arabic|Arabic Pop', 4301 8066 => 'Tones|Ringtones|Arabic|Islamic', 4302 8067 => 'Tones|Ringtones|Arabic|Khaleeji', 4303 8068 => 'Tones|Ringtones|Arabic|North African', 4304 8069 => 'Tones|Ringtones|Blues|Acoustic Blues', 4305 8070 => 'Tones|Ringtones|Blues|Chicago Blues', 4306 8071 => 'Tones|Ringtones|Blues|Classic Blues', 4307 8072 => 'Tones|Ringtones|Blues|Contemporary Blues', 4308 8073 => 'Tones|Ringtones|Blues|Country Blues', 4309 8074 => 'Tones|Ringtones|Blues|Delta Blues', 4310 8075 => 'Tones|Ringtones|Blues|Electric Blues', 4311 8076 => 'Tones|Ringtones|Brazilian', 4312 8077 => 'Tones|Ringtones|Brazilian|Axe', # (Axé) 4313 8078 => 'Tones|Ringtones|Brazilian|Baile Funk', 4314 8079 => 'Tones|Ringtones|Brazilian|Bossa Nova', 4315 8080 => 'Tones|Ringtones|Brazilian|Choro', 4316 8081 => 'Tones|Ringtones|Brazilian|Forro', # (Forró) 4317 8082 => 'Tones|Ringtones|Brazilian|Frevo', 4318 8083 => 'Tones|Ringtones|Brazilian|MPB', 4319 8084 => 'Tones|Ringtones|Brazilian|Pagode', 4320 8085 => 'Tones|Ringtones|Brazilian|Samba', 4321 8086 => 'Tones|Ringtones|Brazilian|Sertanejo', 4322 8087 => "Tones|Ringtones|Children's Music|Lullabies", 4323 8088 => "Tones|Ringtones|Children's Music|Sing-Along", 4324 8089 => "Tones|Ringtones|Children's Music|Stories", 4325 8090 => 'Tones|Ringtones|Chinese', 4326 8091 => 'Tones|Ringtones|Chinese|Chinese Classical', 4327 8092 => 'Tones|Ringtones|Chinese|Chinese Flute', 4328 8093 => 'Tones|Ringtones|Chinese|Chinese Opera', 4329 8094 => 'Tones|Ringtones|Chinese|Chinese Orchestral', 4330 8095 => 'Tones|Ringtones|Chinese|Chinese Regional Folk', 4331 8096 => 'Tones|Ringtones|Chinese|Chinese Strings', 4332 8097 => 'Tones|Ringtones|Chinese|Taiwanese Folk', 4333 8098 => 'Tones|Ringtones|Chinese|Tibetan Native Music', 4334 8099 => 'Tones|Ringtones|Christian & Gospel', 4335 8100 => 'Tones|Ringtones|Christian & Gospel|CCM', 4336 8101 => 'Tones|Ringtones|Christian & Gospel|Christian Metal', 4337 8102 => 'Tones|Ringtones|Christian & Gospel|Christian Pop', 4338 8103 => 'Tones|Ringtones|Christian & Gospel|Christian Rap', 4339 8104 => 'Tones|Ringtones|Christian & Gospel|Christian Rock', 4340 8105 => 'Tones|Ringtones|Christian & Gospel|Classic Christian', 4341 8106 => 'Tones|Ringtones|Christian & Gospel|Contemporary Gospel', 4342 8107 => 'Tones|Ringtones|Christian & Gospel|Gospel', 4343 8108 => 'Tones|Ringtones|Christian & Gospel|Praise & Worship', 4344 8109 => 'Tones|Ringtones|Christian & Gospel|Southern Gospel', 4345 8110 => 'Tones|Ringtones|Christian & Gospel|Traditional Gospel', 4346 8111 => 'Tones|Ringtones|Classical|Avant-Garde', 4347 8112 => 'Tones|Ringtones|Classical|Baroque Era', 4348 8113 => 'Tones|Ringtones|Classical|Chamber Music', 4349 8114 => 'Tones|Ringtones|Classical|Chant', 4350 8115 => 'Tones|Ringtones|Classical|Choral', 4351 8116 => 'Tones|Ringtones|Classical|Classical Crossover', 4352 8117 => 'Tones|Ringtones|Classical|Early Music', 4353 8118 => 'Tones|Ringtones|Classical|High Classical', 4354 8119 => 'Tones|Ringtones|Classical|Impressionist', 4355 8120 => 'Tones|Ringtones|Classical|Medieval Era', 4356 8121 => 'Tones|Ringtones|Classical|Minimalism', 4357 8122 => 'Tones|Ringtones|Classical|Modern Era', 4358 8123 => 'Tones|Ringtones|Classical|Orchestral', 4359 8124 => 'Tones|Ringtones|Classical|Renaissance', 4360 8125 => 'Tones|Ringtones|Classical|Romantic Era', 4361 8126 => 'Tones|Ringtones|Classical|Wedding Music', 4362 8127 => 'Tones|Ringtones|Comedy|Novelty', 4363 8128 => 'Tones|Ringtones|Comedy|Standup Comedy', 4364 8129 => 'Tones|Ringtones|Country|Alternative Country', 4365 8130 => 'Tones|Ringtones|Country|Americana', 4366 8131 => 'Tones|Ringtones|Country|Bluegrass', 4367 8132 => 'Tones|Ringtones|Country|Contemporary Bluegrass', 4368 8133 => 'Tones|Ringtones|Country|Contemporary Country', 4369 8134 => 'Tones|Ringtones|Country|Country Gospel', 4370 8135 => 'Tones|Ringtones|Country|Honky Tonk', 4371 8136 => 'Tones|Ringtones|Country|Outlaw Country', 4372 8137 => 'Tones|Ringtones|Country|Thai Country', 4373 8138 => 'Tones|Ringtones|Country|Traditional Bluegrass', 4374 8139 => 'Tones|Ringtones|Country|Traditional Country', 4375 8140 => 'Tones|Ringtones|Country|Urban Cowboy', 4376 8141 => 'Tones|Ringtones|Dance|Breakbeat', 4377 8142 => 'Tones|Ringtones|Dance|Exercise', 4378 8143 => 'Tones|Ringtones|Dance|Garage', 4379 8144 => 'Tones|Ringtones|Dance|Hardcore', 4380 8145 => 'Tones|Ringtones|Dance|House', 4381 8146 => "Tones|Ringtones|Dance|Jungle/Drum'n'bass", 4382 8147 => 'Tones|Ringtones|Dance|Techno', 4383 8148 => 'Tones|Ringtones|Dance|Trance', 4384 8149 => 'Tones|Ringtones|Disney', 4385 8150 => 'Tones|Ringtones|Easy Listening', 4386 8151 => 'Tones|Ringtones|Easy Listening|Lounge', 4387 8152 => 'Tones|Ringtones|Easy Listening|Swing', 4388 8153 => 'Tones|Ringtones|Electronic|Ambient', 4389 8154 => 'Tones|Ringtones|Electronic|Downtempo', 4390 8155 => 'Tones|Ringtones|Electronic|Electronica', 4391 8156 => 'Tones|Ringtones|Electronic|IDM/Experimental', 4392 8157 => 'Tones|Ringtones|Electronic|Industrial', 4393 8158 => 'Tones|Ringtones|Fitness & Workout', 4394 8159 => 'Tones|Ringtones|Folk', 4395 8160 => 'Tones|Ringtones|Hip-Hop/Rap|Alternative Rap', 4396 8161 => 'Tones|Ringtones|Hip-Hop/Rap|Chinese Hip-Hop', 4397 8162 => 'Tones|Ringtones|Hip-Hop/Rap|Dirty South', 4398 8163 => 'Tones|Ringtones|Hip-Hop/Rap|East Coast Rap', 4399 8164 => 'Tones|Ringtones|Hip-Hop/Rap|Gangsta Rap', 4400 8165 => 'Tones|Ringtones|Hip-Hop/Rap|Hardcore Rap', 4401 8166 => 'Tones|Ringtones|Hip-Hop/Rap|Hip-Hop', 4402 8167 => 'Tones|Ringtones|Hip-Hop/Rap|Korean Hip-Hop', 4403 8168 => 'Tones|Ringtones|Hip-Hop/Rap|Latin Rap', 4404 8169 => 'Tones|Ringtones|Hip-Hop/Rap|Old School Rap', 4405 8170 => 'Tones|Ringtones|Hip-Hop/Rap|Rap', 4406 8171 => 'Tones|Ringtones|Hip-Hop/Rap|Underground Rap', 4407 8172 => 'Tones|Ringtones|Hip-Hop/Rap|West Coast Rap', 4408 8173 => 'Tones|Ringtones|Holiday|Chanukah', 4409 8174 => 'Tones|Ringtones|Holiday|Christmas', 4410 8175 => "Tones|Ringtones|Holiday|Christmas: Children's", 4411 8176 => 'Tones|Ringtones|Holiday|Christmas: Classic', 4412 8177 => 'Tones|Ringtones|Holiday|Christmas: Classical', 4413 8178 => 'Tones|Ringtones|Holiday|Christmas: Jazz', 4414 8179 => 'Tones|Ringtones|Holiday|Christmas: Modern', 4415 8180 => 'Tones|Ringtones|Holiday|Christmas: Pop', 4416 8181 => 'Tones|Ringtones|Holiday|Christmas: R&B', 4417 8182 => 'Tones|Ringtones|Holiday|Christmas: Religious', 4418 8183 => 'Tones|Ringtones|Holiday|Christmas: Rock', 4419 8184 => 'Tones|Ringtones|Holiday|Easter', 4420 8185 => 'Tones|Ringtones|Holiday|Halloween', 4421 8186 => 'Tones|Ringtones|Holiday|Thanksgiving', 4422 8187 => 'Tones|Ringtones|Indian', 4423 8188 => 'Tones|Ringtones|Indian|Bollywood', 4424 8189 => 'Tones|Ringtones|Indian|Devotional & Spiritual', 4425 8190 => 'Tones|Ringtones|Indian|Ghazals', 4426 8191 => 'Tones|Ringtones|Indian|Indian Classical', 4427 8192 => 'Tones|Ringtones|Indian|Indian Folk', 4428 8193 => 'Tones|Ringtones|Indian|Indian Pop', 4429 8194 => 'Tones|Ringtones|Indian|Regional Indian', 4430 8195 => 'Tones|Ringtones|Indian|Sufi', 4431 8196 => 'Tones|Ringtones|Indian|Regional Indian|Tamil', 4432 8197 => 'Tones|Ringtones|Indian|Regional Indian|Telugu', 4433 8198 => 'Tones|Ringtones|Instrumental', 4434 8199 => 'Tones|Ringtones|Jazz|Avant-Garde Jazz', 4435 8201 => 'Tones|Ringtones|Jazz|Big Band', 4436 8202 => 'Tones|Ringtones|Jazz|Bop', 4437 8203 => 'Tones|Ringtones|Jazz|Contemporary Jazz', 4438 8204 => 'Tones|Ringtones|Jazz|Cool Jazz', 4439 8205 => 'Tones|Ringtones|Jazz|Crossover Jazz', 4440 8206 => 'Tones|Ringtones|Jazz|Dixieland', 4441 8207 => 'Tones|Ringtones|Jazz|Fusion', 4442 8208 => 'Tones|Ringtones|Jazz|Hard Bop', 4443 8209 => 'Tones|Ringtones|Jazz|Latin Jazz', 4444 8210 => 'Tones|Ringtones|Jazz|Mainstream Jazz', 4445 8211 => 'Tones|Ringtones|Jazz|Ragtime', 4446 8212 => 'Tones|Ringtones|Jazz|Smooth Jazz', 4447 8213 => 'Tones|Ringtones|Jazz|Trad Jazz', 4448 8214 => 'Tones|Ringtones|Pop|K-Pop', 4449 8215 => 'Tones|Ringtones|Karaoke', 4450 8216 => 'Tones|Ringtones|Korean', 4451 8217 => 'Tones|Ringtones|Korean|Korean Classical', 4452 8218 => 'Tones|Ringtones|Korean|Korean Trad Instrumental', 4453 8219 => 'Tones|Ringtones|Korean|Korean Trad Song', 4454 8220 => 'Tones|Ringtones|Korean|Korean Trad Theater', 4455 8221 => 'Tones|Ringtones|Latin|Alternative & Rock in Spanish', 4456 8222 => 'Tones|Ringtones|Latin|Baladas y Boleros', 4457 8223 => 'Tones|Ringtones|Latin|Contemporary Latin', 4458 8224 => 'Tones|Ringtones|Latin|Latin Jazz', 4459 8225 => 'Tones|Ringtones|Latin|Latin Urban', 4460 8226 => 'Tones|Ringtones|Latin|Pop in Spanish', 4461 8227 => 'Tones|Ringtones|Latin|Raices', 4462 8228 => 'Tones|Ringtones|Latin|Musica Mexicana', # (Música Mexicana) 4463 8229 => 'Tones|Ringtones|Latin|Salsa y Tropical', 4464 8230 => 'Tones|Ringtones|Marching Bands', 4465 8231 => 'Tones|Ringtones|New Age|Healing', 4466 8232 => 'Tones|Ringtones|New Age|Meditation', 4467 8233 => 'Tones|Ringtones|New Age|Nature', 4468 8234 => 'Tones|Ringtones|New Age|Relaxation', 4469 8235 => 'Tones|Ringtones|New Age|Travel', 4470 8236 => 'Tones|Ringtones|Orchestral', 4471 8237 => 'Tones|Ringtones|Pop|Adult Contemporary', 4472 8238 => 'Tones|Ringtones|Pop|Britpop', 4473 8239 => 'Tones|Ringtones|Pop|C-Pop', 4474 8240 => 'Tones|Ringtones|Pop|Cantopop/HK-Pop', 4475 8241 => 'Tones|Ringtones|Pop|Indo Pop', 4476 8242 => 'Tones|Ringtones|Pop|Korean Folk-Pop', 4477 8243 => 'Tones|Ringtones|Pop|Malaysian Pop', 4478 8244 => 'Tones|Ringtones|Pop|Mandopop', 4479 8245 => 'Tones|Ringtones|Pop|Manilla Sound', 4480 8246 => 'Tones|Ringtones|Pop|Oldies', 4481 8247 => 'Tones|Ringtones|Pop|Original Pilipino Music', 4482 8248 => 'Tones|Ringtones|Pop|Pinoy Pop', 4483 8249 => 'Tones|Ringtones|Pop|Pop/Rock', 4484 8250 => 'Tones|Ringtones|Pop|Soft Rock', 4485 8251 => 'Tones|Ringtones|Pop|Tai-Pop', 4486 8252 => 'Tones|Ringtones|Pop|Teen Pop', 4487 8253 => 'Tones|Ringtones|Pop|Thai Pop', 4488 8254 => 'Tones|Ringtones|R&B/Soul|Contemporary R&B', 4489 8255 => 'Tones|Ringtones|R&B/Soul|Disco', 4490 8256 => 'Tones|Ringtones|R&B/Soul|Doo Wop', 4491 8257 => 'Tones|Ringtones|R&B/Soul|Funk', 4492 8258 => 'Tones|Ringtones|R&B/Soul|Motown', 4493 8259 => 'Tones|Ringtones|R&B/Soul|Neo-Soul', 4494 8260 => 'Tones|Ringtones|R&B/Soul|Soul', 4495 8261 => 'Tones|Ringtones|Reggae|Modern Dancehall', 4496 8262 => 'Tones|Ringtones|Reggae|Dub', 4497 8263 => 'Tones|Ringtones|Reggae|Roots Reggae', 4498 8264 => 'Tones|Ringtones|Reggae|Ska', 4499 8265 => 'Tones|Ringtones|Rock|Adult Alternative', 4500 8266 => 'Tones|Ringtones|Rock|American Trad Rock', 4501 8267 => 'Tones|Ringtones|Rock|Arena Rock', 4502 8268 => 'Tones|Ringtones|Rock|Blues-Rock', 4503 8269 => 'Tones|Ringtones|Rock|British Invasion', 4504 8270 => 'Tones|Ringtones|Rock|Chinese Rock', 4505 8271 => 'Tones|Ringtones|Rock|Death Metal/Black Metal', 4506 8272 => 'Tones|Ringtones|Rock|Glam Rock', 4507 8273 => 'Tones|Ringtones|Rock|Hair Metal', 4508 8274 => 'Tones|Ringtones|Rock|Hard Rock', 4509 8275 => 'Tones|Ringtones|Rock|Metal', 4510 8276 => 'Tones|Ringtones|Rock|Jam Bands', 4511 8277 => 'Tones|Ringtones|Rock|Korean Rock', 4512 8278 => 'Tones|Ringtones|Rock|Prog-Rock/Art Rock', 4513 8279 => 'Tones|Ringtones|Rock|Psychedelic', 4514 8280 => 'Tones|Ringtones|Rock|Rock & Roll', 4515 8281 => 'Tones|Ringtones|Rock|Rockabilly', 4516 8282 => 'Tones|Ringtones|Rock|Roots Rock', 4517 8283 => 'Tones|Ringtones|Rock|Singer/Songwriter', 4518 8284 => 'Tones|Ringtones|Rock|Southern Rock', 4519 8285 => 'Tones|Ringtones|Rock|Surf', 4520 8286 => 'Tones|Ringtones|Rock|Tex-Mex', 4521 8287 => 'Tones|Ringtones|Singer/Songwriter|Alternative Folk', 4522 8288 => 'Tones|Ringtones|Singer/Songwriter|Contemporary Folk', 4523 8289 => 'Tones|Ringtones|Singer/Songwriter|Contemporary Singer/Songwriter', 4524 8290 => 'Tones|Ringtones|Singer/Songwriter|Folk-Rock', 4525 8291 => 'Tones|Ringtones|Singer/Songwriter|New Acoustic', 4526 8292 => 'Tones|Ringtones|Singer/Songwriter|Traditional Folk', 4527 8293 => 'Tones|Ringtones|Soundtrack|Foreign Cinema', 4528 8294 => 'Tones|Ringtones|Soundtrack|Musicals', 4529 8295 => 'Tones|Ringtones|Soundtrack|Original Score', 4530 8296 => 'Tones|Ringtones|Soundtrack|Sound Effects', 4531 8297 => 'Tones|Ringtones|Soundtrack|Soundtrack', 4532 8298 => 'Tones|Ringtones|Soundtrack|TV Soundtrack', 4533 8299 => 'Tones|Ringtones|Vocal|Standards', 4534 8300 => 'Tones|Ringtones|Vocal|Traditional Pop', 4535 8301 => 'Tones|Ringtones|Vocal|Trot', 4536 8302 => 'Tones|Ringtones|Jazz|Vocal Jazz', 4537 8303 => 'Tones|Ringtones|Vocal|Vocal Pop', 4538 8304 => 'Tones|Ringtones|African', 4539 8305 => 'Tones|Ringtones|African|Afrikaans', 4540 8306 => 'Tones|Ringtones|African|Afro-Beat', 4541 8307 => 'Tones|Ringtones|African|Afro-Pop', 4542 8308 => 'Tones|Ringtones|Turkish|Arabesque', 4543 8309 => 'Tones|Ringtones|World|Asia', 4544 8310 => 'Tones|Ringtones|World|Australia', 4545 8311 => 'Tones|Ringtones|World|Cajun', 4546 8312 => 'Tones|Ringtones|World|Calypso', 4547 8313 => 'Tones|Ringtones|World|Caribbean', 4548 8314 => 'Tones|Ringtones|World|Celtic', 4549 8315 => 'Tones|Ringtones|World|Celtic Folk', 4550 8316 => 'Tones|Ringtones|World|Contemporary Celtic', 4551 8317 => 'Tones|Ringtones|World|Dangdut', 4552 8318 => 'Tones|Ringtones|World|Dini', 4553 8319 => 'Tones|Ringtones|World|Europe', 4554 8320 => 'Tones|Ringtones|World|Fado', 4555 8321 => 'Tones|Ringtones|World|Farsi', 4556 8322 => 'Tones|Ringtones|World|Flamenco', 4557 8323 => 'Tones|Ringtones|World|France', 4558 8324 => 'Tones|Ringtones|Turkish|Halk', 4559 8325 => 'Tones|Ringtones|World|Hawaii', 4560 8326 => 'Tones|Ringtones|World|Iberia', 4561 8327 => 'Tones|Ringtones|World|Indonesian Religious', 4562 8328 => 'Tones|Ringtones|World|Israeli', 4563 8329 => 'Tones|Ringtones|World|Japan', 4564 8330 => 'Tones|Ringtones|World|Klezmer', 4565 8331 => 'Tones|Ringtones|World|North America', 4566 8332 => 'Tones|Ringtones|World|Polka', 4567 8333 => 'Tones|Ringtones|Russian', 4568 8334 => 'Tones|Ringtones|Russian|Russian Chanson', 4569 8335 => 'Tones|Ringtones|Turkish|Sanat', 4570 8336 => 'Tones|Ringtones|World|Soca', 4571 8337 => 'Tones|Ringtones|World|South Africa', 4572 8338 => 'Tones|Ringtones|World|South America', 4573 8339 => 'Tones|Ringtones|World|Tango', 4574 8340 => 'Tones|Ringtones|World|Traditional Celtic', 4575 8341 => 'Tones|Ringtones|Turkish', 4576 8342 => 'Tones|Ringtones|World|Worldbeat', 4577 8343 => 'Tones|Ringtones|World|Zydeco', 4578 8345 => 'Tones|Ringtones|Classical|Art Song', 4579 8346 => 'Tones|Ringtones|Classical|Brass & Woodwinds', 4580 8347 => 'Tones|Ringtones|Classical|Solo Instrumental', 4581 8348 => 'Tones|Ringtones|Classical|Contemporary Era', 4582 8349 => 'Tones|Ringtones|Classical|Oratorio', 4583 8350 => 'Tones|Ringtones|Classical|Cantata', 4584 8351 => 'Tones|Ringtones|Classical|Electronic', 4585 8352 => 'Tones|Ringtones|Classical|Sacred', 4586 8353 => 'Tones|Ringtones|Classical|Guitar', 4587 8354 => 'Tones|Ringtones|Classical|Piano', 4588 8355 => 'Tones|Ringtones|Classical|Violin', 4589 8356 => 'Tones|Ringtones|Classical|Cello', 4590 8357 => 'Tones|Ringtones|Classical|Percussion', 4591 8358 => 'Tones|Ringtones|Electronic|Dubstep', 4592 8359 => 'Tones|Ringtones|Electronic|Bass', 4593 8360 => 'Tones|Ringtones|Hip-Hop/Rap|UK Hip Hop', 4594 8361 => 'Tones|Ringtones|Reggae|Lovers Rock', 4595 8362 => 'Tones|Ringtones|Alternative|EMO', 4596 8363 => 'Tones|Ringtones|Alternative|Pop Punk', 4597 8364 => 'Tones|Ringtones|Alternative|Indie Pop', 4598 8365 => 'Tones|Ringtones|New Age|Yoga', 4599 8366 => 'Tones|Ringtones|Pop|Tribute', 4600 8367 => 'Tones|Ringtones|Pop|Shows', 4601 8368 => 'Tones|Ringtones|Cuban', 4602 8369 => 'Tones|Ringtones|Cuban|Mambo', 4603 8370 => 'Tones|Ringtones|Cuban|Chachacha', 4604 8371 => 'Tones|Ringtones|Cuban|Guajira', 4605 8372 => 'Tones|Ringtones|Cuban|Son', 4606 8373 => 'Tones|Ringtones|Cuban|Bolero', 4607 8374 => 'Tones|Ringtones|Cuban|Guaracha', 4608 8375 => 'Tones|Ringtones|Cuban|Timba', 4609 8376 => 'Tones|Ringtones|Soundtrack|Video Game', 4610 8377 => 'Tones|Ringtones|Indian|Regional Indian|Punjabi|Punjabi Pop', 4611 8378 => 'Tones|Ringtones|Indian|Regional Indian|Bengali|Rabindra Sangeet', 4612 8379 => 'Tones|Ringtones|Indian|Regional Indian|Malayalam', 4613 8380 => 'Tones|Ringtones|Indian|Regional Indian|Kannada', 4614 8381 => 'Tones|Ringtones|Indian|Regional Indian|Marathi', 4615 8382 => 'Tones|Ringtones|Indian|Regional Indian|Gujarati', 4616 8383 => 'Tones|Ringtones|Indian|Regional Indian|Assamese', 4617 8384 => 'Tones|Ringtones|Indian|Regional Indian|Bhojpuri', 4618 8385 => 'Tones|Ringtones|Indian|Regional Indian|Haryanvi', 4619 8386 => 'Tones|Ringtones|Indian|Regional Indian|Odia', 4620 8387 => 'Tones|Ringtones|Indian|Regional Indian|Rajasthani', 4621 8388 => 'Tones|Ringtones|Indian|Regional Indian|Urdu', 4622 8389 => 'Tones|Ringtones|Indian|Regional Indian|Punjabi', 4623 8390 => 'Tones|Ringtones|Indian|Regional Indian|Bengali', 4624 8391 => 'Tones|Ringtones|Indian|Indian Classical|Carnatic Classical', 4625 8392 => 'Tones|Ringtones|Indian|Indian Classical|Hindustani Classical', 4626 8393 => 'Tones|Ringtones|African|Afro House', 4627 8394 => 'Tones|Ringtones|African|Afro Soul', 4628 8395 => 'Tones|Ringtones|African|Afrobeats', 4629 8396 => 'Tones|Ringtones|African|Benga', 4630 8397 => 'Tones|Ringtones|African|Bongo-Flava', 4631 8398 => 'Tones|Ringtones|African|Coupe-Decale', 4632 8399 => 'Tones|Ringtones|African|Gqom', 4633 8400 => 'Tones|Ringtones|African|Highlife', 4634 8401 => 'Tones|Ringtones|African|Kuduro', 4635 8402 => 'Tones|Ringtones|African|Kizomba', 4636 8403 => 'Tones|Ringtones|African|Kwaito', 4637 8404 => 'Tones|Ringtones|African|Mbalax', 4638 8405 => 'Tones|Ringtones|African|Ndombolo', 4639 8406 => 'Tones|Ringtones|African|Shangaan Electro', 4640 8407 => 'Tones|Ringtones|African|Soukous', 4641 8408 => 'Tones|Ringtones|African|Taarab', 4642 8409 => 'Tones|Ringtones|African|Zouglou', 4643 8410 => 'Tones|Ringtones|Turkish|Ozgun', 4644 8411 => 'Tones|Ringtones|Turkish|Fantezi', 4645 8412 => 'Tones|Ringtones|Turkish|Religious', 4646 8413 => 'Tones|Ringtones|Pop|Turkish Pop', 4647 8414 => 'Tones|Ringtones|Rock|Turkish Rock', 4648 8415 => 'Tones|Ringtones|Alternative|Turkish Alternative', 4649 8416 => 'Tones|Ringtones|Hip-Hop/Rap|Turkish Hip-Hop/Rap', 4650 8417 => 'Tones|Ringtones|African|Maskandi', 4651 8418 => 'Tones|Ringtones|Russian|Russian Romance', 4652 8419 => 'Tones|Ringtones|Russian|Russian Bard', 4653 8420 => 'Tones|Ringtones|Russian|Russian Pop', 4654 8421 => 'Tones|Ringtones|Russian|Russian Rock', 4655 8422 => 'Tones|Ringtones|Russian|Russian Hip-Hop', 4656 8423 => 'Tones|Ringtones|Arabic|Levant', 4657 8424 => 'Tones|Ringtones|Arabic|Levant|Dabke', 4658 8425 => 'Tones|Ringtones|Arabic|Maghreb Rai', 4659 8426 => 'Tones|Ringtones|Arabic|Khaleeji|Khaleeji Jalsat', 4660 8427 => 'Tones|Ringtones|Arabic|Khaleeji|Khaleeji Shailat', 4661 8428 => 'Tones|Ringtones|Tarab', 4662 8429 => 'Tones|Ringtones|Tarab|Iraqi Tarab', 4663 8430 => 'Tones|Ringtones|Tarab|Egyptian Tarab', 4664 8431 => 'Tones|Ringtones|Tarab|Khaleeji Tarab', 4665 8432 => 'Tones|Ringtones|Pop|Levant Pop', 4666 8433 => 'Tones|Ringtones|Pop|Iraqi Pop', 4667 8434 => 'Tones|Ringtones|Pop|Egyptian Pop', 4668 8435 => 'Tones|Ringtones|Pop|Maghreb Pop', 4669 8436 => 'Tones|Ringtones|Pop|Khaleeji Pop', 4670 8437 => 'Tones|Ringtones|Hip-Hop/Rap|Levant Hip-Hop', 4671 8438 => 'Tones|Ringtones|Hip-Hop/Rap|Egyptian Hip-Hop', 4672 8439 => 'Tones|Ringtones|Hip-Hop/Rap|Maghreb Hip-Hop', 4673 8440 => 'Tones|Ringtones|Hip-Hop/Rap|Khaleeji Hip-Hop', 4674 8441 => 'Tones|Ringtones|Alternative|Indie Levant', 4675 8442 => 'Tones|Ringtones|Alternative|Indie Egyptian', 4676 8443 => 'Tones|Ringtones|Alternative|Indie Maghreb', 4677 8444 => 'Tones|Ringtones|Electronic|Levant Electronic', 4678 8445 => "Tones|Ringtones|Electronic|Electro-Cha'abi", 4679 8446 => 'Tones|Ringtones|Electronic|Maghreb Electronic', 4680 8447 => 'Tones|Ringtones|Folk|Iraqi Folk', 4681 8448 => 'Tones|Ringtones|Folk|Khaleeji Folk', 4682 8449 => 'Tones|Ringtones|Dance|Maghreb Dance', 4683 9002 => 'Books|Nonfiction', 4684 9003 => 'Books|Romance', 4685 9004 => 'Books|Travel & Adventure', 4686 9007 => 'Books|Arts & Entertainment', 4687 9008 => 'Books|Biographies & Memoirs', 4688 9009 => 'Books|Business & Personal Finance', 4689 9010 => 'Books|Children & Teens', 4690 9012 => 'Books|Humor', 4691 9015 => 'Books|History', 4692 9018 => 'Books|Religion & Spirituality', 4693 9019 => 'Books|Science & Nature', 4694 9020 => 'Books|Sci-Fi & Fantasy', 4695 9024 => 'Books|Lifestyle & Home', 4696 9025 => 'Books|Self-Development', 4697 9026 => 'Books|Comics & Graphic Novels', 4698 9027 => 'Books|Computers & Internet', 4699 9028 => 'Books|Cookbooks, Food & Wine', 4700 9029 => 'Books|Professional & Technical', 4701 9030 => 'Books|Parenting', 4702 9031 => 'Books|Fiction & Literature', 4703 9032 => 'Books|Mysteries & Thrillers', 4704 9033 => 'Books|Reference', 4705 9034 => 'Books|Politics & Current Events', 4706 9035 => 'Books|Sports & Outdoors', 4707 10001 => 'Books|Lifestyle & Home|Antiques & Collectibles', 4708 10002 => 'Books|Arts & Entertainment|Art & Architecture', 4709 10003 => 'Books|Religion & Spirituality|Bibles', 4710 10004 => 'Books|Self-Development|Spirituality', 4711 10005 => 'Books|Business & Personal Finance|Industries & Professions', 4712 10006 => 'Books|Business & Personal Finance|Marketing & Sales', 4713 10007 => 'Books|Business & Personal Finance|Small Business & Entrepreneurship', 4714 10008 => 'Books|Business & Personal Finance|Personal Finance', 4715 10009 => 'Books|Business & Personal Finance|Reference', 4716 10010 => 'Books|Business & Personal Finance|Careers', 4717 10011 => 'Books|Business & Personal Finance|Economics', 4718 10012 => 'Books|Business & Personal Finance|Investing', 4719 10013 => 'Books|Business & Personal Finance|Finance', 4720 10014 => 'Books|Business & Personal Finance|Management & Leadership', 4721 10015 => 'Books|Comics & Graphic Novels|Graphic Novels', 4722 10016 => 'Books|Comics & Graphic Novels|Manga', 4723 10017 => 'Books|Computers & Internet|Computers', 4724 10018 => 'Books|Computers & Internet|Databases', 4725 10019 => 'Books|Computers & Internet|Digital Media', 4726 10020 => 'Books|Computers & Internet|Internet', 4727 10021 => 'Books|Computers & Internet|Network', 4728 10022 => 'Books|Computers & Internet|Operating Systems', 4729 10023 => 'Books|Computers & Internet|Programming', 4730 10024 => 'Books|Computers & Internet|Software', 4731 10025 => 'Books|Computers & Internet|System Administration', 4732 10026 => 'Books|Cookbooks, Food & Wine|Beverages', 4733 10027 => 'Books|Cookbooks, Food & Wine|Courses & Dishes', 4734 10028 => 'Books|Cookbooks, Food & Wine|Special Diet', 4735 10029 => 'Books|Cookbooks, Food & Wine|Special Occasions', 4736 10030 => 'Books|Cookbooks, Food & Wine|Methods', 4737 10031 => 'Books|Cookbooks, Food & Wine|Reference', 4738 10032 => 'Books|Cookbooks, Food & Wine|Regional & Ethnic', 4739 10033 => 'Books|Cookbooks, Food & Wine|Specific Ingredients', 4740 10034 => 'Books|Lifestyle & Home|Crafts & Hobbies', 4741 10035 => 'Books|Professional & Technical|Design', 4742 10036 => 'Books|Arts & Entertainment|Theater', 4743 10037 => 'Books|Professional & Technical|Education', 4744 10038 => 'Books|Nonfiction|Family & Relationships', 4745 10039 => 'Books|Fiction & Literature|Action & Adventure', 4746 10040 => 'Books|Fiction & Literature|African American', 4747 10041 => 'Books|Fiction & Literature|Religious', 4748 10042 => 'Books|Fiction & Literature|Classics', 4749 10043 => 'Books|Fiction & Literature|Erotica', 4750 10044 => 'Books|Sci-Fi & Fantasy|Fantasy', 4751 10045 => 'Books|Fiction & Literature|Gay', 4752 10046 => 'Books|Fiction & Literature|Ghost', 4753 10047 => 'Books|Fiction & Literature|Historical', 4754 10048 => 'Books|Fiction & Literature|Horror', 4755 10049 => 'Books|Fiction & Literature|Literary', 4756 10050 => 'Books|Mysteries & Thrillers|Hard-Boiled', 4757 10051 => 'Books|Mysteries & Thrillers|Historical', 4758 10052 => 'Books|Mysteries & Thrillers|Police Procedural', 4759 10053 => 'Books|Mysteries & Thrillers|Short Stories', 4760 10054 => 'Books|Mysteries & Thrillers|British Detectives', 4761 10055 => 'Books|Mysteries & Thrillers|Women Sleuths', 4762 10056 => 'Books|Romance|Erotic Romance', 4763 10057 => 'Books|Romance|Contemporary', 4764 10058 => 'Books|Romance|Paranormal', 4765 10059 => 'Books|Romance|Historical', 4766 10060 => 'Books|Romance|Short Stories', 4767 10061 => 'Books|Romance|Suspense', 4768 10062 => 'Books|Romance|Western', 4769 10063 => 'Books|Sci-Fi & Fantasy|Science Fiction', 4770 10064 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature', 4771 10065 => 'Books|Fiction & Literature|Short Stories', 4772 10066 => 'Books|Reference|Foreign Languages', 4773 10067 => 'Books|Arts & Entertainment|Games', 4774 10068 => 'Books|Lifestyle & Home|Gardening', 4775 10069 => 'Books|Self-Development|Health & Fitness', 4776 10070 => 'Books|History|Africa', 4777 10071 => 'Books|History|Americas', 4778 10072 => 'Books|History|Ancient', 4779 10073 => 'Books|History|Asia', 4780 10074 => 'Books|History|Australia & Oceania', 4781 10075 => 'Books|History|Europe', 4782 10076 => 'Books|History|Latin America', 4783 10077 => 'Books|History|Middle East', 4784 10078 => 'Books|History|Military', 4785 10079 => 'Books|History|United States', 4786 10080 => 'Books|History|World', 4787 10081 => "Books|Children & Teens|Children's Fiction", 4788 10082 => "Books|Children & Teens|Children's Nonfiction", 4789 10083 => 'Books|Professional & Technical|Law', 4790 10084 => 'Books|Fiction & Literature|Literary Criticism', 4791 10085 => 'Books|Science & Nature|Mathematics', 4792 10086 => 'Books|Professional & Technical|Medical', 4793 10087 => 'Books|Arts & Entertainment|Music', 4794 10088 => 'Books|Science & Nature|Nature', 4795 10089 => 'Books|Arts & Entertainment|Performing Arts', 4796 10090 => 'Books|Lifestyle & Home|Pets', 4797 10091 => 'Books|Nonfiction|Philosophy', 4798 10092 => 'Books|Arts & Entertainment|Photography', 4799 10093 => 'Books|Fiction & Literature|Poetry', 4800 10094 => 'Books|Self-Development|Psychology', 4801 10095 => 'Books|Reference|Almanacs & Yearbooks', 4802 10096 => 'Books|Reference|Atlases & Maps', 4803 10097 => 'Books|Reference|Catalogs & Directories', 4804 10098 => 'Books|Reference|Consumer Guides', 4805 10099 => 'Books|Reference|Dictionaries & Thesauruses', 4806 10100 => 'Books|Reference|Encyclopedias', 4807 10101 => 'Books|Reference|Etiquette', 4808 10102 => 'Books|Reference|Quotations', 4809 10103 => 'Books|Reference|Words & Language', 4810 10104 => 'Books|Reference|Writing', 4811 10105 => 'Books|Religion & Spirituality|Bible Studies', 4812 10106 => 'Books|Religion & Spirituality|Buddhism', 4813 10107 => 'Books|Religion & Spirituality|Christianity', 4814 10108 => 'Books|Religion & Spirituality|Hinduism', 4815 10109 => 'Books|Religion & Spirituality|Islam', 4816 10110 => 'Books|Religion & Spirituality|Judaism', 4817 10111 => 'Books|Science & Nature|Astronomy', 4818 10112 => 'Books|Science & Nature|Chemistry', 4819 10113 => 'Books|Science & Nature|Earth Sciences', 4820 10114 => 'Books|Science & Nature|Essays', 4821 10115 => 'Books|Science & Nature|History', 4822 10116 => 'Books|Science & Nature|Life Sciences', 4823 10117 => 'Books|Science & Nature|Physics', 4824 10118 => 'Books|Science & Nature|Reference', 4825 10119 => 'Books|Self-Development|Self-Improvement', 4826 10120 => 'Books|Nonfiction|Social Science', 4827 10121 => 'Books|Sports & Outdoors|Baseball', 4828 10122 => 'Books|Sports & Outdoors|Basketball', 4829 10123 => 'Books|Sports & Outdoors|Coaching', 4830 10124 => 'Books|Sports & Outdoors|Extreme Sports', 4831 10125 => 'Books|Sports & Outdoors|Football', 4832 10126 => 'Books|Sports & Outdoors|Golf', 4833 10127 => 'Books|Sports & Outdoors|Hockey', 4834 10128 => 'Books|Sports & Outdoors|Mountaineering', 4835 10129 => 'Books|Sports & Outdoors|Outdoors', 4836 10130 => 'Books|Sports & Outdoors|Racket Sports', 4837 10131 => 'Books|Sports & Outdoors|Reference', 4838 10132 => 'Books|Sports & Outdoors|Soccer', 4839 10133 => 'Books|Sports & Outdoors|Training', 4840 10134 => 'Books|Sports & Outdoors|Water Sports', 4841 10135 => 'Books|Sports & Outdoors|Winter Sports', 4842 10136 => 'Books|Reference|Study Aids', 4843 10137 => 'Books|Professional & Technical|Engineering', 4844 10138 => 'Books|Nonfiction|Transportation', 4845 10139 => 'Books|Travel & Adventure|Africa', 4846 10140 => 'Books|Travel & Adventure|Asia', 4847 10141 => 'Books|Travel & Adventure|Specialty Travel', 4848 10142 => 'Books|Travel & Adventure|Canada', 4849 10143 => 'Books|Travel & Adventure|Caribbean', 4850 10144 => 'Books|Travel & Adventure|Latin America', 4851 10145 => 'Books|Travel & Adventure|Essays & Memoirs', 4852 10146 => 'Books|Travel & Adventure|Europe', 4853 10147 => 'Books|Travel & Adventure|Middle East', 4854 10148 => 'Books|Travel & Adventure|United States', 4855 10149 => 'Books|Nonfiction|True Crime', 4856 11001 => 'Books|Sci-Fi & Fantasy|Fantasy|Contemporary', 4857 11002 => 'Books|Sci-Fi & Fantasy|Fantasy|Epic', 4858 11003 => 'Books|Sci-Fi & Fantasy|Fantasy|Historical', 4859 11004 => 'Books|Sci-Fi & Fantasy|Fantasy|Paranormal', 4860 11005 => 'Books|Sci-Fi & Fantasy|Fantasy|Short Stories', 4861 11006 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|Adventure', 4862 11007 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|High Tech', 4863 11008 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|Short Stories', 4864 11009 => 'Books|Professional & Technical|Education|Language Arts & Disciplines', 4865 11010 => 'Books|Communications & Media', 4866 11011 => 'Books|Communications & Media|Broadcasting', 4867 11012 => 'Books|Communications & Media|Digital Media', 4868 11013 => 'Books|Communications & Media|Journalism', 4869 11014 => 'Books|Communications & Media|Photojournalism', 4870 11015 => 'Books|Communications & Media|Print', 4871 11016 => 'Books|Communications & Media|Speech', 4872 11017 => 'Books|Communications & Media|Writing', 4873 11018 => 'Books|Arts & Entertainment|Art & Architecture|Urban Planning', 4874 11019 => 'Books|Arts & Entertainment|Dance', 4875 11020 => 'Books|Arts & Entertainment|Fashion', 4876 11021 => 'Books|Arts & Entertainment|Film', 4877 11022 => 'Books|Arts & Entertainment|Interior Design', 4878 11023 => 'Books|Arts & Entertainment|Media Arts', 4879 11024 => 'Books|Arts & Entertainment|Radio', 4880 11025 => 'Books|Arts & Entertainment|TV', 4881 11026 => 'Books|Arts & Entertainment|Visual Arts', 4882 11027 => 'Books|Biographies & Memoirs|Arts & Entertainment', 4883 11028 => 'Books|Biographies & Memoirs|Business', 4884 11029 => 'Books|Biographies & Memoirs|Culinary', 4885 11030 => 'Books|Biographies & Memoirs|Gay & Lesbian', 4886 11031 => 'Books|Biographies & Memoirs|Historical', 4887 11032 => 'Books|Biographies & Memoirs|Literary', 4888 11033 => 'Books|Biographies & Memoirs|Media & Journalism', 4889 11034 => 'Books|Biographies & Memoirs|Military', 4890 11035 => 'Books|Biographies & Memoirs|Politics', 4891 11036 => 'Books|Biographies & Memoirs|Religious', 4892 11037 => 'Books|Biographies & Memoirs|Science & Technology', 4893 11038 => 'Books|Biographies & Memoirs|Sports', 4894 11039 => 'Books|Biographies & Memoirs|Women', 4895 11040 => 'Books|Romance|New Adult', 4896 11042 => 'Books|Romance|Romantic Comedy', 4897 11043 => 'Books|Romance|Gay & Lesbian', 4898 11044 => 'Books|Fiction & Literature|Essays', 4899 11045 => 'Books|Fiction & Literature|Anthologies', 4900 11046 => 'Books|Fiction & Literature|Comparative Literature', 4901 11047 => 'Books|Fiction & Literature|Drama', 4902 11049 => 'Books|Fiction & Literature|Fairy Tales, Myths & Fables', 4903 11050 => 'Books|Fiction & Literature|Family', 4904 11051 => 'Books|Comics & Graphic Novels|Manga|School Drama', 4905 11052 => 'Books|Comics & Graphic Novels|Manga|Human Drama', 4906 11053 => 'Books|Comics & Graphic Novels|Manga|Family Drama', 4907 11054 => 'Books|Sports & Outdoors|Boxing', 4908 11055 => 'Books|Sports & Outdoors|Cricket', 4909 11056 => 'Books|Sports & Outdoors|Cycling', 4910 11057 => 'Books|Sports & Outdoors|Equestrian', 4911 11058 => 'Books|Sports & Outdoors|Martial Arts & Self Defense', 4912 11059 => 'Books|Sports & Outdoors|Motor Sports', 4913 11060 => 'Books|Sports & Outdoors|Rugby', 4914 11061 => 'Books|Sports & Outdoors|Running', 4915 11062 => 'Books|Self-Development|Diet & Nutrition', 4916 11063 => 'Books|Science & Nature|Agriculture', 4917 11064 => 'Books|Science & Nature|Atmosphere', 4918 11065 => 'Books|Science & Nature|Biology', 4919 11066 => 'Books|Science & Nature|Ecology', 4920 11067 => 'Books|Science & Nature|Environment', 4921 11068 => 'Books|Science & Nature|Geography', 4922 11069 => 'Books|Science & Nature|Geology', 4923 11070 => 'Books|Nonfiction|Social Science|Anthropology', 4924 11071 => 'Books|Nonfiction|Social Science|Archaeology', 4925 11072 => 'Books|Nonfiction|Social Science|Civics', 4926 11073 => 'Books|Nonfiction|Social Science|Government', 4927 11074 => 'Books|Nonfiction|Social Science|Social Studies', 4928 11075 => 'Books|Nonfiction|Social Science|Social Welfare', 4929 11076 => 'Books|Nonfiction|Social Science|Society', 4930 11077 => 'Books|Nonfiction|Philosophy|Aesthetics', 4931 11078 => 'Books|Nonfiction|Philosophy|Epistemology', 4932 11079 => 'Books|Nonfiction|Philosophy|Ethics', 4933 11080 => 'Books|Nonfiction|Philosophy|Language', 4934 11081 => 'Books|Nonfiction|Philosophy|Logic', 4935 11082 => 'Books|Nonfiction|Philosophy|Metaphysics', 4936 11083 => 'Books|Nonfiction|Philosophy|Political', 4937 11084 => 'Books|Nonfiction|Philosophy|Religion', 4938 11085 => 'Books|Reference|Manuals', 4939 11086 => 'Books|Kids', 4940 11087 => 'Books|Kids|Animals', 4941 11088 => 'Books|Kids|Basic Concepts', 4942 11089 => 'Books|Kids|Basic Concepts|Alphabet', 4943 11090 => 'Books|Kids|Basic Concepts|Body', 4944 11091 => 'Books|Kids|Basic Concepts|Colors', 4945 11092 => 'Books|Kids|Basic Concepts|Counting & Numbers', 4946 11093 => 'Books|Kids|Basic Concepts|Date & Time', 4947 11094 => 'Books|Kids|Basic Concepts|General', 4948 11095 => 'Books|Kids|Basic Concepts|Money', 4949 11096 => 'Books|Kids|Basic Concepts|Opposites', 4950 11097 => 'Books|Kids|Basic Concepts|Seasons', 4951 11098 => 'Books|Kids|Basic Concepts|Senses & Sensation', 4952 11099 => 'Books|Kids|Basic Concepts|Size & Shape', 4953 11100 => 'Books|Kids|Basic Concepts|Sounds', 4954 11101 => 'Books|Kids|Basic Concepts|Words', 4955 11102 => 'Books|Kids|Biography', 4956 11103 => 'Books|Kids|Careers & Occupations', 4957 11104 => 'Books|Kids|Computers & Technology', 4958 11105 => 'Books|Kids|Cooking & Food', 4959 11106 => 'Books|Kids|Arts & Entertainment', 4960 11107 => 'Books|Kids|Arts & Entertainment|Art', 4961 11108 => 'Books|Kids|Arts & Entertainment|Crafts', 4962 11109 => 'Books|Kids|Arts & Entertainment|Music', 4963 11110 => 'Books|Kids|Arts & Entertainment|Performing Arts', 4964 11111 => 'Books|Kids|Family', 4965 11112 => 'Books|Kids|Fiction', 4966 11113 => 'Books|Kids|Fiction|Action & Adventure', 4967 11114 => 'Books|Kids|Fiction|Animals', 4968 11115 => 'Books|Kids|Fiction|Classics', 4969 11116 => 'Books|Kids|Fiction|Comics & Graphic Novels', 4970 11117 => 'Books|Kids|Fiction|Culture, Places & People', 4971 11118 => 'Books|Kids|Fiction|Family & Relationships', 4972 11119 => 'Books|Kids|Fiction|Fantasy', 4973 11120 => 'Books|Kids|Fiction|Fairy Tales, Myths & Fables', 4974 11121 => 'Books|Kids|Fiction|Favorite Characters', 4975 11122 => 'Books|Kids|Fiction|Historical', 4976 11123 => 'Books|Kids|Fiction|Holidays & Celebrations', 4977 11124 => 'Books|Kids|Fiction|Monsters & Ghosts', 4978 11125 => 'Books|Kids|Fiction|Mysteries', 4979 11126 => 'Books|Kids|Fiction|Nature', 4980 11127 => 'Books|Kids|Fiction|Religion', 4981 11128 => 'Books|Kids|Fiction|Sci-Fi', 4982 11129 => 'Books|Kids|Fiction|Social Issues', 4983 11130 => 'Books|Kids|Fiction|Sports & Recreation', 4984 11131 => 'Books|Kids|Fiction|Transportation', 4985 11132 => 'Books|Kids|Games & Activities', 4986 11133 => 'Books|Kids|General Nonfiction', 4987 11134 => 'Books|Kids|Health', 4988 11135 => 'Books|Kids|History', 4989 11136 => 'Books|Kids|Holidays & Celebrations', 4990 11137 => 'Books|Kids|Holidays & Celebrations|Birthdays', 4991 11138 => 'Books|Kids|Holidays & Celebrations|Christmas & Advent', 4992 11139 => 'Books|Kids|Holidays & Celebrations|Easter & Lent', 4993 11140 => 'Books|Kids|Holidays & Celebrations|General', 4994 11141 => 'Books|Kids|Holidays & Celebrations|Halloween', 4995 11142 => 'Books|Kids|Holidays & Celebrations|Hanukkah', 4996 11143 => 'Books|Kids|Holidays & Celebrations|Other', 4997 11144 => 'Books|Kids|Holidays & Celebrations|Passover', 4998 11145 => 'Books|Kids|Holidays & Celebrations|Patriotic Holidays', 4999 11146 => 'Books|Kids|Holidays & Celebrations|Ramadan', 5000 11147 => 'Books|Kids|Holidays & Celebrations|Thanksgiving', 5001 11148 => "Books|Kids|Holidays & Celebrations|Valentine's Day", 5002 11149 => 'Books|Kids|Humor', 5003 11150 => 'Books|Kids|Humor|Jokes & Riddles', 5004 11151 => 'Books|Kids|Poetry', 5005 11152 => 'Books|Kids|Learning to Read', 5006 11153 => 'Books|Kids|Learning to Read|Chapter Books', 5007 11154 => 'Books|Kids|Learning to Read|Early Readers', 5008 11155 => 'Books|Kids|Learning to Read|Intermediate Readers', 5009 11156 => 'Books|Kids|Nursery Rhymes', 5010 11157 => 'Books|Kids|Government', 5011 11158 => 'Books|Kids|Reference', 5012 11159 => 'Books|Kids|Religion', 5013 11160 => 'Books|Kids|Science & Nature', 5014 11161 => 'Books|Kids|Social Issues', 5015 11162 => 'Books|Kids|Social Studies', 5016 11163 => 'Books|Kids|Sports & Recreation', 5017 11164 => 'Books|Kids|Transportation', 5018 11165 => 'Books|Young Adult', 5019 11166 => 'Books|Young Adult|Animals', 5020 11167 => 'Books|Young Adult|Biography', 5021 11168 => 'Books|Young Adult|Careers & Occupations', 5022 11169 => 'Books|Young Adult|Computers & Technology', 5023 11170 => 'Books|Young Adult|Cooking & Food', 5024 11171 => 'Books|Young Adult|Arts & Entertainment', 5025 11172 => 'Books|Young Adult|Arts & Entertainment|Art', 5026 11173 => 'Books|Young Adult|Arts & Entertainment|Crafts', 5027 11174 => 'Books|Young Adult|Arts & Entertainment|Music', 5028 11175 => 'Books|Young Adult|Arts & Entertainment|Performing Arts', 5029 11176 => 'Books|Young Adult|Family', 5030 11177 => 'Books|Young Adult|Fiction', 5031 11178 => 'Books|Young Adult|Fiction|Action & Adventure', 5032 11179 => 'Books|Young Adult|Fiction|Animals', 5033 11180 => 'Books|Young Adult|Fiction|Classics', 5034 11181 => 'Books|Young Adult|Fiction|Comics & Graphic Novels', 5035 11182 => 'Books|Young Adult|Fiction|Culture, Places & People', 5036 11183 => 'Books|Young Adult|Fiction|Dystopian', 5037 11184 => 'Books|Young Adult|Fiction|Family & Relationships', 5038 11185 => 'Books|Young Adult|Fiction|Fantasy', 5039 11186 => 'Books|Young Adult|Fiction|Fairy Tales, Myths & Fables', 5040 11187 => 'Books|Young Adult|Fiction|Favorite Characters', 5041 11188 => 'Books|Young Adult|Fiction|Historical', 5042 11189 => 'Books|Young Adult|Fiction|Holidays & Celebrations', 5043 11190 => 'Books|Young Adult|Fiction|Horror, Monsters & Ghosts', 5044 11191 => 'Books|Young Adult|Fiction|Crime & Mystery', 5045 11192 => 'Books|Young Adult|Fiction|Nature', 5046 11193 => 'Books|Young Adult|Fiction|Religion', 5047 11194 => 'Books|Young Adult|Fiction|Romance', 5048 11195 => 'Books|Young Adult|Fiction|Sci-Fi', 5049 11196 => 'Books|Young Adult|Fiction|Coming of Age', 5050 11197 => 'Books|Young Adult|Fiction|Sports & Recreation', 5051 11198 => 'Books|Young Adult|Fiction|Transportation', 5052 11199 => 'Books|Young Adult|Games & Activities', 5053 11200 => 'Books|Young Adult|General Nonfiction', 5054 11201 => 'Books|Young Adult|Health', 5055 11202 => 'Books|Young Adult|History', 5056 11203 => 'Books|Young Adult|Holidays & Celebrations', 5057 11204 => 'Books|Young Adult|Holidays & Celebrations|Birthdays', 5058 11205 => 'Books|Young Adult|Holidays & Celebrations|Christmas & Advent', 5059 11206 => 'Books|Young Adult|Holidays & Celebrations|Easter & Lent', 5060 11207 => 'Books|Young Adult|Holidays & Celebrations|General', 5061 11208 => 'Books|Young Adult|Holidays & Celebrations|Halloween', 5062 11209 => 'Books|Young Adult|Holidays & Celebrations|Hanukkah', 5063 11210 => 'Books|Young Adult|Holidays & Celebrations|Other', 5064 11211 => 'Books|Young Adult|Holidays & Celebrations|Passover', 5065 11212 => 'Books|Young Adult|Holidays & Celebrations|Patriotic Holidays', 5066 11213 => 'Books|Young Adult|Holidays & Celebrations|Ramadan', 5067 11214 => 'Books|Young Adult|Holidays & Celebrations|Thanksgiving', 5068 11215 => "Books|Young Adult|Holidays & Celebrations|Valentine's Day", 5069 11216 => 'Books|Young Adult|Humor', 5070 11217 => 'Books|Young Adult|Humor|Jokes & Riddles', 5071 11218 => 'Books|Young Adult|Poetry', 5072 11219 => 'Books|Young Adult|Politics & Government', 5073 11220 => 'Books|Young Adult|Reference', 5074 11221 => 'Books|Young Adult|Religion', 5075 11222 => 'Books|Young Adult|Science & Nature', 5076 11223 => 'Books|Young Adult|Coming of Age', 5077 11224 => 'Books|Young Adult|Social Studies', 5078 11225 => 'Books|Young Adult|Sports & Recreation', 5079 11226 => 'Books|Young Adult|Transportation', 5080 11227 => 'Books|Communications & Media', 5081 11228 => 'Books|Military & Warfare', 5082 11229 => 'Books|Romance|Inspirational', 5083 11231 => 'Books|Romance|Holiday', 5084 11232 => 'Books|Romance|Wholesome', 5085 11233 => 'Books|Romance|Military', 5086 11234 => 'Books|Arts & Entertainment|Art History', 5087 11236 => 'Books|Arts & Entertainment|Design', 5088 11243 => 'Books|Business & Personal Finance|Accounting', 5089 11244 => 'Books|Business & Personal Finance|Hospitality', 5090 11245 => 'Books|Business & Personal Finance|Real Estate', 5091 11246 => 'Books|Humor|Jokes & Riddles', 5092 11247 => 'Books|Religion & Spirituality|Comparative Religion', 5093 11255 => 'Books|Cookbooks, Food & Wine|Culinary Arts', 5094 11259 => 'Books|Mysteries & Thrillers|Cozy', 5095 11260 => 'Books|Politics & Current Events|Current Events', 5096 11261 => 'Books|Politics & Current Events|Foreign Policy & International Relations', 5097 11262 => 'Books|Politics & Current Events|Local Government', 5098 11263 => 'Books|Politics & Current Events|National Government', 5099 11264 => 'Books|Politics & Current Events|Political Science', 5100 11265 => 'Books|Politics & Current Events|Public Administration', 5101 11266 => 'Books|Politics & Current Events|World Affairs', 5102 11273 => 'Books|Nonfiction|Family & Relationships|Family & Childcare', 5103 11274 => 'Books|Nonfiction|Family & Relationships|Love & Romance', 5104 11275 => 'Books|Sci-Fi & Fantasy|Fantasy|Urban', 5105 11276 => 'Books|Reference|Foreign Languages|Arabic', 5106 11277 => 'Books|Reference|Foreign Languages|Bilingual Editions', 5107 11278 => 'Books|Reference|Foreign Languages|African Languages', 5108 11279 => 'Books|Reference|Foreign Languages|Ancient Languages', 5109 11280 => 'Books|Reference|Foreign Languages|Chinese', 5110 11281 => 'Books|Reference|Foreign Languages|English', 5111 11282 => 'Books|Reference|Foreign Languages|French', 5112 11283 => 'Books|Reference|Foreign Languages|German', 5113 11284 => 'Books|Reference|Foreign Languages|Hebrew', 5114 11285 => 'Books|Reference|Foreign Languages|Hindi', 5115 11286 => 'Books|Reference|Foreign Languages|Italian', 5116 11287 => 'Books|Reference|Foreign Languages|Japanese', 5117 11288 => 'Books|Reference|Foreign Languages|Korean', 5118 11289 => 'Books|Reference|Foreign Languages|Linguistics', 5119 11290 => 'Books|Reference|Foreign Languages|Other Languages', 5120 11291 => 'Books|Reference|Foreign Languages|Portuguese', 5121 11292 => 'Books|Reference|Foreign Languages|Russian', 5122 11293 => 'Books|Reference|Foreign Languages|Spanish', 5123 11294 => 'Books|Reference|Foreign Languages|Speech Pathology', 5124 11295 => 'Books|Science & Nature|Mathematics|Advanced Mathematics', 5125 11296 => 'Books|Science & Nature|Mathematics|Algebra', 5126 11297 => 'Books|Science & Nature|Mathematics|Arithmetic', 5127 11298 => 'Books|Science & Nature|Mathematics|Calculus', 5128 11299 => 'Books|Science & Nature|Mathematics|Geometry', 5129 11300 => 'Books|Science & Nature|Mathematics|Statistics', 5130 11301 => 'Books|Professional & Technical|Medical|Veterinary', 5131 11302 => 'Books|Professional & Technical|Medical|Neuroscience', 5132 11303 => 'Books|Professional & Technical|Medical|Immunology', 5133 11304 => 'Books|Professional & Technical|Medical|Nursing', 5134 11305 => 'Books|Professional & Technical|Medical|Pharmacology & Toxicology', 5135 11306 => 'Books|Professional & Technical|Medical|Anatomy & Physiology', 5136 11307 => 'Books|Professional & Technical|Medical|Dentistry', 5137 11308 => 'Books|Professional & Technical|Medical|Emergency Medicine', 5138 11309 => 'Books|Professional & Technical|Medical|Genetics', 5139 11310 => 'Books|Professional & Technical|Medical|Psychiatry', 5140 11311 => 'Books|Professional & Technical|Medical|Radiology', 5141 11312 => 'Books|Professional & Technical|Medical|Alternative Medicine', 5142 11317 => 'Books|Nonfiction|Philosophy|Political Philosophy', 5143 11319 => 'Books|Nonfiction|Philosophy|Philosophy of Language', 5144 11320 => 'Books|Nonfiction|Philosophy|Philosophy of Religion', 5145 11327 => 'Books|Nonfiction|Social Science|Sociology', 5146 11329 => 'Books|Professional & Technical|Engineering|Aeronautics', 5147 11330 => 'Books|Professional & Technical|Engineering|Chemical & Petroleum Engineering', 5148 11331 => 'Books|Professional & Technical|Engineering|Civil Engineering', 5149 11332 => 'Books|Professional & Technical|Engineering|Computer Science', 5150 11333 => 'Books|Professional & Technical|Engineering|Electrical Engineering', 5151 11334 => 'Books|Professional & Technical|Engineering|Environmental Engineering', 5152 11335 => 'Books|Professional & Technical|Engineering|Mechanical Engineering', 5153 11336 => 'Books|Professional & Technical|Engineering|Power Resources', 5154 11337 => 'Books|Comics & Graphic Novels|Manga|Boys', 5155 11338 => 'Books|Comics & Graphic Novels|Manga|Men', 5156 11339 => 'Books|Comics & Graphic Novels|Manga|Girls', 5157 11340 => 'Books|Comics & Graphic Novels|Manga|Women', 5158 11341 => 'Books|Comics & Graphic Novels|Manga|Other', 5159 11342 => 'Books|Comics & Graphic Novels|Manga|Yaoi', 5160 11343 => 'Books|Comics & Graphic Novels|Manga|Comic Essays', 5161 12001 => 'Mac App Store|Business', 5162 12002 => 'Mac App Store|Developer Tools', 5163 12003 => 'Mac App Store|Education', 5164 12004 => 'Mac App Store|Entertainment', 5165 12005 => 'Mac App Store|Finance', 5166 12006 => 'Mac App Store|Games', 5167 12007 => 'Mac App Store|Health & Fitness', 5168 12008 => 'Mac App Store|Lifestyle', 5169 12010 => 'Mac App Store|Medical', 5170 12011 => 'Mac App Store|Music', 5171 12012 => 'Mac App Store|News', 5172 12013 => 'Mac App Store|Photography', 5173 12014 => 'Mac App Store|Productivity', 5174 12015 => 'Mac App Store|Reference', 5175 12016 => 'Mac App Store|Social Networking', 5176 12017 => 'Mac App Store|Sports', 5177 12018 => 'Mac App Store|Travel', 5178 12019 => 'Mac App Store|Utilities', 5179 12020 => 'Mac App Store|Video', 5180 12021 => 'Mac App Store|Weather', 5181 12022 => 'Mac App Store|Graphics & Design', 5182 12201 => 'Mac App Store|Games|Action', 5183 12202 => 'Mac App Store|Games|Adventure', 5184 12203 => 'Mac App Store|Games|Casual', 5185 12204 => 'Mac App Store|Games|Board', 5186 12205 => 'Mac App Store|Games|Card', 5187 12206 => 'Mac App Store|Games|Casino', 5188 12207 => 'Mac App Store|Games|Dice', 5189 12208 => 'Mac App Store|Games|Educational', 5190 12209 => 'Mac App Store|Games|Family', 5191 12210 => 'Mac App Store|Games|Kids', 5192 12211 => 'Mac App Store|Games|Music', 5193 12212 => 'Mac App Store|Games|Puzzle', 5194 12213 => 'Mac App Store|Games|Racing', 5195 12214 => 'Mac App Store|Games|Role Playing', 5196 12215 => 'Mac App Store|Games|Simulation', 5197 12216 => 'Mac App Store|Games|Sports', 5198 12217 => 'Mac App Store|Games|Strategy', 5199 12218 => 'Mac App Store|Games|Trivia', 5200 12219 => 'Mac App Store|Games|Word', 5201 13001 => 'App Store|Magazines & Newspapers|News & Politics', 5202 13002 => 'App Store|Magazines & Newspapers|Fashion & Style', 5203 13003 => 'App Store|Magazines & Newspapers|Home & Garden', 5204 13004 => 'App Store|Magazines & Newspapers|Outdoors & Nature', 5205 13005 => 'App Store|Magazines & Newspapers|Sports & Leisure', 5206 13006 => 'App Store|Magazines & Newspapers|Automotive', 5207 13007 => 'App Store|Magazines & Newspapers|Arts & Photography', 5208 13008 => 'App Store|Magazines & Newspapers|Brides & Weddings', 5209 13009 => 'App Store|Magazines & Newspapers|Business & Investing', 5210 13010 => "App Store|Magazines & Newspapers|Children's Magazines", 5211 13011 => 'App Store|Magazines & Newspapers|Computers & Internet', 5212 13012 => 'App Store|Magazines & Newspapers|Cooking, Food & Drink', 5213 13013 => 'App Store|Magazines & Newspapers|Crafts & Hobbies', 5214 13014 => 'App Store|Magazines & Newspapers|Electronics & Audio', 5215 13015 => 'App Store|Magazines & Newspapers|Entertainment', 5216 13017 => 'App Store|Magazines & Newspapers|Health, Mind & Body', 5217 13018 => 'App Store|Magazines & Newspapers|History', 5218 13019 => 'App Store|Magazines & Newspapers|Literary Magazines & Journals', 5219 13020 => "App Store|Magazines & Newspapers|Men's Interest", 5220 13021 => 'App Store|Magazines & Newspapers|Movies & Music', 5221 13023 => 'App Store|Magazines & Newspapers|Parenting & Family', 5222 13024 => 'App Store|Magazines & Newspapers|Pets', 5223 13025 => 'App Store|Magazines & Newspapers|Professional & Trade', 5224 13026 => 'App Store|Magazines & Newspapers|Regional News', 5225 13027 => 'App Store|Magazines & Newspapers|Science', 5226 13028 => 'App Store|Magazines & Newspapers|Teens', 5227 13029 => 'App Store|Magazines & Newspapers|Travel & Regional', 5228 13030 => "App Store|Magazines & Newspapers|Women's Interest", 5229 15000 => 'Textbooks|Arts & Entertainment', 5230 15001 => 'Textbooks|Arts & Entertainment|Art & Architecture', 5231 15002 => 'Textbooks|Arts & Entertainment|Art & Architecture|Urban Planning', 5232 15003 => 'Textbooks|Arts & Entertainment|Art History', 5233 15004 => 'Textbooks|Arts & Entertainment|Dance', 5234 15005 => 'Textbooks|Arts & Entertainment|Design', 5235 15006 => 'Textbooks|Arts & Entertainment|Fashion', 5236 15007 => 'Textbooks|Arts & Entertainment|Film', 5237 15008 => 'Textbooks|Arts & Entertainment|Games', 5238 15009 => 'Textbooks|Arts & Entertainment|Interior Design', 5239 15010 => 'Textbooks|Arts & Entertainment|Media Arts', 5240 15011 => 'Textbooks|Arts & Entertainment|Music', 5241 15012 => 'Textbooks|Arts & Entertainment|Performing Arts', 5242 15013 => 'Textbooks|Arts & Entertainment|Photography', 5243 15014 => 'Textbooks|Arts & Entertainment|Theater', 5244 15015 => 'Textbooks|Arts & Entertainment|TV', 5245 15016 => 'Textbooks|Arts & Entertainment|Visual Arts', 5246 15017 => 'Textbooks|Biographies & Memoirs', 5247 15018 => 'Textbooks|Business & Personal Finance', 5248 15019 => 'Textbooks|Business & Personal Finance|Accounting', 5249 15020 => 'Textbooks|Business & Personal Finance|Careers', 5250 15021 => 'Textbooks|Business & Personal Finance|Economics', 5251 15022 => 'Textbooks|Business & Personal Finance|Finance', 5252 15023 => 'Textbooks|Business & Personal Finance|Hospitality', 5253 15024 => 'Textbooks|Business & Personal Finance|Industries & Professions', 5254 15025 => 'Textbooks|Business & Personal Finance|Investing', 5255 15026 => 'Textbooks|Business & Personal Finance|Management & Leadership', 5256 15027 => 'Textbooks|Business & Personal Finance|Marketing & Sales', 5257 15028 => 'Textbooks|Business & Personal Finance|Personal Finance', 5258 15029 => 'Textbooks|Business & Personal Finance|Real Estate', 5259 15030 => 'Textbooks|Business & Personal Finance|Reference', 5260 15031 => 'Textbooks|Business & Personal Finance|Small Business & Entrepreneurship', 5261 15032 => 'Textbooks|Children & Teens', 5262 15033 => 'Textbooks|Children & Teens|Fiction', 5263 15034 => 'Textbooks|Children & Teens|Nonfiction', 5264 15035 => 'Textbooks|Comics & Graphic Novels', 5265 15036 => 'Textbooks|Comics & Graphic Novels|Graphic Novels', 5266 15037 => 'Textbooks|Comics & Graphic Novels|Manga', 5267 15038 => 'Textbooks|Communications & Media', 5268 15039 => 'Textbooks|Communications & Media|Broadcasting', 5269 15040 => 'Textbooks|Communications & Media|Digital Media', 5270 15041 => 'Textbooks|Communications & Media|Journalism', 5271 15042 => 'Textbooks|Communications & Media|Photojournalism', 5272 15043 => 'Textbooks|Communications & Media|Print', 5273 15044 => 'Textbooks|Communications & Media|Speech', 5274 15045 => 'Textbooks|Communications & Media|Writing', 5275 15046 => 'Textbooks|Computers & Internet', 5276 15047 => 'Textbooks|Computers & Internet|Computers', 5277 15048 => 'Textbooks|Computers & Internet|Databases', 5278 15049 => 'Textbooks|Computers & Internet|Digital Media', 5279 15050 => 'Textbooks|Computers & Internet|Internet', 5280 15051 => 'Textbooks|Computers & Internet|Network', 5281 15052 => 'Textbooks|Computers & Internet|Operating Systems', 5282 15053 => 'Textbooks|Computers & Internet|Programming', 5283 15054 => 'Textbooks|Computers & Internet|Software', 5284 15055 => 'Textbooks|Computers & Internet|System Administration', 5285 15056 => 'Textbooks|Cookbooks, Food & Wine', 5286 15057 => 'Textbooks|Cookbooks, Food & Wine|Beverages', 5287 15058 => 'Textbooks|Cookbooks, Food & Wine|Courses & Dishes', 5288 15059 => 'Textbooks|Cookbooks, Food & Wine|Culinary Arts', 5289 15060 => 'Textbooks|Cookbooks, Food & Wine|Methods', 5290 15061 => 'Textbooks|Cookbooks, Food & Wine|Reference', 5291 15062 => 'Textbooks|Cookbooks, Food & Wine|Regional & Ethnic', 5292 15063 => 'Textbooks|Cookbooks, Food & Wine|Special Diet', 5293 15064 => 'Textbooks|Cookbooks, Food & Wine|Special Occasions', 5294 15065 => 'Textbooks|Cookbooks, Food & Wine|Specific Ingredients', 5295 15066 => 'Textbooks|Engineering', 5296 15067 => 'Textbooks|Engineering|Aeronautics', 5297 15068 => 'Textbooks|Engineering|Chemical & Petroleum Engineering', 5298 15069 => 'Textbooks|Engineering|Civil Engineering', 5299 15070 => 'Textbooks|Engineering|Computer Science', 5300 15071 => 'Textbooks|Engineering|Electrical Engineering', 5301 15072 => 'Textbooks|Engineering|Environmental Engineering', 5302 15073 => 'Textbooks|Engineering|Mechanical Engineering', 5303 15074 => 'Textbooks|Engineering|Power Resources', 5304 15075 => 'Textbooks|Fiction & Literature', 5305 15076 => 'Textbooks|Fiction & Literature|Latino', 5306 15077 => 'Textbooks|Fiction & Literature|Action & Adventure', 5307 15078 => 'Textbooks|Fiction & Literature|African American', 5308 15079 => 'Textbooks|Fiction & Literature|Anthologies', 5309 15080 => 'Textbooks|Fiction & Literature|Classics', 5310 15081 => 'Textbooks|Fiction & Literature|Comparative Literature', 5311 15082 => 'Textbooks|Fiction & Literature|Erotica', 5312 15083 => 'Textbooks|Fiction & Literature|Gay', 5313 15084 => 'Textbooks|Fiction & Literature|Ghost', 5314 15085 => 'Textbooks|Fiction & Literature|Historical', 5315 15086 => 'Textbooks|Fiction & Literature|Horror', 5316 15087 => 'Textbooks|Fiction & Literature|Literary', 5317 15088 => 'Textbooks|Fiction & Literature|Literary Criticism', 5318 15089 => 'Textbooks|Fiction & Literature|Poetry', 5319 15090 => 'Textbooks|Fiction & Literature|Religious', 5320 15091 => 'Textbooks|Fiction & Literature|Short Stories', 5321 15092 => 'Textbooks|Health, Mind & Body', 5322 15093 => 'Textbooks|Health, Mind & Body|Fitness', 5323 15094 => 'Textbooks|Health, Mind & Body|Self-Improvement', 5324 15095 => 'Textbooks|History', 5325 15096 => 'Textbooks|History|Africa', 5326 15097 => 'Textbooks|History|Americas', 5327 15098 => 'Textbooks|History|Americas|Canada', 5328 15099 => 'Textbooks|History|Americas|Latin America', 5329 15100 => 'Textbooks|History|Americas|United States', 5330 15101 => 'Textbooks|History|Ancient', 5331 15102 => 'Textbooks|History|Asia', 5332 15103 => 'Textbooks|History|Australia & Oceania', 5333 15104 => 'Textbooks|History|Europe', 5334 15105 => 'Textbooks|History|Middle East', 5335 15106 => 'Textbooks|History|Military', 5336 15107 => 'Textbooks|History|World', 5337 15108 => 'Textbooks|Humor', 5338 15109 => 'Textbooks|Language Studies', 5339 15110 => 'Textbooks|Language Studies|African Languages', 5340 15111 => 'Textbooks|Language Studies|Ancient Languages', 5341 15112 => 'Textbooks|Language Studies|Arabic', 5342 15113 => 'Textbooks|Language Studies|Bilingual Editions', 5343 15114 => 'Textbooks|Language Studies|Chinese', 5344 15115 => 'Textbooks|Language Studies|English', 5345 15116 => 'Textbooks|Language Studies|French', 5346 15117 => 'Textbooks|Language Studies|German', 5347 15118 => 'Textbooks|Language Studies|Hebrew', 5348 15119 => 'Textbooks|Language Studies|Hindi', 5349 15120 => 'Textbooks|Language Studies|Indigenous Languages', 5350 15121 => 'Textbooks|Language Studies|Italian', 5351 15122 => 'Textbooks|Language Studies|Japanese', 5352 15123 => 'Textbooks|Language Studies|Korean', 5353 15124 => 'Textbooks|Language Studies|Linguistics', 5354 15125 => 'Textbooks|Language Studies|Other Language', 5355 15126 => 'Textbooks|Language Studies|Portuguese', 5356 15127 => 'Textbooks|Language Studies|Russian', 5357 15128 => 'Textbooks|Language Studies|Spanish', 5358 15129 => 'Textbooks|Language Studies|Speech Pathology', 5359 15130 => 'Textbooks|Lifestyle & Home', 5360 15131 => 'Textbooks|Lifestyle & Home|Antiques & Collectibles', 5361 15132 => 'Textbooks|Lifestyle & Home|Crafts & Hobbies', 5362 15133 => 'Textbooks|Lifestyle & Home|Gardening', 5363 15134 => 'Textbooks|Lifestyle & Home|Pets', 5364 15135 => 'Textbooks|Mathematics', 5365 15136 => 'Textbooks|Mathematics|Advanced Mathematics', 5366 15137 => 'Textbooks|Mathematics|Algebra', 5367 15138 => 'Textbooks|Mathematics|Arithmetic', 5368 15139 => 'Textbooks|Mathematics|Calculus', 5369 15140 => 'Textbooks|Mathematics|Geometry', 5370 15141 => 'Textbooks|Mathematics|Statistics', 5371 15142 => 'Textbooks|Medicine', 5372 15143 => 'Textbooks|Medicine|Anatomy & Physiology', 5373 15144 => 'Textbooks|Medicine|Dentistry', 5374 15145 => 'Textbooks|Medicine|Emergency Medicine', 5375 15146 => 'Textbooks|Medicine|Genetics', 5376 15147 => 'Textbooks|Medicine|Immunology', 5377 15148 => 'Textbooks|Medicine|Neuroscience', 5378 15149 => 'Textbooks|Medicine|Nursing', 5379 15150 => 'Textbooks|Medicine|Pharmacology & Toxicology', 5380 15151 => 'Textbooks|Medicine|Psychiatry', 5381 15152 => 'Textbooks|Medicine|Psychology', 5382 15153 => 'Textbooks|Medicine|Radiology', 5383 15154 => 'Textbooks|Medicine|Veterinary', 5384 15155 => 'Textbooks|Mysteries & Thrillers', 5385 15156 => 'Textbooks|Mysteries & Thrillers|British Detectives', 5386 15157 => 'Textbooks|Mysteries & Thrillers|Hard-Boiled', 5387 15158 => 'Textbooks|Mysteries & Thrillers|Historical', 5388 15159 => 'Textbooks|Mysteries & Thrillers|Police Procedural', 5389 15160 => 'Textbooks|Mysteries & Thrillers|Short Stories', 5390 15161 => 'Textbooks|Mysteries & Thrillers|Women Sleuths', 5391 15162 => 'Textbooks|Nonfiction', 5392 15163 => 'Textbooks|Nonfiction|Family & Relationships', 5393 15164 => 'Textbooks|Nonfiction|Transportation', 5394 15165 => 'Textbooks|Nonfiction|True Crime', 5395 15166 => 'Textbooks|Parenting', 5396 15167 => 'Textbooks|Philosophy', 5397 15168 => 'Textbooks|Philosophy|Aesthetics', 5398 15169 => 'Textbooks|Philosophy|Epistemology', 5399 15170 => 'Textbooks|Philosophy|Ethics', 5400 15171 => 'Textbooks|Philosophy|Philosophy of Language', 5401 15172 => 'Textbooks|Philosophy|Logic', 5402 15173 => 'Textbooks|Philosophy|Metaphysics', 5403 15174 => 'Textbooks|Philosophy|Political Philosophy', 5404 15175 => 'Textbooks|Philosophy|Philosophy of Religion', 5405 15176 => 'Textbooks|Politics & Current Events', 5406 15177 => 'Textbooks|Politics & Current Events|Current Events', 5407 15178 => 'Textbooks|Politics & Current Events|Foreign Policy & International Relations', 5408 15179 => 'Textbooks|Politics & Current Events|Local Governments', 5409 15180 => 'Textbooks|Politics & Current Events|National Governments', 5410 15181 => 'Textbooks|Politics & Current Events|Political Science', 5411 15182 => 'Textbooks|Politics & Current Events|Public Administration', 5412 15183 => 'Textbooks|Politics & Current Events|World Affairs', 5413 15184 => 'Textbooks|Professional & Technical', 5414 15185 => 'Textbooks|Professional & Technical|Design', 5415 15186 => 'Textbooks|Professional & Technical|Language Arts & Disciplines', 5416 15187 => 'Textbooks|Professional & Technical|Engineering', 5417 15188 => 'Textbooks|Professional & Technical|Law', 5418 15189 => 'Textbooks|Professional & Technical|Medical', 5419 15190 => 'Textbooks|Reference', 5420 15191 => 'Textbooks|Reference|Almanacs & Yearbooks', 5421 15192 => 'Textbooks|Reference|Atlases & Maps', 5422 15193 => 'Textbooks|Reference|Catalogs & Directories', 5423 15194 => 'Textbooks|Reference|Consumer Guides', 5424 15195 => 'Textbooks|Reference|Dictionaries & Thesauruses', 5425 15196 => 'Textbooks|Reference|Encyclopedias', 5426 15197 => 'Textbooks|Reference|Etiquette', 5427 15198 => 'Textbooks|Reference|Quotations', 5428 15199 => 'Textbooks|Reference|Study Aids', 5429 15200 => 'Textbooks|Reference|Words & Language', 5430 15201 => 'Textbooks|Reference|Writing', 5431 15202 => 'Textbooks|Religion & Spirituality', 5432 15203 => 'Textbooks|Religion & Spirituality|Bible Studies', 5433 15204 => 'Textbooks|Religion & Spirituality|Bibles', 5434 15205 => 'Textbooks|Religion & Spirituality|Buddhism', 5435 15206 => 'Textbooks|Religion & Spirituality|Christianity', 5436 15207 => 'Textbooks|Religion & Spirituality|Comparative Religion', 5437 15208 => 'Textbooks|Religion & Spirituality|Hinduism', 5438 15209 => 'Textbooks|Religion & Spirituality|Islam', 5439 15210 => 'Textbooks|Religion & Spirituality|Judaism', 5440 15211 => 'Textbooks|Religion & Spirituality|Spirituality', 5441 15212 => 'Textbooks|Romance', 5442 15213 => 'Textbooks|Romance|Contemporary', 5443 15214 => 'Textbooks|Romance|Erotic Romance', 5444 15215 => 'Textbooks|Romance|Paranormal', 5445 15216 => 'Textbooks|Romance|Historical', 5446 15217 => 'Textbooks|Romance|Short Stories', 5447 15218 => 'Textbooks|Romance|Suspense', 5448 15219 => 'Textbooks|Romance|Western', 5449 15220 => 'Textbooks|Sci-Fi & Fantasy', 5450 15221 => 'Textbooks|Sci-Fi & Fantasy|Fantasy', 5451 15222 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Contemporary', 5452 15223 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Epic', 5453 15224 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Historical', 5454 15225 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Paranormal', 5455 15226 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Short Stories', 5456 15227 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction', 5457 15228 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature', 5458 15229 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|Adventure', 5459 15230 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|High Tech', 5460 15231 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|Short Stories', 5461 15232 => 'Textbooks|Science & Nature', 5462 15233 => 'Textbooks|Science & Nature|Agriculture', 5463 15234 => 'Textbooks|Science & Nature|Astronomy', 5464 15235 => 'Textbooks|Science & Nature|Atmosphere', 5465 15236 => 'Textbooks|Science & Nature|Biology', 5466 15237 => 'Textbooks|Science & Nature|Chemistry', 5467 15238 => 'Textbooks|Science & Nature|Earth Sciences', 5468 15239 => 'Textbooks|Science & Nature|Ecology', 5469 15240 => 'Textbooks|Science & Nature|Environment', 5470 15241 => 'Textbooks|Science & Nature|Essays', 5471 15242 => 'Textbooks|Science & Nature|Geography', 5472 15243 => 'Textbooks|Science & Nature|Geology', 5473 15244 => 'Textbooks|Science & Nature|History', 5474 15245 => 'Textbooks|Science & Nature|Life Sciences', 5475 15246 => 'Textbooks|Science & Nature|Nature', 5476 15247 => 'Textbooks|Science & Nature|Physics', 5477 15248 => 'Textbooks|Science & Nature|Reference', 5478 15249 => 'Textbooks|Social Science', 5479 15250 => 'Textbooks|Social Science|Anthropology', 5480 15251 => 'Textbooks|Social Science|Archaeology', 5481 15252 => 'Textbooks|Social Science|Civics', 5482 15253 => 'Textbooks|Social Science|Government', 5483 15254 => 'Textbooks|Social Science|Social Studies', 5484 15255 => 'Textbooks|Social Science|Social Welfare', 5485 15256 => 'Textbooks|Social Science|Society', 5486 15257 => 'Textbooks|Social Science|Society|African Studies', 5487 15258 => 'Textbooks|Social Science|Society|American Studies', 5488 15259 => 'Textbooks|Social Science|Society|Asia Pacific Studies', 5489 15260 => 'Textbooks|Social Science|Society|Cross-Cultural Studies', 5490 15261 => 'Textbooks|Social Science|Society|European Studies', 5491 15262 => 'Textbooks|Social Science|Society|Immigration & Emigration', 5492 15263 => 'Textbooks|Social Science|Society|Indigenous Studies', 5493 15264 => 'Textbooks|Social Science|Society|Latin & Caribbean Studies', 5494 15265 => 'Textbooks|Social Science|Society|Middle Eastern Studies', 5495 15266 => 'Textbooks|Social Science|Society|Race & Ethnicity Studies', 5496 15267 => 'Textbooks|Social Science|Society|Sexuality Studies', 5497 15268 => "Textbooks|Social Science|Society|Women's Studies", 5498 15269 => 'Textbooks|Social Science|Sociology', 5499 15270 => 'Textbooks|Sports & Outdoors', 5500 15271 => 'Textbooks|Sports & Outdoors|Baseball', 5501 15272 => 'Textbooks|Sports & Outdoors|Basketball', 5502 15273 => 'Textbooks|Sports & Outdoors|Coaching', 5503 15274 => 'Textbooks|Sports & Outdoors|Equestrian', 5504 15275 => 'Textbooks|Sports & Outdoors|Extreme Sports', 5505 15276 => 'Textbooks|Sports & Outdoors|Football', 5506 15277 => 'Textbooks|Sports & Outdoors|Golf', 5507 15278 => 'Textbooks|Sports & Outdoors|Hockey', 5508 15279 => 'Textbooks|Sports & Outdoors|Motor Sports', 5509 15280 => 'Textbooks|Sports & Outdoors|Mountaineering', 5510 15281 => 'Textbooks|Sports & Outdoors|Outdoors', 5511 15282 => 'Textbooks|Sports & Outdoors|Racket Sports', 5512 15283 => 'Textbooks|Sports & Outdoors|Reference', 5513 15284 => 'Textbooks|Sports & Outdoors|Soccer', 5514 15285 => 'Textbooks|Sports & Outdoors|Training', 5515 15286 => 'Textbooks|Sports & Outdoors|Water Sports', 5516 15287 => 'Textbooks|Sports & Outdoors|Winter Sports', 5517 15288 => 'Textbooks|Teaching & Learning', 5518 15289 => 'Textbooks|Teaching & Learning|Adult Education', 5519 15290 => 'Textbooks|Teaching & Learning|Curriculum & Teaching', 5520 15291 => 'Textbooks|Teaching & Learning|Educational Leadership', 5521 15292 => 'Textbooks|Teaching & Learning|Educational Technology', 5522 15293 => 'Textbooks|Teaching & Learning|Family & Childcare', 5523 15294 => 'Textbooks|Teaching & Learning|Information & Library Science', 5524 15295 => 'Textbooks|Teaching & Learning|Learning Resources', 5525 15296 => 'Textbooks|Teaching & Learning|Psychology & Research', 5526 15297 => 'Textbooks|Teaching & Learning|Special Education', 5527 15298 => 'Textbooks|Travel & Adventure', 5528 15299 => 'Textbooks|Travel & Adventure|Africa', 5529 15300 => 'Textbooks|Travel & Adventure|Americas', 5530 15301 => 'Textbooks|Travel & Adventure|Americas|Canada', 5531 15302 => 'Textbooks|Travel & Adventure|Americas|Latin America', 5532 15303 => 'Textbooks|Travel & Adventure|Americas|United States', 5533 15304 => 'Textbooks|Travel & Adventure|Asia', 5534 15305 => 'Textbooks|Travel & Adventure|Caribbean', 5535 15306 => 'Textbooks|Travel & Adventure|Essays & Memoirs', 5536 15307 => 'Textbooks|Travel & Adventure|Europe', 5537 15308 => 'Textbooks|Travel & Adventure|Middle East', 5538 15309 => 'Textbooks|Travel & Adventure|Oceania', 5539 15310 => 'Textbooks|Travel & Adventure|Specialty Travel', 5540 15311 => 'Textbooks|Comics & Graphic Novels|Comics', 5541 15312 => 'Textbooks|Reference|Manuals', 5542 16001 => 'App Store|Stickers|Emoji & Expressions', 5543 16003 => 'App Store|Stickers|Animals & Nature', 5544 16005 => 'App Store|Stickers|Art', 5545 16006 => 'App Store|Stickers|Celebrations', 5546 16007 => 'App Store|Stickers|Celebrities', 5547 16008 => 'App Store|Stickers|Comics & Cartoons', 5548 16009 => 'App Store|Stickers|Eating & Drinking', 5549 16010 => 'App Store|Stickers|Gaming', 5550 16014 => 'App Store|Stickers|Movies & TV', 5551 16015 => 'App Store|Stickers|Music', 5552 16017 => 'App Store|Stickers|People', 5553 16019 => 'App Store|Stickers|Places & Objects', 5554 16021 => 'App Store|Stickers|Sports & Activities', 5555 16025 => 'App Store|Stickers|Kids & Family', 5556 16026 => 'App Store|Stickers|Fashion', 5557 100000 => 'Music|Christian & Gospel', 5558 100001 => 'Music|Classical|Art Song', 5559 100002 => 'Music|Classical|Brass & Woodwinds', 5560 100003 => 'Music|Classical|Solo Instrumental', 5561 100004 => 'Music|Classical|Contemporary Era', 5562 100005 => 'Music|Classical|Oratorio', 5563 100006 => 'Music|Classical|Cantata', 5564 100007 => 'Music|Classical|Electronic', 5565 100008 => 'Music|Classical|Sacred', 5566 100009 => 'Music|Classical|Guitar', 5567 100010 => 'Music|Classical|Piano', 5568 100011 => 'Music|Classical|Violin', 5569 100012 => 'Music|Classical|Cello', 5570 100013 => 'Music|Classical|Percussion', 5571 100014 => 'Music|Electronic|Dubstep', 5572 100015 => 'Music|Electronic|Bass', 5573 100016 => 'Music|Hip-Hop/Rap|UK Hip-Hop', 5574 100017 => 'Music|Reggae|Lovers Rock', 5575 100018 => 'Music|Alternative|EMO', 5576 100019 => 'Music|Alternative|Pop Punk', 5577 100020 => 'Music|Alternative|Indie Pop', 5578 100021 => 'Music|New Age|Yoga', 5579 100022 => 'Music|Pop|Tribute', 5580 100023 => 'Music|Pop|Shows', 5581 100024 => 'Music|Cuban', 5582 100025 => 'Music|Cuban|Mambo', 5583 100026 => 'Music|Cuban|Chachacha', 5584 100027 => 'Music|Cuban|Guajira', 5585 100028 => 'Music|Cuban|Son', 5586 100029 => 'Music|Cuban|Bolero', 5587 100030 => 'Music|Cuban|Guaracha', 5588 100031 => 'Music|Cuban|Timba', 5589 100032 => 'Music|Soundtrack|Video Game', 5590 100033 => 'Music|Indian|Regional Indian|Punjabi|Punjabi Pop', 5591 100034 => 'Music|Indian|Regional Indian|Bengali|Rabindra Sangeet', 5592 100035 => 'Music|Indian|Regional Indian|Malayalam', 5593 100036 => 'Music|Indian|Regional Indian|Kannada', 5594 100037 => 'Music|Indian|Regional Indian|Marathi', 5595 100038 => 'Music|Indian|Regional Indian|Gujarati', 5596 100039 => 'Music|Indian|Regional Indian|Assamese', 5597 100040 => 'Music|Indian|Regional Indian|Bhojpuri', 5598 100041 => 'Music|Indian|Regional Indian|Haryanvi', 5599 100042 => 'Music|Indian|Regional Indian|Odia', 5600 100043 => 'Music|Indian|Regional Indian|Rajasthani', 5601 100044 => 'Music|Indian|Regional Indian|Urdu', 5602 100045 => 'Music|Indian|Regional Indian|Punjabi', 5603 100046 => 'Music|Indian|Regional Indian|Bengali', 5604 100047 => 'Music|Indian|Indian Classical|Carnatic Classical', 5605 100048 => 'Music|Indian|Indian Classical|Hindustani Classical', 5606 100049 => 'Music|African|Afro House', 5607 100050 => 'Music|African|Afro Soul', 5608 100051 => 'Music|African|Afrobeats', 5609 100052 => 'Music|African|Benga', 5610 100053 => 'Music|African|Bongo-Flava', 5611 100054 => 'Music|African|Coupe-Decale', 5612 100055 => 'Music|African|Gqom', 5613 100056 => 'Music|African|Highlife', 5614 100057 => 'Music|African|Kuduro', 5615 100058 => 'Music|African|Kizomba', 5616 100059 => 'Music|African|Kwaito', 5617 100060 => 'Music|African|Mbalax', 5618 100061 => 'Music|African|Ndombolo', 5619 100062 => 'Music|African|Shangaan Electro', 5620 100063 => 'Music|African|Soukous', 5621 100064 => 'Music|African|Taarab', 5622 100065 => 'Music|African|Zouglou', 5623 100066 => 'Music|Turkish|Ozgun', 5624 100067 => 'Music|Turkish|Fantezi', 5625 100068 => 'Music|Turkish|Religious', 5626 100069 => 'Music|Pop|Turkish Pop', 5627 100070 => 'Music|Rock|Turkish Rock', 5628 100071 => 'Music|Alternative|Turkish Alternative', 5629 100072 => 'Music|Hip-Hop/Rap|Turkish Hip-Hop/Rap', 5630 100073 => 'Music|African|Maskandi', 5631 100074 => 'Music|Russian|Russian Romance', 5632 100075 => 'Music|Russian|Russian Bard', 5633 100076 => 'Music|Russian|Russian Pop', 5634 100077 => 'Music|Russian|Russian Rock', 5635 100078 => 'Music|Russian|Russian Hip-Hop', 5636 100079 => 'Music|Arabic|Levant', 5637 100080 => 'Music|Arabic|Levant|Dabke', 5638 100081 => 'Music|Arabic|Maghreb Rai', 5639 100082 => 'Music|Arabic|Khaleeji|Khaleeji Jalsat', 5640 100083 => 'Music|Arabic|Khaleeji|Khaleeji Shailat', 5641 100084 => 'Music|Tarab', 5642 100085 => 'Music|Tarab|Iraqi Tarab', 5643 100086 => 'Music|Tarab|Egyptian Tarab', 5644 100087 => 'Music|Tarab|Khaleeji Tarab', 5645 100088 => 'Music|Pop|Levant Pop', 5646 100089 => 'Music|Pop|Iraqi Pop', 5647 100090 => 'Music|Pop|Egyptian Pop', 5648 100091 => 'Music|Pop|Maghreb Pop', 5649 100092 => 'Music|Pop|Khaleeji Pop', 5650 100093 => 'Music|Hip-Hop/Rap|Levant Hip-Hop', 5651 100094 => 'Music|Hip-Hop/Rap|Egyptian Hip-Hop', 5652 100095 => 'Music|Hip-Hop/Rap|Maghreb Hip-Hop', 5653 100096 => 'Music|Hip-Hop/Rap|Khaleeji Hip-Hop', 5654 100097 => 'Music|Alternative|Indie Levant', 5655 100098 => 'Music|Alternative|Indie Egyptian', 5656 100099 => 'Music|Alternative|Indie Maghreb', 5657 100100 => 'Music|Electronic|Levant Electronic', 5658 100101 => "Music|Electronic|Electro-Cha'abi", 5659 100102 => 'Music|Electronic|Maghreb Electronic', 5660 100103 => 'Music|Folk|Iraqi Folk', 5661 100104 => 'Music|Folk|Khaleeji Folk', 5662 100105 => 'Music|Dance|Maghreb Dance', 5663 40000000 => 'iTunes U', 5664 40000001 => 'iTunes U|Business & Economics', 5665 40000002 => 'iTunes U|Business & Economics|Economics', 5666 40000003 => 'iTunes U|Business & Economics|Finance', 5667 40000004 => 'iTunes U|Business & Economics|Hospitality', 5668 40000005 => 'iTunes U|Business & Economics|Management', 5669 40000006 => 'iTunes U|Business & Economics|Marketing', 5670 40000007 => 'iTunes U|Business & Economics|Personal Finance', 5671 40000008 => 'iTunes U|Business & Economics|Real Estate', 5672 40000009 => 'iTunes U|Engineering', 5673 40000010 => 'iTunes U|Engineering|Chemical & Petroleum Engineering', 5674 40000011 => 'iTunes U|Engineering|Civil Engineering', 5675 40000012 => 'iTunes U|Engineering|Computer Science', 5676 40000013 => 'iTunes U|Engineering|Electrical Engineering', 5677 40000014 => 'iTunes U|Engineering|Environmental Engineering', 5678 40000015 => 'iTunes U|Engineering|Mechanical Engineering', 5679 40000016 => 'iTunes U|Music, Art, & Design', 5680 40000017 => 'iTunes U|Music, Art, & Design|Architecture', 5681 40000019 => 'iTunes U|Music, Art, & Design|Art History', 5682 40000020 => 'iTunes U|Music, Art, & Design|Dance', 5683 40000021 => 'iTunes U|Music, Art, & Design|Film', 5684 40000022 => 'iTunes U|Music, Art, & Design|Design', 5685 40000023 => 'iTunes U|Music, Art, & Design|Interior Design', 5686 40000024 => 'iTunes U|Music, Art, & Design|Music', 5687 40000025 => 'iTunes U|Music, Art, & Design|Theater', 5688 40000026 => 'iTunes U|Health & Medicine', 5689 40000027 => 'iTunes U|Health & Medicine|Anatomy & Physiology', 5690 40000028 => 'iTunes U|Health & Medicine|Behavioral Science', 5691 40000029 => 'iTunes U|Health & Medicine|Dentistry', 5692 40000030 => 'iTunes U|Health & Medicine|Diet & Nutrition', 5693 40000031 => 'iTunes U|Health & Medicine|Emergency Medicine', 5694 40000032 => 'iTunes U|Health & Medicine|Genetics', 5695 40000033 => 'iTunes U|Health & Medicine|Gerontology', 5696 40000034 => 'iTunes U|Health & Medicine|Health & Exercise Science', 5697 40000035 => 'iTunes U|Health & Medicine|Immunology', 5698 40000036 => 'iTunes U|Health & Medicine|Neuroscience', 5699 40000037 => 'iTunes U|Health & Medicine|Pharmacology & Toxicology', 5700 40000038 => 'iTunes U|Health & Medicine|Psychiatry', 5701 40000039 => 'iTunes U|Health & Medicine|Global Health', 5702 40000040 => 'iTunes U|Health & Medicine|Radiology', 5703 40000041 => 'iTunes U|History', 5704 40000042 => 'iTunes U|History|Ancient History', 5705 40000043 => 'iTunes U|History|Medieval History', 5706 40000044 => 'iTunes U|History|Military History', 5707 40000045 => 'iTunes U|History|Modern History', 5708 40000046 => 'iTunes U|History|African History', 5709 40000047 => 'iTunes U|History|Asia-Pacific History', 5710 40000048 => 'iTunes U|History|European History', 5711 40000049 => 'iTunes U|History|Middle Eastern History', 5712 40000050 => 'iTunes U|History|North American History', 5713 40000051 => 'iTunes U|History|South American History', 5714 40000053 => 'iTunes U|Communications & Journalism', 5715 40000054 => 'iTunes U|Philosophy', 5716 40000055 => 'iTunes U|Religion & Spirituality', 5717 40000056 => 'iTunes U|Languages', 5718 40000057 => 'iTunes U|Languages|African Languages', 5719 40000058 => 'iTunes U|Languages|Ancient Languages', 5720 40000061 => 'iTunes U|Languages|English', 5721 40000063 => 'iTunes U|Languages|French', 5722 40000064 => 'iTunes U|Languages|German', 5723 40000065 => 'iTunes U|Languages|Italian', 5724 40000066 => 'iTunes U|Languages|Linguistics', 5725 40000068 => 'iTunes U|Languages|Spanish', 5726 40000069 => 'iTunes U|Languages|Speech Pathology', 5727 40000070 => 'iTunes U|Writing & Literature', 5728 40000071 => 'iTunes U|Writing & Literature|Anthologies', 5729 40000072 => 'iTunes U|Writing & Literature|Biography', 5730 40000073 => 'iTunes U|Writing & Literature|Classics', 5731 40000074 => 'iTunes U|Writing & Literature|Literary Criticism', 5732 40000075 => 'iTunes U|Writing & Literature|Fiction', 5733 40000076 => 'iTunes U|Writing & Literature|Poetry', 5734 40000077 => 'iTunes U|Mathematics', 5735 40000078 => 'iTunes U|Mathematics|Advanced Mathematics', 5736 40000079 => 'iTunes U|Mathematics|Algebra', 5737 40000080 => 'iTunes U|Mathematics|Arithmetic', 5738 40000081 => 'iTunes U|Mathematics|Calculus', 5739 40000082 => 'iTunes U|Mathematics|Geometry', 5740 40000083 => 'iTunes U|Mathematics|Statistics', 5741 40000084 => 'iTunes U|Science', 5742 40000085 => 'iTunes U|Science|Agricultural', 5743 40000086 => 'iTunes U|Science|Astronomy', 5744 40000087 => 'iTunes U|Science|Atmosphere', 5745 40000088 => 'iTunes U|Science|Biology', 5746 40000089 => 'iTunes U|Science|Chemistry', 5747 40000090 => 'iTunes U|Science|Ecology', 5748 40000091 => 'iTunes U|Science|Geography', 5749 40000092 => 'iTunes U|Science|Geology', 5750 40000093 => 'iTunes U|Science|Physics', 5751 40000094 => 'iTunes U|Social Science', 5752 40000095 => 'iTunes U|Law & Politics|Law', 5753 40000096 => 'iTunes U|Law & Politics|Political Science', 5754 40000097 => 'iTunes U|Law & Politics|Public Administration', 5755 40000098 => 'iTunes U|Social Science|Psychology', 5756 40000099 => 'iTunes U|Social Science|Social Welfare', 5757 40000100 => 'iTunes U|Social Science|Sociology', 5758 40000101 => 'iTunes U|Society', 5759 40000103 => 'iTunes U|Society|Asia Pacific Studies', 5760 40000104 => 'iTunes U|Society|European Studies', 5761 40000105 => 'iTunes U|Society|Indigenous Studies', 5762 40000106 => 'iTunes U|Society|Latin & Caribbean Studies', 5763 40000107 => 'iTunes U|Society|Middle Eastern Studies', 5764 40000108 => "iTunes U|Society|Women's Studies", 5765 40000109 => 'iTunes U|Teaching & Learning', 5766 40000110 => 'iTunes U|Teaching & Learning|Curriculum & Teaching', 5767 40000111 => 'iTunes U|Teaching & Learning|Educational Leadership', 5768 40000112 => 'iTunes U|Teaching & Learning|Family & Childcare', 5769 40000113 => 'iTunes U|Teaching & Learning|Learning Resources', 5770 40000114 => 'iTunes U|Teaching & Learning|Psychology & Research', 5771 40000115 => 'iTunes U|Teaching & Learning|Special Education', 5772 40000116 => 'iTunes U|Music, Art, & Design|Culinary Arts', 5773 40000117 => 'iTunes U|Music, Art, & Design|Fashion', 5774 40000118 => 'iTunes U|Music, Art, & Design|Media Arts', 5775 40000119 => 'iTunes U|Music, Art, & Design|Photography', 5776 40000120 => 'iTunes U|Music, Art, & Design|Visual Art', 5777 40000121 => 'iTunes U|Business & Economics|Entrepreneurship', 5778 40000122 => 'iTunes U|Communications & Journalism|Broadcasting', 5779 40000123 => 'iTunes U|Communications & Journalism|Digital Media', 5780 40000124 => 'iTunes U|Communications & Journalism|Journalism', 5781 40000125 => 'iTunes U|Communications & Journalism|Photojournalism', 5782 40000126 => 'iTunes U|Communications & Journalism|Print', 5783 40000127 => 'iTunes U|Communications & Journalism|Speech', 5784 40000128 => 'iTunes U|Communications & Journalism|Writing', 5785 40000129 => 'iTunes U|Health & Medicine|Nursing', 5786 40000130 => 'iTunes U|Languages|Arabic', 5787 40000131 => 'iTunes U|Languages|Chinese', 5788 40000132 => 'iTunes U|Languages|Hebrew', 5789 40000133 => 'iTunes U|Languages|Hindi', 5790 40000134 => 'iTunes U|Languages|Indigenous Languages', 5791 40000135 => 'iTunes U|Languages|Japanese', 5792 40000136 => 'iTunes U|Languages|Korean', 5793 40000137 => 'iTunes U|Languages|Other Languages', 5794 40000138 => 'iTunes U|Languages|Portuguese', 5795 40000139 => 'iTunes U|Languages|Russian', 5796 40000140 => 'iTunes U|Law & Politics', 5797 40000141 => 'iTunes U|Law & Politics|Foreign Policy & International Relations', 5798 40000142 => 'iTunes U|Law & Politics|Local Governments', 5799 40000143 => 'iTunes U|Law & Politics|National Governments', 5800 40000144 => 'iTunes U|Law & Politics|World Affairs', 5801 40000145 => 'iTunes U|Writing & Literature|Comparative Literature', 5802 40000146 => 'iTunes U|Philosophy|Aesthetics', 5803 40000147 => 'iTunes U|Philosophy|Epistemology', 5804 40000148 => 'iTunes U|Philosophy|Ethics', 5805 40000149 => 'iTunes U|Philosophy|Metaphysics', 5806 40000150 => 'iTunes U|Philosophy|Political Philosophy', 5807 40000151 => 'iTunes U|Philosophy|Logic', 5808 40000152 => 'iTunes U|Philosophy|Philosophy of Language', 5809 40000153 => 'iTunes U|Philosophy|Philosophy of Religion', 5810 40000154 => 'iTunes U|Social Science|Archaeology', 5811 40000155 => 'iTunes U|Social Science|Anthropology', 5812 40000156 => 'iTunes U|Religion & Spirituality|Buddhism', 5813 40000157 => 'iTunes U|Religion & Spirituality|Christianity', 5814 40000158 => 'iTunes U|Religion & Spirituality|Comparative Religion', 5815 40000159 => 'iTunes U|Religion & Spirituality|Hinduism', 5816 40000160 => 'iTunes U|Religion & Spirituality|Islam', 5817 40000161 => 'iTunes U|Religion & Spirituality|Judaism', 5818 40000162 => 'iTunes U|Religion & Spirituality|Other Religions', 5819 40000163 => 'iTunes U|Religion & Spirituality|Spirituality', 5820 40000164 => 'iTunes U|Science|Environment', 5821 40000165 => 'iTunes U|Society|African Studies', 5822 40000166 => 'iTunes U|Society|American Studies', 5823 40000167 => 'iTunes U|Society|Cross-cultural Studies', 5824 40000168 => 'iTunes U|Society|Immigration & Emigration', 5825 40000169 => 'iTunes U|Society|Race & Ethnicity Studies', 5826 40000170 => 'iTunes U|Society|Sexuality Studies', 5827 40000171 => 'iTunes U|Teaching & Learning|Educational Technology', 5828 40000172 => 'iTunes U|Teaching & Learning|Information/Library Science', 5829 40000173 => 'iTunes U|Languages|Dutch', 5830 40000174 => 'iTunes U|Languages|Luxembourgish', 5831 40000175 => 'iTunes U|Languages|Swedish', 5832 40000176 => 'iTunes U|Languages|Norwegian', 5833 40000177 => 'iTunes U|Languages|Finnish', 5834 40000178 => 'iTunes U|Languages|Danish', 5835 40000179 => 'iTunes U|Languages|Polish', 5836 40000180 => 'iTunes U|Languages|Turkish', 5837 40000181 => 'iTunes U|Languages|Flemish', 5838 50000024 => 'Audiobooks', 5839 50000040 => 'Audiobooks|Fiction', 5840 50000041 => 'Audiobooks|Arts & Entertainment', 5841 50000042 => 'Audiobooks|Biographies & Memoirs', 5842 50000043 => 'Audiobooks|Business & Personal Finance', 5843 50000044 => 'Audiobooks|Kids & Young Adults', 5844 50000045 => 'Audiobooks|Classics', 5845 50000046 => 'Audiobooks|Comedy', 5846 50000047 => 'Audiobooks|Drama & Poetry', 5847 50000048 => 'Audiobooks|Speakers & Storytellers', 5848 50000049 => 'Audiobooks|History', 5849 50000050 => 'Audiobooks|Languages', 5850 50000051 => 'Audiobooks|Mysteries & Thrillers', 5851 50000052 => 'Audiobooks|Nonfiction', 5852 50000053 => 'Audiobooks|Religion & Spirituality', 5853 50000054 => 'Audiobooks|Science & Nature', 5854 50000055 => 'Audiobooks|Sci Fi & Fantasy', 5855 50000056 => 'Audiobooks|Self-Development', 5856 50000057 => 'Audiobooks|Sports & Outdoors', 5857 50000058 => 'Audiobooks|Technology', 5858 50000059 => 'Audiobooks|Travel & Adventure', 5859 50000061 => 'Music|Spoken Word', 5860 50000063 => 'Music|Disney', 5861 50000064 => 'Music|French Pop', 5862 50000066 => 'Music|German Pop', 5863 50000068 => 'Music|German Folk', 5864 50000069 => 'Audiobooks|Romance', 5865 50000070 => 'Audiobooks|Audiobooks Latino', 5866 50000071 => 'Books|Comics & Graphic Novels|Manga|Action', 5867 50000072 => 'Books|Comics & Graphic Novels|Manga|Comedy', 5868 50000073 => 'Books|Comics & Graphic Novels|Manga|Erotica', 5869 50000074 => 'Books|Comics & Graphic Novels|Manga|Fantasy', 5870 50000075 => 'Books|Comics & Graphic Novels|Manga|Four Cell Manga', 5871 50000076 => 'Books|Comics & Graphic Novels|Manga|Gay & Lesbian', 5872 50000077 => 'Books|Comics & Graphic Novels|Manga|Hard-Boiled', 5873 50000078 => 'Books|Comics & Graphic Novels|Manga|Heroes', 5874 50000079 => 'Books|Comics & Graphic Novels|Manga|Historical Fiction', 5875 50000080 => 'Books|Comics & Graphic Novels|Manga|Mecha', 5876 50000081 => 'Books|Comics & Graphic Novels|Manga|Mystery', 5877 50000082 => 'Books|Comics & Graphic Novels|Manga|Nonfiction', 5878 50000083 => 'Books|Comics & Graphic Novels|Manga|Religious', 5879 50000084 => 'Books|Comics & Graphic Novels|Manga|Romance', 5880 50000085 => 'Books|Comics & Graphic Novels|Manga|Romantic Comedy', 5881 50000086 => 'Books|Comics & Graphic Novels|Manga|Science Fiction', 5882 50000087 => 'Books|Comics & Graphic Novels|Manga|Sports', 5883 50000088 => 'Books|Fiction & Literature|Light Novels', 5884 50000089 => 'Books|Comics & Graphic Novels|Manga|Horror', 5885 50000090 => 'Books|Comics & Graphic Novels|Comics', 5886 50000091 => 'Books|Romance|Multicultural', 5887 50000092 => 'Audiobooks|Erotica', 5888 50000093 => 'Audiobooks|Light Novels', 5889 }, 5890 }, 5891 grup => { Name => 'Grouping', Avoid => 1 }, #10 5892 hdvd => { #10 5893 Name => 'HDVideo', 5894 Format => 'int8u', #24 5895 Writable => 'int8s', #27 5896 PrintConv => { 0 => 'No', 1 => 'Yes' }, 5897 }, 5898 keyw => 'Keyword', #7 5899 ldes => 'LongDescription', #10 5900 pcst => { #7 5901 Name => 'Podcast', 5902 Format => 'int8u', #23 5903 Writable => 'int8s', #27 5904 PrintConv => { 0 => 'No', 1 => 'Yes' }, 5905 }, 5906 perf => 'Performer', 5907 plID => { #10 (or TV season) 5908 Name => 'PlayListID', 5909 Format => 'int8u', # actually int64u, but split it up 5910 Writable => 'int32s', #27 5911 }, 5912 purd => 'PurchaseDate', #7 5913 purl => 'PodcastURL', #7 5914 rtng => { #10 5915 Name => 'Rating', 5916 Format => 'int8u', #23 5917 Writable => 'int8s', #27 5918 PrintConv => { 5919 0 => 'none', 5920 1 => 'Explicit', 5921 2 => 'Clean', 5922 4 => 'Explicit (old)', 5923 }, 5924 }, 5925 sfID => { #10 5926 Name => 'AppleStoreCountry', 5927 Format => 'int32u', 5928 Writable => 'int32s', #27 5929 SeparateTable => 1, 5930 PrintConv => { #21 5931 143441 => 'United States', # US 5932 143442 => 'France', # FR 5933 143443 => 'Germany', # DE 5934 143444 => 'United Kingdom', # GB 5935 143445 => 'Austria', # AT 5936 143446 => 'Belgium', # BE 5937 143447 => 'Finland', # FI 5938 143448 => 'Greece', # GR 5939 143449 => 'Ireland', # IE 5940 143450 => 'Italy', # IT 5941 143451 => 'Luxembourg', # LU 5942 143452 => 'Netherlands', # NL 5943 143453 => 'Portugal', # PT 5944 143454 => 'Spain', # ES 5945 143455 => 'Canada', # CA 5946 143456 => 'Sweden', # SE 5947 143457 => 'Norway', # NO 5948 143458 => 'Denmark', # DK 5949 143459 => 'Switzerland', # CH 5950 143460 => 'Australia', # AU 5951 143461 => 'New Zealand', # NZ 5952 143462 => 'Japan', # JP 5953 143463 => 'Hong Kong', # HK 5954 143464 => 'Singapore', # SG 5955 143465 => 'China', # CN 5956 143466 => 'Republic of Korea', # KR 5957 143467 => 'India', # IN 5958 143468 => 'Mexico', # MX 5959 143469 => 'Russia', # RU 5960 143470 => 'Taiwan', # TW 5961 143471 => 'Vietnam', # VN 5962 143472 => 'South Africa', # ZA 5963 143473 => 'Malaysia', # MY 5964 143474 => 'Philippines', # PH 5965 143475 => 'Thailand', # TH 5966 143476 => 'Indonesia', # ID 5967 143477 => 'Pakistan', # PK 5968 143478 => 'Poland', # PL 5969 143479 => 'Saudi Arabia', # SA 5970 143480 => 'Turkey', # TR 5971 143481 => 'United Arab Emirates', # AE 5972 143482 => 'Hungary', # HU 5973 143483 => 'Chile', # CL 5974 143484 => 'Nepal', # NP 5975 143485 => 'Panama', # PA 5976 143486 => 'Sri Lanka', # LK 5977 143487 => 'Romania', # RO 5978 143489 => 'Czech Republic', # CZ 5979 143491 => 'Israel', # IL 5980 143492 => 'Ukraine', # UA 5981 143493 => 'Kuwait', # KW 5982 143494 => 'Croatia', # HR 5983 143495 => 'Costa Rica', # CR 5984 143496 => 'Slovakia', # SK 5985 143497 => 'Lebanon', # LB 5986 143498 => 'Qatar', # QA 5987 143499 => 'Slovenia', # SI 5988 143501 => 'Colombia', # CO 5989 143502 => 'Venezuela', # VE 5990 143503 => 'Brazil', # BR 5991 143504 => 'Guatemala', # GT 5992 143505 => 'Argentina', # AR 5993 143506 => 'El Salvador', # SV 5994 143507 => 'Peru', # PE 5995 143508 => 'Dominican Republic', # DO 5996 143509 => 'Ecuador', # EC 5997 143510 => 'Honduras', # HN 5998 143511 => 'Jamaica', # JM 5999 143512 => 'Nicaragua', # NI 6000 143513 => 'Paraguay', # PY 6001 143514 => 'Uruguay', # UY 6002 143515 => 'Macau', # MO 6003 143516 => 'Egypt', # EG 6004 143517 => 'Kazakhstan', # KZ 6005 143518 => 'Estonia', # EE 6006 143519 => 'Latvia', # LV 6007 143520 => 'Lithuania', # LT 6008 143521 => 'Malta', # MT 6009 143523 => 'Moldova', # MD 6010 143524 => 'Armenia', # AM 6011 143525 => 'Botswana', # BW 6012 143526 => 'Bulgaria', # BG 6013 143528 => 'Jordan', # JO 6014 143529 => 'Kenya', # KE 6015 143530 => 'Macedonia', # MK 6016 143531 => 'Madagascar', # MG 6017 143532 => 'Mali', # ML 6018 143533 => 'Mauritius', # MU 6019 143534 => 'Niger', # NE 6020 143535 => 'Senegal', # SN 6021 143536 => 'Tunisia', # TN 6022 143537 => 'Uganda', # UG 6023 143538 => 'Anguilla', # AI 6024 143539 => 'Bahamas', # BS 6025 143540 => 'Antigua and Barbuda', # AG 6026 143541 => 'Barbados', # BB 6027 143542 => 'Bermuda', # BM 6028 143543 => 'British Virgin Islands', # VG 6029 143544 => 'Cayman Islands', # KY 6030 143545 => 'Dominica', # DM 6031 143546 => 'Grenada', # GD 6032 143547 => 'Montserrat', # MS 6033 143548 => 'St. Kitts and Nevis', # KN 6034 143549 => 'St. Lucia', # LC 6035 143550 => 'St. Vincent and The Grenadines', # VC 6036 143551 => 'Trinidad and Tobago', # TT 6037 143552 => 'Turks and Caicos', # TC 6038 143553 => 'Guyana', # GY 6039 143554 => 'Suriname', # SR 6040 143555 => 'Belize', # BZ 6041 143556 => 'Bolivia', # BO 6042 143557 => 'Cyprus', # CY 6043 143558 => 'Iceland', # IS 6044 143559 => 'Bahrain', # BH 6045 143560 => 'Brunei Darussalam', # BN 6046 143561 => 'Nigeria', # NG 6047 143562 => 'Oman', # OM 6048 143563 => 'Algeria', # DZ 6049 143564 => 'Angola', # AO 6050 143565 => 'Belarus', # BY 6051 143566 => 'Uzbekistan', # UZ 6052 143568 => 'Azerbaijan', # AZ 6053 143571 => 'Yemen', # YE 6054 143572 => 'Tanzania', # TZ 6055 143573 => 'Ghana', # GH 6056 143575 => 'Albania', # AL 6057 143576 => 'Benin', # BJ 6058 143577 => 'Bhutan', # BT 6059 143578 => 'Burkina Faso', # BF 6060 143579 => 'Cambodia', # KH 6061 143580 => 'Cape Verde', # CV 6062 143581 => 'Chad', # TD 6063 143582 => 'Republic of the Congo', # CG 6064 143583 => 'Fiji', # FJ 6065 143584 => 'Gambia', # GM 6066 143585 => 'Guinea-Bissau', # GW 6067 143586 => 'Kyrgyzstan', # KG 6068 143587 => "Lao People's Democratic Republic", # LA 6069 143588 => 'Liberia', # LR 6070 143589 => 'Malawi', # MW 6071 143590 => 'Mauritania', # MR 6072 143591 => 'Federated States of Micronesia', # FM 6073 143592 => 'Mongolia', # MN 6074 143593 => 'Mozambique', # MZ 6075 143594 => 'Namibia', # NA 6076 143595 => 'Palau', # PW 6077 143597 => 'Papua New Guinea', # PG 6078 143598 => 'Sao Tome and Principe', # ST (São Tomé and Príncipe) 6079 143599 => 'Seychelles', # SC 6080 143600 => 'Sierra Leone', # SL 6081 143601 => 'Solomon Islands', # SB 6082 143602 => 'Swaziland', # SZ 6083 143603 => 'Tajikistan', # TJ 6084 143604 => 'Turkmenistan', # TM 6085 143605 => 'Zimbabwe', # ZW 6086 }, 6087 }, 6088 soaa => 'SortAlbumArtist', #10 6089 soal => 'SortAlbum', #10 6090 soar => 'SortArtist', #10 6091 soco => 'SortComposer', #10 6092 sonm => 'SortName', #10 6093 sosn => 'SortShow', #10 6094 stik => { #10 6095 Name => 'MediaType', 6096 Format => 'int8u', #23 6097 Writable => 'int8s', #27 6098 PrintConvColumns => 2, 6099 PrintConv => { #(http://weblog.xanga.com/gryphondwb/615474010/iphone-ringtones---what-did-itunes-741-really-do.html) 6100 0 => 'Movie (old)', #forum9059 (was Movie) 6101 1 => 'Normal (Music)', 6102 2 => 'Audiobook', 6103 5 => 'Whacked Bookmark', 6104 6 => 'Music Video', 6105 9 => 'Movie', #forum9059 (was Short Film) 6106 10 => 'TV Show', 6107 11 => 'Booklet', 6108 14 => 'Ringtone', 6109 21 => 'Podcast', #15 6110 23 => 'iTunes U', #forum9059 6111 }, 6112 }, 6113 rate => 'RatingPercent', #PH 6114 titl => { Name => 'Title', Avoid => 1 }, 6115 tven => 'TVEpisodeID', #7 6116 tves => { #7/10 6117 Name => 'TVEpisode', 6118 Format => 'int32u', 6119 Writable => 'int32s', #27 6120 }, 6121 tvnn => 'TVNetworkName', #7 6122 tvsh => 'TVShow', #10 6123 tvsn => { #7/10 6124 Name => 'TVSeason', 6125 Format => 'int32u', 6126 }, 6127 yrrc => 'Year', #(ffmpeg source) 6128 itnu => { #PH (iTunes 10.5) 6129 Name => 'iTunesU', 6130 Format => 'int8u', #27 6131 Writable => 'int8s', #27 6132 Description => 'iTunes U', 6133 PrintConv => { 0 => 'No', 1 => 'Yes' }, 6134 }, 6135 #https://github.com/communitymedia/mediautilities/blob/master/src/net/sourceforge/jaad/mp4/boxes/BoxTypes.java 6136 gshh => { Name => 'GoogleHostHeader', Format => 'string' }, 6137 gspm => { Name => 'GooglePingMessage', Format => 'string' }, 6138 gspu => { Name => 'GooglePingURL', Format => 'string' }, 6139 gssd => { Name => 'GoogleSourceData', Format => 'string' }, 6140 gsst => { Name => 'GoogleStartTime', Format => 'string' }, 6141 gstd => { 6142 Name => 'GoogleTrackDuration', 6143 Format => 'string', 6144 ValueConv => '$val / 1000', 6145 ValueConvInv => '$val * 1000', 6146 PrintConv => 'ConvertDuration($val)', 6147 PrintConvInv => q{ 6148 $val =~ s/ s$//; 6149 my @a = split /(:| days )/, $val; 6150 my $sign = ($val =~ s/^-//) ? -1 : 1; 6151 $a[0] += shift(@a) * 24 if @a == 4; 6152 $a[0] += shift(@a) * 60 while @a > 1; 6153 return $a[0] * $sign; 6154 }, 6155 }, 6156 6157 # atoms observed in AAX audiobooks (ref PH) 6158 "\xa9cpy" => { Name => 'Copyright', Avoid => 1, Groups => { 2 => 'Author' } }, 6159 "\xa9pub" => 'Publisher', 6160 "\xa9nrt" => 'Narrator', 6161 '@pti' => 'ParentTitle', # (guess -- same as "\xa9nam") 6162 '@PST' => 'ParentShortTitle', # (guess -- same as "\xa9nam") 6163 '@ppi' => 'ParentProductID', # (guess -- same as 'prID') 6164 '@sti' => 'ShortTitle', # (guess -- same as "\xa9nam") 6165 prID => 'ProductID', 6166 rldt => { Name => 'ReleaseDate', Groups => { 2 => 'Time' }}, 6167 CDEK => { Name => 'Unknown_CDEK', Unknown => 1 }, # eg: "B004ZMTFEG" - used in URL's ("asin=") 6168 CDET => { Name => 'Unknown_CDET', Unknown => 1 }, # eg: "ADBL" 6169 VERS => 'ProductVersion', 6170 GUID => 'GUID', 6171 AACR => { Name => 'Unknown_AACR', Unknown => 1 }, # eg: "CR!1T1H1QH6WX7T714G2BMFX3E9MC4S" 6172 # ausr - 30 bytes (User Alias?) 6173 "\xa9xyz" => { #PH (written by Google Photos) 6174 Name => 'GPSCoordinates', 6175 Groups => { 2 => 'Location' }, 6176 ValueConv => \&ConvertISO6709, 6177 ValueConvInv => \&ConvInvISO6709, 6178 PrintConv => \&PrintGPSCoordinates, 6179 PrintConvInv => \&PrintInvGPSCoordinates, 6180 }, 6181 # the following tags written by iTunes 12.5.1.21 6182 # (ref https://www.ventismedia.com/mantis/view.php?id=14963 6183 # https://community.mp3tag.de/t/x-mp4-new-tag-problems/19488) 6184 "\xa9wrk" => 'Work', #PH 6185 "\xa9mvn" => 'MovementName', #PH 6186 "\xa9mvi" => { #PH 6187 Name => 'MovementNumber', 6188 Format => 'int16u', #27 6189 Writable => 'int16s', #27 6190 }, 6191 "\xa9mvc" => { #PH 6192 Name => 'MovementCount', 6193 Format => 'int16u', #27 6194 Writable => 'int16s', #27 6195 }, 6196 shwm => { #PH 6197 Name => 'ShowMovement', 6198 Format => 'int8u', #27 6199 Writable => 'int8s', #27 6200 PrintConv => { 0 => 'No', 1 => 'Yes' }, 6201 }, 6202); 6203 6204# tag decoded from timed face records 6205%Image::ExifTool::QuickTime::FaceInfo = ( 6206 PROCESS_PROC => \&ProcessMOV, 6207 GROUPS => { 2 => 'Video' }, 6208 crec => { 6209 Name => 'FaceRec', 6210 SubDirectory => { 6211 TagTable => 'Image::ExifTool::QuickTime::FaceRec', 6212 }, 6213 }, 6214); 6215 6216# tag decoded from timed face records 6217%Image::ExifTool::QuickTime::FaceRec = ( 6218 PROCESS_PROC => \&ProcessMOV, 6219 GROUPS => { 2 => 'Video' }, 6220 cits => { 6221 Name => 'FaceItem', 6222 SubDirectory => { 6223 TagTable => 'Image::ExifTool::QuickTime::Keys', 6224 ProcessProc => \&Process_mebx, 6225 }, 6226 }, 6227); 6228 6229# item list keys (ref PH) 6230%Image::ExifTool::QuickTime::Keys = ( 6231 PROCESS_PROC => \&ProcessKeys, 6232 WRITE_PROC => \&WriteKeys, 6233 CHECK_PROC => \&CheckQTValue, 6234 VARS => { LONG_TAGS => 7 }, 6235 WRITABLE => 1, 6236 # (not PREFERRED when writing) 6237 GROUPS => { 1 => 'Keys' }, 6238 WRITE_GROUP => 'Keys', 6239 LANG_INFO => \&GetLangInfo, 6240 NOTES => q{ 6241 This directory contains a list of key names which are used to decode tags 6242 written by the "mdta" handler. Also in this table are a few tags found in 6243 timed metadata that are not yet writable by ExifTool. The prefix of 6244 "com.apple.quicktime." has been removed from the TagID's below. These tags 6245 support alternate languages in the same way as the 6246 L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags. Note 6247 that by default, 6248 L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> and 6249 L<UserData|Image::ExifTool::TagNames/QuickTime UserData Tags> tags are 6250 preferred when writing, so to create a tag when a same-named tag exists in 6251 either of these tables, either the "Keys" location must be specified (eg. 6252 C<-Keys:Author=Phil> on the command line), or the PREFERRED level must be 6253 changed via L<the config file|../config.html#PREF>. 6254 }, 6255 version => 'Version', 6256 album => 'Album', 6257 artist => { }, 6258 artwork => { }, 6259 author => { Name => 'Author', Groups => { 2 => 'Author' } }, 6260 comment => { }, 6261 copyright => { Name => 'Copyright', Groups => { 2 => 'Author' } }, 6262 creationdate=> { 6263 Name => 'CreationDate', 6264 Groups => { 2 => 'Time' }, 6265 Shift => 'Time', 6266 ValueConv => q{ 6267 require Image::ExifTool::XMP; 6268 $val = Image::ExifTool::XMP::ConvertXMPDate($val,1); 6269 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 6270 return $val; 6271 }, 6272 ValueConvInv => q{ 6273 require Image::ExifTool::XMP; 6274 $val = Image::ExifTool::XMP::FormatXMPDate($val); 6275 $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon 6276 return $val; 6277 }, 6278 PrintConv => '$self->ConvertDateTime($val)', 6279 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 6280 }, 6281 description => { }, 6282 director => { }, 6283 displayname => { Name => 'DisplayName' }, 6284 title => { }, #22 6285 genre => { }, 6286 information => { }, 6287 keywords => { }, 6288 producer => { }, #22 6289 make => { Name => 'Make', Groups => { 2 => 'Camera' } }, 6290 model => { Name => 'Model', Groups => { 2 => 'Camera' } }, 6291 publisher => { }, 6292 software => { }, 6293 year => { Groups => { 2 => 'Time' } }, 6294 'camera.identifier' => 'CameraIdentifier', # (iPhone 4) 6295 'camera.framereadouttimeinmicroseconds' => { # (iPhone 4) 6296 Name => 'FrameReadoutTime', 6297 ValueConv => '$val * 1e-6', 6298 ValueConvInv => 'int($val * 1e6 + 0.5)', 6299 PrintConv => '$val * 1e6 . " microseconds"', 6300 PrintConvInv => '$val =~ s/ .*//; $val * 1e-6', 6301 }, 6302 'location.ISO6709' => { 6303 Name => 'GPSCoordinates', 6304 Groups => { 2 => 'Location' }, 6305 Notes => q{ 6306 Google Photos may ignore this if the coorinates have more than 5 digits 6307 after the decimal 6308 }, 6309 ValueConv => \&ConvertISO6709, 6310 ValueConvInv => \&ConvInvISO6709, 6311 PrintConv => \&PrintGPSCoordinates, 6312 PrintConvInv => \&PrintInvGPSCoordinates, 6313 }, 6314 'location.name' => { Name => 'LocationName', Groups => { 2 => 'Location' } }, 6315 'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } }, 6316 'location.note' => { Name => 'LocationNote', Groups => { 2 => 'Location' } }, 6317 'location.role' => { 6318 Name => 'LocationRole', 6319 Groups => { 2 => 'Location' }, 6320 PrintConv => { 6321 0 => 'Shooting Location', 6322 1 => 'Real Location', 6323 2 => 'Fictional Location', 6324 }, 6325 }, 6326 'location.date' => { 6327 Name => 'LocationDate', 6328 Groups => { 2 => 'Time' }, 6329 Shift => 'Time', 6330 ValueConv => q{ 6331 require Image::ExifTool::XMP; 6332 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 6333 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 6334 return $val; 6335 }, 6336 ValueConvInv => q{ 6337 require Image::ExifTool::XMP; 6338 $val = Image::ExifTool::XMP::FormatXMPDate($val); 6339 $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon 6340 return $val; 6341 }, 6342 PrintConv => '$self->ConvertDateTime($val)', 6343 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 6344 }, 6345 'location.accuracy.horizontal' => { Name => 'LocationAccuracyHorizontal' }, 6346 'live-photo.auto' => { Name => 'LivePhotoAuto', Writable => 'int8u' }, 6347 'live-photo.vitality-score' => { Name => 'LivePhotoVitalityScore', Writable => 'float' }, 6348 'live-photo.vitality-scoring-version' => { Name => 'LivePhotoVitalityScoringVersion', Writable => 'int64s' }, 6349 'apple.photos.variation-identifier' => { Name => 'ApplePhotosVariationIdentifier', Writable => 'int64s' }, 6350 'direction.facing' => { Name => 'CameraDirection', Groups => { 2 => 'Location' } }, 6351 'direction.motion' => { Name => 'CameraMotion', Groups => { 2 => 'Location' } }, 6352 'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } }, 6353 'player.version' => 'PlayerVersion', 6354 'player.movie.visual.brightness'=> 'Brightness', 6355 'player.movie.visual.color' => 'Color', 6356 'player.movie.visual.tint' => 'Tint', 6357 'player.movie.visual.contrast' => 'Contrast', 6358 'player.movie.audio.gain' => 'AudioGain', 6359 'player.movie.audio.treble' => 'Trebel', 6360 'player.movie.audio.bass' => 'Bass', 6361 'player.movie.audio.balance' => 'Balance', 6362 'player.movie.audio.pitchshift' => 'PitchShift', 6363 'player.movie.audio.mute' => { 6364 Name => 'Mute', 6365 Format => 'int8u', 6366 PrintConv => { 0 => 'Off', 1 => 'On' }, 6367 }, 6368 'rating.user' => 'UserRating', # (Canon ELPH 510 HS) 6369 'collection.user' => 'UserCollection', #22 6370 'Encoded_With' => 'EncodedWith', 6371# 6372# the following tags aren't in the com.apple.quicktime namespace: 6373# 6374 'com.apple.photos.captureMode' => 'CaptureMode', 6375 'com.android.version' => 'AndroidVersion', 6376# 6377# also seen 6378# 6379 # com.divergentmedia.clipwrap.model ('NEX-FS700EK') 6380 # com.divergentmedia.clipwrap.model1 ('49') 6381 # com.divergentmedia.clipwrap.model2 ('0') 6382 # com.divergentmedia.clipwrap.manufacturer ('Sony') 6383 # com.divergentmedia.clipwrap.originalDateTime ('2013/2/6 10:30:40+0200') 6384# 6385# seen in timed metadata (mebx), and added dynamically to the table via SaveMetaKeys() 6386# NOTE: these tags are not writable! (timed metadata cannot yet be written) 6387# 6388 # (mdta)com.apple.quicktime.video-orientation (dtyp=66, int16s) 6389 'video-orientation' => { 6390 Name => 'VideoOrientation', 6391 Writable => 0, 6392 PrintConv => \%Image::ExifTool::Exif::orientation, #PH (NC) 6393 }, 6394 # (mdta)com.apple.quicktime.live-photo-info (dtyp=com.apple.quicktime.com.apple.quicktime.live-photo-info) 6395 'live-photo-info' => { 6396 Name => 'LivePhotoInfo', 6397 Writable => 0, 6398 # not sure what these values mean, but unpack them anyway - PH 6399 # (ignore the fact that the "f" and "l" unpacks won't work on a big-endian machine) 6400 ValueConv => 'join " ",unpack "VfVVf6c4lCCcclf4Vvv", $val', 6401 }, 6402 # (mdta)com.apple.quicktime.still-image-time (dtyp=65, int8s) 6403 'still-image-time' => { # (found in live photo) 6404 Name => 'StillImageTime', 6405 Writable => 0, 6406 Notes => q{ 6407 this tag always has a value of -1; the time of the still image is obtained 6408 from the associated SampleTime 6409 }, 6410 }, 6411 # (mdta)com.apple.quicktime.detected-face (dtyp='com.apple.quicktime.detected-face') 6412 'detected-face' => { 6413 Name => 'FaceInfo', 6414 Writable => 0, 6415 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FaceInfo' }, 6416 }, 6417 # ---- detected-face fields ( ---- 6418 # --> back here after a round trip through FaceInfo -> FaceRec -> FaceItem 6419 # (fiel)com.apple.quicktime.detected-face.bounds (dtyp=80, float[8]) 6420 'detected-face.bounds' => { 6421 Name => 'DetectedFaceBounds', 6422 Writable => 0, 6423 # round to a reasonable number of decimal places 6424 PrintConv => 'my @a=split " ",$val;$_=int($_*1e6+.5)/1e6 foreach @a;join " ",@a', 6425 PrintConvInv => '$val', 6426 }, 6427 # (fiel)com.apple.quicktime.detected-face.face-id (dtyp=77, int32u) 6428 'detected-face.face-id' => { Name => 'DetectedFaceID', Writable => 0 }, 6429 # (fiel)com.apple.quicktime.detected-face.roll-angle (dtyp=23, float) 6430 'detected-face.roll-angle' => { Name => 'DetectedFaceRollAngle', Writable => 0 }, 6431 # (fiel)com.apple.quicktime.detected-face.yaw-angle (dtyp=23, float) 6432 'detected-face.yaw-angle' => { Name => 'DetectedFaceYawAngle', Writable => 0 }, 6433# 6434# seen in Apple ProRes RAW file 6435# 6436 # (mdta)com.apple.proapps.manufacturer (eg. "Sony") 6437 # (mdta)com.apple.proapps.exif.{Exif}.FNumber (float, eg. 1.0) 6438 # (mdta)org.smpte.rdd18.lens.irisfnumber (eg. "F1.0") 6439 # (mdta)com.apple.proapps.exif.{Exif}.ShutterSpeedValue (float, eg. 1.006) 6440 # (mdta)org.smpte.rdd18.camera.shutterspeed_angle (eg. "179.2deg") 6441 # (mdta)org.smpte.rdd18.camera.neutraldensityfilterwheelsetting (eg. "ND1") 6442 # (mdta)org.smpte.rdd18.camera.whitebalance (eg. "4300K") 6443 # (mdta)com.apple.proapps.exif.{Exif}.ExposureIndex (float, eg. 4000) 6444 # (mdta)org.smpte.rdd18.camera.isosensitivity (eg. "4000") 6445 # (mdta)com.apple.proapps.image.{TIFF}.Make (eg. "Atmos") 6446 # (mdta)com.apple.proapps.image.{TIFF}.Model (eg. "ShogunInferno") 6447 # (mdta)com.apple.proapps.image.{TIFF}.Software (eg. "9.0") 6448); 6449 6450# iTunes info ('----') atoms 6451%Image::ExifTool::QuickTime::iTunesInfo = ( 6452 PROCESS_PROC => \&ProcessMOV, 6453 GROUPS => { 2 => 'Audio' }, 6454 NOTES => q{ 6455 ExifTool will extract any iTunesInfo tags that exist, even if they are not 6456 defined in this table. 6457 }, 6458 # 'mean'/'name'/'data' atoms form a triplet, but unfortunately 6459 # I haven't been able to find any documentation on this. 6460 # 'mean' is normally 'com.apple.iTunes' 6461 mean => { 6462 Name => 'Mean', 6463 # the 'Triplet' flag tells ProcessMOV() to generate 6464 # a single tag from the mean/name/data triplet 6465 Triplet => 1, 6466 Hidden => 1, 6467 }, 6468 name => { 6469 Name => 'Name', 6470 Triplet => 1, 6471 Hidden => 1, 6472 }, 6473 data => { 6474 Name => 'Data', 6475 Triplet => 1, 6476 Hidden => 1, 6477 }, 6478 # the tag ID's below are composed from "mean/name", 6479 # but "mean/" is omitted if it is "com.apple.iTunes/": 6480 'iTunMOVI' => { 6481 Name => 'iTunMOVI', 6482 SubDirectory => { TagTable => 'Image::ExifTool::PLIST::Main' }, 6483 }, 6484 'tool' => { 6485 Name => 'iTunTool', 6486 Description => 'iTunTool', 6487 Format => 'int32u', 6488 PrintConv => 'sprintf("0x%.8x",$val)', 6489 }, 6490 'iTunEXTC' => { 6491 Name => 'ContentRating', 6492 Notes => 'standard | rating | score | reasons', 6493 # eg. 'us-tv|TV-14|500|V', 'mpaa|PG-13|300|For violence and sexuality' 6494 # (see http://shadowofged.blogspot.ca/2008/06/itunes-content-ratings.html) 6495 }, 6496 'iTunNORM' => { 6497 Name => 'VolumeNormalization', 6498 PrintConv => '$val=~s/ 0+(\w)/ $1/g; $val=~s/^\s+//; $val', 6499 }, 6500 'iTunSMPB' => { 6501 Name => 'iTunSMPB', 6502 Description => 'iTunSMPB', 6503 # hex format, similar to iTunNORM, but 12 words instead of 10, 6504 # and 4th word is 16 hex digits (all others are 8) 6505 # (gives AAC encoder delay, ref http://code.google.com/p/l-smash/issues/detail?id=1) 6506 PrintConv => '$val=~s/ 0+(\w)/ $1/g; $val=~s/^\s+//; $val', 6507 }, 6508 # (CDDB = Compact Disc DataBase) 6509 # iTunes_CDDB_1 = <CDDB1 disk ID>+<# tracks>+<logical block address for each track>... 6510 'iTunes_CDDB_1' => 'CDDB1Info', 6511 'iTunes_CDDB_TrackNumber' => 'CDDBTrackNumber', 6512 'Encoding Params' => { 6513 Name => 'EncodingParams', 6514 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::EncodingParams' }, 6515 }, 6516 # also heard about 'iTunPGAP', but I haven't seen a sample 6517 DISCNUMBER => 'DiscNumber', #PH 6518 TRACKNUMBER => 'TrackNumber', #PH 6519 popularimeter => 'Popularimeter', #PH 6520); 6521 6522# iTunes audio encoding parameters 6523# ref https://developer.apple.com/library/mac/#documentation/MusicAudio/Reference/AudioCodecServicesRef/Reference/reference.html 6524%Image::ExifTool::QuickTime::EncodingParams = ( 6525 PROCESS_PROC => \&ProcessEncodingParams, 6526 GROUPS => { 2 => 'Audio' }, 6527 # (I have commented out the ones that don't have integer values because they 6528 # probably don't appear, and definitely wouldn't work with current decoding - PH) 6529 6530 # global codec properties 6531 #'lnam' => 'AudioCodecName', 6532 #'lmak' => 'AudioCodecManufacturer', 6533 #'lfor' => 'AudioCodecFormat', 6534 'vpk?' => 'AudioHasVariablePacketByteSizes', 6535 #'ifm#' => 'AudioSupportedInputFormats', 6536 #'ofm#' => 'AudioSupportedOutputFormats', 6537 #'aisr' => 'AudioAvailableInputSampleRates', 6538 #'aosr' => 'AudioAvailableOutputSampleRates', 6539 'abrt' => 'AudioAvailableBitRateRange', 6540 'mnip' => 'AudioMinimumNumberInputPackets', 6541 'mnop' => 'AudioMinimumNumberOutputPackets', 6542 'cmnc' => 'AudioAvailableNumberChannels', 6543 'lmrc' => 'AudioDoesSampleRateConversion', 6544 #'aicl' => 'AudioAvailableInputChannelLayoutTags', 6545 #'aocl' => 'AudioAvailableOutputChannelLayoutTags', 6546 #'if4o' => 'AudioInputFormatsForOutputFormat', 6547 #'of4i' => 'AudioOutputFormatsForInputFormat', 6548 #'acfi' => 'AudioFormatInfo', 6549 6550 # instance codec properties 6551 'tbuf' => 'AudioInputBufferSize', 6552 'pakf' => 'AudioPacketFrameSize', 6553 'pakb' => 'AudioMaximumPacketByteSize', 6554 #'ifmt' => 'AudioCurrentInputFormat', 6555 #'ofmt' => 'AudioCurrentOutputFormat', 6556 #'kuki' => 'AudioMagicCookie', 6557 'ubuf' => 'AudioUsedInputBufferSize', 6558 'init' => 'AudioIsInitialized', 6559 'brat' => 'AudioCurrentTargetBitRate', 6560 #'cisr' => 'AudioCurrentInputSampleRate', 6561 #'cosr' => 'AudioCurrentOutputSampleRate', 6562 'srcq' => 'AudioQualitySetting', 6563 #'brta' => 'AudioApplicableBitRateRange', 6564 #'isra' => 'AudioApplicableInputSampleRates', 6565 #'osra' => 'AudioApplicableOutputSampleRates', 6566 'pad0' => 'AudioZeroFramesPadded', 6567 'prmm' => 'AudioCodecPrimeMethod', 6568 #'prim' => 'AudioCodecPrimeInfo', 6569 #'icl ' => 'AudioInputChannelLayout', 6570 #'ocl ' => 'AudioOutputChannelLayout', 6571 #'acs ' => 'AudioCodecSettings', 6572 #'acfl' => 'AudioCodecFormatList', 6573 'acbf' => 'AudioBitRateControlMode', 6574 'vbrq' => 'AudioVBRQuality', 6575 'mdel' => 'AudioMinimumDelayMode', 6576 6577 # deprecated 6578 'pakd' => 'AudioRequiresPacketDescription', 6579 #'brt#' => 'AudioAvailableBitRates', 6580 'acef' => 'AudioExtendFrequencies', 6581 'ursr' => 'AudioUseRecommendedSampleRate', 6582 'oppr' => 'AudioOutputPrecedence', 6583 #'loud' => 'AudioCurrentLoudnessStatistics', 6584 6585 # others 6586 'vers' => 'AudioEncodingParamsVersion', #PH 6587 'cdcv' => { #PH 6588 Name => 'AudioComponentVersion', 6589 ValueConv => 'join ".", unpack("ncc", pack("N",$val))', 6590 }, 6591); 6592 6593# print to video data block 6594%Image::ExifTool::QuickTime::Video = ( 6595 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6596 GROUPS => { 2 => 'Video' }, 6597 0 => { 6598 Name => 'DisplaySize', 6599 PrintConv => { 6600 0 => 'Normal', 6601 1 => 'Double Size', 6602 2 => 'Half Size', 6603 3 => 'Full Screen', 6604 4 => 'Current Size', 6605 }, 6606 }, 6607 6 => { 6608 Name => 'SlideShow', 6609 PrintConv => { 6610 0 => 'No', 6611 1 => 'Yes', 6612 }, 6613 }, 6614); 6615 6616# 'hnti' atoms 6617%Image::ExifTool::QuickTime::HintInfo = ( 6618 PROCESS_PROC => \&ProcessMOV, 6619 GROUPS => { 2 => 'Video' }, 6620 'rtp ' => { 6621 Name => 'RealtimeStreamingProtocol', 6622 PrintConv => '$val=~s/^sdp /(SDP) /; $val', 6623 }, 6624 'sdp ' => 'StreamingDataProtocol', 6625); 6626 6627# 'hinf' atoms 6628%Image::ExifTool::QuickTime::HintTrackInfo = ( 6629 PROCESS_PROC => \&ProcessMOV, 6630 GROUPS => { 2 => 'Video' }, 6631 trpY => { Name => 'TotalBytes', Format => 'int64u' }, #(documented) 6632 trpy => { Name => 'TotalBytes', Format => 'int64u' }, #(observed) 6633 totl => { Name => 'TotalBytes', Format => 'int32u' }, 6634 nump => { Name => 'NumPackets', Format => 'int64u' }, 6635 npck => { Name => 'NumPackets', Format => 'int32u' }, 6636 tpyl => { Name => 'TotalBytesNoRTPHeaders', Format => 'int64u' }, 6637 tpaY => { Name => 'TotalBytesNoRTPHeaders', Format => 'int32u' }, #(documented) 6638 tpay => { Name => 'TotalBytesNoRTPHeaders', Format => 'int32u' }, #(observed) 6639 maxr => { 6640 Name => 'MaxDataRate', 6641 Format => 'int32u', 6642 Count => 2, 6643 PrintConv => 'my @a=split(" ",$val);sprintf("%d bytes in %.3f s",$a[1],$a[0]/1000)', 6644 }, 6645 dmed => { Name => 'MediaTrackBytes', Format => 'int64u' }, 6646 dimm => { Name => 'ImmediateDataBytes', Format => 'int64u' }, 6647 drep => { Name => 'RepeatedDataBytes', Format => 'int64u' }, 6648 tmin => { 6649 Name => 'MinTransmissionTime', 6650 Format => 'int32u', 6651 PrintConv => 'sprintf("%.3f s",$val/1000)', 6652 }, 6653 tmax => { 6654 Name => 'MaxTransmissionTime', 6655 Format => 'int32u', 6656 PrintConv => 'sprintf("%.3f s",$val/1000)', 6657 }, 6658 pmax => { Name => 'LargestPacketSize', Format => 'int32u' }, 6659 dmax => { 6660 Name => 'LargestPacketDuration', 6661 Format => 'int32u', 6662 PrintConv => 'sprintf("%.3f s",$val/1000)', 6663 }, 6664 payt => { 6665 Name => 'PayloadType', 6666 Format => 'undef', # (necessary to prevent decoding as string!) 6667 ValueConv => 'unpack("N",$val) . " " . substr($val, 5)', 6668 PrintConv => '$val=~s/ /, /;$val', 6669 }, 6670); 6671 6672# MP4 media box (ref 5) 6673%Image::ExifTool::QuickTime::Media = ( 6674 PROCESS_PROC => \&ProcessMOV, 6675 WRITE_PROC => \&WriteQuickTime, 6676 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 6677 NOTES => 'MP4 media box.', 6678 mdhd => { 6679 Name => 'MediaHeader', 6680 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MediaHeader' }, 6681 }, 6682 hdlr => { 6683 Name => 'Handler', 6684 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' }, 6685 }, 6686 minf => { 6687 Name => 'MediaInfo', 6688 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MediaInfo' }, 6689 }, 6690); 6691 6692# MP4 media header box (ref 5) 6693%Image::ExifTool::QuickTime::MediaHeader = ( 6694 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6695 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 6696 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 6697 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 6698 FORMAT => 'int32u', 6699 DATAMEMBER => [ 0, 1, 2, 3, 4 ], 6700 0 => { 6701 Name => 'MediaHeaderVersion', 6702 RawConv => '$$self{MediaHeaderVersion} = $val', 6703 }, 6704 1 => { 6705 Name => 'MediaCreateDate', 6706 Groups => { 2 => 'Time' }, 6707 %timeInfo, 6708 # this is int64u if MediaHeaderVersion == 1 (ref 5/13) 6709 Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4', 6710 }, 6711 2 => { 6712 Name => 'MediaModifyDate', 6713 Groups => { 2 => 'Time' }, 6714 %timeInfo, 6715 # this is int64u if MediaHeaderVersion == 1 (ref 5/13) 6716 Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4', 6717 }, 6718 3 => { 6719 Name => 'MediaTimeScale', 6720 RawConv => '$$self{MediaTS} = $val', 6721 }, 6722 4 => { 6723 Name => 'MediaDuration', 6724 RawConv => '$$self{MediaTS} ? $val / $$self{MediaTS} : $val', 6725 PrintConv => '$$self{MediaTS} ? ConvertDuration($val) : $val', 6726 # this is int64u if MediaHeaderVersion == 1 (ref 5/13) 6727 Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4', 6728 }, 6729 5 => { 6730 Name => 'MediaLanguageCode', 6731 Format => 'int16u', 6732 RawConv => '$val ? $val : undef', 6733 # allow both Macintosh (for MOV files) and ISO (for MP4 files) language codes 6734 ValueConv => '($val < 0x400 or $val == 0x7fff) ? $val : pack "C*", map { (($val>>$_)&0x1f)+0x60 } 10, 5, 0', 6735 PrintConv => q{ 6736 return $val unless $val =~ /^\d+$/; 6737 require Image::ExifTool::Font; 6738 return $Image::ExifTool::Font::ttLang{Macintosh}{$val} || "Unknown ($val)"; 6739 }, 6740 }, 6741); 6742 6743# MP4 media information box (ref 5) 6744%Image::ExifTool::QuickTime::MediaInfo = ( 6745 PROCESS_PROC => \&ProcessMOV, 6746 WRITE_PROC => \&WriteQuickTime, 6747 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 6748 NOTES => 'MP4 media info box.', 6749 vmhd => { 6750 Name => 'VideoHeader', 6751 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::VideoHeader' }, 6752 }, 6753 smhd => { 6754 Name => 'AudioHeader', 6755 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AudioHeader' }, 6756 }, 6757 hmhd => { 6758 Name => 'HintHeader', 6759 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintHeader' }, 6760 }, 6761 nmhd => { 6762 Name => 'NullMediaHeader', 6763 Flags => ['Binary','Unknown'], 6764 }, 6765 dinf => { 6766 Name => 'DataInfo', # (don't change this name -- used to recognize directory when writing) 6767 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' }, 6768 }, 6769 gmhd => { 6770 Name => 'GenMediaHeader', 6771 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::GenMediaHeader' }, 6772 }, 6773 hdlr => { #PH 6774 Name => 'Handler', 6775 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' }, 6776 }, 6777 stbl => { 6778 Name => 'SampleTable', 6779 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SampleTable' }, 6780 }, 6781); 6782 6783# MP4 video media header (ref 5) 6784%Image::ExifTool::QuickTime::VideoHeader = ( 6785 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6786 GROUPS => { 2 => 'Video' }, 6787 NOTES => 'MP4 video media header.', 6788 FORMAT => 'int16u', 6789 2 => { 6790 Name => 'GraphicsMode', 6791 PrintHex => 1, 6792 SeparateTable => 'GraphicsMode', 6793 PrintConv => \%graphicsMode, 6794 }, 6795 3 => { Name => 'OpColor', Format => 'int16u[3]' }, 6796); 6797 6798# MP4 audio media header (ref 5) 6799%Image::ExifTool::QuickTime::AudioHeader = ( 6800 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6801 GROUPS => { 2 => 'Audio' }, 6802 NOTES => 'MP4 audio media header.', 6803 FORMAT => 'int16u', 6804 2 => { Name => 'Balance', Format => 'fixed16s' }, 6805); 6806 6807# MP4 hint media header (ref 5) 6808%Image::ExifTool::QuickTime::HintHeader = ( 6809 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6810 NOTES => 'MP4 hint media header.', 6811 FORMAT => 'int16u', 6812 2 => 'MaxPDUSize', 6813 3 => 'AvgPDUSize', 6814 4 => { Name => 'MaxBitrate', Format => 'int32u', PrintConv => 'ConvertBitrate($val)' }, 6815 6 => { Name => 'AvgBitrate', Format => 'int32u', PrintConv => 'ConvertBitrate($val)' }, 6816); 6817 6818# MP4 sample table box (ref 5) 6819%Image::ExifTool::QuickTime::SampleTable = ( 6820 PROCESS_PROC => \&ProcessMOV, 6821 WRITE_PROC => \&WriteQuickTime, 6822 GROUPS => { 2 => 'Video' }, 6823 NOTES => 'MP4 sample table box.', 6824 stsd => [ 6825 { 6826 Name => 'AudioSampleDesc', 6827 Condition => '$$self{HandlerType} and $$self{HandlerType} eq "soun"', 6828 SubDirectory => { 6829 TagTable => 'Image::ExifTool::QuickTime::AudioSampleDesc', 6830 ProcessProc => \&ProcessSampleDesc, 6831 }, 6832 },{ 6833 Name => 'VideoSampleDesc', 6834 Condition => '$$self{HandlerType} and $$self{HandlerType} eq "vide"', 6835 SubDirectory => { 6836 TagTable => 'Image::ExifTool::QuickTime::ImageDesc', 6837 ProcessProc => \&ProcessSampleDesc, 6838 }, 6839 },{ 6840 Name => 'HintSampleDesc', 6841 Condition => '$$self{HandlerType} and $$self{HandlerType} eq "hint"', 6842 SubDirectory => { 6843 TagTable => 'Image::ExifTool::QuickTime::HintSampleDesc', 6844 ProcessProc => \&ProcessSampleDesc, 6845 }, 6846 },{ 6847 Name => 'MetaSampleDesc', 6848 Condition => '$$self{HandlerType} and $$self{HandlerType} eq "meta"', 6849 SubDirectory => { 6850 TagTable => 'Image::ExifTool::QuickTime::MetaSampleDesc', 6851 ProcessProc => \&ProcessSampleDesc, 6852 }, 6853 },{ 6854 Name => 'OtherSampleDesc', 6855 SubDirectory => { 6856 TagTable => 'Image::ExifTool::QuickTime::OtherSampleDesc', 6857 ProcessProc => \&ProcessSampleDesc, 6858 }, 6859 }, 6860 # (Note: "alis" HandlerType handled by the parent audio or video handler) 6861 ], 6862 stts => [ # decoding time-to-sample table 6863 { 6864 Name => 'VideoFrameRate', 6865 Notes => 'average rate calculated from time-to-sample table for video media', 6866 Condition => '$$self{HandlerType} and $$self{HandlerType} eq "vide"', 6867 Format => 'undef', # (necessary to prevent decoding as string!) 6868 # (must be RawConv so appropriate MediaTS is used in calculation) 6869 RawConv => 'Image::ExifTool::QuickTime::CalcSampleRate($self, \$val)', 6870 PrintConv => 'int($val * 1000 + 0.5) / 1000', 6871 }, 6872 { 6873 Name => 'TimeToSampleTable', 6874 Flags => ['Binary','Unknown'], 6875 }, 6876 ], 6877 ctts => { 6878 Name => 'CompositionTimeToSample', 6879 Flags => ['Binary','Unknown'], 6880 }, 6881 stsc => { 6882 Name => 'SampleToChunk', 6883 Flags => ['Binary','Unknown'], 6884 }, 6885 stsz => { 6886 Name => 'SampleSizes', 6887 Flags => ['Binary','Unknown'], 6888 }, 6889 stz2 => { 6890 Name => 'CompactSampleSizes', 6891 Flags => ['Binary','Unknown'], 6892 }, 6893 stco => { 6894 Name => 'ChunkOffset', 6895 Flags => ['Binary','Unknown'], 6896 }, 6897 co64 => { 6898 Name => 'ChunkOffset64', 6899 Flags => ['Binary','Unknown'], 6900 }, 6901 stss => { 6902 Name => 'SyncSampleTable', 6903 Flags => ['Binary','Unknown'], 6904 }, 6905 stsh => { 6906 Name => 'ShadowSyncSampleTable', 6907 Flags => ['Binary','Unknown'], 6908 }, 6909 padb => { 6910 Name => 'SamplePaddingBits', 6911 Flags => ['Binary','Unknown'], 6912 }, 6913 stdp => { 6914 Name => 'SampleDegradationPriority', 6915 Flags => ['Binary','Unknown'], 6916 }, 6917 sdtp => { 6918 Name => 'IdependentAndDisposableSamples', 6919 Flags => ['Binary','Unknown'], 6920 }, 6921 sbgp => { 6922 Name => 'SampleToGroup', 6923 Flags => ['Binary','Unknown'], 6924 }, 6925 sgpd => { 6926 Name => 'SampleGroupDescription', 6927 Flags => ['Binary','Unknown'], 6928 # bytes 4-7 give grouping type (ref ISO/IEC 14496-15:2014) 6929 # tsas - temporal sublayer sample 6930 # stsa - step-wise temporal layer access 6931 # avss - AVC sample 6932 # tscl - temporal layer scalability 6933 # sync - sync sample 6934 }, 6935 subs => { 6936 Name => 'Sub-sampleInformation', 6937 Flags => ['Binary','Unknown'], 6938 }, 6939 cslg => { 6940 Name => 'CompositionToDecodeTimelineMapping', 6941 Flags => ['Binary','Unknown'], 6942 }, 6943 stps => { 6944 Name => 'PartialSyncSamples', 6945 ValueConv => 'join " ",unpack("x8N*",$val)', 6946 }, 6947 # mark - 8 bytes all zero (GoPro) 6948); 6949 6950# MP4 audio sample description box (ref 5/AtomicParsley 0.9.4 parsley.cpp) 6951%Image::ExifTool::QuickTime::AudioSampleDesc = ( 6952 PROCESS_PROC => \&ProcessHybrid, 6953 VARS => { ID_LABEL => 'ID/Index' }, 6954 GROUPS => { 2 => 'Audio' }, 6955 NOTES => q{ 6956 MP4 audio sample description. This hybrid atom contains both data and child 6957 atoms. 6958 }, 6959 4 => { 6960 Name => 'AudioFormat', 6961 Format => 'undef[4]', 6962 RawConv => q{ 6963 $$self{AudioFormat} = $val; 6964 return undef unless $val =~ /^[\w ]{4}$/i; 6965 # check for protected audio format 6966 $self->OverrideFileType('M4P') if $val eq 'drms' and $$self{VALUE}{FileType} eq 'M4A'; 6967 return $val; 6968 }, 6969 # see this link for print conversions (not complete): 6970 # https://github.com/yannickcr/brooser/blob/master/php/librairies/getid3/module.audio-video.quicktime.php 6971 }, 6972 20 => { #PH 6973 Name => 'AudioVendorID', 6974 Condition => '$$self{AudioFormat} ne "mp4s"', 6975 Format => 'undef[4]', 6976 RawConv => '$val eq "\0\0\0\0" ? undef : $val', 6977 PrintConv => \%vendorID, 6978 SeparateTable => 'VendorID', 6979 }, 6980 24 => { Name => 'AudioChannels', Format => 'int16u' }, 6981 26 => { Name => 'AudioBitsPerSample', Format => 'int16u' }, 6982 32 => { Name => 'AudioSampleRate', Format => 'fixed32u' }, 6983# 6984# Observed offsets for child atoms of various AudioFormat types: 6985# 6986# AudioFormat Offset Child atoms 6987# ----------- ------ ---------------- 6988# mp4a 52 * wave, chan, esds, SA3D(Insta360 spherical video params?,also GoPro Max) 6989# in24 52 wave, chan 6990# "ms\0\x11" 52 wave 6991# sowt 52 chan 6992# mp4a 36 * esds, pinf 6993# drms 36 esds, sinf 6994# samr 36 damr 6995# alac 36 alac 6996# ac-3 36 dac3 6997# 6998# (* child atoms found at different offsets in mp4a) 6999# 7000 pinf => { 7001 Name => 'PurchaseInfo', 7002 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ProtectionInfo' }, 7003 }, 7004 sinf => { # "protection scheme information" 7005 Name => 'ProtectionInfo', #3 7006 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ProtectionInfo' }, 7007 }, 7008 # f - 16/36 bytes 7009 # esds - 31/40/42/43 bytes - ES descriptor (ref 3) 7010 damr => { #3 7011 Name => 'DecodeConfig', 7012 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DecodeConfig' }, 7013 }, 7014 wave => { 7015 Name => 'Wave', 7016 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Wave' }, 7017 }, 7018 chan => { 7019 Name => 'AudioChannelLayout', 7020 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ChannelLayout' }, 7021 } 7022 # alac - 28 bytes 7023 # adrm - AAX DRM atom? 148 bytes 7024 # aabd - AAX unknown 17kB (contains 'aavd' strings) 7025 # SA3D - written by Garmin VIRB360 7026); 7027 7028# AMR decode config box (ref 3) 7029%Image::ExifTool::QuickTime::DecodeConfig = ( 7030 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7031 GROUPS => { 2 => 'Audio' }, 7032 0 => { 7033 Name => 'EncoderVendor', 7034 Format => 'undef[4]', 7035 }, 7036 4 => 'EncoderVersion', 7037 # 5 - int16u - packet modes 7038 # 7 - int8u - number of packet mode changes 7039 # 8 - int8u - bytes per packet 7040); 7041 7042%Image::ExifTool::QuickTime::ProtectionInfo = ( 7043 PROCESS_PROC => \&ProcessMOV, 7044 GROUPS => { 2 => 'Audio' }, 7045 NOTES => 'Child atoms found in "sinf" and/or "pinf" atoms.', 7046 frma => 'OriginalFormat', 7047 # imif - IPMP information 7048 schm => { 7049 Name => 'SchemeType', 7050 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeType' }, 7051 }, 7052 schi => { 7053 Name => 'SchemeInfo', 7054 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeInfo' }, 7055 }, 7056 enda => { 7057 Name => 'Endianness', 7058 Format => 'int16u', 7059 PrintConv => { 7060 0 => 'Big-endian (Motorola, MM)', 7061 1 => 'Little-endian (Intel, II)', 7062 }, 7063 }, 7064 # skcr 7065); 7066 7067%Image::ExifTool::QuickTime::Wave = ( 7068 PROCESS_PROC => \&ProcessMOV, 7069 frma => 'PurchaseFileFormat', 7070 enda => { 7071 Name => 'Endianness', 7072 Format => 'int16u', 7073 PrintConv => { 7074 0 => 'Big-endian (Motorola, MM)', 7075 1 => 'Little-endian (Intel, II)', 7076 }, 7077 }, 7078 # "ms\0\x11" - 20 bytes 7079); 7080 7081# audio channel layout (ref CoreAudioTypes.h) 7082%Image::ExifTool::QuickTime::ChannelLayout = ( 7083 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7084 GROUPS => { 2 => 'Audio' }, 7085 DATAMEMBER => [ 0, 8 ], 7086 NOTES => 'Audio channel layout.', 7087 # 0 - version and flags 7088 4 => { 7089 Name => 'LayoutFlags', 7090 Format => 'int16u', 7091 RawConv => '$$self{LayoutFlags} = $val', 7092 PrintConvColumns => 2, 7093 PrintConv => { 7094 0 => 'UseDescriptions', 7095 1 => 'UseBitmap', 7096 100 => 'Mono', 7097 101 => 'Stereo', 7098 102 => 'StereoHeadphones', 7099 100 => 'Mono', 7100 101 => 'Stereo', 7101 102 => 'StereoHeadphones', 7102 103 => 'MatrixStereo', 7103 104 => 'MidSide', 7104 105 => 'XY', 7105 106 => 'Binaural', 7106 107 => 'Ambisonic_B_Format', 7107 108 => 'Quadraphonic', 7108 109 => 'Pentagonal', 7109 110 => 'Hexagonal', 7110 111 => 'Octagonal', 7111 112 => 'Cube', 7112 113 => 'MPEG_3_0_A', 7113 114 => 'MPEG_3_0_B', 7114 115 => 'MPEG_4_0_A', 7115 116 => 'MPEG_4_0_B', 7116 117 => 'MPEG_5_0_A', 7117 118 => 'MPEG_5_0_B', 7118 119 => 'MPEG_5_0_C', 7119 120 => 'MPEG_5_0_D', 7120 121 => 'MPEG_5_1_A', 7121 122 => 'MPEG_5_1_B', 7122 123 => 'MPEG_5_1_C', 7123 124 => 'MPEG_5_1_D', 7124 125 => 'MPEG_6_1_A', 7125 126 => 'MPEG_7_1_A', 7126 127 => 'MPEG_7_1_B', 7127 128 => 'MPEG_7_1_C', 7128 129 => 'Emagic_Default_7_1', 7129 130 => 'SMPTE_DTV', 7130 131 => 'ITU_2_1', 7131 132 => 'ITU_2_2', 7132 133 => 'DVD_4', 7133 134 => 'DVD_5', 7134 135 => 'DVD_6', 7135 136 => 'DVD_10', 7136 137 => 'DVD_11', 7137 138 => 'DVD_18', 7138 139 => 'AudioUnit_6_0', 7139 140 => 'AudioUnit_7_0', 7140 141 => 'AAC_6_0', 7141 142 => 'AAC_6_1', 7142 143 => 'AAC_7_0', 7143 144 => 'AAC_Octagonal', 7144 145 => 'TMH_10_2_std', 7145 146 => 'TMH_10_2_full', 7146 147 => 'DiscreteInOrder', 7147 148 => 'AudioUnit_7_0_Front', 7148 149 => 'AC3_1_0_1', 7149 150 => 'AC3_3_0', 7150 151 => 'AC3_3_1', 7151 152 => 'AC3_3_0_1', 7152 153 => 'AC3_2_1_1', 7153 154 => 'AC3_3_1_1', 7154 155 => 'EAC_6_0_A', 7155 156 => 'EAC_7_0_A', 7156 157 => 'EAC3_6_1_A', 7157 158 => 'EAC3_6_1_B', 7158 159 => 'EAC3_6_1_C', 7159 160 => 'EAC3_7_1_A', 7160 161 => 'EAC3_7_1_B', 7161 162 => 'EAC3_7_1_C', 7162 163 => 'EAC3_7_1_D', 7163 164 => 'EAC3_7_1_E', 7164 165 => 'EAC3_7_1_F', 7165 166 => 'EAC3_7_1_G', 7166 167 => 'EAC3_7_1_H', 7167 168 => 'DTS_3_1', 7168 169 => 'DTS_4_1', 7169 170 => 'DTS_6_0_A', 7170 171 => 'DTS_6_0_B', 7171 172 => 'DTS_6_0_C', 7172 173 => 'DTS_6_1_A', 7173 174 => 'DTS_6_1_B', 7174 175 => 'DTS_6_1_C', 7175 176 => 'DTS_7_0', 7176 177 => 'DTS_7_1', 7177 178 => 'DTS_8_0_A', 7178 179 => 'DTS_8_0_B', 7179 180 => 'DTS_8_1_A', 7180 181 => 'DTS_8_1_B', 7181 182 => 'DTS_6_1_D', 7182 183 => 'AAC_7_1_B', 7183 0xffff => 'Unknown', 7184 }, 7185 }, 7186 6 => { 7187 Name => 'AudioChannels', 7188 Condition => '$$self{LayoutFlags} != 0 and $$self{LayoutFlags} != 1', 7189 Format => 'int16u', 7190 }, 7191 8 => { 7192 Name => 'AudioChannelTypes', 7193 Condition => '$$self{LayoutFlags} == 1', 7194 Format => 'int32u', 7195 PrintConv => { BITMASK => { 7196 0 => 'Left', 7197 1 => 'Right', 7198 2 => 'Center', 7199 3 => 'LFEScreen', 7200 4 => 'LeftSurround', 7201 5 => 'RightSurround', 7202 6 => 'LeftCenter', 7203 7 => 'RightCenter', 7204 8 => 'CenterSurround', 7205 9 => 'LeftSurroundDirect', 7206 10 => 'RightSurroundDirect', 7207 11 => 'TopCenterSurround', 7208 12 => 'VerticalHeightLeft', 7209 13 => 'VerticalHeightCenter', 7210 14 => 'VerticalHeightRight', 7211 15 => 'TopBackLeft', 7212 16 => 'TopBackCenter', 7213 17 => 'TopBackRight', 7214 }}, 7215 }, 7216 12 => { 7217 Name => 'NumChannelDescriptions', 7218 Condition => '$$self{LayoutFlags} == 1', 7219 Format => 'int32u', 7220 RawConv => '$$self{NumChannelDescriptions} = $val', 7221 }, 7222 16 => { 7223 Name => 'Channel1Label', 7224 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0', 7225 Format => 'int32u', 7226 SeparateTable => 'ChannelLabel', 7227 PrintConv => \%channelLabel, 7228 }, 7229 20 => { 7230 Name => 'Channel1Flags', 7231 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0', 7232 Format => 'int32u', 7233 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7234 }, 7235 24 => { 7236 Name => 'Channel1Coordinates', 7237 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0', 7238 Notes => q{ 7239 3 numbers: for rectangular coordinates left/right, back/front, down/up; for 7240 spherical coordinates left/right degrees, down/up degrees, distance 7241 }, 7242 Format => 'float[3]', 7243 }, 7244 36 => { 7245 Name => 'Channel2Label', 7246 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1', 7247 Format => 'int32u', 7248 SeparateTable => 'ChannelLabel', 7249 PrintConv => \%channelLabel, 7250 }, 7251 40 => { 7252 Name => 'Channel2Flags', 7253 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1', 7254 Format => 'int32u', 7255 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7256 }, 7257 44 => { 7258 Name => 'Channel2Coordinates', 7259 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1', 7260 Format => 'float[3]', 7261 }, 7262 56 => { 7263 Name => 'Channel3Label', 7264 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2', 7265 Format => 'int32u', 7266 SeparateTable => 'ChannelLabel', 7267 PrintConv => \%channelLabel, 7268 }, 7269 60 => { 7270 Name => 'Channel3Flags', 7271 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2', 7272 Format => 'int32u', 7273 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7274 }, 7275 64 => { 7276 Name => 'Channel3Coordinates', 7277 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2', 7278 Format => 'float[3]', 7279 }, 7280 76 => { 7281 Name => 'Channel4Label', 7282 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3', 7283 Format => 'int32u', 7284 SeparateTable => 'ChannelLabel', 7285 PrintConv => \%channelLabel, 7286 }, 7287 80 => { 7288 Name => 'Channel4Flags', 7289 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3', 7290 Format => 'int32u', 7291 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7292 }, 7293 84 => { 7294 Name => 'Channel4Coordinates', 7295 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3', 7296 Format => 'float[3]', 7297 }, 7298 96 => { 7299 Name => 'Channel5Label', 7300 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4', 7301 Format => 'int32u', 7302 SeparateTable => 'ChannelLabel', 7303 PrintConv => \%channelLabel, 7304 }, 7305 100 => { 7306 Name => 'Channel5Flags', 7307 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4', 7308 Format => 'int32u', 7309 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7310 }, 7311 104 => { 7312 Name => 'Channel5Coordinates', 7313 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4', 7314 Format => 'float[3]', 7315 }, 7316 116 => { 7317 Name => 'Channel6Label', 7318 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5', 7319 Format => 'int32u', 7320 SeparateTable => 'ChannelLabel', 7321 PrintConv => \%channelLabel, 7322 }, 7323 120 => { 7324 Name => 'Channel6Flags', 7325 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5', 7326 Format => 'int32u', 7327 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7328 }, 7329 124 => { 7330 Name => 'Channel6Coordinates', 7331 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5', 7332 Format => 'float[3]', 7333 }, 7334 136 => { 7335 Name => 'Channel7Label', 7336 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6', 7337 Format => 'int32u', 7338 SeparateTable => 'ChannelLabel', 7339 PrintConv => \%channelLabel, 7340 }, 7341 140 => { 7342 Name => 'Channel7Flags', 7343 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6', 7344 Format => 'int32u', 7345 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7346 }, 7347 144 => { 7348 Name => 'Channel7Coordinates', 7349 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6', 7350 Format => 'float[3]', 7351 }, 7352 156 => { 7353 Name => 'Channel8Label', 7354 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7', 7355 Format => 'int32u', 7356 SeparateTable => 'ChannelLabel', 7357 PrintConv => \%channelLabel, 7358 }, 7359 160 => { 7360 Name => 'Channel8Flags', 7361 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7', 7362 Format => 'int32u', 7363 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7364 }, 7365 164 => { 7366 Name => 'Channel8Coordinates', 7367 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7', 7368 Format => 'float[3]', 7369 }, 7370 # (arbitrarily decode only first 8 channels) 7371); 7372 7373# scheme type atom 7374# ref http://xhelmboyx.tripod.com/formats/mp4-layout.txt 7375%Image::ExifTool::QuickTime::SchemeType = ( 7376 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7377 GROUPS => { 2 => 'Audio' }, 7378 # 0 - 4 bytes version 7379 4 => { Name => 'SchemeType', Format => 'undef[4]' }, 7380 8 => { Name => 'SchemeVersion', Format => 'int16u' }, 7381 10 => { Name => 'SchemeURL', Format => 'string[$size-10]' }, 7382); 7383 7384%Image::ExifTool::QuickTime::SchemeInfo = ( 7385 PROCESS_PROC => \&ProcessMOV, 7386 GROUPS => { 2 => 'Audio' }, 7387 user => { 7388 Name => 'UserID', 7389 Groups => { 2 => 'Author' }, 7390 ValueConv => '"0x" . unpack("H*",$val)', 7391 }, 7392 cert => { # ref http://www.onvif.org/specs/stream/ONVIF-ExportFileFormat-Spec-v100.pdf 7393 Name => 'Certificate', 7394 ValueConv => '"0x" . unpack("H*",$val)', 7395 }, 7396 'key ' => { 7397 Name => 'KeyID', 7398 ValueConv => '"0x" . unpack("H*",$val)', 7399 }, 7400 iviv => { 7401 Name => 'InitializationVector', 7402 ValueConv => 'unpack("H*",$val)', 7403 }, 7404 righ => { 7405 Name => 'Rights', 7406 Groups => { 2 => 'Author' }, 7407 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Rights' }, 7408 }, 7409 name => { Name => 'UserName', Groups => { 2 => 'Author' } }, 7410 # chtb 7411 # priv - private data 7412 # sign 7413 # adkm - Adobe DRM key management system (ref http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf) 7414 # iKMS 7415 # iSFM 7416 # iSLT 7417); 7418 7419%Image::ExifTool::QuickTime::Rights = ( 7420 PROCESS_PROC => \&ProcessRights, 7421 GROUPS => { 2 => 'Audio' }, 7422 veID => 'ItemVendorID', #PH ("VendorID" ref 19) 7423 plat => 'Platform', #18? 7424 aver => 'VersionRestrictions', #19 ("appversion?" ref 18) 7425 tran => 'TransactionID', #18 7426 song => 'ItemID', #19 ("appid" ref 18) 7427 tool => { 7428 Name => 'ItemTool', #PH (guess) ("itunes build?" ref 18) 7429 Format => 'string', 7430 }, 7431 medi => 'MediaFlags', #PH (?) 7432 mode => 'ModeFlags', #PH (?) 0x04 is HD flag (https://compilr.com/heksesang/requiem-mac/UnDrm.java) 7433); 7434 7435# MP4 hint sample description box (ref 5) 7436# (ref https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-SW1) 7437%Image::ExifTool::QuickTime::HintSampleDesc = ( 7438 PROCESS_PROC => \&ProcessHybrid, 7439 VARS => { ID_LABEL => 'ID/Index' }, 7440 NOTES => 'MP4 hint sample description.', 7441 4 => { Name => 'HintFormat', Format => 'undef[4]' }, 7442 # 14 - int16u DataReferenceIndex 7443 16 => { Name => 'HintTrackVersion', Format => 'int16u' }, 7444 # 18 - int16u LastCompatibleHintTrackVersion 7445 20 => { Name => 'MaxPacketSize', Format => 'int32u' }, 7446# 7447# Observed offsets for child atoms of various HintFormat types: 7448# 7449# HintFormat Offset Child atoms 7450# ----------- ------ ---------------- 7451# "rtp " 24 tims 7452# 7453 tims => { Name => 'RTPTimeScale', Format => 'int32u' }, 7454 tsro => { Name => 'TimestampRandomOffset', Format => 'int32u' }, 7455 snro => { Name => 'SequenceNumberRandomOffset', Format => 'int32u' }, 7456); 7457 7458# MP4 metadata sample description box 7459%Image::ExifTool::QuickTime::MetaSampleDesc = ( 7460 PROCESS_PROC => \&ProcessHybrid, 7461 NOTES => 'MP4 metadata sample description.', 7462 4 => { 7463 Name => 'MetaFormat', 7464 Format => 'undef[4]', 7465 RawConv => '$$self{MetaFormat} = $val', 7466 }, 7467# 7468# Observed offsets for child atoms of various MetaFormat types: 7469# 7470# MetaFormat Offset Child atoms 7471# ----------- ------ ---------------- 7472# mebx 24 keys,btrt,lidp,lidl 7473# fdsc - - 7474# gpmd - - 7475# rtmd - - 7476# CTMD - - 7477# 7478 'keys' => { #PH (iPhone7+ hevc) 7479 Name => 'Keys', 7480 SubDirectory => { 7481 TagTable => 'Image::ExifTool::QuickTime::Keys', 7482 ProcessProc => \&ProcessMetaKeys, 7483 }, 7484 }, 7485 btrt => { 7486 Name => 'BitrateInfo', 7487 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Bitrate' }, 7488 }, 7489); 7490 7491# MP4 generic sample description box 7492%Image::ExifTool::QuickTime::OtherSampleDesc = ( 7493 PROCESS_PROC => \&ProcessHybrid, 7494 4 => { 7495 Name => 'OtherFormat', 7496 Format => 'undef[4]', 7497 RawConv => '$$self{MetaFormat} = $val', # (yes, use MetaFormat for this too) 7498 }, 7499# 7500# Observed offsets for child atoms of various OtherFormat types: 7501# 7502# OtherFormat Offset Child atoms 7503# ----------- ------ ---------------- 7504# avc1 86 avcC 7505# mp4a 36 esds 7506# mp4s 16 esds 7507# tmcd 34 name 7508# data - - 7509# 7510 ftab => { Name => 'FontTable', Format => 'undef', ValueConv => 'substr($val, 5)' }, 7511 name => { Name => 'OtherName', Format => 'undef', ValueConv => 'substr($val, 4)' }, 7512 # mrlh = GM header? 7513 # mrlv = GM data 7514 # mrld = GM data (448-byte records): 7515 # 0 - int32u count 7516 # 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=% 7517 # 8 - int32u ? (0,1,3,4,5) 7518 # 12 - string[64] units 7519 # 76 - int32u ? (1,3,7,15) 7520 # 80 - int32u 0 7521 # 84 - undef[4] ? 7522 # 88 - int16u[6] ? 7523 # 100 - undef[32] ? 7524 # 132 - string[64] measurement name 7525 # 196 - string[64] measurement name 7526); 7527 7528# MP4 data information box (ref 5) 7529%Image::ExifTool::QuickTime::DataInfo = ( 7530 PROCESS_PROC => \&ProcessMOV, 7531 WRITE_PROC => \&WriteQuickTime, # (necessary to parse dref even though we don't change it) 7532 NOTES => 'MP4 data information box.', 7533 dref => { 7534 Name => 'DataRef', 7535 SubDirectory => { 7536 TagTable => 'Image::ExifTool::QuickTime::DataRef', 7537 Start => 8, 7538 }, 7539 }, 7540); 7541 7542# Generic media header 7543%Image::ExifTool::QuickTime::GenMediaHeader = ( 7544 PROCESS_PROC => \&ProcessMOV, 7545 gmin => { 7546 Name => 'GenMediaInfo', 7547 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::GenMediaInfo' }, 7548 }, 7549 text => { 7550 Name => 'Text', 7551 Flags => ['Binary','Unknown'], 7552 }, 7553 tmcd => { 7554 Name => 'TimeCode', 7555 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TimeCode' }, 7556 }, 7557); 7558 7559# TimeCode header 7560%Image::ExifTool::QuickTime::TimeCode = ( 7561 PROCESS_PROC => \&ProcessMOV, 7562 tcmi => { 7563 Name => 'TCMediaInfo', 7564 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TCMediaInfo' }, 7565 }, 7566); 7567 7568# TimeCode media info (ref 12) 7569%Image::ExifTool::QuickTime::TCMediaInfo = ( 7570 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7571 GROUPS => { 2 => 'Video' }, 7572 4 => { 7573 Name => 'TextFont', 7574 Format => 'int16u', 7575 PrintConv => { 0 => 'System' }, 7576 }, 7577 6 => { 7578 Name => 'TextFace', 7579 Format => 'int16u', 7580 PrintConv => { 7581 0 => 'Plain', 7582 BITMASK => { 7583 0 => 'Bold', 7584 1 => 'Italic', 7585 2 => 'Underline', 7586 3 => 'Outline', 7587 4 => 'Shadow', 7588 5 => 'Condense', 7589 6 => 'Extend', 7590 }, 7591 }, 7592 }, 7593 8 => { 7594 Name => 'TextSize', 7595 Format => 'int16u', 7596 }, 7597 # 10 - reserved 7598 12 => { 7599 Name => 'TextColor', 7600 Format => 'int16u[3]', 7601 }, 7602 18 => { 7603 Name => 'BackgroundColor', 7604 Format => 'int16u[3]', 7605 }, 7606 24 => { 7607 Name => 'FontName', 7608 Format => 'pstring', 7609 ValueConv => '$self->Decode($val, $self->Options("CharsetQuickTime"))', 7610 }, 7611); 7612 7613# Generic media info (ref http://sourceforge.jp/cvs/view/ntvrec/ntvrec/libqtime/gmin.h?view=co) 7614%Image::ExifTool::QuickTime::GenMediaInfo = ( 7615 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7616 GROUPS => { 2 => 'Video' }, 7617 0 => 'GenMediaVersion', 7618 1 => { Name => 'GenFlags', Format => 'int8u[3]' }, 7619 4 => { Name => 'GenGraphicsMode', 7620 Format => 'int16u', 7621 PrintHex => 1, 7622 SeparateTable => 'GraphicsMode', 7623 PrintConv => \%graphicsMode, 7624 }, 7625 6 => { Name => 'GenOpColor', Format => 'int16u[3]' }, 7626 12 => { Name => 'GenBalance', Format => 'fixed16s' }, 7627); 7628 7629# MP4 data reference box (ref 5) 7630%Image::ExifTool::QuickTime::DataRef = ( 7631 PROCESS_PROC => \&ProcessMOV, 7632 WRITE_PROC => \&WriteQuickTime, # (necessary to parse dref even though we don't change it) 7633 NOTES => 'MP4 data reference box.', 7634 'url ' => { 7635 Name => 'URL', 7636 Format => 'undef', # (necessary to prevent decoding as string!) 7637 RawConv => q{ 7638 # ignore if self-contained (flags bit 0 set) 7639 return undef if unpack("N",$val) & 0x01; 7640 $_ = substr($val,4); s/\0.*//s; $_; 7641 }, 7642 }, 7643 "url\0" => { # (written by GoPro) 7644 Name => 'URL', 7645 Format => 'undef', # (necessary to prevent decoding as string!) 7646 RawConv => q{ 7647 # ignore if self-contained (flags bit 0 set) 7648 return undef if unpack("N",$val) & 0x01; 7649 $_ = substr($val,4); s/\0.*//s; $_; 7650 }, 7651 }, 7652 'urn ' => { 7653 Name => 'URN', 7654 Format => 'undef', # (necessary to prevent decoding as string!) 7655 RawConv => q{ 7656 return undef if unpack("N",$val) & 0x01; 7657 $_ = substr($val,4); s/\0+/; /; s/\0.*//s; $_; 7658 }, 7659 }, 7660); 7661 7662# MP4 handler box (ref 5) 7663%Image::ExifTool::QuickTime::Handler = ( 7664 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7665 GROUPS => { 2 => 'Video' }, 7666 4 => { #PH 7667 Name => 'HandlerClass', 7668 Format => 'undef[4]', 7669 RawConv => '$val eq "\0\0\0\0" ? undef : $val', 7670 PrintConv => { 7671 mhlr => 'Media Handler', 7672 dhlr => 'Data Handler', 7673 }, 7674 }, 7675 8 => { 7676 Name => 'HandlerType', 7677 Format => 'undef[4]', 7678 RawConv => q{ 7679 $$self{HandlerType} = $val unless $val eq 'alis' or $val eq 'url '; 7680 $$self{HasHandler}{$val} = 1; # remember all our handlers 7681 return $val; 7682 }, 7683 PrintConvColumns => 2, 7684 PrintConv => { 7685 alis => 'Alias Data', #PH 7686 crsm => 'Clock Reference', #3 7687 hint => 'Hint Track', 7688 ipsm => 'IPMP', #3 7689 m7sm => 'MPEG-7 Stream', #3 7690 meta => 'NRT Metadata', #PH 7691 mdir => 'Metadata', #3 7692 mdta => 'Metadata Tags', #PH 7693 mjsm => 'MPEG-J', #3 7694 ocsm => 'Object Content', #3 7695 odsm => 'Object Descriptor', #3 7696 priv => 'Private', #PH 7697 sdsm => 'Scene Description', #3 7698 soun => 'Audio Track', 7699 text => 'Text', #PH (but what type? subtitle?) 7700 tmcd => 'Time Code', #PH 7701 'url '=> 'URL', #3 7702 vide => 'Video Track', 7703 subp => 'Subpicture', #http://www.google.nl/patents/US7778526 7704 nrtm => 'Non-Real Time Metadata', #PH (Sony ILCE-7S) [how is this different from "meta"?] 7705 pict => 'Picture', # (HEIC images) 7706 camm => 'Camera Metadata', # (Insta360 MP4) 7707 psmd => 'Panasonic Static Metadata', #PH (Leica C-Lux CAM-DC25) 7708 data => 'Data', #PH (GPS and G-sensor data from DataKam) 7709 sbtl => 'Subtitle', #PH (TomTom Bandit Action Cam) 7710 }, 7711 }, 7712 12 => { #PH 7713 Name => 'HandlerVendorID', 7714 Format => 'undef[4]', 7715 RawConv => '$val eq "\0\0\0\0" ? undef : $val', 7716 PrintConv => \%vendorID, 7717 SeparateTable => 'VendorID', 7718 }, 7719 24 => { 7720 Name => 'HandlerDescription', 7721 Format => 'string', 7722 # (sometimes this is a Pascal string, and sometimes it is a C string) 7723 RawConv => q{ 7724 $val=substr($val,1,ord($1)) if $val=~/^([\0-\x1f])/ and ord($1)<length($val); 7725 length $val ? $val : undef; 7726 }, 7727 }, 7728); 7729 7730# Flip uuid data (ref PH) 7731%Image::ExifTool::QuickTime::Flip = ( 7732 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7733 FORMAT => 'int32u', 7734 FIRST_ENTRY => 0, 7735 NOTES => 'Found in MP4 files from Flip Video cameras.', 7736 GROUPS => { 1 => 'MakerNotes', 2 => 'Image' }, 7737 1 => 'PreviewImageWidth', 7738 2 => 'PreviewImageHeight', 7739 13 => 'PreviewImageLength', 7740 14 => { # (confirmed for FlipVideoMinoHD) 7741 Name => 'SerialNumber', 7742 Groups => { 2 => 'Camera' }, 7743 Format => 'string[16]', 7744 }, 7745 28 => { 7746 Name => 'PreviewImage', 7747 Groups => { 2 => 'Preview' }, 7748 Format => 'undef[$val{13}]', 7749 RawConv => '$self->ValidateImage(\$val, $tag)', 7750 }, 7751); 7752 7753# atoms in Pittasoft "free" atom 7754%Image::ExifTool::QuickTime::Pittasoft = ( 7755 PROCESS_PROC => \&ProcessMOV, 7756 NOTES => 'Tags found in Pittasoft Blackvue dashcam "free" data.', 7757 cprt => 'Copyright', 7758 thum => { 7759 Name => 'PreviewImage', 7760 Groups => { 2 => 'Preview' }, 7761 Binary => 1, 7762 RawConv => q{ 7763 return undef unless length $val > 4; 7764 my $len = unpack('N', $val); 7765 return undef unless length $val >= 4 + $len; 7766 return substr($val, 4, $len); 7767 }, 7768 }, 7769 ptnm => { 7770 Name => 'OriginalFileName', 7771 ValueConv => 'substr($val, 4, -1)', 7772 }, 7773 ptrh => { 7774 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' }, 7775 # contains these atoms: 7776 # ptvi - 27 bytes: '..avc1...' 7777 # ptso - 16 bytes: '..mp4a...' 7778 }, 7779 'gps ' => { 7780 Name => 'GPSLog', 7781 Binary => 1, # (ASCII NMEA track log with leading timestamps) 7782 Notes => 'parsed to extract GPS separately when ExtractEmbedded is used', 7783 RawConv => q{ 7784 $val =~ s/\0+$//; # remove trailing nulls 7785 if (length $val and $$self{OPTIONS}{ExtractEmbedded}) { 7786 my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); 7787 Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl); 7788 } 7789 return $val; 7790 }, 7791 }, 7792 '3gf ' => { 7793 Name => 'AccelData', 7794 SubDirectory => { 7795 TagTable => 'Image::ExifTool::QuickTime::Stream', 7796 ProcessProc => \&Process_3gf, 7797 }, 7798 }, 7799 sttm => { 7800 Name => 'StartTime', 7801 Format => 'int64u', 7802 Groups => { 2 => 'Time' }, 7803 RawConv => '$$self{StartTime} = $val', 7804 # (ms since Jan 1, 1970, in local time zone - PH) 7805 ValueConv => q{ 7806 my $secs = int($val / 1000); 7807 return ConvertUnixTime($secs) . sprintf(".%03d",$val - $secs * 1000); 7808 }, 7809 PrintConv => '$self->ConvertDateTime($val)', 7810 }, 7811); 7812 7813# QuickTime composite tags 7814%Image::ExifTool::QuickTime::Composite = ( 7815 GROUPS => { 2 => 'Video' }, 7816 Rotation => { 7817 Notes => q{ 7818 writing this tag updates QuickTime MatrixStructure for all tracks with a 7819 non-zero image size 7820 }, 7821 Require => { 7822 0 => 'QuickTime:MatrixStructure', 7823 1 => 'QuickTime:HandlerType', 7824 }, 7825 Writable => 1, 7826 Protected => 1, 7827 WriteAlso => { 7828 MatrixStructure => 'Image::ExifTool::QuickTime::GetRotationMatrix($val)', 7829 }, 7830 ValueConv => 'Image::ExifTool::QuickTime::CalcRotation($self)', 7831 ValueConvInv => '$val', 7832 }, 7833 AvgBitrate => { 7834 Priority => 0, # let QuickTime::AvgBitrate take priority 7835 Require => { 7836 0 => 'QuickTime::MediaDataSize', 7837 1 => 'QuickTime::Duration', 7838 }, 7839 RawConv => q{ 7840 return undef unless $val[1]; 7841 $val[1] /= $$self{TimeScale} if $$self{TimeScale}; 7842 my $key = 'MediaDataSize'; 7843 my $size = $val[0]; 7844 for (;;) { 7845 $key = $self->NextTagKey($key) or last; 7846 $size += $self->GetValue($key, 'ValueConv'); 7847 } 7848 return int($size * 8 / $val[1] + 0.5); 7849 }, 7850 PrintConv => 'ConvertBitrate($val)', 7851 }, 7852 GPSLatitude => { 7853 Require => 'QuickTime:GPSCoordinates', 7854 Groups => { 2 => 'Location' }, 7855 ValueConv => 'my @c = split " ", $val; $c[0]', 7856 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', 7857 }, 7858 GPSLongitude => { 7859 Require => 'QuickTime:GPSCoordinates', 7860 Groups => { 2 => 'Location' }, 7861 ValueConv => 'my @c = split " ", $val; $c[1]', 7862 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', 7863 }, 7864 # split altitude into GPSAltitude/GPSAltitudeRef like EXIF and XMP 7865 GPSAltitude => { 7866 Require => 'QuickTime:GPSCoordinates', 7867 Groups => { 2 => 'Location' }, 7868 Priority => 0, # (because it may not exist) 7869 ValueConv => 'my @c = split " ", $val; defined $c[2] ? abs($c[2]) : undef', 7870 PrintConv => '"$val m"', 7871 }, 7872 GPSAltitudeRef => { 7873 Require => 'QuickTime:GPSCoordinates', 7874 Groups => { 2 => 'Location' }, 7875 Priority => 0, # (because altitude information may not exist) 7876 ValueConv => 'my @c = split " ", $val; defined $c[2] ? ($c[2] < 0 ? 1 : 0) : undef', 7877 PrintConv => { 7878 0 => 'Above Sea Level', 7879 1 => 'Below Sea Level', 7880 }, 7881 }, 7882 GPSLatitude2 => { 7883 Name => 'GPSLatitude', 7884 Require => 'QuickTime:LocationInformation', 7885 Groups => { 2 => 'Location' }, 7886 ValueConv => '$val =~ /Lat=([-+.\d]+)/; $1', 7887 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', 7888 }, 7889 GPSLongitude2 => { 7890 Name => 'GPSLongitude', 7891 Require => 'QuickTime:LocationInformation', 7892 Groups => { 2 => 'Location' }, 7893 ValueConv => '$val =~ /Lon=([-+.\d]+)/; $1', 7894 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', 7895 }, 7896 GPSAltitude2 => { 7897 Name => 'GPSAltitude', 7898 Require => 'QuickTime:LocationInformation', 7899 Groups => { 2 => 'Location' }, 7900 ValueConv => '$val =~ /Alt=([-+.\d]+)/; abs($1)', 7901 PrintConv => '"$val m"', 7902 }, 7903 GPSAltitudeRef2 => { 7904 Name => 'GPSAltitudeRef', 7905 Require => 'QuickTime:LocationInformation', 7906 Groups => { 2 => 'Location' }, 7907 ValueConv => '$val =~ /Alt=([-+.\d]+)/; $1 < 0 ? 1 : 0', 7908 PrintConv => { 7909 0 => 'Above Sea Level', 7910 1 => 'Below Sea Level', 7911 }, 7912 }, 7913 CDDBDiscPlayTime => { 7914 Require => 'CDDB1Info', 7915 Groups => { 2 => 'Audio' }, 7916 ValueConv => '$val =~ /^..([a-z0-9]{4})/i ? hex($1) : undef', 7917 PrintConv => 'ConvertDuration($val)', 7918 }, 7919 CDDBDiscTracks => { 7920 Require => 'CDDB1Info', 7921 Groups => { 2 => 'Audio' }, 7922 ValueConv => '$val =~ /^.{6}([a-z0-9]{2})/i ? hex($1) : undef', 7923 }, 7924); 7925 7926# add our composite tags 7927Image::ExifTool::AddCompositeTags('Image::ExifTool::QuickTime'); 7928 7929 7930#------------------------------------------------------------------------------ 7931# AutoLoad our routines when necessary 7932# 7933sub AUTOLOAD 7934{ 7935 # (Note: no need to autoload routines in QuickTimeStream that use Stream table) 7936 if ($AUTOLOAD eq 'Image::ExifTool::QuickTime::Process_mebx') { 7937 require 'Image/ExifTool/QuickTimeStream.pl'; 7938 no strict 'refs'; 7939 return &$AUTOLOAD(@_); 7940 } else { 7941 return Image::ExifTool::DoAutoLoad($AUTOLOAD, @_); 7942 } 7943} 7944 7945#------------------------------------------------------------------------------ 7946# Get rotation matrix 7947# Inputs: 0) angle in degrees 7948# Returns: 9-element rotation matrix as a string (with 0 x/y offsets) 7949sub GetRotationMatrix($) 7950{ 7951 my $ang = 3.1415926536 * shift() / 180; 7952 my $cos = cos $ang; 7953 my $sin = sin $ang; 7954 my $msn = -$sin; 7955 return "$cos $sin 0 $msn $cos 0 0 0 1"; 7956} 7957 7958#------------------------------------------------------------------------------ 7959# Get rotation angle from a matrix 7960# Inputs: 0) rotation matrix as a string 7961# Return: positive rotation angle in degrees rounded to 3 decimal points, 7962# or undef on error 7963sub GetRotationAngle($) 7964{ 7965 my $rotMatrix = shift; 7966 my @a = split ' ', $rotMatrix; 7967 return undef if $a[0]==0 and $a[1]==0; 7968 # calculate the rotation angle (assume uniform rotation) 7969 my $angle = atan2($a[1], $a[0]) * 180 / 3.14159; 7970 $angle += 360 if $angle < 0; 7971 return int($angle * 1000 + 0.5) / 1000; 7972} 7973 7974#------------------------------------------------------------------------------ 7975# Calculate rotation of video track 7976# Inputs: 0) ExifTool object ref 7977# Returns: rotation angle or undef 7978sub CalcRotation($) 7979{ 7980 my $et = shift; 7981 my $value = $$et{VALUE}; 7982 my ($i, $track); 7983 # get the video track family 1 group (eg. "Track1"); 7984 for ($i=0; ; ++$i) { 7985 my $idx = $i ? " ($i)" : ''; 7986 my $tag = "HandlerType$idx"; 7987 last unless $$value{$tag}; 7988 next unless $$value{$tag} eq 'vide'; 7989 $track = $et->GetGroup($tag, 1); 7990 last; 7991 } 7992 return undef unless $track; 7993 # get the video track matrix 7994 for ($i=0; ; ++$i) { 7995 my $idx = $i ? " ($i)" : ''; 7996 my $tag = "MatrixStructure$idx"; 7997 last unless $$value{$tag}; 7998 next unless $et->GetGroup($tag, 1) eq $track; 7999 return GetRotationAngle($$value{$tag}); 8000 } 8001 return undef; 8002} 8003 8004#------------------------------------------------------------------------------ 8005# Get MatrixStructure for a given rotation angle 8006# Inputs: 0) rotation angle (deg), 1) ExifTool ref 8007# Returns: matrix structure as a string, or undef if it can't be rotated 8008# - requires ImageSizeLookahead to determine the video image size, and doesn't 8009# rotate matrix unless image size is valid 8010sub GetMatrixStructure($$) 8011{ 8012 my ($val, $et) = @_; 8013 my @a = split ' ', $val; 8014 # pass straight through if it already has an offset 8015 return $val unless $a[6] == 0 and $a[7] == 0; 8016 my @s = split ' ', $$et{ImageSizeLookahead}; 8017 my ($w, $h) = @s[12,13]; 8018 return undef unless $w and $h; # don't rotate 0-sized track 8019 $_ = Image::ExifTool::QuickTime::FixWrongFormat($_) foreach $w,$h; 8020 # apply necessary offsets for the standard rotations 8021 my $angle = GetRotationAngle($val); 8022 return undef unless defined $angle; 8023 if ($angle == 90) { 8024 @a[6,7] = ($h, 0); 8025 } elsif ($angle == 180) { 8026 @a[6,7] = ($w, $h); 8027 } elsif ($angle == 270) { 8028 @a[6,7] = (0, $w); 8029 } 8030 return "@a"; 8031} 8032 8033#------------------------------------------------------------------------------ 8034# Determine the average sample rate from a time-to-sample table 8035# Inputs: 0) ExifTool object ref, 1) time-to-sample table data ref 8036# Returns: average sample rate (in Hz) 8037sub CalcSampleRate($$) 8038{ 8039 my ($et, $valPt) = @_; 8040 my @dat = unpack('N*', $$valPt); 8041 my ($num, $dur) = (0, 0); 8042 my $i; 8043 for ($i=2; $i<@dat-1; $i+=2) { 8044 $num += $dat[$i]; # total number of samples 8045 $dur += $dat[$i] * $dat[$i+1]; # total sample duration 8046 } 8047 return undef unless $num and $dur and $$et{MediaTS}; 8048 return $num * $$et{MediaTS} / $dur; 8049} 8050 8051#------------------------------------------------------------------------------ 8052# Fix incorrect format for ImageWidth/Height as written by Pentax 8053sub FixWrongFormat($) 8054{ 8055 my $val = shift; 8056 return undef unless $val; 8057 return $val & 0xfff00000 ? unpack('n',pack('N',$val)) : $val; 8058} 8059 8060#------------------------------------------------------------------------------ 8061# Convert ISO 6709 string to standard lag/lon format 8062# Inputs: 0) ISO 6709 string (lat, lon, and optional alt) 8063# Returns: position in decimal degrees with altitude if available 8064# Notes: Wikipedia indicates altitude may be in feet -- how is this specified? 8065sub ConvertISO6709($) 8066{ 8067 my $val = shift; 8068 if ($val =~ /^([-+]\d{1,2}(?:\.\d*)?)([-+]\d{1,3}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) { 8069 # +DD.DDD+DDD.DDD+AA.AAA 8070 $val = ($1 + 0) . ' ' . ($2 + 0); 8071 $val .= ' ' . ($3 + 0) if $3; 8072 } elsif ($val =~ /^([-+])(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) { 8073 # +DDMM.MMM+DDDMM.MMM+AA.AAA 8074 my $lat = $2 + $3 / 60; 8075 $lat = -$lat if $1 eq '-'; 8076 my $lon = $5 + $6 / 60; 8077 $lon = -$lon if $4 eq '-'; 8078 $val = "$lat $lon"; 8079 $val .= ' ' . ($7 + 0) if $7; 8080 } elsif ($val =~ /^([-+])(\d{2})(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2})(\d{2}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) { 8081 # +DDMMSS.SSS+DDDMMSS.SSS+AA.AAA 8082 my $lat = $2 + $3 / 60 + $4 / 3600; 8083 $lat = -$lat if $1 eq '-'; 8084 my $lon = $6 + $7 / 60 + $8 / 3600; 8085 $lon = -$lon if $5 eq '-'; 8086 $val = "$lat $lon"; 8087 $val .= ' ' . ($9 + 0) if $9; 8088 } 8089 return $val; 8090} 8091 8092#------------------------------------------------------------------------------ 8093# Convert Nero chapter list (ref ffmpeg libavformat/movenc.c) 8094# Inputs: 0) binary chpl data 8095# Returns: chapter list 8096sub ConvertChapterList($) 8097{ 8098 my $val = shift; 8099 my $size = length $val; 8100 return '<invalid>' if $size < 9; 8101 my $num = Get8u(\$val, 8); 8102 my ($i, @chapters); 8103 my $pos = 9; 8104 for ($i=0; $i<$num; ++$i) { 8105 last if $pos + 9 > $size; 8106 my $dur = Get64u(\$val, $pos) / 10000000; 8107 my $len = Get8u(\$val, $pos + 8); 8108 last if $pos + 9 + $len > $size; 8109 my $title = substr($val, $pos + 9, $len); 8110 $pos += 9 + $len; 8111 push @chapters, "$dur $title"; 8112 } 8113 return \@chapters; # return as a list 8114} 8115 8116#------------------------------------------------------------------------------ 8117# Print conversion for a Nero chapter list item 8118# Inputs: 0) ValueConv chapter string 8119# Returns: formatted chapter string 8120sub PrintChapter($) 8121{ 8122 my $val = shift; 8123 $val =~ /^(\S+) (.*)/ or return $val; 8124 my ($dur, $title) = ($1, $2); 8125 my $h = int($dur / 3600); 8126 $dur -= $h * 3600; 8127 my $m = int($dur / 60); 8128 my $s = $dur - $m * 60; 8129 my $ss = sprintf('%06.3f', $s); 8130 if ($ss >= 60) { 8131 $ss = '00.000'; 8132 ++$m >= 60 and $m -= 60, ++$h; 8133 } 8134 return sprintf("[%d:%.2d:%s] %s",$h,$m,$ss,$title); 8135} 8136 8137#------------------------------------------------------------------------------ 8138# Format GPSCoordinates for printing 8139# Inputs: 0) string with numerical lat, lon and optional alt, separated by spaces 8140# 1) ExifTool object reference 8141# Returns: PrintConv value 8142sub PrintGPSCoordinates($) 8143{ 8144 my ($val, $et) = @_; 8145 my @v = split ' ', $val; 8146 my $prt = Image::ExifTool::GPS::ToDMS($et, $v[0], 1, "N") . ', ' . 8147 Image::ExifTool::GPS::ToDMS($et, $v[1], 1, "E"); 8148 if (defined $v[2]) { 8149 $prt .= ', ' . ($v[2] < 0 ? -$v[2] . ' m Below' : $v[2] . ' m Above') . ' Sea Level'; 8150 } 8151 return $prt; 8152} 8153 8154#------------------------------------------------------------------------------ 8155# Unpack packed ISO 639/T language code 8156# Inputs: 0) packed language code (or undef/0), 1) true to not treat 'und' and 'eng' as default 8157# Returns: language code, or undef/0 for default language, or 'err' for format error 8158sub UnpackLang($;$) 8159{ 8160 my ($lang, $noDef) = @_; 8161 if ($lang) { 8162 # language code is packed in 5-bit characters 8163 $lang = pack 'C*', map { (($lang>>$_)&0x1f)+0x60 } 10, 5, 0; 8164 # validate language code 8165 if ($lang =~ /^[a-z]+$/) { 8166 # treat 'eng' or 'und' as the default language 8167 undef $lang if ($lang eq 'und' or $lang eq 'eng') and not $noDef; 8168 } else { 8169 $lang = 'err'; # invalid language code 8170 } 8171 } 8172 return $lang; 8173} 8174 8175#------------------------------------------------------------------------------ 8176# Get language code string given QuickTime language and country codes 8177# Inputs: 0) numerical language code, 1) numerical country code, 2) no defaults 8178# Returns: language code string (ie. "fra-FR") or undef for default language 8179sub GetLangCode($;$$) 8180{ 8181 my ($lang, $ctry, $noDef) = @_; 8182 # ignore country ('ctry') and language lists ('lang') for now 8183 undef $ctry if $ctry and $ctry <= 255; 8184 undef $lang if $lang and $lang <= 255; 8185 $lang = UnpackLang($lang, $noDef); 8186 # add country code if specified 8187 if ($ctry) { 8188 $ctry = unpack('a2',pack('n',$ctry)); # unpack as ISO 3166-1 8189 # treat 'ZZ' like a default country (see ref 12) 8190 undef $ctry if $ctry eq 'ZZ'; 8191 if ($ctry and $ctry =~ /^[A-Z]{2}$/) { 8192 $lang or $lang = 'und'; 8193 $lang .= "-$ctry"; 8194 } 8195 } 8196 return $lang; 8197} 8198 8199#------------------------------------------------------------------------------ 8200# Get langInfo hash and save details about alt-lang tags 8201# Inputs: 0) ExifTool ref, 1) tagInfo hash ref, 2) locale code 8202# Returns: new tagInfo hash ref, or undef if invalid 8203sub GetLangInfoQT($$$) 8204{ 8205 my ($et, $tagInfo, $langCode) = @_; 8206 my $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $langCode); 8207 if ($langInfo) { 8208 $$et{QTLang} or $$et{QTLang} = [ ]; 8209 push @{$$et{QTLang}}, $$langInfo{Name}; 8210 } 8211 return $langInfo; 8212} 8213 8214#------------------------------------------------------------------------------ 8215# Get variable-length integer from data (used by ParseItemLocation) 8216# Inputs: 0) data ref, 1) start position, 2) integer size in bytes (0, 4 or 8), 8217# 3) default value 8218# Returns: integer value, and updates current position 8219sub GetVarInt($$$;$) 8220{ 8221 my ($dataPt, $pos, $n, $default) = @_; 8222 my $len = length $$dataPt; 8223 $_[1] = $pos + $n; # update current position 8224 return undef if $pos + $n > $len; 8225 if ($n == 0) { 8226 return $default || 0; 8227 } elsif ($n == 4) { 8228 return Get32u($dataPt, $pos); 8229 } elsif ($n == 8) { 8230 return Get64u($dataPt, $pos); 8231 } 8232 return undef; 8233} 8234 8235#------------------------------------------------------------------------------ 8236# Get null-terminated string from binary data (used by ParseItemInfoEntry) 8237# Inputs: 0) data ref, 1) start position 8238# Returns: string, and updates current position 8239sub GetString($$) 8240{ 8241 my ($dataPt, $pos) = @_; 8242 my $len = length $$dataPt; 8243 my $str = ''; 8244 while ($pos < $len) { 8245 my $ch = substr($$dataPt, $pos, 1); 8246 ++$pos; 8247 last if ord($ch) == 0; 8248 $str .= $ch; 8249 } 8250 $_[1] = $pos; # update current position 8251 return $str; 8252} 8253 8254#------------------------------------------------------------------------------ 8255# Get a printable version of the tag ID 8256# Inputs: 0) tag ID, 1) Flag: 0x01 - print as 4- or 8-digit hex value if necessary 8257# 0x02 - put leading backslash before escaped character 8258# Returns: Printable tag ID 8259sub PrintableTagID($;$) 8260{ 8261 my $tag = $_[0]; 8262 my $n = ($tag =~ s/([\x00-\x1f\x7f-\xff])/'x'.unpack('H*',$1)/eg); 8263 if ($n and $_[1]) { 8264 if ($n > 2 and $_[1] & 0x01) { 8265 $tag = '0x' . unpack('H8', $_[0]); 8266 $tag =~ s/^0x0000/0x/; 8267 } elsif ($_[1] & 0x02) { 8268 ($tag = $_[0]) =~ s/([\x00-\x1f\x7f-\xff])/'\\x'.unpack('H*',$1)/eg; 8269 } 8270 } 8271 return $tag; 8272} 8273 8274#============================================================================== 8275# The following ParseXxx routines parse various boxes to extract this 8276# information about embedded items in a $$et{ItemInfo} hash, keyed by item ID: 8277# 8278# iloc: 8279# ConstructionMethod - offset type: 0=file, 1=idat, 2=item 8280# DataReferenceIndex - 0 for "this file", otherwise index in dref box 8281# BaseOffset - base for file offsets 8282# Extents - list of details for data in file: 8283# 0) index (extent_index) 8284# 1) offset (extent_offset) 8285# 2) length (extent_length) 8286# 3) nlen (length_size) 8287# 4) lenPt (pointer to length word) 8288# infe: 8289# ProtectionIndex - index if item is protected (0 for unprotected) 8290# Name - item name 8291# ContentType - mime type of item 8292# ContentEncoding - item encoding 8293# URI - URI of a 'uri '-type item 8294# ipma: 8295# Association - list of associated properties in the ipco container 8296# Essential - list of "essential" flags for the associated properties 8297# cdsc: 8298# RefersTo - hash lookup of flags based on referred item ID 8299# other: 8300# DocNum - exiftool document number for this item 8301# 8302#------------------------------------------------------------------------------ 8303# Parse item location (iloc) box (ref ISO 14496-12:2015 pg.79) 8304# Inputs: 0) iloc data, 1) ExifTool ref 8305# Returns: undef, and fills in ExifTool ItemInfo hash 8306# Notes: see also Handle_iloc() in WriteQuickTime.pl 8307sub ParseItemLocation($$) 8308{ 8309 my ($val, $et) = @_; 8310 my ($i, $j, $num, $pos, $id); 8311 my ($extent_index, $extent_offset, $extent_length); 8312 8313 my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose'); 8314 my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { }); 8315 my $len = length $val; 8316 return undef if $len < 8; 8317 my $ver = Get8u(\$val, 0); 8318 my $siz = Get16u(\$val, 4); 8319 my $noff = ($siz >> 12); 8320 my $nlen = ($siz >> 8) & 0x0f; 8321 my $nbas = ($siz >> 4) & 0x0f; 8322 my $nind = $siz & 0x0f; 8323 if ($ver < 2) { 8324 $num = Get16u(\$val, 6); 8325 $pos = 8; 8326 } else { 8327 return undef if $len < 10; 8328 $num = Get32u(\$val, 6); 8329 $pos = 10; 8330 } 8331 for ($i=0; $i<$num; ++$i) { 8332 if ($ver < 2) { 8333 return undef if $pos + 2 > $len; 8334 $id = Get16u(\$val, $pos); 8335 $pos += 2; 8336 } else { 8337 return undef if $pos + 4 > $len; 8338 $id = Get32u(\$val, $pos); 8339 $pos += 4; 8340 } 8341 if ($ver == 1 or $ver == 2) { 8342 return undef if $pos + 2 > $len; 8343 $$items{$id}{ConstructionMethod} = Get16u(\$val, $pos) & 0x0f; 8344 $pos += 2; 8345 } 8346 return undef if $pos + 2 > $len; 8347 $$items{$id}{DataReferenceIndex} = Get16u(\$val, $pos); 8348 $pos += 2; 8349 $$items{$id}{BaseOffset} = GetVarInt(\$val, $pos, $nbas); 8350 return undef if $pos + 2 > $len; 8351 my $ext_num = Get16u(\$val, $pos); 8352 $pos += 2; 8353 my @extents; 8354 for ($j=0; $j<$ext_num; ++$j) { 8355 if ($ver == 1 or $ver == 2) { 8356 $extent_index = GetVarInt(\$val, $pos, $nind, 1); 8357 } 8358 $extent_offset = GetVarInt(\$val, $pos, $noff); 8359 $extent_length = GetVarInt(\$val, $pos, $nlen); 8360 return undef unless defined $extent_length; 8361 $et->VPrint(1, "$$et{INDENT} Item $id: const_meth=", 8362 defined $$items{$id}{ConstructionMethod} ? $$items{$id}{ConstructionMethod} : '', 8363 sprintf(" base=0x%x offset=0x%x len=0x%x\n", $$items{$id}{BaseOffset}, 8364 $extent_offset, $extent_length)) if $verbose; 8365 push @extents, [ $extent_index, $extent_offset, $extent_length, $nlen, $pos-$nlen ]; 8366 } 8367 # save item location information keyed on 1-based item ID: 8368 $$items{$id}{Extents} = \@extents; 8369 } 8370 return undef; 8371} 8372 8373#------------------------------------------------------------------------------ 8374# Parse content describes entry (cdsc) box 8375# Inputs: 0) cdsc data, 1) ExifTool ref 8376# Returns: undef, and fills in ExifTool ItemInfo hash 8377sub ParseContentDescribes($$) 8378{ 8379 my ($val, $et) = @_; 8380 my ($id, $count, @to); 8381 if ($$et{ItemRefVersion}) { 8382 return undef if length $val < 10; 8383 ($id, $count, @to) = unpack('NnN*', $val); 8384 } else { 8385 return undef if length $val < 6; 8386 ($id, $count, @to) = unpack('nnn*', $val); 8387 } 8388 if ($count > @to) { 8389 my $str = 'Missing values in ContentDescribes box'; 8390 $$et{IsWriting} ? $et->Error($str) : $et->Warn($str); 8391 } elsif ($count < @to) { 8392 $et->Warn('Ignored extra values in ContentDescribes box', 1); 8393 @to = $count; 8394 } 8395 # add all referenced item ID's to a "RefersTo" lookup 8396 $$et{ItemInfo}{$id}{RefersTo}{$_} = 1 foreach @to; 8397 return undef; 8398} 8399 8400#------------------------------------------------------------------------------ 8401# Parse item information entry (infe) box (ref ISO 14496-12:2015 pg.82) 8402# Inputs: 0) infe data, 1) ExifTool ref 8403# Returns: undef, and fills in ExifTool ItemInfo hash 8404sub ParseItemInfoEntry($$) 8405{ 8406 my ($val, $et) = @_; 8407 my $id; 8408 8409 my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose'); 8410 my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { }); 8411 my $len = length $val; 8412 return undef if $len < 4; 8413 my $ver = Get8u(\$val, 0); 8414 my $pos = 4; 8415 return undef if $pos + 4 > $len; 8416 if ($ver == 0 or $ver == 1) { 8417 $id = Get16u(\$val, $pos); 8418 $$items{$id}{ProtectionIndex} = Get16u(\$val, $pos + 2); 8419 $pos += 4; 8420 $$items{$id}{Name} = GetString(\$val, $pos); 8421 $$items{$id}{ContentType} = GetString(\$val, $pos); 8422 $$items{$id}{ContentEncoding} = GetString(\$val, $pos); 8423 } else { 8424 if ($ver == 2) { 8425 $id = Get16u(\$val, $pos); 8426 $pos += 2; 8427 } elsif ($ver == 3) { 8428 $id = Get32u(\$val, $pos); 8429 $pos += 4; 8430 } 8431 return undef if $pos + 6 > $len; 8432 $$items{$id}{ProtectionIndex} = Get16u(\$val, $pos); 8433 my $type = substr($val, $pos + 2, 4); 8434 $$items{$id}{Type} = $type; 8435 $pos += 6; 8436 $$items{$id}{Name} = GetString(\$val, $pos); 8437 if ($type eq 'mime') { 8438 $$items{$id}{ContentType} = GetString(\$val, $pos); 8439 $$items{$id}{ContentEncoding} = GetString(\$val, $pos); 8440 } elsif ($type eq 'uri ') { 8441 $$items{$id}{URI} = GetString(\$val, $pos); 8442 } 8443 } 8444 $et->VPrint(1, "$$et{INDENT} Item $id: Type=", $$items{$id}{Type} || '', 8445 ' Name=', $$items{$id}{Name} || '', 8446 ' ContentType=', $$items{$id}{ContentType} || '', 8447 "\n") if $verbose > 1; 8448 return undef; 8449} 8450 8451#------------------------------------------------------------------------------ 8452# Parse item property association (ipma) box (ref https://github.com/gpac/gpac/blob/master/src/isomedia/iff.c) 8453# Inputs: 0) ipma data, 1) ExifTool ref 8454# Returns: undef, and fills in ExifTool ItemInfo hash 8455sub ParseItemPropAssoc($$) 8456{ 8457 my ($val, $et) = @_; 8458 my ($i, $j, $id); 8459 8460 my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose'); 8461 my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { }); 8462 my $len = length $val; 8463 return undef if $len < 8; 8464 my $ver = Get8u(\$val, 0); 8465 my $flg = Get32u(\$val, 0); 8466 my $num = Get32u(\$val, 4); 8467 my $pos = 8; 8468 for ($i=0; $i<$num; ++$i) { 8469 if ($ver == 0) { 8470 return undef if $pos + 3 > $len; 8471 $id = Get16u(\$val, $pos); 8472 $pos += 2; 8473 } else { 8474 return undef if $pos + 5 > $len; 8475 $id = Get32u(\$val, $pos); 8476 $pos += 4; 8477 } 8478 my $n = Get8u(\$val, $pos++); 8479 my (@association, @essential); 8480 if ($flg & 0x01) { 8481 return undef if $pos + $n * 2 > $len; 8482 for ($j=0; $j<$n; ++$j) { 8483 my $tmp = Get16u(\$val, $pos + $j * 2); 8484 push @association, $tmp & 0x7fff; 8485 push @essential, ($tmp & 0x8000) ? 1 : 0; 8486 } 8487 $pos += $n * 2; 8488 } else { 8489 return undef if $pos + $n > $len; 8490 for ($j=0; $j<$n; ++$j) { 8491 my $tmp = Get8u(\$val, $pos + $j); 8492 push @association, $tmp & 0x7f; 8493 push @essential, ($tmp & 0x80) ? 1 : 0; 8494 } 8495 $pos += $n; 8496 } 8497 $$items{$id}{Association} = \@association; 8498 $$items{$id}{Essential} = \@essential; 8499 $et->VPrint(1, "$$et{INDENT} Item $id properties: @association\n") if $verbose > 1; 8500 } 8501 return undef; 8502} 8503 8504#------------------------------------------------------------------------------ 8505# Process item information now 8506# Inputs: 0) ExifTool ref 8507sub HandleItemInfo($) 8508{ 8509 my $et = shift; 8510 my $raf = $$et{RAF}; 8511 my $items = $$et{ItemInfo}; 8512 my $verbose = $et->Options('Verbose'); 8513 my $buff; 8514 8515 # extract information from EXIF/XMP metadata items 8516 if ($items and $raf) { 8517 push @{$$et{PATH}}, 'ItemInformation'; 8518 my $curPos = $raf->Tell(); 8519 my $primary = $$et{PrimaryItem}; 8520 my $id; 8521 $et->VerboseDir('Processing items from ItemInformation', scalar(keys %$items)); 8522 foreach $id (sort { $a <=> $b } keys %$items) { 8523 my $item = $$items{$id}; 8524 my $type = $$item{ContentType} || $$item{Type} || next; 8525 if ($verbose) { 8526 # add up total length of this item for the verbose output 8527 my $len = 0; 8528 if ($$item{Extents} and @{$$item{Extents}}) { 8529 $len += $$_[2] foreach @{$$item{Extents}}; 8530 } 8531 $et->VPrint(0, "$$et{INDENT}Item $id) '${type}' ($len bytes)\n"); 8532 } 8533 # get ExifTool name for this item 8534 my $name = { Exif => 'EXIF', 'application/rdf+xml' => 'XMP' }->{$type} || ''; 8535 my ($warn, $extent); 8536 $warn = "Can't currently decode encoded $type metadata" if $$item{ContentEncoding}; 8537 $warn = "Can't currently decode protected $type metadata" if $$item{ProtectionIndex}; 8538 $warn = "Can't currently extract $type with construction method $$item{ConstructionMethod}" if $$item{ConstructionMethod}; 8539 $et->WarnOnce($warn) if $warn and $name; 8540 $warn = 'Not this file' if $$item{DataReferenceIndex}; # (can only extract from "this file") 8541 unless (($$item{Extents} and @{$$item{Extents}}) or $warn) { 8542 $warn = "No Extents for $type item"; 8543 $et->WarnOnce($warn) if $name; 8544 } 8545 if ($warn) { 8546 $et->VPrint(0, "$$et{INDENT} [not extracted] ($warn)\n") if $verbose > 2; 8547 next; 8548 } 8549 my $base = $$item{BaseOffset} || 0; 8550 if ($verbose > 2) { 8551 # do verbose hex dump 8552 my $len = 0; 8553 undef $buff; 8554 my $val = ''; 8555 my $maxLen = $verbose > 3 ? 2048 : 96; 8556 foreach $extent (@{$$item{Extents}}) { 8557 my $n = $$extent[2]; 8558 my $more = $maxLen - $len; 8559 if ($more > 0 and $n) { 8560 $more = $n if $more > $n; 8561 $val .= $buff if defined $buff; 8562 $raf->Seek($$extent[1] + $base, 0) or last; 8563 $raf->Read($buff, $more) or last; 8564 } 8565 $len += $n; 8566 } 8567 if (defined $buff) { 8568 $buff = $val . $buff if length $val; 8569 $et->VerboseDump(\$buff, DataPos => $$item{Extents}[0][1] + $base); 8570 my $snip = $len - length $buff; 8571 $et->VPrint(0, "$$et{INDENT} [snip $snip bytes]\n") if $snip; 8572 } 8573 } 8574 next unless $name; 8575 # assemble the data for this item 8576 undef $buff; 8577 my $val = ''; 8578 foreach $extent (@{$$item{Extents}}) { 8579 $val .= $buff if defined $buff; 8580 $raf->Seek($$extent[1] + $base, 0) or last; 8581 $raf->Read($buff, $$extent[2]) or last; 8582 } 8583 next unless defined $buff; 8584 $buff = $val . $buff if length $val; 8585 next unless length $buff; # ignore empty directories 8586 my ($start, $subTable, $proc); 8587 my $pos = $$item{Extents}[0][1] + $base; 8588 if ($name eq 'EXIF' and length $buff >= 4) { 8589 if ($buff =~ /^(MM\0\x2a|II\x2a\0)/) { 8590 $et->Warn('Missing Exif header'); 8591 $start = 0; 8592 } elsif ($buff =~ /^Exif\0\0/) { 8593 # (haven't seen this yet, but it is just a matter of time 8594 # until someone screws it up like this) 8595 $et->Warn('Missing Exif header size'); 8596 $start = 6; 8597 } else { 8598 my $n = unpack('N', $buff); 8599 $start = 4 + $n; # skip "Exif\0\0" header if it exists 8600 if ($start > length($buff)) { 8601 $et->Warn('Invalid EXIF header'); 8602 next; 8603 } 8604 if ($$et{HTML_DUMP}) { 8605 $et->HDump($pos, 4, 'Exif header length', "Value: $n"); 8606 $et->HDump($pos+4, $start-4, 'Exif header') if $n; 8607 } 8608 } 8609 $subTable = GetTagTable('Image::ExifTool::Exif::Main'); 8610 $proc = \&Image::ExifTool::ProcessTIFF; 8611 } else { 8612 $start = 0; 8613 $subTable = GetTagTable('Image::ExifTool::XMP::Main'); 8614 } 8615 my %dirInfo = ( 8616 DataPt => \$buff, 8617 DataLen => length $buff, 8618 DirStart => $start, 8619 DirLen => length($buff) - $start, 8620 DataPos => $pos, 8621 Base => $pos + $start, # (needed for HtmlDump and IsOffset tags in binary data) 8622 ); 8623 # handle processing of metadata for sub-documents 8624 if (defined $primary and $$item{RefersTo} and not $$item{RefersTo}{$primary}) { 8625 # set document number if this doesn't refer to the primary document 8626 $$et{DOC_NUM} = ++$$et{DOC_COUNT}; 8627 # associate this document number with the lowest item index 8628 my ($lowest) = sort { $a <=> $b } keys %{$$item{RefersTo}}; 8629 $$items{$lowest}{DocNum} = $$et{DOC_NUM}; 8630 } 8631 $et->ProcessDirectory(\%dirInfo, $subTable, $proc); 8632 delete $$et{DOC_NUM}; 8633 } 8634 $raf->Seek($curPos, 0); # seek back to original position 8635 pop @{$$et{PATH}}; 8636 } 8637 # process the item properties now that we should know their associations and document numbers 8638 if ($$et{ItemPropertyContainer}) { 8639 my ($dirInfo, $subTable, $proc) = @{$$et{ItemPropertyContainer}}; 8640 $$et{IsItemProperty} = 1; # set item property flag 8641 $et->ProcessDirectory($dirInfo, $subTable, $proc); 8642 delete $$et{ItemPropertyContainer}; 8643 delete $$et{IsItemProperty}; 8644 delete $$et{DOC_NUM}; 8645 } 8646 delete $$et{ItemInfo}; 8647} 8648 8649#------------------------------------------------------------------------------ 8650# Warn if ExtractEmbedded option isn't used 8651# Inputs: 0) ExifTool ref 8652sub EEWarn($) 8653{ 8654 my $et = shift; 8655 $et->WarnOnce('The ExtractEmbedded option may find more tags in the media data',3); 8656} 8657 8658#------------------------------------------------------------------------------ 8659# Get quicktime format from flags word 8660# Inputs: 0) quicktime atom flags, 1) data length 8661# Returns: ExifTool format string 8662sub QuickTimeFormat($$) 8663{ 8664 my ($flags, $len) = @_; 8665 my $format; 8666 if ($flags == 0x15 or $flags == 0x16) { 8667 $format = { 1=>'int8', 2=>'int16', 4=>'int32', 8=>'int64' }->{$len}; 8668 $format .= $flags == 0x15 ? 's' : 'u' if $format; 8669 } elsif ($flags == 0x17) { 8670 $format = 'float'; 8671 } elsif ($flags == 0x18) { 8672 $format = 'double'; 8673 } elsif ($flags == 0x00) { 8674 $format = { 1=>'int8u', 2=>'int16u' }->{$len}; 8675 } 8676 return $format; 8677} 8678 8679#------------------------------------------------------------------------------ 8680# Process MPEG-4 MTDT atom (ref 11) 8681# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8682# Returns: 1 on success 8683sub ProcessMetaData($$$) 8684{ 8685 my ($et, $dirInfo, $tagTablePtr) = @_; 8686 my $dataPt = $$dirInfo{DataPt}; 8687 my $dirLen = length $$dataPt; 8688 my $verbose = $et->Options('Verbose'); 8689 return 0 unless $dirLen >= 2; 8690 my $count = Get16u($dataPt, 0); 8691 $verbose and $et->VerboseDir('MetaData', $count); 8692 my $i; 8693 my $pos = 2; 8694 for ($i=0; $i<$count; ++$i) { 8695 last if $pos + 10 > $dirLen; 8696 my $size = Get16u($dataPt, $pos); 8697 last if $size < 10 or $size + $pos > $dirLen; 8698 my $tag = Get32u($dataPt, $pos + 2); 8699 my $lang = Get16u($dataPt, $pos + 6); 8700 my $enc = Get16u($dataPt, $pos + 8); 8701 my $val = substr($$dataPt, $pos + 10, $size); 8702 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 8703 if ($tagInfo) { 8704 # convert language code to ASCII (ignore read-only bit) 8705 $lang = UnpackLang($lang); 8706 # handle alternate languages 8707 if ($lang) { 8708 my $langInfo = GetLangInfoQT($et, $tagInfo, $lang); 8709 $tagInfo = $langInfo if $langInfo; 8710 } 8711 $verbose and $et->VerboseInfo($tag, $tagInfo, 8712 Value => $val, 8713 DataPt => $dataPt, 8714 Start => $pos + 10, 8715 Size => $size - 10, 8716 ); 8717 # convert from UTF-16 BE if necessary 8718 $val = $et->Decode($val, 'UCS2') if $enc == 1; 8719 if ($enc == 0 and $$tagInfo{Unknown}) { 8720 # binary data 8721 $et->FoundTag($tagInfo, \$val); 8722 } else { 8723 $et->FoundTag($tagInfo, $val); 8724 } 8725 } 8726 $pos += $size; 8727 } 8728 return 1; 8729} 8730 8731#------------------------------------------------------------------------------ 8732# Process sample description table 8733# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8734# Returns: 1 on success 8735# (ref https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25691) 8736sub ProcessSampleDesc($$$) 8737{ 8738 my ($et, $dirInfo, $tagTablePtr) = @_; 8739 my $dataPt = $$dirInfo{DataPt}; 8740 my $pos = $$dirInfo{DirStart} || 0; 8741 my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $pos); 8742 return 0 if $pos + 8 > $dirLen; 8743 8744 my $num = Get32u($dataPt, 4); # get number of sample entries in table 8745 $pos += 8; 8746 my $i; 8747 for ($i=0; $i<$num; ++$i) { # loop through sample entries 8748 last if $pos + 8 > $dirLen; 8749 my $size = Get32u($dataPt, $pos); 8750 last if $pos + $size > $dirLen; 8751 $$dirInfo{DirStart} = $pos; 8752 $$dirInfo{DirLen} = $size; 8753 ProcessHybrid($et, $dirInfo, $tagTablePtr); 8754 $pos += $size; 8755 } 8756 return 1; 8757} 8758 8759#------------------------------------------------------------------------------ 8760# Process hybrid binary data + QuickTime container (ref PH) 8761# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8762# Returns: 1 on success 8763sub ProcessHybrid($$$) 8764{ 8765 my ($et, $dirInfo, $tagTablePtr) = @_; 8766 # brute-force search for child atoms after first 8 bytes of binary data 8767 my $dataPt = $$dirInfo{DataPt}; 8768 my $dirStart = $$dirInfo{DirStart} || 0; 8769 my $dirLen = $$dirInfo{DirLen} || length($$dataPt) - $dirStart; 8770 my $end = $dirStart + $dirLen; 8771 my $pos = $dirStart + 8; # skip length/version 8772 my $try = $pos; 8773 my $childPos; 8774 8775 while ($pos <= $end - 8) { 8776 my $tag = substr($$dataPt, $try+4, 4); 8777 # look only for well-behaved tag ID's 8778 $tag =~ /[^\w ]/ and $try = ++$pos, next; 8779 my $size = Get32u($dataPt, $try); 8780 if ($size + $try == $end) { 8781 # the atom ends exactly at the end of the parent -- this must be it 8782 $childPos = $pos; 8783 $$dirInfo{DirLen} = $pos; # the binary data ends at the first child atom 8784 last; 8785 } 8786 if ($size < 8 or $size + $try > $end - 8) { 8787 $try = ++$pos; # fail. try next position 8788 } else { 8789 $try += $size; # could be another atom following this 8790 } 8791 } 8792 # process binary data 8793 $$dirInfo{MixedTags} = 1; # ignore non-integer tag ID's 8794 $et->ProcessBinaryData($dirInfo, $tagTablePtr); 8795 # process child atoms if found 8796 if ($childPos) { 8797 $$dirInfo{DirStart} = $childPos; 8798 $$dirInfo{DirLen} = $end - $childPos; 8799 ProcessMOV($et, $dirInfo, $tagTablePtr); 8800 } 8801 return 1; 8802} 8803 8804#------------------------------------------------------------------------------ 8805# Process iTunes 'righ' atom (ref PH) 8806# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8807# Returns: 1 on success 8808sub ProcessRights($$$) 8809{ 8810 my ($et, $dirInfo, $tagTablePtr) = @_; 8811 my $dataPt = $$dirInfo{DataPt}; 8812 my $dataPos = $$dirInfo{Base}; 8813 my $dirLen = length $$dataPt; 8814 my $unknown = $$et{OPTIONS}{Unknown} || $$et{OPTIONS}{Verbose}; 8815 my $pos; 8816 $et->VerboseDir('righ', $dirLen / 8); 8817 for ($pos = 0; $pos + 8 <= $dirLen; $pos += 8) { 8818 my $tag = substr($$dataPt, $pos, 4); 8819 last if $tag eq "\0\0\0\0"; 8820 my $val = substr($$dataPt, $pos + 4, 4); 8821 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 8822 unless ($tagInfo) { 8823 next unless $unknown; 8824 my $name = PrintableTagID($tag); 8825 $tagInfo = { 8826 Name => "Unknown_$name", 8827 Description => "Unknown $name", 8828 Unknown => 1, 8829 }, 8830 AddTagToTable($tagTablePtr, $tag, $tagInfo); 8831 } 8832 $val = '0x' . unpack('H*', $val) unless $$tagInfo{Format}; 8833 $et->HandleTag($tagTablePtr, $tag, $val, 8834 DataPt => $dataPt, 8835 DataPos => $dataPos, 8836 Start => $pos + 4, 8837 Size => 4, 8838 ); 8839 } 8840 return 1; 8841} 8842 8843#------------------------------------------------------------------------------ 8844# Process iTunes Encoding Params (ref PH) 8845# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8846# Returns: 1 on success 8847sub ProcessEncodingParams($$$) 8848{ 8849 my ($et, $dirInfo, $tagTablePtr) = @_; 8850 my $dataPt = $$dirInfo{DataPt}; 8851 my $dirLen = length $$dataPt; 8852 my $pos; 8853 $et->VerboseDir('Encoding Params', $dirLen / 8); 8854 for ($pos = 0; $pos + 8 <= $dirLen; $pos += 8) { 8855 my ($tag, $val) = unpack("x${pos}a4N", $$dataPt); 8856 $et->HandleTag($tagTablePtr, $tag, $val); 8857 } 8858 return 1; 8859} 8860 8861#------------------------------------------------------------------------------ 8862# Read Meta Keys and add tags to ItemList table ('mdta' handler) (ref PH) 8863# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8864# Returns: 1 on success 8865sub ProcessKeys($$$) 8866{ 8867 local $_; 8868 my ($et, $dirInfo, $tagTablePtr) = @_; 8869 my $dataPt = $$dirInfo{DataPt}; 8870 my $dirLen = length $$dataPt; 8871 my $out; 8872 if ($et->Options('Verbose')) { 8873 $et->VerboseDir('Keys'); 8874 $out = $et->Options('TextOut'); 8875 } 8876 my $pos = 8; 8877 my $index = 1; 8878 ++$$et{KeysCount}; # increment key count for this directory 8879 my $itemList = GetTagTable('Image::ExifTool::QuickTime::ItemList'); 8880 my $userData = GetTagTable('Image::ExifTool::QuickTime::UserData'); 8881 while ($pos < $dirLen - 4) { 8882 my $len = unpack("x${pos}N", $$dataPt); 8883 last if $len < 8 or $pos + $len > $dirLen; 8884 delete $$tagTablePtr{$index}; 8885 my $ns = substr($$dataPt, $pos + 4, 4); 8886 my $tag = substr($$dataPt, $pos + 8, $len - 8); 8887 $tag =~ s/\0.*//s; # truncate at null 8888 my $full = $tag; 8889 $tag =~ s/^com\.(apple\.quicktime\.)?// if $ns eq 'mdta'; # remove apple quicktime domain 8890 $tag = "Tag_$ns" unless $tag; 8891 my $short = $tag; 8892 my $tagInfo; 8893 for (;;) { 8894 $tagInfo = $et->GetTagInfo($tagTablePtr, $tag) and last; 8895 # also try ItemList and UserData tables 8896 $tagInfo = $et->GetTagInfo($itemList, $tag) and last; 8897 $tagInfo = $et->GetTagInfo($userData, $tag) and last; 8898 # (I have some samples where the tag is a reversed ItemList or UserData tag ID) 8899 if ($tag =~ /^\w{3}\xa9$/) { 8900 $tag = pack('N', unpack('V', $tag)); 8901 $tagInfo = $et->GetTagInfo($itemList, $tag) and last; 8902 $tagInfo = $et->GetTagInfo($userData, $tag); 8903 last; 8904 } 8905 if ($tag eq $full) { 8906 $tag = $short; 8907 last; 8908 } 8909 $tag = $full; 8910 } 8911 my ($newInfo, $msg); 8912 if ($tagInfo) { 8913 # copy tag information into new Keys tag 8914 $newInfo = { 8915 Name => $$tagInfo{Name}, 8916 Format => $$tagInfo{Format}, 8917 ValueConv => $$tagInfo{ValueConv}, 8918 ValueConvInv => $$tagInfo{ValueConvInv}, 8919 PrintConv => $$tagInfo{PrintConv}, 8920 PrintConvInv => $$tagInfo{PrintConvInv}, 8921 Writable => defined $$tagInfo{Writable} ? $$tagInfo{Writable} : 1, 8922 SubDirectory => $$tagInfo{SubDirectory}, 8923 }; 8924 my $groups = $$tagInfo{Groups}; 8925 $$newInfo{Groups} = $groups ? { %$groups } : { }; 8926 $$newInfo{Groups}{$_} or $$newInfo{Groups}{$_} = $$tagTablePtr{GROUPS}{$_} foreach 0..2; 8927 $$newInfo{Groups}{1} = 'Keys'; 8928 } elsif ($tag =~ /^[-\w. ]+$/ or $tag =~ /\w{4}/) { 8929 # create info for tags with reasonable id's 8930 my $name = ucfirst $tag; 8931 $name =~ tr/-0-9a-zA-Z_. //dc; 8932 $name =~ s/[. ]+(.?)/\U$1/g; 8933 $name =~ s/_([a-z])/_\U$1/g; 8934 $name =~ s/([a-z])_([A-Z])/$1$2/g; 8935 $name = "Tag_$name" if length $name < 2; 8936 $newInfo = { Name => $name, Groups => { 1 => 'Keys' } }; 8937 $msg = ' (Unknown)'; 8938 } 8939 # substitute this tag in the ItemList table with the given index 8940 my $id = $$et{KeysCount} . '.' . $index; 8941 if (ref $$itemList{$id} eq 'HASH') { 8942 # delete other languages too if they exist 8943 my $oldInfo = $$itemList{$id}; 8944 if ($$oldInfo{OtherLang}) { 8945 delete $$itemList{$_} foreach @{$$oldInfo{OtherLang}}; 8946 } 8947 delete $$itemList{$id}; 8948 } 8949 if ($newInfo) { 8950 $$newInfo{KeysID} = $tag; # save original ID for use in family 7 group name 8951 AddTagToTable($itemList, $id, $newInfo); 8952 $msg or $msg = ''; 8953 $out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $tag$msg\n"; 8954 } 8955 $pos += $len; 8956 ++$index; 8957 } 8958 return 1; 8959} 8960 8961#------------------------------------------------------------------------------ 8962# Process keys in MetaSampleDesc directory 8963# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8964# Returns: 1 on success 8965sub ProcessMetaKeys($$$) 8966{ 8967 my ($et, $dirInfo, $tagTablePtr) = @_; 8968 # save this information to decode timed metadata samples when ExtractEmbedded is used 8969 SaveMetaKeys($et, $dirInfo, $tagTablePtr) if $$et{OPTIONS}{ExtractEmbedded}; 8970 return 1; 8971} 8972 8973#------------------------------------------------------------------------------ 8974# Process a QuickTime atom 8975# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) optional tag table ref 8976# Returns: 1 on success 8977sub ProcessMOV($$;$) 8978{ 8979 local $_; 8980 my ($et, $dirInfo, $tagTablePtr) = @_; 8981 my $raf = $$dirInfo{RAF}; 8982 my $dataPt = $$dirInfo{DataPt}; 8983 my $verbose = $et->Options('Verbose'); 8984 my $validate = $$et{OPTIONS}{Validate}; 8985 my $dataPos = $$dirInfo{Base} || 0; 8986 my $dirID = $$dirInfo{DirID} || ''; 8987 my $charsetQuickTime = $et->Options('CharsetQuickTime'); 8988 my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index); 8989 my ($dirEnd, $unkOpt, %saveOptions, $atomCount); 8990 8991 my $topLevel = not $$et{InQuickTime}; 8992 $$et{InQuickTime} = 1; 8993 $$et{HandlerType} = $$et{MetaFormat} = '' unless defined $$et{HandlerType}; 8994 8995 unless (defined $$et{KeysCount}) { 8996 $$et{KeysCount} = 0; # initialize ItemList key directory count 8997 $doDefaultLang = 1; # flag to generate default language tags 8998 } 8999 # more convenient to package data as a RandomAccess file 9000 unless ($raf) { 9001 $raf = new File::RandomAccess($dataPt); 9002 $dirEnd = $dataPos + $$dirInfo{DirLen} + ($$dirInfo{DirStart} || 0) if $$dirInfo{DirLen}; 9003 } 9004 # skip leading bytes if necessary 9005 if ($$dirInfo{DirStart}) { 9006 $raf->Seek($$dirInfo{DirStart}, 1) or return 0; 9007 $dataPos += $$dirInfo{DirStart}; 9008 } 9009 # read size/tag name atom header 9010 $raf->Read($buff,8) == 8 or return 0; 9011 $dataPos += 8; 9012 if ($tagTablePtr) { 9013 $isUserData = ($tagTablePtr eq \%Image::ExifTool::QuickTime::UserData); 9014 } else { 9015 $tagTablePtr = GetTagTable('Image::ExifTool::QuickTime::Main'); 9016 } 9017 ($size, $tag) = unpack('Na4', $buff); 9018 if ($dataPt) { 9019 $verbose and $et->VerboseDir($$dirInfo{DirName}); 9020 } else { 9021 # check on file type if called with a RAF 9022 $$tagTablePtr{$tag} or return 0; 9023 if ($tag eq 'ftyp' and $size >= 12) { 9024 # read ftyp atom to see what type of file this is 9025 my $fileType; 9026 if ($raf->Read($buff, $size-8) == $size-8) { 9027 $raf->Seek(-($size-8), 1); 9028 my $type = substr($buff, 0, 4); 9029 $$et{save_ftyp} = $type; 9030 # see if we know the extension for this file type 9031 if ($ftypLookup{$type} and $ftypLookup{$type} =~ /\(\.(\w+)/) { 9032 $fileType = $1; 9033 # check compatible brands 9034 } elsif ($buff =~ /^.{8}(.{4})+(mp41|mp42|avc1)/s) { 9035 $fileType = 'MP4'; 9036 } elsif ($buff =~ /^.{8}(.{4})+(f4v )/s) { 9037 $fileType = 'F4V'; 9038 } elsif ($buff =~ /^.{8}(.{4})+(qt )/s) { 9039 $fileType = 'MOV'; 9040 } 9041 } 9042 $fileType or $fileType = 'MP4'; # default to MP4 9043 $et->SetFileType($fileType, $mimeLookup{$fileType} || 'video/mp4'); 9044 # temporarily set ExtractEmbedded option for CRX files 9045 $saveOptions{ExtractEmbedded} = $et->Options(ExtractEmbedded => 1) if $fileType eq 'CRX'; 9046 } else { 9047 $et->SetFileType(); # MOV 9048 } 9049 SetByteOrder('MM'); 9050 $$et{PRIORITY_DIR} = 'XMP'; # have XMP take priority 9051 } 9052 $$raf{NoBuffer} = 1 if $et->Options('FastScan'); # disable buffering in FastScan mode 9053 9054 my $ee = $$et{OPTIONS}{ExtractEmbedded}; 9055 if ($ee) { 9056 $unkOpt = $$et{OPTIONS}{Unknown}; 9057 require 'Image/ExifTool/QuickTimeStream.pl'; 9058 } 9059 if ($$tagTablePtr{VARS}) { 9060 $index = $$tagTablePtr{VARS}{START_INDEX}; 9061 $atomCount = $$tagTablePtr{VARS}{ATOM_COUNT}; 9062 } 9063 for (;;) { 9064 my ($eeTag, $ignore); 9065 last if defined $atomCount and --$atomCount < 0; 9066 if ($size < 8) { 9067 if ($size == 0) { 9068 if ($dataPt) { 9069 # a zero size isn't legal for contained atoms, but Canon uses it to 9070 # terminate the CNTH atom (eg. CanonEOS100D.mov), so tolerate it here 9071 my $pos = $raf->Tell() - 4; 9072 $raf->Seek(0,2); 9073 my $str = $$dirInfo{DirName} . ' with ' . ($raf->Tell() - $pos) . ' bytes'; 9074 $et->VPrint(0,"$$et{INDENT}\[Terminator found in $str remaining]"); 9075 } else { 9076 my $t = PrintableTagID($tag,2); 9077 $et->VPrint(0,"$$et{INDENT}Tag '${t}' extends to end of file"); 9078 } 9079 last; 9080 } 9081 $size == 1 or $et->Warn('Invalid atom size'), last; 9082 # read extended atom size 9083 $raf->Read($buff, 8) == 8 or $et->Warn('Truncated atom header'), last; 9084 $dataPos += 8; 9085 my ($hi, $lo) = unpack('NN', $buff); 9086 if ($hi or $lo > 0x7fffffff) { 9087 if ($hi > 0x7fffffff) { 9088 $et->Warn('Invalid atom size'); 9089 last; 9090 } elsif (not $et->Options('LargeFileSupport')) { 9091 $et->Warn('End of processing at large atom (LargeFileSupport not enabled)'); 9092 last; 9093 } 9094 } 9095 $size = $hi * 4294967296 + $lo - 16; 9096 $size < 0 and $et->Warn('Invalid extended size'), last; 9097 } else { 9098 $size -= 8; 9099 } 9100 if ($validate) { 9101 $$et{ValidatePath} or $$et{ValidatePath} = { }; 9102 my $path = join('-', @{$$et{PATH}}, $tag); 9103 $path =~ s/-Track-/-$$et{SET_GROUP1}-/ if $$et{SET_GROUP1}; 9104 if ($$et{ValidatePath}{$path} and not $dupTagOK{$tag} and not $dupDirOK{$dirID}) { 9105 my $i = Get32u(\$tag,0); 9106 my $str = $i < 255 ? "index $i" : "tag '" . PrintableTagID($tag,2) . "'"; 9107 $et->WarnOnce("Duplicate $str at " . join('-', @{$$et{PATH}})); 9108 $$et{ValidatePath} = { } if $path eq 'MOV-moov'; # avoid warnings for all contained dups 9109 } 9110 $$et{ValidatePath}{$path} = 1; 9111 } 9112 if ($isUserData and $$et{SET_GROUP1}) { 9113 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 9114 # add track name to UserData tags inside tracks 9115 $tag = $$et{SET_GROUP1} . $tag; 9116 if (not $$tagTablePtr{$tag} and $tagInfo) { 9117 my %newInfo = %$tagInfo; 9118 foreach ('Name', 'Description') { 9119 next unless $$tagInfo{$_}; 9120 $newInfo{$_} = $$et{SET_GROUP1} . $$tagInfo{$_}; 9121 $newInfo{$_} =~ s/^(Track\d+)Track/$1/; # remove duplicate "Track" in name 9122 } 9123 AddTagToTable($tagTablePtr, $tag, \%newInfo); 9124 } 9125 } 9126 # set flag to store additional information for ExtractEmbedded option 9127 my $handlerType = $$et{HandlerType}; 9128 if ($eeBox{$handlerType} and $eeBox{$handlerType}{$tag}) { 9129 if ($ee) { 9130 # (there is another 'gps ' box with a track log that doesn't contain offsets) 9131 if ($tag ne 'gps ' or $eeBox{$handlerType}{$tag} eq $dirID) { 9132 $eeTag = 1; 9133 $$et{OPTIONS}{Unknown} = 1; # temporarily enable "Unknown" option 9134 } 9135 } elsif ($handlerType ne 'vide' and not $$et{OPTIONS}{Validate}) { 9136 EEWarn($et); 9137 } 9138 } elsif ($ee and $ee > 1 and $eeBox2{$handlerType} and $eeBox2{$handlerType}{$tag}) { 9139 $eeTag = 1; 9140 $$et{OPTIONS}{Unknown} = 1; 9141 } 9142 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 9143 9144 $$et{OPTIONS}{Unknown} = $unkOpt if $eeTag; # restore Unknown option 9145 9146 # allow numerical tag ID's 9147 unless ($tagInfo) { 9148 my $id = $$et{KeysCount} . '.' . unpack('N', $tag); 9149 if ($$tagTablePtr{$id}) { 9150 $tagInfo = $et->GetTagInfo($tagTablePtr, $id); 9151 $tag = $id; 9152 } 9153 } 9154 # generate tagInfo if Unknown option set 9155 if (not defined $tagInfo and ($$et{OPTIONS}{Unknown} or 9156 $verbose or $tag =~ /^\xa9/)) 9157 { 9158 my $name = PrintableTagID($tag,1); 9159 if ($name =~ /^xa9(.*)/) { 9160 $tagInfo = { 9161 Name => "UserData_$1", 9162 Description => "User Data $1", 9163 }; 9164 } else { 9165 $tagInfo = { 9166 Name => "Unknown_$name", 9167 Description => "Unknown $name", 9168 %unknownInfo, 9169 }; 9170 } 9171 AddTagToTable($tagTablePtr, $tag, $tagInfo); 9172 } 9173 # save required tag sizes 9174 if ($$tagTablePtr{"$tag-size"}) { 9175 $et->HandleTag($tagTablePtr, "$tag-size", $size); 9176 $et->HandleTag($tagTablePtr, "$tag-offset", $raf->Tell()) if $$tagTablePtr{"$tag-offset"}; 9177 } 9178 # load values only if associated with a tag (or verbose) and not too big 9179 if ($size > 0x2000000) { # start to get worried above 32 MB 9180 # check for RIFF trailer (written by Auto-Vox dashcam) 9181 if ($buff =~ /^(gpsa|gps0|gsen|gsea)...\0/s) { # (yet seen only gpsa as first record) 9182 $et->VPrint(0, "Found RIFF trailer"); 9183 if ($et->Options('ExtractEmbedded')) { 9184 $raf->Seek(-8, 1) or last; # seek back to start of trailer 9185 my $tbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); 9186 ProcessRIFFTrailer($et, { RAF => $raf }, $tbl); 9187 } else { 9188 EEWarn($et); 9189 } 9190 last; 9191 } 9192 $ignore = 1; 9193 if ($tagInfo and not $$tagInfo{Unknown} and not $eeTag) { 9194 my $t = PrintableTagID($tag,2); 9195 if ($size > 0x8000000) { 9196 $et->Warn("Skipping '${t}' atom > 128 MB", 1); 9197 } else { 9198 $et->Warn("Skipping '${t}' atom > 32 MB", 2) or $ignore = 0; 9199 } 9200 } 9201 } 9202 if (defined $tagInfo and not $ignore) { 9203 # set document number for this item property if necessary 9204 if ($$et{IsItemProperty}) { 9205 my $items = $$et{ItemInfo}; 9206 my ($id, $prop, $docNum, $lowest); 9207 my $primary = $$et{PrimaryItem} || 0; 9208ItemID: foreach $id (keys %$items) { 9209 next unless $$items{$id}{Association}; 9210 my $item = $$items{$id}; 9211 foreach $prop (@{$$item{Association}}) { 9212 next unless $prop == $index; 9213 if ($id == $primary or (not $dontInherit{$tag} and 9214 (not $$item{RefersTo} or $$item{RefersTo}{$primary}))) 9215 { 9216 # this is associated with the primary item or an item describing 9217 # the primary item, so consider this part of the main document 9218 undef $docNum; 9219 undef $lowest; 9220 last ItemID; 9221 } elsif ($$item{DocNum}) { 9222 # this property is already associated with an item that has 9223 # an ExifTool document number, so use the lowest associated DocNum 9224 $docNum = $$item{DocNum} if not defined $docNum or $docNum > $$item{DocNum}; 9225 } elsif (not defined $lowest or $lowest > $id) { 9226 # keep track of the lowest associated item ID 9227 $lowest = $id; 9228 } 9229 } 9230 } 9231 if (not defined $docNum and defined $lowest) { 9232 # this is the first time we've seen metadata from this item, 9233 # so use a new document number 9234 $docNum = ++$$et{DOC_COUNT}; 9235 $$items{$lowest}{DocNum} = $docNum; 9236 } 9237 $$et{DOC_NUM} = $docNum; 9238 } 9239 my $val; 9240 my $missing = $size - $raf->Read($val, $size); 9241 if ($missing) { 9242 my $t = PrintableTagID($tag,2); 9243 $et->Warn("Truncated '${t}' data (missing $missing bytes)"); 9244 last; 9245 } 9246 # use value to get tag info if necessary 9247 $tagInfo or $tagInfo = $et->GetTagInfo($tagTablePtr, $tag, \$val); 9248 my $hasData = ($$dirInfo{HasData} and $val =~ /\0...data\0/s); 9249 if ($verbose and not $hasData) { 9250 my $tval; 9251 if ($tagInfo and $$tagInfo{Format}) { 9252 $tval = ReadValue(\$val, 0, $$tagInfo{Format}, $$tagInfo{Count}, length($val)); 9253 } 9254 $et->VerboseInfo($tag, $tagInfo, 9255 Value => $tval, 9256 DataPt => \$val, 9257 DataPos => $dataPos, 9258 Size => $size, 9259 Format => $tagInfo ? $$tagInfo{Format} : undef, 9260 Index => $index, 9261 ); 9262 # print iref item ID numbers 9263 if ($dirID eq 'iref') { 9264 my ($id, $count, @to, $i); 9265 if ($$et{ItemRefVersion}) { 9266 ($id, $count, @to) = unpack('NnN*', $val) if length $val >= 10; 9267 } else { 9268 ($id, $count, @to) = unpack('nnn*', $val) if length $val >= 6; 9269 } 9270 defined $id or $id = '<err>', $count = 0; 9271 $id .= " (wrong count: $count)" if $count != @to; 9272 # convert sequential numbers to a range 9273 for ($i=1; $i<@to; ) { 9274 $to[$i-1] =~ /(\d+)$/ and $to[$i] == $1 + 1 or ++$i, next; 9275 $to[$i-1] =~ s/(-.*)?$/-$to[$i]/; 9276 splice @to, $i, 1; 9277 } 9278 $et->VPrint(1, "$$et{INDENT} Item $id refers to: ",join(',',@to),"\n"); 9279 } 9280 } 9281 # extract metadata from stream if ExtractEmbedded option is enabled 9282 if ($eeTag) { 9283 ParseTag($et, $tag, \$val); 9284 # forget this tag if we generated it only for ExtractEmbedded 9285 undef $tagInfo if $tagInfo and $$tagInfo{Unknown} and not $unkOpt; 9286 } 9287 9288 # handle iTunesInfo mean/name/data triplets 9289 if ($tagInfo and $$tagInfo{Triplet}) { 9290 if ($tag eq 'data' and $triplet{mean} and $triplet{name}) { 9291 $tag = $triplet{name}; 9292 # add 'mean' to name unless it is 'com.apple.iTunes' 9293 $tag = $triplet{mean} . '/' . $tag unless $triplet{mean} eq 'com.apple.iTunes'; 9294 $tagInfo = $et->GetTagInfo($tagTablePtr, $tag, \$val); 9295 unless ($tagInfo) { 9296 my $name = $triplet{name}; 9297 my $desc = $name; 9298 $name =~ tr/-_a-zA-Z0-9//dc; 9299 $desc =~ tr/_/ /; 9300 $tagInfo = { 9301 Name => $name, 9302 Description => $desc, 9303 }; 9304 AddTagToTable($tagTablePtr, $tag, $tagInfo); 9305 } 9306 # ignore 8-byte header 9307 $val = substr($val, 8) if length($val) >= 8; 9308 unless ($$tagInfo{Format} or $$tagInfo{SubDirectory}) { 9309 # extract as binary if it contains any non-ASCII or control characters 9310 if ($val =~ /[^\x20-\x7e]/) { 9311 my $buff = $val; 9312 $val = \$buff; 9313 } 9314 } 9315 undef %triplet; 9316 } else { 9317 undef %triplet if $tag eq 'mean'; 9318 $triplet{$tag} = substr($val,4) if length($val) > 4; 9319 undef $tagInfo; # don't store this tag 9320 } 9321 } 9322 if ($tagInfo) { 9323 my $subdir = $$tagInfo{SubDirectory}; 9324 if ($subdir) { 9325 my $start = $$subdir{Start} || 0; 9326 my ($base, $dPos) = ($dataPos, 0); 9327 if ($$subdir{Base}) { 9328 $dPos -= eval $$subdir{Base}; 9329 $base -= $dPos; 9330 } 9331 my %dirInfo = ( 9332 DataPt => \$val, 9333 DataLen => $size, 9334 DirStart => $start, 9335 DirLen => $size - $start, 9336 DirName => $$subdir{DirName} || $$tagInfo{Name}, 9337 DirID => $tag, 9338 HasData => $$subdir{HasData}, 9339 Multi => $$subdir{Multi}, 9340 IgnoreProp => $$subdir{IgnoreProp}, # (XML hack) 9341 DataPos => $dPos, 9342 Base => $base, # (needed for IsOffset tags in binary data) 9343 ); 9344 $dirInfo{BlockInfo} = $tagInfo if $$tagInfo{BlockExtract}; 9345 if ($$subdir{ByteOrder} and $$subdir{ByteOrder} =~ /^Little/) { 9346 SetByteOrder('II'); 9347 } 9348 my $oldGroup1 = $$et{SET_GROUP1}; 9349 if ($$tagInfo{SubDirectory} and $$tagInfo{SubDirectory}{TagTable} and 9350 $$tagInfo{SubDirectory}{TagTable} eq 'Image::ExifTool::QuickTime::Track') 9351 { 9352 $track or $track = 0; 9353 $$et{SET_GROUP1} = 'Track' . (++$track); 9354 } 9355 my $subTable = GetTagTable($$subdir{TagTable}); 9356 my $proc = $$subdir{ProcessProc}; 9357 # make ProcessMOV() the default processing procedure for subdirectories 9358 $proc = \&ProcessMOV unless $proc or $$subTable{PROCESS_PROC}; 9359 if ($size > $start) { 9360 # delay processing of ipco box until after all other boxes 9361 if ($tag eq 'ipco' and not $$et{IsItemProperty}) { 9362 $$et{ItemPropertyContainer} = [ \%dirInfo, $subTable, $proc ]; 9363 $et->VPrint(0,"$$et{INDENT}\[Process ipco box later]"); 9364 } else { 9365 $et->ProcessDirectory(\%dirInfo, $subTable, $proc); 9366 } 9367 } 9368 if ($tag eq 'stbl') { 9369 # process sample data when exiting SampleTable box if extracting embedded 9370 ProcessSamples($et) if $ee; 9371 } elsif ($tag eq 'minf') { 9372 $$et{HandlerType} = ''; # reset handler type at end of media info box 9373 } 9374 $$et{SET_GROUP1} = $oldGroup1; 9375 SetByteOrder('MM'); 9376 } elsif ($hasData) { 9377 # handle atoms containing 'data' tags 9378 # (currently ignore contained atoms: 'itif', 'name', etc.) 9379 my $pos = 0; 9380 for (;;) { 9381 last if $pos + 16 > $size; 9382 my ($len, $type, $flags, $ctry, $lang) = unpack("x${pos}Na4Nnn", $val); 9383 last if $pos + $len > $size; 9384 my ($value, $langInfo, $oldDir); 9385 my $format = $$tagInfo{Format}; 9386 if ($type eq 'data' and $len >= 16) { 9387 $pos += 16; 9388 $len -= 16; 9389 $value = substr($val, $pos, $len); 9390 # format flags (ref 12): 9391 # 0x0=binary, 0x1=UTF-8, 0x2=UTF-16, 0x3=ShiftJIS, 9392 # 0x4=UTF-8 0x5=UTF-16, 0xd=JPEG, 0xe=PNG, 9393 # 0x15=signed int, 0x16=unsigned int, 0x17=float, 9394 # 0x18=double, 0x1b=BMP, 0x1c='meta' atom 9395 if ($stringEncoding{$flags}) { 9396 # handle all string formats 9397 $value = $et->Decode($value, $stringEncoding{$flags}); 9398 # (shouldn't be null terminated, but some software writes it anyway) 9399 $value =~ s/\0$// unless $$tagInfo{Binary}; 9400 } else { 9401 if (not $format) { 9402 $format = QuickTimeFormat($flags, $len); 9403 } elsif ($format =~ /^int\d+([us])$/) { 9404 # adjust integer to available length (but not int64) 9405 my $fmt = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len}; 9406 $format = $fmt . $1 if defined $fmt; 9407 } 9408 if ($format) { 9409 $value = ReadValue(\$value, 0, $format, $$tagInfo{Count}, $len); 9410 } elsif (not $$tagInfo{ValueConv}) { 9411 # make binary data a scalar reference unless a ValueConv exists 9412 my $buf = $value; 9413 $value = \$buf; 9414 } 9415 } 9416 } 9417 if ($ctry or $lang) { 9418 my $langCode = GetLangCode($lang, $ctry); 9419 if ($langCode) { 9420 # get tagInfo for other language 9421 $langInfo = GetLangInfoQT($et, $tagInfo, $langCode); 9422 # save other language tag ID's so we can delete later if necessary 9423 if ($langInfo) { 9424 $$tagInfo{OtherLang} or $$tagInfo{OtherLang} = [ ]; 9425 push @{$$tagInfo{OtherLang}}, $$langInfo{TagID}; 9426 } 9427 } 9428 } 9429 $langInfo or $langInfo = $tagInfo; 9430 $et->VerboseInfo($tag, $langInfo, 9431 Value => ref $value ? $$value : $value, 9432 DataPt => \$val, 9433 DataPos => $dataPos, 9434 Start => $pos, 9435 Size => $len, 9436 Format => $format, 9437 Index => $index, 9438 Extra => sprintf(", Type='${type}', Flags=0x%x, Lang=0x%.4x",$flags,$lang), 9439 ) if $verbose; 9440 # use "Keys" in path instead of ItemList if this was defined by a Keys tag 9441 my $isKey = $$tagInfo{Groups} && $$tagInfo{Groups}{1} && $$tagInfo{Groups}{1} eq 'Keys'; 9442 if ($isKey) { 9443 $oldDir = $$et{PATH}[-1]; 9444 $$et{PATH}[-1] = 'Keys'; 9445 } 9446 $et->FoundTag($langInfo, $value) if defined $value; 9447 $$et{PATH}[-1] = $oldDir if $isKey; 9448 $pos += $len; 9449 } 9450 } elsif ($tag =~ /^\xa9/ or $$tagInfo{IText}) { 9451 # parse international text to extract all languages 9452 my $pos = 0; 9453 if ($$tagInfo{Format}) { 9454 $et->FoundTag($tagInfo, ReadValue(\$val, 0, $$tagInfo{Format}, undef, length($val))); 9455 $pos = $size; 9456 } 9457 for (;;) { 9458 my ($len, $lang); 9459 if ($$tagInfo{IText} and $$tagInfo{IText} >= 6) { 9460 last if $pos + $$tagInfo{IText} > $size; 9461 $pos += $$tagInfo{IText} - 2; 9462 $lang = unpack("x${pos}n", $val); 9463 $pos += 2; 9464 $len = $size - $pos; 9465 } else { 9466 last if $pos + 4 > $size; 9467 ($len, $lang) = unpack("x${pos}nn", $val); 9468 $pos += 4; 9469 # according to the QuickTime spec (ref 12), $len should include 9470 # 4 bytes for length and type words, but nobody (including 9471 # Apple, Pentax and Kodak) seems to add these in, so try 9472 # to allow for either 9473 if ($pos + $len > $size) { 9474 $len -= 4; 9475 last if $pos + $len > $size or $len < 0; 9476 } 9477 } 9478 # ignore any empty entries (or null padding) after the first 9479 next if not $len and $pos; 9480 my $str = substr($val, $pos, $len); 9481 my ($langInfo, $enc); 9482 if (($lang < 0x400 or $lang == 0x7fff) and $str !~ /^\xfe\xff/) { 9483 # this is a Macintosh language code 9484 # a language code of 0 is Macintosh english, so treat as default 9485 if ($lang) { 9486 if ($lang == 0x7fff) { 9487 # technically, ISO 639-2 doesn't have a 2-character 9488 # equivalent for 'und', but use 'un' anyway 9489 $lang = 'un'; 9490 } else { 9491 # use Font.pm to look up language string 9492 require Image::ExifTool::Font; 9493 $lang = $Image::ExifTool::Font::ttLang{Macintosh}{$lang}; 9494 } 9495 } 9496 # the spec says only "Macintosh text encoding", but 9497 # allow this to be configured by the user 9498 $enc = $charsetQuickTime; 9499 } else { 9500 # convert language code to ASCII (ignore read-only bit) 9501 $lang = UnpackLang($lang); 9502 # may be either UTF-8 or UTF-16BE 9503 $enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8'; 9504 } 9505 unless ($$tagInfo{NoDecode}) { 9506 $str = $et->Decode($str, $enc); 9507 $str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags) 9508 } 9509 if ($$tagInfo{IText} and $$tagInfo{IText} > 6) { 9510 my $n = $$tagInfo{IText} - 6; 9511 # add back extra bytes (eg. 'rtng' box) 9512 $str = substr($val, $pos-$n-2, $n) . $str; 9513 } 9514 $langInfo = GetLangInfoQT($et, $tagInfo, $lang) if $lang; 9515 $et->FoundTag($langInfo || $tagInfo, $str); 9516 $pos += $len; 9517 } 9518 } else { 9519 my $format = $$tagInfo{Format}; 9520 if ($format) { 9521 $val = ReadValue(\$val, 0, $format, $$tagInfo{Count}, length($val)); 9522 } 9523 my $oldBase; 9524 if ($$tagInfo{SetBase}) { 9525 $oldBase = $$et{BASE}; 9526 $$et{BASE} = $dataPos; 9527 } 9528 my $key = $et->FoundTag($tagInfo, $val); 9529 $$et{BASE} = $oldBase if defined $oldBase; 9530 # decode if necessary (NOTE: must be done after RawConv) 9531 if (defined $key and (not $format or $format =~ /^string/) and 9532 not $$tagInfo{Unknown} and not $$tagInfo{ValueConv} and 9533 not $$tagInfo{Binary} and defined $$et{VALUE}{$key} and not ref $val) 9534 { 9535 my $vp = \$$et{VALUE}{$key}; 9536 if (not ref $$vp and length($$vp) <= 65536 and $$vp =~ /[\x80-\xff]/) { 9537 # the encoding of this is not specified, so use CharsetQuickTime 9538 # unless the string is valid UTF-8 9539 require Image::ExifTool::XMP; 9540 my $enc = Image::ExifTool::XMP::IsUTF8($vp) > 0 ? 'UTF8' : $charsetQuickTime; 9541 $$vp = $et->Decode($$vp, $enc); 9542 } 9543 } 9544 } 9545 } 9546 } else { 9547 $et->VerboseInfo($tag, $tagInfo, 9548 Size => $size, 9549 Extra => sprintf(' at offset 0x%.4x', $raf->Tell()), 9550 ) if $verbose; 9551 if ($size and (not $raf->Seek($size-1, 1) or $raf->Read($buff, 1) != 1)) { 9552 my $t = PrintableTagID($tag,2); 9553 $et->Warn("Truncated '${t}' data"); 9554 last; 9555 } 9556 } 9557 $dataPos += $size + 8; # point to start of next atom data 9558 last if $dirEnd and $dataPos >= $dirEnd; # (note: ignores last value if 0 bytes) 9559 $raf->Read($buff, 8) == 8 or last; 9560 ($size, $tag) = unpack('Na4', $buff); 9561 ++$index if defined $index; 9562 } 9563 # tweak file type based on track content ("iso*" and "dash" ftyp only) 9564 if ($topLevel and $$et{VALUE}{FileType} and $$et{VALUE}{FileType} eq 'MP4' and 9565 $$et{save_ftyp} and $$et{HasHandler} and $$et{save_ftyp} =~ /^(iso|dash)/ and 9566 $$et{HasHandler}{soun} and not $$et{HasHandler}{vide}) 9567 { 9568 $et->OverrideFileType('M4A', 'audio/mp4'); 9569 } 9570 # fill in missing defaults for alternate language tags 9571 # (the first language is taken as the default) 9572 if ($doDefaultLang and $$et{QTLang}) { 9573QTLang: foreach $tag (@{$$et{QTLang}}) { 9574 next unless defined $$et{VALUE}{$tag}; 9575 my $langInfo = $$et{TAG_INFO}{$tag} or next; 9576 my $tagInfo = $$langInfo{SrcTagInfo} or next; 9577 my $infoHash = $$et{TAG_INFO}; 9578 my $name = $$tagInfo{Name}; 9579 # loop through all instances of this tag name and generate the default-language 9580 # version only if we don't already have a QuickTime tag with this name 9581 my ($i, $key); 9582 for ($i=0, $key=$name; $$infoHash{$key}; ++$i, $key="$name ($i)") { 9583 next QTLang if $et->GetGroup($key, 0) eq 'QuickTime'; 9584 } 9585 $et->FoundTag($tagInfo, $$et{VALUE}{$tag}); 9586 } 9587 delete $$et{QTLang}; 9588 } 9589 # process item information now that we are done processing its 'meta' container 9590 HandleItemInfo($et) if $topLevel or $dirID eq 'meta'; 9591 9592 ScanMediaData($et) if $ee and $topLevel; # brute force scan for metadata embedded in media data 9593 9594 # restore any changed options 9595 $et->Options($_ => $saveOptions{$_}) foreach keys %saveOptions; 9596 return 1; 9597} 9598 9599#------------------------------------------------------------------------------ 9600# Process a QuickTime Image File 9601# Inputs: 0) ExifTool object reference, 1) directory information reference 9602# Returns: 1 on success 9603sub ProcessQTIF($$) 9604{ 9605 my ($et, $dirInfo) = @_; 9606 my $table = GetTagTable('Image::ExifTool::QuickTime::ImageFile'); 9607 return ProcessMOV($et, $dirInfo, $table); 9608} 9609 96101; # end 9611 9612__END__ 9613 9614=head1 NAME 9615 9616Image::ExifTool::QuickTime - Read QuickTime and MP4 meta information 9617 9618=head1 SYNOPSIS 9619 9620This module is used by Image::ExifTool 9621 9622=head1 DESCRIPTION 9623 9624This module contains routines required by Image::ExifTool to extract 9625information from QuickTime and MP4 video, M4A audio, and HEIC image files. 9626 9627=head1 AUTHOR 9628 9629Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com) 9630 9631This library is free software; you can redistribute it and/or modify it 9632under the same terms as Perl itself. 9633 9634=head1 REFERENCES 9635 9636=over 4 9637 9638=item L<http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html> 9639 9640=item L<http://search.cpan.org/dist/MP4-Info-1.04/> 9641 9642=item L<http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt> 9643 9644=item L<http://wiki.multimedia.cx/index.php?title=Apple_QuickTime> 9645 9646=item L<http://atomicparsley.sourceforge.net/mpeg-4files.html> 9647 9648=item L<http://wiki.multimedia.cx/index.php?title=QuickTime_container> 9649 9650=item L<http://code.google.com/p/mp4v2/wiki/iTunesMetadata> 9651 9652=item L<http://www.canieti.com.mx/assets/files/1011/IEC_100_1384_DC.pdf> 9653 9654=item L<http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v10.pdf> 9655 9656=back 9657 9658=head1 SEE ALSO 9659 9660L<Image::ExifTool::TagNames/QuickTime Tags>, 9661L<Image::ExifTool(3pm)|Image::ExifTool> 9662 9663=cut 9664 9665