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.56'; 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 SaveMetaKeys($$$); 69# ++^^^^^^^^^^^^++ 70sub ParseItemLocation($$); 71sub ParseContentDescribes($$); 72sub ParseItemInfoEntry($$); 73sub ParseItemPropAssoc($$); 74sub FixWrongFormat($); 75sub GetMatrixStructure($$); 76sub ConvertISO6709($); 77sub ConvInvISO6709($); 78sub ConvertChapterList($); 79sub PrintChapter($); 80sub PrintGPSCoordinates($); 81sub PrintInvGPSCoordinates($); 82sub UnpackLang($;$); 83sub WriteKeys($$$); 84sub WriteQuickTime($$$); 85sub WriteMOV($$); 86sub GetLangInfo($$); 87sub CheckQTValue($$$); 88 89# MIME types for all entries in the ftypLookup with file extensions 90# (defaults to 'video/mp4' if not found in this lookup) 91my %mimeLookup = ( 92 '3G2' => 'video/3gpp2', 93 '3GP' => 'video/3gpp', 94 AAX => 'audio/vnd.audible.aax', 95 DVB => 'video/vnd.dvb.file', 96 F4A => 'audio/mp4', 97 F4B => 'audio/mp4', 98 JP2 => 'image/jp2', 99 JPM => 'image/jpm', 100 JPX => 'image/jpx', 101 M4A => 'audio/mp4', 102 M4B => 'audio/mp4', 103 M4P => 'audio/mp4', 104 M4V => 'video/x-m4v', 105 MOV => 'video/quicktime', 106 MQV => 'video/quicktime', 107 HEIC => 'image/heic', 108 HEVC => 'image/heic-sequence', 109 HEICS=> 'image/heic-sequence', 110 HEIF => 'image/heif', 111 HEIFS=> 'image/heif-sequence', 112 AVIF => 'image/avif', #PH (NC) 113 CRX => 'video/x-canon-crx', # (will get overridden) 114); 115 116# look up file type from ftyp atom type, with MIME type in comment if known 117# (ref http://www.ftyps.com/) 118my %ftypLookup = ( 119 '3g2a' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-0 V1.0', # video/3gpp2 120 '3g2b' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-A V1.0.0', # video/3gpp2 121 '3g2c' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-B v1.0', # video/3gpp2 122 '3ge6' => '3GPP (.3GP) Release 6 MBMS Extended Presentations', # video/3gpp 123 '3ge7' => '3GPP (.3GP) Release 7 MBMS Extended Presentations', # video/3gpp 124 '3gg6' => '3GPP Release 6 General Profile', # video/3gpp 125 '3gp1' => '3GPP Media (.3GP) Release 1 (probably non-existent)', # video/3gpp 126 '3gp2' => '3GPP Media (.3GP) Release 2 (probably non-existent)', # video/3gpp 127 '3gp3' => '3GPP Media (.3GP) Release 3 (probably non-existent)', # video/3gpp 128 '3gp4' => '3GPP Media (.3GP) Release 4', # video/3gpp 129 '3gp5' => '3GPP Media (.3GP) Release 5', # video/3gpp 130 '3gp6' => '3GPP Media (.3GP) Release 6 Basic Profile', # video/3gpp 131 '3gp6' => '3GPP Media (.3GP) Release 6 Progressive Download', # video/3gpp 132 '3gp6' => '3GPP Media (.3GP) Release 6 Streaming Servers', # video/3gpp 133 '3gs7' => '3GPP Media (.3GP) Release 7 Streaming Servers', # video/3gpp 134 'aax ' => 'Audible Enhanced Audiobook (.AAX)', #PH 135 'avc1' => 'MP4 Base w/ AVC ext [ISO 14496-12:2005]', # video/mp4 136 'CAEP' => 'Canon Digital Camera', 137 'caqv' => 'Casio Digital Camera', 138 'CDes' => 'Convergent Design', 139 'da0a' => 'DMB MAF w/ MPEG Layer II aud, MOT slides, DLS, JPG/PNG/MNG images', 140 'da0b' => 'DMB MAF, extending DA0A, with 3GPP timed text, DID, TVA, REL, IPMP', 141 'da1a' => 'DMB MAF audio with ER-BSAC audio, JPG/PNG/MNG images', 142 'da1b' => 'DMB MAF, extending da1a, with 3GPP timed text, DID, TVA, REL, IPMP', 143 'da2a' => 'DMB MAF aud w/ HE-AAC v2 aud, MOT slides, DLS, JPG/PNG/MNG images', 144 'da2b' => 'DMB MAF, extending da2a, with 3GPP timed text, DID, TVA, REL, IPMP', 145 'da3a' => 'DMB MAF aud with HE-AAC aud, JPG/PNG/MNG images', 146 'da3b' => 'DMB MAF, extending da3a w/ BIFS, 3GPP timed text, DID, TVA, REL, IPMP', 147 'dmb1' => 'DMB MAF supporting all the components defined in the specification', 148 'dmpf' => 'Digital Media Project', # various 149 'drc1' => 'Dirac (wavelet compression), encapsulated in ISO base media (MP4)', 150 'dv1a' => 'DMB MAF vid w/ AVC vid, ER-BSAC aud, BIFS, JPG/PNG/MNG images, TS', 151 'dv1b' => 'DMB MAF, extending dv1a, with 3GPP timed text, DID, TVA, REL, IPMP', 152 'dv2a' => 'DMB MAF vid w/ AVC vid, HE-AAC v2 aud, BIFS, JPG/PNG/MNG images, TS', 153 'dv2b' => 'DMB MAF, extending dv2a, with 3GPP timed text, DID, TVA, REL, IPMP', 154 'dv3a' => 'DMB MAF vid w/ AVC vid, HE-AAC aud, BIFS, JPG/PNG/MNG images, TS', 155 'dv3b' => 'DMB MAF, extending dv3a, with 3GPP timed text, DID, TVA, REL, IPMP', 156 'dvr1' => 'DVB (.DVB) over RTP', # video/vnd.dvb.file 157 'dvt1' => 'DVB (.DVB) over MPEG-2 Transport Stream', # video/vnd.dvb.file 158 'F4A ' => 'Audio for Adobe Flash Player 9+ (.F4A)', # audio/mp4 159 'F4B ' => 'Audio Book for Adobe Flash Player 9+ (.F4B)', # audio/mp4 160 'F4P ' => 'Protected Video for Adobe Flash Player 9+ (.F4P)', # video/mp4 161 'F4V ' => 'Video for Adobe Flash Player 9+ (.F4V)', # video/mp4 162 'isc2' => 'ISMACryp 2.0 Encrypted File', # ?/enc-isoff-generic 163 'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4 164 'isom' => 'MP4 Base Media v1 [IS0 14496-12:2003]', # video/mp4 165 'JP2 ' => 'JPEG 2000 Image (.JP2) [ISO 15444-1 ?]', # image/jp2 166 'JP20' => 'Unknown, from GPAC samples (prob non-existent)', 167 'jpm ' => 'JPEG 2000 Compound Image (.JPM) [ISO 15444-6]', # image/jpm 168 'jpx ' => 'JPEG 2000 with extensions (.JPX) [ISO 15444-2]', # image/jpx 169 'KDDI' => '3GPP2 EZmovie for KDDI 3G cellphones', # video/3gpp2 170 #LCAG => (found in CompatibleBrands of Leica MOV videos) 171 'M4A ' => 'Apple iTunes AAC-LC (.M4A) Audio', # audio/x-m4a 172 'M4B ' => 'Apple iTunes AAC-LC (.M4B) Audio Book', # audio/mp4 173 'M4P ' => 'Apple iTunes AAC-LC (.M4P) AES Protected Audio', # audio/mp4 174 'M4V ' => 'Apple iTunes Video (.M4V) Video', # video/x-m4v 175 'M4VH' => 'Apple TV (.M4V)', # video/x-m4v 176 'M4VP' => 'Apple iPhone (.M4V)', # video/x-m4v 177 'mj2s' => 'Motion JPEG 2000 [ISO 15444-3] Simple Profile', # video/mj2 178 'mjp2' => 'Motion JPEG 2000 [ISO 15444-3] General Profile', # video/mj2 179 'mmp4' => 'MPEG-4/3GPP Mobile Profile (.MP4/3GP) (for NTT)', # video/mp4 180 'mp21' => 'MPEG-21 [ISO/IEC 21000-9]', # various 181 'mp41' => 'MP4 v1 [ISO 14496-1:ch13]', # video/mp4 182 'mp42' => 'MP4 v2 [ISO 14496-14]', # video/mp4 183 'mp71' => 'MP4 w/ MPEG-7 Metadata [per ISO 14496-12]', # various 184 'MPPI' => 'Photo Player, MAF [ISO/IEC 23000-3]', # various 185 'mqt ' => 'Sony / Mobile QuickTime (.MQV) US Patent 7,477,830 (Sony Corp)', # video/quicktime 186 'MSNV' => 'MPEG-4 (.MP4) for SonyPSP', # audio/mp4 187 'NDAS' => 'MP4 v2 [ISO 14496-14] Nero Digital AAC Audio', # audio/mp4 188 'NDSC' => 'MPEG-4 (.MP4) Nero Cinema Profile', # video/mp4 189 'NDSH' => 'MPEG-4 (.MP4) Nero HDTV Profile', # video/mp4 190 'NDSM' => 'MPEG-4 (.MP4) Nero Mobile Profile', # video/mp4 191 'NDSP' => 'MPEG-4 (.MP4) Nero Portable Profile', # video/mp4 192 'NDSS' => 'MPEG-4 (.MP4) Nero Standard Profile', # video/mp4 193 'NDXC' => 'H.264/MPEG-4 AVC (.MP4) Nero Cinema Profile', # video/mp4 194 'NDXH' => 'H.264/MPEG-4 AVC (.MP4) Nero HDTV Profile', # video/mp4 195 'NDXM' => 'H.264/MPEG-4 AVC (.MP4) Nero Mobile Profile', # video/mp4 196 'NDXP' => 'H.264/MPEG-4 AVC (.MP4) Nero Portable Profile', # video/mp4 197 'NDXS' => 'H.264/MPEG-4 AVC (.MP4) Nero Standard Profile', # video/mp4 198 'odcf' => 'OMA DCF DRM Format 2.0 (OMA-TS-DRM-DCF-V2_0-20060303-A)', # various 199 'opf2' => 'OMA PDCF DRM Format 2.1 (OMA-TS-DRM-DCF-V2_1-20070724-C)', 200 'opx2' => 'OMA PDCF DRM + XBS extensions (OMA-TS-DRM_XBS-V1_0-20070529-C)', 201 'pana' => 'Panasonic Digital Camera', 202 'qt ' => 'Apple QuickTime (.MOV/QT)', # video/quicktime 203 'ROSS' => 'Ross Video', 204 'sdv ' => 'SD Memory Card Video', # various? 205 'ssc1' => 'Samsung stereoscopic, single stream', 206 'ssc2' => 'Samsung stereoscopic, dual stream', 207 'XAVC' => 'Sony XAVC', #PH 208 'heic' => 'High Efficiency Image Format HEVC still image (.HEIC)', # image/heic 209 'hevc' => 'High Efficiency Image Format HEVC sequence (.HEICS)', # image/heic-sequence 210 'mif1' => 'High Efficiency Image Format still image (.HEIF)', # image/heif 211 'msf1' => 'High Efficiency Image Format sequence (.HEIFS)', # image/heif-sequence 212 'heix' => 'High Efficiency Image Format still image (.HEIF)', # image/heif (ref PH, Canon 1DXmkIII) 213 'avif' => 'AV1 Image File Format (.AVIF)', # image/avif 214 'crx ' => 'Canon Raw (.CRX)', #PH (CR3 or CRM; use Canon CompressorVersion to decide) 215); 216 217# information for int32u date/time tags (time zero is Jan 1, 1904) 218my %timeInfo = ( 219 Notes => 'converted from UTC to local time if the QuickTimeUTC option is set', 220 Shift => 'Time', 221 Writable => 1, 222 Permanent => 1, 223 DelValue => 0, 224 # It is not uncommon for brain-dead software to use the wrong time zero, 225 # so assume a time zero of Jan 1, 1970 if the date is before this 226 # Note: This value will be in UTC if generated by a system that is aware of the time zone 227 RawConv => q{ 228 my $offset = (66 * 365 + 17) * 24 * 3600; 229 return $val - $offset if $val >= $offset or $$self{OPTIONS}{QuickTimeUTC}; 230 if ($val and not $$self{IsWriting}) { 231 $self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1); 232 } 233 return $val; 234 }, 235 RawConvInv => q{ 236 if ($$self{FileType} eq 'CR3' and not $self->Options('QuickTimeUTC')) { 237 # convert to UTC 238 my $offset = (66 * 365 + 17) * 24 * 3600; 239 $val = ConvertUnixTime($val - $offset); 240 $val = GetUnixTime($val, 1) + $offset; 241 } 242 return $val; 243 }, 244 # (all CR3 files store UTC times - PH) 245 ValueConv => 'ConvertUnixTime($val, $self->Options("QuickTimeUTC") || $$self{FileType} eq "CR3")', 246 ValueConvInv => 'GetUnixTime($val, $self->Options("QuickTimeUTC")) + (66 * 365 + 17) * 24 * 3600', 247 PrintConv => '$self->ConvertDateTime($val)', 248 PrintConvInv => '$self->InverseDateTime($val)', 249 # (can't put Groups here because they aren't constant!) 250); 251# information for duration tags 252my %durationInfo = ( 253 ValueConv => '$$self{TimeScale} ? $val / $$self{TimeScale} : $val', 254 PrintConv => '$$self{TimeScale} ? ConvertDuration($val) : $val', 255); 256# handle unknown tags 257my %unknownInfo = ( 258 Unknown => 1, 259 ValueConv => '$val =~ /^([\x20-\x7e]*)\0*$/ ? $1 : \$val', 260); 261# parsing for most of the 3gp udta language text boxes 262my %langText = ( 263 Notes => 'used in 3gp videos', 264 IText => 6, 265 Avoid => 1, 266); 267 268# 4-character Vendor ID codes (ref PH) 269my %vendorID = ( 270 appl => 'Apple', 271 fe20 => 'Olympus (fe20)', # (FE200) 272 FFMP => 'FFmpeg', 273 'GIC '=> 'General Imaging Co.', 274 kdak => 'Kodak', 275 KMPI => 'Konica-Minolta', 276 leic => 'Leica', 277 mino => 'Minolta', 278 niko => 'Nikon', 279 NIKO => 'Nikon', 280 olym => 'Olympus', 281 pana => 'Panasonic', 282 pent => 'Pentax', 283 pr01 => 'Olympus (pr01)', # (FE100,FE110,FE115) 284 sany => 'Sanyo', 285 'SMI '=> 'Sorenson Media Inc.', 286 ZORA => 'Zoran Corporation', 287 'AR.D'=> 'Parrot AR.Drone', 288 ' KD '=> 'Kodak', # (FZ201) 289); 290 291# QuickTime data atom encodings for string types (ref 12) 292%stringEncoding = ( 293 1 => 'UTF8', 294 2 => 'UTF16', 295 3 => 'ShiftJIS', 296 4 => 'UTF8', 297 5 => 'UTF16', 298); 299 300my %graphicsMode = ( 301 # (ref http://homepage.mac.com/vanhoek/MovieGuts%20docs/64.html) 302 0x00 => 'srcCopy', 303 0x01 => 'srcOr', 304 0x02 => 'srcXor', 305 0x03 => 'srcBic', 306 0x04 => 'notSrcCopy', 307 0x05 => 'notSrcOr', 308 0x06 => 'notSrcXor', 309 0x07 => 'notSrcBic', 310 0x08 => 'patCopy', 311 0x09 => 'patOr', 312 0x0a => 'patXor', 313 0x0b => 'patBic', 314 0x0c => 'notPatCopy', 315 0x0d => 'notPatOr', 316 0x0e => 'notPatXor', 317 0x0f => 'notPatBic', 318 0x20 => 'blend', 319 0x21 => 'addPin', 320 0x22 => 'addOver', 321 0x23 => 'subPin', 322 0x24 => 'transparent', 323 0x25 => 'addMax', 324 0x26 => 'subOver', 325 0x27 => 'addMin', 326 0x31 => 'grayishTextOr', 327 0x32 => 'hilite', 328 0x40 => 'ditherCopy', 329 # the following ref ISO/IEC 15444-3 330 0x100 => 'Alpha', 331 0x101 => 'White Alpha', 332 0x102 => 'Pre-multiplied Black Alpha', 333 0x110 => 'Component Alpha', 334); 335 336my %channelLabel = ( 337 0xFFFFFFFF => 'Unknown', 338 0 => 'Unused', 339 100 => 'UseCoordinates', 340 1 => 'Left', 341 2 => 'Right', 342 3 => 'Center', 343 4 => 'LFEScreen', 344 5 => 'LeftSurround', 345 6 => 'RightSurround', 346 7 => 'LeftCenter', 347 8 => 'RightCenter', 348 9 => 'CenterSurround', 349 10 => 'LeftSurroundDirect', 350 11 => 'RightSurroundDirect', 351 12 => 'TopCenterSurround', 352 13 => 'VerticalHeightLeft', 353 14 => 'VerticalHeightCenter', 354 15 => 'VerticalHeightRight', 355 16 => 'TopBackLeft', 356 17 => 'TopBackCenter', 357 18 => 'TopBackRight', 358 33 => 'RearSurroundLeft', 359 34 => 'RearSurroundRight', 360 35 => 'LeftWide', 361 36 => 'RightWide', 362 37 => 'LFE2', 363 38 => 'LeftTotal', 364 39 => 'RightTotal', 365 40 => 'HearingImpaired', 366 41 => 'Narration', 367 42 => 'Mono', 368 43 => 'DialogCentricMix', 369 44 => 'CenterSurroundDirect', 370 45 => 'Haptic', 371 200 => 'Ambisonic_W', 372 201 => 'Ambisonic_X', 373 202 => 'Ambisonic_Y', 374 203 => 'Ambisonic_Z', 375 204 => 'MS_Mid', 376 205 => 'MS_Side', 377 206 => 'XY_X', 378 207 => 'XY_Y', 379 301 => 'HeadphonesLeft', 380 302 => 'HeadphonesRight', 381 304 => 'ClickTrack', 382 305 => 'ForeignLanguage', 383 400 => 'Discrete', 384 0x10000 => 'Discrete_0', 385 0x10001 => 'Discrete_1', 386 0x10002 => 'Discrete_2', 387 0x10003 => 'Discrete_3', 388 0x10004 => 'Discrete_4', 389 0x10005 => 'Discrete_5', 390 0x10006 => 'Discrete_6', 391 0x10007 => 'Discrete_7', 392 0x10008 => 'Discrete_8', 393 0x10009 => 'Discrete_9', 394 0x1000a => 'Discrete_10', 395 0x1000b => 'Discrete_11', 396 0x1000c => 'Discrete_12', 397 0x1000d => 'Discrete_13', 398 0x1000e => 'Discrete_14', 399 0x1000f => 'Discrete_15', 400 0x1ffff => 'Discrete_65535', 401); 402 403# properties which don't get inherited from the parent 404my %dontInherit = ( 405 ispe => 1, # size of parent may be different 406 hvcC => 1, # (likely redundant) 407); 408 409# tags that may be duplicated and directories that may contain duplicate tags 410# (used only to avoid warnings when Validate-ing) 411my %dupTagOK = ( mdat => 1, trak => 1, free => 1, infe => 1, sgpd => 1, dimg => 1, CCDT => 1, 412 sbgp => 1, csgm => 1, uuid => 1, cdsc => 1, maxr => 1, '----' => 1 ); 413my %dupDirOK = ( ipco => 1, '----' => 1 ); 414 415# the usual atoms required to decode timed metadata with the ExtractEmbedded option 416my %eeStd = ( stco => 'stbl', co64 => 'stbl', stsz => 'stbl', stz2 => 'stbl', 417 stsc => 'stbl', stts => 'stbl' ); 418 419# boxes and their containers for the various handler types that we want to save 420# when the ExtractEmbedded is enabled (currently only the 'gps ' container name is 421# used, but others have been checked against all available sample files and may be 422# useful in the future if the names are used for different boxes on other locations) 423my %eeBox = ( 424 # (note: vide is only processed if specific atoms exist in the VideoSampleDesc) 425 vide => { %eeStd, 426 JPEG => 'stsd', 427 # avcC => 'stsd', # (uncomment to parse H264 stream) 428 }, 429 text => { %eeStd }, 430 meta => { %eeStd }, 431 sbtl => { %eeStd }, 432 data => { %eeStd }, 433 camm => { %eeStd }, # (Insta360) 434 ctbx => { %eeStd }, # (GM cars) 435 '' => { 'gps ' => 'moov', 'GPS ' => 'main' }, # (no handler -- in top level 'moov' box, and main) 436); 437 438# QuickTime atoms 439%Image::ExifTool::QuickTime::Main = ( 440 PROCESS_PROC => \&ProcessMOV, 441 WRITE_PROC => \&WriteQuickTime, # (only needs to be defined for directories to process when writing) 442 GROUPS => { 2 => 'Video' }, 443 meta => { # 'meta' is found here in my Sony ILCE-7S MP4 sample - PH 444 Name => 'Meta', 445 SubDirectory => { 446 TagTable => 'Image::ExifTool::QuickTime::Meta', 447 Start => 4, # skip 4-byte version number header 448 }, 449 }, 450 meco => { #ISO14496-12:2015 451 Name => 'OtherMeta', 452 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' }, 453 }, 454 free => [ 455 { 456 Name => 'KodakFree', 457 # (found in Kodak M5370 MP4 videos) 458 Condition => '$$valPt =~ /^\0\0\0.Seri/s', 459 SubDirectory => { TagTable => 'Image::ExifTool::Kodak::Free' }, 460 },{ 461 Name => 'Pittasoft', 462 # (Pittasoft Blackview dashcam MP4 videos) 463 Condition => '$$valPt =~ /^\0\0..(cprt|sttm|ptnm|ptrh|thum|gps |3gf )/s', 464 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' }, 465 },{ 466 Unknown => 1, 467 Binary => 1, 468 }, 469 # (also Samsung WB750 uncompressed thumbnail data starting with "SDIC\0") 470 ], 471 # fre1 - 4 bytes: "june" (Kodak PixPro SP360) 472 frea => { 473 Name => 'Kodak_frea', 474 SubDirectory => { TagTable => 'Image::ExifTool::Kodak::frea' }, 475 }, 476 skip => [ 477 { 478 Name => 'CanonSkip', 479 Condition => '$$valPt =~ /^\0.{3}(CNDB|CNCV|CNMN|CNFV|CNTH|CNDM)/s', 480 SubDirectory => { TagTable => 'Image::ExifTool::Canon::Skip' }, 481 }, 482 { 483 Name => 'PreviewImage', # (found in DuDuBell M1 dashcam MOV files) 484 Groups => { 2 => 'Preview' }, 485 Condition => '$$valPt =~ /^.{12}\xff\xd8\xff/', 486 Binary => 1, 487 RawConv => q{ 488 my $len = Get32u(\$val, 8); 489 return undef unless length($val) >= $len + 12; 490 return substr($val, 12, $len); 491 }, 492 }, 493 { Name => 'Skip', Unknown => 1, Binary => 1 }, 494 ], 495 wide => { Unknown => 1, Binary => 1 }, 496 ftyp => { #MP4 497 Name => 'FileType', 498 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FileType' }, 499 }, 500 pnot => { 501 Name => 'Preview', 502 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Preview' }, 503 }, 504 PICT => { 505 Name => 'PreviewPICT', 506 Groups => { 2 => 'Preview' }, 507 Binary => 1, 508 }, 509 pict => { #8 510 Name => 'PreviewPICT', 511 Groups => { 2 => 'Preview' }, 512 Binary => 1, 513 }, 514 # (note that moov is present for an HEIF sequence) 515 moov => { 516 Name => 'Movie', 517 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Movie' }, 518 }, 519 moof => { 520 Name => 'MovieFragment', 521 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieFragment' }, 522 }, 523 # mfra - movie fragment random access: contains tfra (track fragment random access), and 524 # mfro (movie fragment random access offset) (ref 5) 525 mdat => { Name => 'MediaData', Unknown => 1, Binary => 1 }, 526 'mdat-size' => { 527 Name => 'MediaDataSize', 528 Notes => q{ 529 not a real tag ID, this tag represents the size of the 'mdat' data in bytes 530 and is used in the AvgBitrate calculation 531 }, 532 }, 533 'mdat-offset' => 'MediaDataOffset', 534 junk => { Unknown => 1, Binary => 1 }, #8 535 uuid => [ 536 { #9 (MP4 files) 537 Name => 'XMP', 538 # *** this is where ExifTool writes XMP in MP4 videos (as per XMP spec) *** 539 Condition => '$$valPt=~/^\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac/', 540 WriteGroup => 'XMP', # (write main XMP tags here) 541 SubDirectory => { 542 TagTable => 'Image::ExifTool::XMP::Main', 543 Start => 16, 544 }, 545 }, 546 { #11 (MP4 files) 547 Name => 'UUID-PROF', 548 Condition => '$$valPt=~/^PROF!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/', 549 SubDirectory => { 550 TagTable => 'Image::ExifTool::QuickTime::Profile', 551 Start => 24, # uid(16) + version(1) + flags(3) + count(4) 552 }, 553 }, 554 { #PH (Flip MP4 files) 555 Name => 'UUID-Flip', 556 Condition => '$$valPt=~/^\x4a\xb0\x3b\x0f\x61\x8d\x40\x75\x82\xb2\xd9\xfa\xce\xd3\x5f\xf5/', 557 SubDirectory => { 558 TagTable => 'Image::ExifTool::QuickTime::Flip', 559 Start => 16, 560 }, 561 }, 562 # "\x98\x7f\xa3\xdf\x2a\x85\x43\xc0\x8f\x8f\xd9\x7c\x47\x1e\x8e\xea" - unknown data in Flip videos 563 { #PH (Canon CR3) 564 Name => 'UUID-Canon2', 565 WriteLast => 1, # MUST come after mdat or DPP will drop mdat when writing! 566 Condition => '$$valPt=~/^\x21\x0f\x16\x87\x91\x49\x11\xe4\x81\x11\x00\x24\x21\x31\xfc\xe4/', 567 SubDirectory => { 568 TagTable => 'Image::ExifTool::Canon::uuid2', 569 Start => 16, 570 }, 571 }, 572 { # (ref https://github.com/JamesHeinrich/getID3/blob/master/getid3/module.audio-video.quicktime.php) 573 Name => 'SensorData', # sensor data for the 360Fly 574 Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/ and $$self{OPTIONS}{ExtractEmbedded}', 575 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Tags360Fly' }, 576 }, 577 { 578 Name => 'SensorData', 579 Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/', 580 Notes => 'raw 360Fly sensor data without ExtractEmbedded option', 581 RawConv => q{ 582 $self->WarnOnce('Use the ExtractEmbedded option to decode timed SensorData',3); 583 return \$val; 584 }, 585 }, 586 { #PH (Canon CR3) 587 Name => 'PreviewImage', 588 Condition => '$$valPt=~/^\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16/', 589 Groups => { 2 => 'Preview' }, 590 # 0x00 - undef[16]: UUID 591 # 0x10 - int32u[2]: "0 1" (version and/or item count?) 592 # 0x18 - int32u: PRVW atom size 593 # 0x20 - int32u: 'PRVW' 594 # 0x30 - int32u: 0 595 # 0x34 - int16u: 1 596 # 0x36 - int16u: image width 597 # 0x38 - int16u: image height 598 # 0x3a - int16u: 1 599 # 0x3c - int32u: preview length 600 RawConv => '$val = substr($val, 0x30); $self->ValidateImage(\$val, $tag)', 601 }, 602 { #8 603 Name => 'UUID-Unknown', 604 %unknownInfo, 605 }, 606 ], 607 _htc => { 608 Name => 'HTCInfo', 609 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HTCInfo' }, 610 }, 611 udta => { 612 Name => 'UserData', 613 SubDirectory => { TagTable => 'Image::ExifTool::FLIR::UserData' }, 614 }, 615 thum => { #PH 616 Name => 'ThumbnailImage', 617 Groups => { 2 => 'Preview' }, 618 Binary => 1, 619 }, 620 'thm ' => { #PH (70mai A800) 621 Name => 'ThumbnailImage', 622 Groups => { 2 => 'Preview' }, 623 Binary => 1, 624 }, 625 ardt => { #PH 626 Name => 'ARDroneFile', 627 ValueConv => 'length($val) > 4 ? substr($val,4) : $val', # remove length 628 }, 629 prrt => { #PH 630 Name => 'ARDroneTelemetry', 631 Notes => q{ 632 telemetry information for each video frame: status1, status2, time, pitch, 633 roll, yaw, speed, altitude 634 }, 635 ValueConv => q{ 636 my $size = length $val; 637 return \$val if $size < 12 or not $$self{OPTIONS}{Binary}; 638 my $len = Get16u(\$val, 2); 639 my $str = ''; 640 SetByteOrder('II'); 641 my $pos = 12; 642 while ($pos + $len <= $size) { 643 my $s1 = Get16u(\$val, $pos); 644 # s2: 7=take-off?, 3=moving, 4=hovering, 9=landing?, 2=landed 645 my $s2 = Get16u(\$val, $pos + 2); 646 $str .= "$s1 $s2"; 647 my $num = int(($len-4)/4); 648 my ($i, $v); 649 for ($i=0; $i<$num; ++$i) { 650 my $pt = $pos + 4 + $i * 4; 651 if ($i > 0 && $i < 4) { 652 $v = GetFloat(\$val, $pt); # pitch/roll/yaw 653 } else { 654 $v = Get32u(\$val, $pt); 655 # convert time to sec, and speed(NC)/altitude to metres 656 $v /= 1000 if $i <= 5; 657 } 658 $str .= " $v"; 659 } 660 $str .= "\n"; 661 $pos += $len; 662 } 663 SetByteOrder('MM'); 664 return \$str; 665 }, 666 }, 667 udat => { #PH (GPS NMEA-format log written by Datakam Player software) 668 Name => 'GPSLog', 669 Binary => 1, # (actually ASCII, but very lengthy) 670 }, 671 # meta - proprietary XML information written by some Flip cameras - PH 672 # beam - 16 bytes found in an iPhone video 673 IDIT => { #PH (written by DuDuBell M1, VSYS M6L dashcams) 674 Name => 'DateTimeOriginal', 675 Description => 'Date/Time Original', 676 Groups => { 2 => 'Time' }, 677 Format => 'string', # (removes trailing "\0") 678 Shift => 'Time', 679 Writable => 1, 680 Permanent => 1, 681 DelValue => '0000-00-00T00:00:00+0000', 682 ValueConv => '$val=~tr/-/:/; $val', 683 ValueConvInv => '$val=~s/(\d+):(\d+):/$1-$2-/; $val', 684 PrintConv => '$self->ConvertDateTime($val)', 685 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 686 }, 687 gps0 => { #PH (DuDuBell M1, VSYS M6L) 688 Name => 'GPSTrack', 689 SubDirectory => { 690 TagTable => 'Image::ExifTool::QuickTime::Stream', 691 ProcessProc => \&Process_gps0, 692 }, 693 }, 694 gsen => { #PH (DuDuBell M1, VSYS M6L) 695 Name => 'GSensor', 696 SubDirectory => { 697 TagTable => 'Image::ExifTool::QuickTime::Stream', 698 ProcessProc => \&Process_gsen, 699 }, 700 }, 701 # gpsa - seen hex "01 20 00 00" (DuDuBell M1, VSYS M6L) 702 # gsea - 20 bytes hex "05 00's..." (DuDuBell M1) "05 08 02 01 ..." (VSYS M6L) 703 'GPS ' => { # GPS data written by 70mai dashcam (parsed in QuickTimeStream.pl) 704 Name => 'GPSDataList2', 705 Unknown => 1, 706 Binary => 1, 707 }, 708); 709 710# MPEG-4 'ftyp' atom 711# (ref http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html) 712%Image::ExifTool::QuickTime::FileType = ( 713 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 714 GROUPS => { 2 => 'Video' }, 715 FORMAT => 'int32u', 716 0 => { 717 Name => 'MajorBrand', 718 Format => 'undef[4]', 719 PrintConv => \%ftypLookup, 720 }, 721 1 => { 722 Name => 'MinorVersion', 723 Format => 'undef[4]', 724 ValueConv => 'sprintf("%x.%x.%x", unpack("nCC", $val))', 725 }, 726 2 => { 727 Name => 'CompatibleBrands', 728 Format => 'undef[$size-8]', 729 # ignore any entry with a null, and return others as a list 730 ValueConv => 'my @a=($val=~/.{4}/sg); @a=grep(!/\0/,@a); \@a', 731 }, 732); 733 734# proprietary HTC atom (HTC One MP4 video) 735%Image::ExifTool::QuickTime::HTCInfo = ( 736 PROCESS_PROC => \&ProcessMOV, 737 GROUPS => { 2 => 'Video' }, 738 NOTES => 'Tags written by some HTC camera phones.', 739 slmt => { 740 Name => 'Unknown_slmt', 741 Unknown => 1, 742 Format => 'int32u', # (observed values: 4) 743 }, 744); 745 746# atoms used in QTIF files 747%Image::ExifTool::QuickTime::ImageFile = ( 748 PROCESS_PROC => \&ProcessMOV, 749 GROUPS => { 2 => 'Image' }, 750 NOTES => 'Tags used in QTIF QuickTime Image Files.', 751 idsc => { 752 Name => 'ImageDescription', 753 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ImageDesc' }, 754 }, 755 idat => { 756 Name => 'ImageData', 757 Binary => 1, 758 }, 759 iicc => { 760 Name => 'ICC_Profile', 761 SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' }, 762 }, 763); 764 765# image description data block 766%Image::ExifTool::QuickTime::ImageDesc = ( 767 PROCESS_PROC => \&ProcessHybrid, 768 VARS => { ID_LABEL => 'ID/Index' }, 769 GROUPS => { 2 => 'Image' }, 770 FORMAT => 'int16u', 771 2 => { 772 Name => 'CompressorID', 773 Format => 'string[4]', 774# not very useful since this isn't a complete list and name is given below 775# # ref http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html 776# PrintConv => { 777# cvid => 'Cinepak', 778# jpeg => 'JPEG', 779# 'smc '=> 'Graphics', 780# 'rle '=> 'Animation', 781# rpza => 'Apple Video', 782# kpcd => 'Kodak Photo CD', 783# 'png '=> 'Portable Network Graphics', 784# mjpa => 'Motion-JPEG (format A)', 785# mjpb => 'Motion-JPEG (format B)', 786# SVQ1 => 'Sorenson video, version 1', 787# SVQ3 => 'Sorenson video, version 3', 788# mp4v => 'MPEG-4 video', 789# 'dvc '=> 'NTSC DV-25 video', 790# dvcp => 'PAL DV-25 video', 791# 'gif '=> 'Compuserve Graphics Interchange Format', 792# h263 => 'H.263 video', 793# tiff => 'Tagged Image File Format', 794# 'raw '=> 'Uncompressed RGB', 795# '2vuY'=> "Uncompressed Y'CbCr, 3x8-bit 4:2:2 (2vuY)", 796# 'yuv2'=> "Uncompressed Y'CbCr, 3x8-bit 4:2:2 (yuv2)", 797# v308 => "Uncompressed Y'CbCr, 8-bit 4:4:4", 798# v408 => "Uncompressed Y'CbCr, 8-bit 4:4:4:4", 799# v216 => "Uncompressed Y'CbCr, 10, 12, 14, or 16-bit 4:2:2", 800# v410 => "Uncompressed Y'CbCr, 10-bit 4:4:4", 801# v210 => "Uncompressed Y'CbCr, 10-bit 4:2:2", 802# hvc1 => 'HEVC', #PH 803# }, 804 }, 805 10 => { 806 Name => 'VendorID', 807 Format => 'string[4]', 808 RawConv => 'length $val ? $val : undef', 809 PrintConv => \%vendorID, 810 SeparateTable => 'VendorID', 811 }, 812 # 14 - ("Quality" in QuickTime docs) ?? 813 16 => 'SourceImageWidth', 814 17 => 'SourceImageHeight', 815 18 => { Name => 'XResolution', Format => 'fixed32u' }, 816 20 => { Name => 'YResolution', Format => 'fixed32u' }, 817 # 24 => 'FrameCount', # always 1 (what good is this?) 818 25 => { 819 Name => 'CompressorName', 820 Format => 'string[32]', 821 # (sometimes this is a Pascal string, and sometimes it is a C string) 822 RawConv => q{ 823 $val=substr($val,1,ord($1)) if $val=~/^([\0-\x1f])/ and ord($1)<length($val); 824 length $val ? $val : undef; 825 }, 826 }, 827 41 => 'BitDepth', 828# 829# Observed offsets for child atoms of various CompressorID types: 830# 831# CompressorID Offset Child atoms 832# ----------- ------ ---------------- 833# avc1 86 avcC, btrt, colr, pasp, fiel, clap, svcC 834# mp4v 86 esds, pasp 835# s263 86 d263 836# 837 btrt => { 838 Name => 'BitrateInfo', 839 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Bitrate' }, 840 }, 841 # Reference for fiel, colr, pasp, clap: 842 # https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9 843 fiel => { 844 Name => 'VideoFieldOrder', 845 ValueConv => 'join(" ", unpack("C*",$val))', 846 PrintConv => [{ 847 1 => 'Progressive', 848 2 => '2:1 Interlaced', 849 }], 850 }, 851 colr => { 852 Name => 'ColorRepresentation', 853 ValueConv => 'join(" ", substr($val,0,4), unpack("x4n*",$val))', 854 }, 855 pasp => { 856 Name => 'PixelAspectRatio', 857 ValueConv => 'join(":", unpack("N*",$val))', 858 }, 859 clap => { 860 Name => 'CleanAperture', 861 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::CleanAperture' }, 862 }, 863 avcC => { 864 # (see http://thompsonng.blogspot.ca/2010/11/mp4-file-format-part-2.html) 865 Name => 'AVCConfiguration', 866 Unknown => 1, 867 Binary => 1, 868 }, 869 JPEG => { # (found in CR3 images; used as a flag to identify JpgFromRaw 'vide' stream) 870 Name => 'JPEGInfo', 871 # (4 bytes all zero) 872 Unknown => 1, 873 Binary => 1, 874 }, 875 # hvcC - HEVC configuration 876 # svcC - 7 bytes: 00 00 00 00 ff e0 00 877 # esds - elementary stream descriptor 878 # d263 879 gama => { Name => 'Gamma', Format => 'fixed32u' }, 880 # mjqt - default quantization table for MJPEG 881 # mjht - default Huffman table for MJPEG 882 # csgm ? (seen in hevc video) 883 CMP1 => { # Canon CR3 884 Name => 'CMP1', 885 SubDirectory => { TagTable => 'Image::ExifTool::Canon::CMP1' }, 886 }, 887 CDI1 => { # Canon CR3 888 Name => 'CDI1', 889 SubDirectory => { 890 TagTable => 'Image::ExifTool::Canon::CDI1', 891 Start => 4, 892 }, 893 }, 894 # JPEG - 4 bytes all 0 (Canon CR3) 895 # free - (Canon CR3) 896# 897# spherical video v2 stuff (untested) 898# 899 st3d => { 900 Name => 'Stereoscopic3D', 901 Format => 'int8u', 902 ValueConv => '$val =~ s/.* //; $val', # (remove leading version/flags bytes?) 903 PrintConv => { 904 0 => 'Monoscopic', 905 1 => 'Stereoscopic Top-Bottom', 906 2 => 'Stereoscopic Left-Right', 907 3 => 'Stereoscopic Stereo-Custom', # (provisional in spec as of 2017-10-10) 908 }, 909 }, 910 sv3d => { 911 Name => 'SphericalVideo', 912 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::sv3d' }, 913 }, 914); 915 916# 'sv3d' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 917%Image::ExifTool::QuickTime::sv3d = ( 918 PROCESS_PROC => \&ProcessMOV, 919 GROUPS => { 2 => 'Video' }, 920 NOTES => q{ 921 Tags defined by the Spherical Video V2 specification. See 922 L<https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md> 923 for the specification. 924 }, 925 svhd => { 926 Name => 'MetadataSource', 927 Format => 'undef', 928 ValueConv => '$val=~tr/\0//d; $val', # (remove version/flags? and terminator?) 929 }, 930 proj => { 931 Name => 'Projection', 932 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::proj' }, 933 }, 934); 935 936# 'proj' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 937%Image::ExifTool::QuickTime::proj = ( 938 PROCESS_PROC => \&ProcessMOV, 939 GROUPS => { 2 => 'Video' }, 940 prhd => { 941 Name => 'ProjectionHeader', 942 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::prhd' }, 943 }, 944 cbmp => { 945 Name => 'CubemapProj', 946 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::cbmp' }, 947 }, 948 equi => { 949 Name => 'EquirectangularProj', 950 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::equi' }, 951 }, 952 # mshp - MeshProjection (P.I.T.A. to decode, for not much reward, see ref) 953); 954 955# 'prhd' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 956%Image::ExifTool::QuickTime::prhd = ( 957 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 958 GROUPS => { 2 => 'Video' }, 959 FORMAT => 'fixed32s', 960 # 0 - version (high 8 bits) / flags (low 24 bits) 961 1 => 'PoseYawDegrees', 962 2 => 'PosePitchDegrees', 963 3 => 'PoseRollDegrees', 964); 965 966# 'cbmp' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 967%Image::ExifTool::QuickTime::cbmp = ( 968 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 969 GROUPS => { 2 => 'Video' }, 970 FORMAT => 'int32u', 971 # 0 - version (high 8 bits) / flags (low 24 bits) 972 1 => 'Layout', 973 2 => 'Padding', 974); 975 976# 'equi' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md) 977%Image::ExifTool::QuickTime::equi = ( 978 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 979 GROUPS => { 2 => 'Video' }, 980 FORMAT => 'int32u', # (actually 0.32 fixed point) 981 # 0 - version (high 8 bits) / flags (low 24 bits) 982 1 => { Name => 'ProjectionBoundsTop', ValueConv => '$val / 4294967296' }, 983 2 => { Name => 'ProjectionBoundsBottom',ValueConv => '$val / 4294967296' }, 984 3 => { Name => 'ProjectionBoundsLeft', ValueConv => '$val / 4294967296' }, 985 4 => { Name => 'ProjectionBoundsRight', ValueConv => '$val / 4294967296' }, 986); 987 988# 'btrt' atom information (ref http://lists.freedesktop.org/archives/gstreamer-commits/2011-October/054459.html) 989%Image::ExifTool::QuickTime::Bitrate = ( 990 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 991 GROUPS => { 2 => 'Video' }, 992 FORMAT => 'int32u', 993 PRIORITY => 0, # often filled with zeros 994 0 => 'BufferSize', 995 1 => 'MaxBitrate', 996 2 => 'AverageBitrate', 997); 998 999# 'clap' atom information (ref https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9) 1000%Image::ExifTool::QuickTime::CleanAperture = ( 1001 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1002 GROUPS => { 2 => 'Video' }, 1003 FORMAT => 'rational64s', 1004 0 => 'CleanApertureWidth', 1005 1 => 'CleanApertureHeight', 1006 2 => 'CleanApertureOffsetX', 1007 3 => 'CleanApertureOffsetY', 1008); 1009 1010# preview data block 1011%Image::ExifTool::QuickTime::Preview = ( 1012 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1013 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1014 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 1015 GROUPS => { 2 => 'Image' }, 1016 FORMAT => 'int16u', 1017 0 => { 1018 Name => 'PreviewDate', 1019 Format => 'int32u', 1020 Groups => { 2 => 'Time' }, 1021 %timeInfo, 1022 }, 1023 2 => 'PreviewVersion', 1024 3 => { 1025 Name => 'PreviewAtomType', 1026 Format => 'string[4]', 1027 }, 1028 5 => 'PreviewAtomIndex', 1029); 1030 1031# movie atoms 1032%Image::ExifTool::QuickTime::Movie = ( 1033 PROCESS_PROC => \&ProcessMOV, 1034 WRITE_PROC => \&WriteQuickTime, 1035 GROUPS => { 2 => 'Video' }, 1036 mvhd => { 1037 Name => 'MovieHeader', 1038 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieHeader' }, 1039 }, 1040 trak => { 1041 Name => 'Track', 1042 CanCreate => 0, # don't create this atom 1043 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' }, 1044 }, 1045 udta => { 1046 Name => 'UserData', 1047 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::UserData' }, 1048 }, 1049 meta => { # 'meta' is found here in my EX-F1 MOV sample - PH 1050 Name => 'Meta', 1051 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 1052 }, 1053 iods => { 1054 Name => 'InitialObjectDescriptor', 1055 Flags => ['Binary','Unknown'], 1056 }, 1057 uuid => [ 1058 { #11 (MP4 files) (also found in QuickTime::Track) 1059 Name => 'UUID-USMT', 1060 Condition => '$$valPt=~/^USMT!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/', 1061 SubDirectory => { 1062 TagTable => 'Image::ExifTool::QuickTime::UserMedia', 1063 Start => 16, 1064 }, 1065 }, 1066 { #PH (Canon SX280) 1067 Name => 'UUID-Canon', 1068 Condition => '$$valPt=~/^\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48/', 1069 SubDirectory => { 1070 TagTable => 'Image::ExifTool::Canon::uuid', 1071 Start => 16, 1072 }, 1073 }, 1074 { 1075 Name => 'UUID-Unknown', 1076 %unknownInfo, 1077 }, 1078 ], 1079 cmov => { 1080 Name => 'CompressedMovie', 1081 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::CMovie' }, 1082 }, 1083 htka => { # (written by HTC One M8 in slow-motion 1280x720 video - PH) 1084 Name => 'HTCTrack', 1085 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' }, 1086 }, 1087 'gps ' => { # GPS data written by Novatek cameras (parsed in QuickTimeStream.pl) 1088 Name => 'GPSDataList', 1089 Unknown => 1, 1090 Binary => 1, 1091 }, 1092 meco => { #ISO14496-12:2015 1093 Name => 'OtherMeta', 1094 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' }, 1095 }, 1096 # prfl - Profile (ref 12) 1097 # clip - clipping --> contains crgn (clip region) (ref 12) 1098 # mvex - movie extends --> contains mehd (movie extends header), trex (track extends) (ref 14) 1099 # ICAT - 4 bytes: "6350" (Nikon CoolPix S6900), "6500" (Panasonic FT7) 1100); 1101 1102# (ref CFFMediaFormat-2_1.pdf) 1103%Image::ExifTool::QuickTime::MovieFragment = ( 1104 PROCESS_PROC => \&ProcessMOV, 1105 WRITE_PROC => \&WriteQuickTime, 1106 GROUPS => { 2 => 'Video' }, 1107 mfhd => { 1108 Name => 'MovieFragmentHeader', 1109 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieFragHdr' }, 1110 }, 1111 traf => { 1112 Name => 'TrackFragment', 1113 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackFragment' }, 1114 }, 1115 meta => { #ISO14496-12:2015 1116 Name => 'Meta', 1117 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 1118 }, 1119); 1120 1121# (ref CFFMediaFormat-2_1.pdf) 1122%Image::ExifTool::QuickTime::MovieFragHdr = ( 1123 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1124 GROUPS => { 2 => 'Video' }, 1125 FORMAT => 'int32u', 1126 1 => 'MovieFragmentSequence', 1127); 1128 1129# (ref CFFMediaFormat-2_1.pdf) 1130%Image::ExifTool::QuickTime::TrackFragment = ( 1131 PROCESS_PROC => \&ProcessMOV, 1132 WRITE_PROC => \&WriteQuickTime, 1133 GROUPS => { 2 => 'Video' }, 1134 meta => { #ISO14496-12:2015 1135 Name => 'Meta', 1136 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 1137 }, 1138 # tfhd - track fragment header 1139 # edts - edits --> contains elst (edit list) (ref PH) 1140 # tfdt - track fragment base media decode time 1141 # trik - trick play box 1142 # trun - track fragment run box 1143 # avcn - AVC NAL unit storage box 1144 # secn - sample encryption box 1145 # saio - sample auxiliary information offsets box 1146 # sbgp - sample to group box 1147 # sgpd - sample group description box 1148 # sdtp - independent and disposable samples (ref 5) 1149 # subs - sub-sample information (ref 5) 1150); 1151 1152# movie header data block 1153%Image::ExifTool::QuickTime::MovieHeader = ( 1154 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1155 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1156 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 1157 GROUPS => { 2 => 'Video' }, 1158 FORMAT => 'int32u', 1159 DATAMEMBER => [ 0, 1, 2, 3, 4 ], 1160 0 => { 1161 Name => 'MovieHeaderVersion', 1162 Format => 'int8u', 1163 RawConv => '$$self{MovieHeaderVersion} = $val', 1164 }, 1165 1 => { 1166 Name => 'CreateDate', 1167 Groups => { 2 => 'Time' }, 1168 %timeInfo, 1169 # this is int64u if MovieHeaderVersion == 1 (ref 13) 1170 Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4', 1171 }, 1172 2 => { 1173 Name => 'ModifyDate', 1174 Groups => { 2 => 'Time' }, 1175 %timeInfo, 1176 # this is int64u if MovieHeaderVersion == 1 (ref 13) 1177 Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4', 1178 }, 1179 3 => { 1180 Name => 'TimeScale', 1181 RawConv => '$$self{TimeScale} = $val', 1182 }, 1183 4 => { 1184 Name => 'Duration', 1185 %durationInfo, 1186 # this is int64u if MovieHeaderVersion == 1 (ref 13) 1187 Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4', 1188 }, 1189 5 => { 1190 Name => 'PreferredRate', 1191 ValueConv => '$val / 0x10000', 1192 }, 1193 6 => { 1194 Name => 'PreferredVolume', 1195 Format => 'int16u', 1196 ValueConv => '$val / 256', 1197 PrintConv => 'sprintf("%.2f%%", $val * 100)', 1198 }, 1199 9 => { 1200 Name => 'MatrixStructure', 1201 Format => 'fixed32s[9]', 1202 # (the right column is fixed 2.30 instead of 16.16) 1203 ValueConv => q{ 1204 my @a = split ' ',$val; 1205 $_ /= 0x4000 foreach @a[2,5,8]; 1206 return "@a"; 1207 }, 1208 }, 1209 18 => { Name => 'PreviewTime', %durationInfo }, 1210 19 => { Name => 'PreviewDuration', %durationInfo }, 1211 20 => { Name => 'PosterTime', %durationInfo }, 1212 21 => { Name => 'SelectionTime', %durationInfo }, 1213 22 => { Name => 'SelectionDuration',%durationInfo }, 1214 23 => { Name => 'CurrentTime', %durationInfo }, 1215 24 => 'NextTrackID', 1216); 1217 1218# track atoms 1219%Image::ExifTool::QuickTime::Track = ( 1220 PROCESS_PROC => \&ProcessMOV, 1221 WRITE_PROC => \&WriteQuickTime, 1222 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 1223 tkhd => { 1224 Name => 'TrackHeader', 1225 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackHeader' }, 1226 }, 1227 udta => { 1228 Name => 'UserData', 1229 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::UserData' }, 1230 }, 1231 mdia => { #MP4 1232 Name => 'Media', 1233 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Media' }, 1234 }, 1235 meta => { #PH (MOV) 1236 Name => 'Meta', 1237 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 1238 }, 1239 tref => { 1240 Name => 'TrackRef', 1241 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackRef' }, 1242 }, 1243 tapt => { 1244 Name => 'TrackAperture', 1245 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackAperture' }, 1246 }, 1247 uuid => [ 1248 { #11 (MP4 files) (also found in QuickTime::Movie) 1249 Name => 'UUID-USMT', 1250 Condition => '$$valPt=~/^USMT!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/', 1251 SubDirectory => { 1252 TagTable => 'Image::ExifTool::QuickTime::UserMedia', 1253 Start => 16, 1254 }, 1255 }, 1256 { #https://github.com/google/spatial-media/blob/master/docs/spherical-video-rfc.md 1257 Name => 'SphericalVideoXML', 1258 Condition => '$$valPt=~/^\xff\xcc\x82\x63\xf8\x55\x4a\x93\x88\x14\x58\x7a\x02\x52\x1f\xdd/', 1259 WriteGroup => 'GSpherical', # write only GSpherical XMP tags here 1260 HandlerType => 'vide', # only write in video tracks 1261 SubDirectory => { 1262 TagTable => 'Image::ExifTool::XMP::Main', 1263 Start => 16, 1264 WriteProc => 'Image::ExifTool::XMP::WriteGSpherical', 1265 }, 1266 }, 1267 { 1268 Name => 'UUID-Unknown', 1269 %unknownInfo, 1270 }, 1271 ], 1272 meco => { #ISO14492-12:2015 pg 83 1273 Name => 'OtherMeta', 1274 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' }, 1275 }, 1276 # edts - edits --> contains elst (edit list) 1277 # clip - clipping --> contains crgn (clip region) 1278 # matt - track matt --> contains kmat (compressed matt) 1279 # load - track loading settings 1280 # imap - track input map --> contains ' in' --> contains ' ty', obid 1281 # prfl - Profile (ref 12) 1282); 1283 1284# track header data block 1285%Image::ExifTool::QuickTime::TrackHeader = ( 1286 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1287 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1288 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 1289 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 1290 FORMAT => 'int32u', 1291 DATAMEMBER => [ 0, 1, 2, 5, 7 ], 1292 0 => { 1293 Name => 'TrackHeaderVersion', 1294 Format => 'int8u', 1295 Priority => 0, 1296 RawConv => '$$self{TrackHeaderVersion} = $val', 1297 }, 1298 1 => { 1299 Name => 'TrackCreateDate', 1300 Priority => 0, 1301 Groups => { 2 => 'Time' }, 1302 %timeInfo, 1303 # this is int64u if TrackHeaderVersion == 1 (ref 13) 1304 Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4', 1305 }, 1306 2 => { 1307 Name => 'TrackModifyDate', 1308 Priority => 0, 1309 Groups => { 2 => 'Time' }, 1310 %timeInfo, 1311 # this is int64u if TrackHeaderVersion == 1 (ref 13) 1312 Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4', 1313 }, 1314 3 => { 1315 Name => 'TrackID', 1316 Priority => 0, 1317 }, 1318 5 => { 1319 Name => 'TrackDuration', 1320 Priority => 0, 1321 %durationInfo, 1322 # this is int64u if TrackHeaderVersion == 1 (ref 13) 1323 Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4', 1324 }, 1325 7 => { # (used only for writing MatrixStructure) 1326 Name => 'ImageSizeLookahead', 1327 Hidden => 1, 1328 Format => 'int32u[14]', 1329 RawConv => '$$self{ImageSizeLookahead} = $val; undef', 1330 }, 1331 8 => { 1332 Name => 'TrackLayer', 1333 Format => 'int16u', 1334 Priority => 0, 1335 }, 1336 9 => { 1337 Name => 'TrackVolume', 1338 Format => 'int16u', 1339 Priority => 0, 1340 ValueConv => '$val / 256', 1341 PrintConv => 'sprintf("%.2f%%", $val * 100)', 1342 }, 1343 10 => { 1344 Name => 'MatrixStructure', 1345 Format => 'fixed32s[9]', 1346 Notes => 'writable for the video track via the Composite Rotation tag', 1347 Writable => 1, 1348 Protected => 1, 1349 Permanent => 1, 1350 # only set rotation if image size is non-zero 1351 RawConvInv => \&GetMatrixStructure, 1352 # (the right column is fixed 2.30 instead of 16.16) 1353 ValueConv => q{ 1354 my @a = split ' ',$val; 1355 $_ /= 0x4000 foreach @a[2,5,8]; 1356 return "@a"; 1357 }, 1358 ValueConvInv => q{ 1359 my @a = split ' ',$val; 1360 $_ *= 0x4000 foreach @a[2,5,8]; 1361 return "@a"; 1362 }, 1363 }, 1364 19 => { 1365 Name => 'ImageWidth', 1366 Priority => 0, 1367 RawConv => \&FixWrongFormat, 1368 }, 1369 20 => { 1370 Name => 'ImageHeight', 1371 Priority => 0, 1372 RawConv => \&FixWrongFormat, 1373 }, 1374); 1375 1376# user data atoms 1377%Image::ExifTool::QuickTime::UserData = ( 1378 PROCESS_PROC => \&ProcessMOV, 1379 WRITE_PROC => \&WriteQuickTime, 1380 CHECK_PROC => \&CheckQTValue, 1381 GROUPS => { 1 => 'UserData', 2 => 'Video' }, 1382 WRITABLE => 1, 1383 PREFERRED => 1, # (preferred over Keys tags when writing) 1384 FORMAT => 'string', 1385 WRITE_GROUP => 'UserData', 1386 LANG_INFO => \&GetLangInfo, 1387 NOTES => q{ 1388 Tag ID's beginning with the copyright symbol (hex 0xa9) are multi-language 1389 text. Alternate language tags are accessed by adding a dash followed by a 1390 3-character ISO 639-2 language code to the tag name. ExifTool will extract 1391 any multi-language user data tags found, even if they aren't in this table. 1392 Note when creating new tags, 1393 L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags are 1394 preferred over these, so to create the tag when a same-named ItemList tag 1395 exists, either "UserData" must be specified (eg. C<-UserData:Artist=Monet> 1396 on the command line), or the PREFERRED level must be changed via 1397 L<the config file|../config.html#PREF>. 1398 }, 1399 "\xa9cpy" => { Name => 'Copyright', Groups => { 2 => 'Author' } }, 1400 "\xa9day" => { 1401 Name => 'ContentCreateDate', 1402 Groups => { 2 => 'Time' }, 1403 Shift => 'Time', 1404 # handle values in the form "2010-02-12T13:27:14-0800" (written by Apple iPhone) 1405 ValueConv => q{ 1406 require Image::ExifTool::XMP; 1407 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 1408 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 1409 return $val; 1410 }, 1411 ValueConvInv => q{ 1412 require Image::ExifTool::XMP; 1413 my $tmp = Image::ExifTool::XMP::FormatXMPDate($val); 1414 ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon 1415 return $val; 1416 }, 1417 PrintConv => '$self->ConvertDateTime($val)', 1418 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 1419 }, 1420 "\xa9ART" => 'Artist', #PH (iTunes 8.0.2) 1421 "\xa9alb" => 'Album', #PH (iTunes 8.0.2) 1422 "\xa9arg" => 'Arranger', #12 1423 "\xa9ark" => 'ArrangerKeywords', #12 1424 "\xa9cmt" => 'Comment', #PH (iTunes 8.0.2) 1425 "\xa9cok" => 'ComposerKeywords', #12 1426 "\xa9com" => 'Composer', #12 1427 "\xa9dir" => 'Director', #12 1428 "\xa9ed1" => 'Edit1', 1429 "\xa9ed2" => 'Edit2', 1430 "\xa9ed3" => 'Edit3', 1431 "\xa9ed4" => 'Edit4', 1432 "\xa9ed5" => 'Edit5', 1433 "\xa9ed6" => 'Edit6', 1434 "\xa9ed7" => 'Edit7', 1435 "\xa9ed8" => 'Edit8', 1436 "\xa9ed9" => 'Edit9', 1437 "\xa9fmt" => 'Format', 1438 "\xa9gen" => 'Genre', #PH (iTunes 8.0.2) 1439 "\xa9grp" => 'Grouping', #PH (NC) 1440 "\xa9inf" => 'Information', 1441 "\xa9isr" => 'ISRCCode', #12 1442 "\xa9lab" => 'RecordLabelName', #12 1443 "\xa9lal" => 'RecordLabelURL', #12 1444 "\xa9lyr" => 'Lyrics', #PH (NC) 1445 "\xa9mak" => 'Make', #12 1446 "\xa9mal" => 'MakerURL', #12 1447 "\xa9mod" => 'Model', #PH 1448 "\xa9nam" => 'Title', #12 1449 "\xa9pdk" => 'ProducerKeywords', #12 1450 "\xa9phg" => 'RecordingCopyright', #12 1451 "\xa9prd" => 'Producer', 1452 "\xa9prf" => 'Performers', 1453 "\xa9prk" => 'PerformerKeywords', #12 1454 "\xa9prl" => 'PerformerURL', 1455 "\xa9req" => 'Requirements', 1456 "\xa9snk" => 'SubtitleKeywords', #12 1457 "\xa9snm" => 'Subtitle', #12 1458 "\xa9src" => 'SourceCredits', #12 1459 "\xa9swf" => 'SongWriter', #12 1460 "\xa9swk" => 'SongWriterKeywords', #12 1461 "\xa9swr" => 'SoftwareVersion', #12 1462 "\xa9too" => 'Encoder', #PH (NC) 1463 "\xa9trk" => 'Track', #PH (NC) 1464 "\xa9wrt" => { Name => 'Composer', Avoid => 1 }, # ("\xa9com" is preferred in UserData) 1465 "\xa9xyz" => { #PH (iPhone 3GS) 1466 Name => 'GPSCoordinates', 1467 Groups => { 2 => 'Location' }, 1468 ValueConv => \&ConvertISO6709, 1469 ValueConvInv => \&ConvInvISO6709, 1470 PrintConv => \&PrintGPSCoordinates, 1471 PrintConvInv => \&PrintInvGPSCoordinates, 1472 }, 1473 # \xa9 tags written by DJI Phantom 3: (ref PH) 1474 "\xa9xsp" => 'SpeedX', #PH (guess) 1475 "\xa9ysp" => 'SpeedY', #PH (guess) 1476 "\xa9zsp" => 'SpeedZ', #PH (guess) 1477 "\xa9fpt" => 'Pitch', #PH 1478 "\xa9fyw" => 'Yaw', #PH 1479 "\xa9frl" => 'Roll', #PH 1480 "\xa9gpt" => 'CameraPitch', #PH 1481 "\xa9gyw" => 'CameraYaw', #PH 1482 "\xa9grl" => 'CameraRoll', #PH 1483 "\xa9enc" => 'EncoderID', #PH (forum9271) 1484 # and the following entries don't have the proper 4-byte header for \xa9 tags: 1485 "\xa9dji" => { Name => 'UserData_dji', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 }, 1486 "\xa9res" => { Name => 'UserData_res', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 }, 1487 "\xa9uid" => { Name => 'UserData_uid', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 }, 1488 "\xa9mdl" => { 1489 Name => 'Model', 1490 Notes => 'non-standard-format DJI tag', 1491 Format => 'string', 1492 Avoid => 1, 1493 }, 1494 # end DJI tags 1495 name => 'Name', 1496 WLOC => { 1497 Name => 'WindowLocation', 1498 Format => 'int16u', 1499 }, 1500 LOOP => { 1501 Name => 'LoopStyle', 1502 Format => 'int32u', 1503 PrintConv => { 1504 1 => 'Normal', 1505 2 => 'Palindromic', 1506 }, 1507 }, 1508 SelO => { 1509 Name => 'PlaySelection', 1510 Format => 'int8u', 1511 }, 1512 AllF => { 1513 Name => 'PlayAllFrames', 1514 Format => 'int8u', 1515 }, 1516 meta => { 1517 Name => 'Meta', 1518 SubDirectory => { 1519 TagTable => 'Image::ExifTool::QuickTime::Meta', 1520 Start => 4, # must skip 4-byte version number header 1521 }, 1522 }, 1523 'ptv '=> { 1524 Name => 'PrintToVideo', 1525 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Video' }, 1526 }, 1527 hnti => { 1528 Name => 'HintInfo', 1529 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintInfo' }, 1530 }, 1531 hinf => { 1532 Name => 'HintTrackInfo', 1533 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintTrackInfo' }, 1534 }, 1535 hinv => 'HintVersion', #PH (guess) 1536 XMP_ => { #PH (Adobe CS3 Bridge) 1537 Name => 'XMP', 1538 WriteGroup => 'XMP', # (write main tags here) 1539 # *** this is where ExifTool writes XMP in MOV videos (as per XMP spec) *** 1540 SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' }, 1541 }, 1542 # the following are 3gp tags, references: 1543 # http://atomicparsley.sourceforge.net 1544 # http://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/TSGS4_25/Docs/ 1545 # (note that all %langText tags are Avoid => 1) 1546 cprt => { Name => 'Copyright', %langText, Groups => { 2 => 'Author' } }, 1547 auth => { Name => 'Author', %langText, Groups => { 2 => 'Author' } }, 1548 titl => { Name => 'Title', %langText }, 1549 dscp => { Name => 'Description',%langText }, 1550 perf => { Name => 'Performer', %langText }, 1551 gnre => { Name => 'Genre', %langText }, 1552 albm => { Name => 'Album', %langText }, 1553 coll => { Name => 'CollectionName', %langText }, #17 1554 rtng => { 1555 Name => 'Rating', 1556 # (4-byte flags, 4-char entity, 4-char criteria, 2-byte lang, string) 1557 RawConv => q{ 1558 return '<err>' unless length $val >= 14; 1559 my $str = 'Entity=' . substr($val,4,4) . ' Criteria=' . substr($val,8,4); 1560 $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters 1561 my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 12)); 1562 $lang = $lang ? "($lang) " : ''; 1563 $val = substr($val, 14); 1564 $val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/; 1565 return $lang . $str . ' ' . $val; 1566 }, 1567 }, 1568 clsf => { 1569 Name => 'Classification', 1570 # (4-byte flags, 4-char entity, 2-byte index, 2-byte lang, string) 1571 RawConv => q{ 1572 return '<err>' unless length $val >= 12; 1573 my $str = 'Entity=' . substr($val,4,4) . ' Index=' . Get16u(\$val,8); 1574 $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters 1575 my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 10)); 1576 $lang = $lang ? "($lang) " : ''; 1577 $val = substr($val, 12); 1578 $val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/; 1579 return $lang . $str . ' ' . $val; 1580 }, 1581 }, 1582 kywd => { 1583 Name => 'Keywords', 1584 # (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings) 1585 RawConv => q{ 1586 return '<err>' unless length $val >= 7; 1587 my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4)); 1588 $lang = $lang ? "($lang) " : ''; 1589 my $num = Get8u(\$val, 6); 1590 my ($i, @vals); 1591 my $pos = 7; 1592 for ($i=0; $i<$num; ++$i) { 1593 last if $pos >= length $val; 1594 my $len = Get8u(\$val, $pos++); 1595 last if $pos + $len > length $val; 1596 my $v = substr($val, $pos, $len); 1597 $v = $self->Decode($v, 'UCS2') if $v =~ /^\xfe\xff/; 1598 push @vals, $v; 1599 $pos += $len; 1600 } 1601 my $sep = $self->Options('ListSep'); 1602 return $lang . join($sep, @vals); 1603 }, 1604 }, 1605 loci => { 1606 Name => 'LocationInformation', 1607 Groups => { 2 => 'Location' }, 1608 # (4-byte flags, 2-byte lang, location string, 1-byte role, 4-byte fixed longitude, 1609 # 4-byte fixed latitude, 4-byte fixed altitude, body string, notes string) 1610 RawConv => q{ 1611 return '<err>' unless length $val >= 6; 1612 my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4)); 1613 $lang = $lang ? "($lang) " : ''; 1614 $val = substr($val, 6); 1615 my $str; 1616 if ($val =~ /^\xfe\xff/) { 1617 $val =~ s/^(\xfe\xff(.{2})*?)\0\0//s or return '<err>'; 1618 $str = $self->Decode($1, 'UCS2'); 1619 } else { 1620 $val =~ s/^(.*?)\0//s or return '<err>'; 1621 $str = $1; 1622 } 1623 $str = '(none)' unless length $str; 1624 return '<err>' if length $val < 13; 1625 my $role = Get8u(\$val, 0); 1626 my $lon = GetFixed32s(\$val, 1); 1627 my $lat = GetFixed32s(\$val, 5); 1628 my $alt = GetFixed32s(\$val, 9); 1629 my $roleStr = {0=>'shooting',1=>'real',2=>'fictional',3=>'reserved'}->{$role}; 1630 $str .= ' Role=' . ($roleStr || "unknown($role)"); 1631 $str .= sprintf(' Lat=%.5f Lon=%.5f Alt=%.2f', $lat, $lon, $alt); 1632 $val = substr($val, 13); 1633 if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) { 1634 $str .= ' Body=' . $self->Decode($1, 'UCS2'); 1635 } elsif ($val =~ s/^(.*?)\0//s) { 1636 $str .= " Body=$1"; 1637 } 1638 if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) { 1639 $str .= ' Notes=' . $self->Decode($1, 'UCS2'); 1640 } elsif ($val =~ s/^(.*?)\0//s) { 1641 $str .= " Notes=$1"; 1642 } 1643 return $lang . $str; 1644 }, 1645 }, 1646 yrrc => { 1647 Name => 'Year', 1648 Groups => { 2 => 'Time' }, 1649 RawConv => 'length($val) >= 6 ? Get16u(\$val,4) : "<err>"', 1650 }, 1651 urat => { #17 1652 Name => 'UserRating', 1653 RawConv => q{ 1654 return '<err>' unless length $val >= 8; 1655 return Get8u(\$val, 7); 1656 }, 1657 }, 1658 # tsel - TrackSelection (ref 17) 1659 # Apple tags (ref 16[dead] -- see ref 25 instead) 1660 angl => { Name => 'CameraAngle', Format => 'string' }, # (NC) 1661 clfn => { Name => 'ClipFileName', Format => 'string' }, # (NC) 1662 clid => { Name => 'ClipID', Format => 'string' }, # (NC) 1663 cmid => { Name => 'CameraID', Format => 'string' }, # (NC) 1664 cmnm => { # (NC) 1665 Name => 'Model', 1666 Description => 'Camera Model Name', 1667 Avoid => 1, 1668 Format => 'string', # (necessary to remove the trailing NULL) 1669 }, 1670 date => { 1671 Name => 'DateTimeOriginal', 1672 Description => 'Date/Time Original', 1673 Groups => { 2 => 'Time' }, 1674 Notes => q{ 1675 Apple Photos has been reported to show a crazy date/time for some MP4 files 1676 containing this tag, but perhaps only if it is missing a time zone 1677 }, #forum10690/11125 1678 Shift => 'Time', 1679 ValueConv => q{ 1680 require Image::ExifTool::XMP; 1681 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 1682 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 1683 return $val; 1684 }, 1685 ValueConvInv => q{ 1686 require Image::ExifTool::XMP; 1687 $val = Image::ExifTool::XMP::FormatXMPDate($val); 1688 $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon 1689 return $val; 1690 }, 1691 PrintConv => '$self->ConvertDateTime($val)', 1692 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 1693 }, 1694 manu => { # (SX280) 1695 Name => 'Make', 1696 Avoid => 1, 1697 # (with Canon there are 6 unknown bytes before the model: "\0\0\0\0\x15\xc7") 1698 RawConv => '$val=~s/^\0{4}..//s; $val=~s/\0.*//; $val', 1699 }, 1700 modl => { # (Samsung GT-S8530, Canon SX280) 1701 Name => 'Model', 1702 Description => 'Camera Model Name', 1703 Avoid => 1, 1704 # (with Canon there are 6 unknown bytes before the model: "\0\0\0\0\x15\xc7") 1705 RawConv => '$val=~s/^\0{4}..//s; $val=~s/\0.*//; $val', 1706 }, 1707 reel => { Name => 'ReelName', Format => 'string' }, # (NC) 1708 scen => { Name => 'Scene', Format => 'string' }, # (NC) 1709 shot => { Name => 'ShotName', Format => 'string' }, # (NC) 1710 slno => { Name => 'SerialNumber', Format => 'string' }, # (NC) 1711 apmd => { Name => 'ApertureMode', Format => 'undef' }, #20 1712 kgtt => { #http://lists.ffmpeg.org/pipermail/ffmpeg-devel-irc/2012-June/000707.html 1713 # 'TrackType' will expand to 'Track#Type' when found inside a track 1714 Name => 'TrackType', 1715 # set flag to process this as international text 1716 # even though the tag ID doesn't start with 0xa9 1717 IText => 4, # IText with 4-byte header 1718 }, 1719 chpl => { # (Nero chapter list) 1720 Name => 'ChapterList', 1721 ValueConv => \&ConvertChapterList, 1722 PrintConv => \&PrintChapter, 1723 }, 1724 # ndrm - 7 bytes (0 0 0 1 0 0 0) Nero Digital Rights Management? (PH) 1725 # other non-Apple tags (ref 16) 1726 # hpix - HipixRichPicture (ref 16, HIPIX) 1727 # strk - sub-track information (ref 16, ISO) 1728# 1729# Manufacturer-specific metadata 1730# 1731 TAGS => [ #PH 1732 # these tags were initially discovered in a Pentax movie, 1733 # but similar information is found in videos from other manufacturers 1734 { 1735 Name => 'FujiFilmTags', 1736 Condition => '$$valPt =~ /^FUJIFILM DIGITAL CAMERA\0/', 1737 SubDirectory => { 1738 TagTable => 'Image::ExifTool::FujiFilm::MOV', 1739 ByteOrder => 'LittleEndian', 1740 }, 1741 }, 1742 { 1743 Name => 'KodakTags', 1744 Condition => '$$valPt =~ /^EASTMAN KODAK COMPANY/', 1745 SubDirectory => { 1746 TagTable => 'Image::ExifTool::Kodak::MOV', 1747 ByteOrder => 'LittleEndian', 1748 }, 1749 }, 1750 { 1751 Name => 'KonicaMinoltaTags', 1752 Condition => '$$valPt =~ /^KONICA MINOLTA DIGITAL CAMERA/', 1753 SubDirectory => { 1754 TagTable => 'Image::ExifTool::Minolta::MOV1', 1755 ByteOrder => 'LittleEndian', 1756 }, 1757 }, 1758 { 1759 Name => 'MinoltaTags', 1760 Condition => '$$valPt =~ /^MINOLTA DIGITAL CAMERA/', 1761 SubDirectory => { 1762 TagTable => 'Image::ExifTool::Minolta::MOV2', 1763 ByteOrder => 'LittleEndian', 1764 }, 1765 }, 1766 { 1767 Name => 'NikonTags', 1768 Condition => '$$valPt =~ /^NIKON DIGITAL CAMERA\0/', 1769 SubDirectory => { 1770 TagTable => 'Image::ExifTool::Nikon::MOV', 1771 ByteOrder => 'LittleEndian', 1772 }, 1773 }, 1774 { 1775 Name => 'OlympusTags1', 1776 Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA\0.{9}\x01\0/s', 1777 SubDirectory => { 1778 TagTable => 'Image::ExifTool::Olympus::MOV1', 1779 ByteOrder => 'LittleEndian', 1780 }, 1781 }, 1782 { 1783 Name => 'OlympusTags2', 1784 Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA(?!\0.{21}\x0a\0{3})/s', 1785 SubDirectory => { 1786 TagTable => 'Image::ExifTool::Olympus::MOV2', 1787 ByteOrder => 'LittleEndian', 1788 }, 1789 }, 1790 { 1791 Name => 'OlympusTags3', 1792 Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA\0/', 1793 SubDirectory => { 1794 TagTable => 'Image::ExifTool::Olympus::MP4', 1795 ByteOrder => 'LittleEndian', 1796 }, 1797 }, 1798 { 1799 Name => 'OlympusTags4', 1800 Condition => '$$valPt =~ /^.{16}OLYM\0/s', 1801 SubDirectory => { 1802 TagTable => 'Image::ExifTool::Olympus::MOV3', 1803 Start => 12, 1804 }, 1805 }, 1806 { 1807 Name => 'PentaxTags', 1808 Condition => '$$valPt =~ /^PENTAX DIGITAL CAMERA\0/', 1809 SubDirectory => { 1810 TagTable => 'Image::ExifTool::Pentax::MOV', 1811 ByteOrder => 'LittleEndian', 1812 }, 1813 }, 1814 { 1815 Name => 'SamsungTags', 1816 Condition => '$$valPt =~ /^SAMSUNG DIGITAL CAMERA\0/', 1817 SubDirectory => { 1818 TagTable => 'Image::ExifTool::Samsung::MP4', 1819 ByteOrder => 'LittleEndian', 1820 }, 1821 }, 1822 { 1823 Name => 'SanyoMOV', 1824 Condition => q{ 1825 $$valPt =~ /^SANYO DIGITAL CAMERA\0/ and 1826 $self->{VALUE}->{FileType} eq "MOV" 1827 }, 1828 SubDirectory => { 1829 TagTable => 'Image::ExifTool::Sanyo::MOV', 1830 ByteOrder => 'LittleEndian', 1831 }, 1832 }, 1833 { 1834 Name => 'SanyoMP4', 1835 Condition => q{ 1836 $$valPt =~ /^SANYO DIGITAL CAMERA\0/ and 1837 $self->{VALUE}->{FileType} eq "MP4" 1838 }, 1839 SubDirectory => { 1840 TagTable => 'Image::ExifTool::Sanyo::MP4', 1841 ByteOrder => 'LittleEndian', 1842 }, 1843 }, 1844 { 1845 Name => 'UnknownTags', 1846 Unknown => 1, 1847 Binary => 1 1848 }, 1849 ], 1850 # ---- Canon ---- 1851 CNCV => { Name => 'CompressorVersion', Format => 'string' }, #PH (5D Mark II) 1852 CNMN => { 1853 Name => 'Model', #PH (EOS 550D) 1854 Description => 'Camera Model Name', 1855 Avoid => 1, 1856 Format => 'string', # (necessary to remove the trailing NULL) 1857 }, 1858 CNFV => { Name => 'FirmwareVersion', Format => 'string' }, #PH (EOS 550D) 1859 CNTH => { #PH (PowerShot S95) 1860 Name => 'CanonCNTH', 1861 SubDirectory => { TagTable => 'Image::ExifTool::Canon::CNTH' }, 1862 }, 1863 CNOP => { #PH (7DmkII) 1864 Name => 'CanonCNOP', 1865 SubDirectory => { TagTable => 'Image::ExifTool::Canon::CNOP' }, 1866 }, 1867 # CNDB - 2112 bytes (550D) 1868 # CNDM - 4 bytes - 0xff,0xd8,0xff,0xd9 (S95) 1869 # CNDG - 10232 bytes, mostly zeros (N100) 1870 # ---- Casio ---- 1871 QVMI => { #PH 1872 Name => 'CasioQVMI', 1873 # Casio stores standard EXIF-format information in MOV videos (eg. EX-S880) 1874 SubDirectory => { 1875 TagTable => 'Image::ExifTool::Exif::Main', 1876 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 1877 DirName => 'IFD0', 1878 Multi => 0, # (no NextIFD pointer) 1879 Start => 10, 1880 ByteOrder => 'BigEndian', 1881 }, 1882 }, 1883 # ---- FujiFilm ---- 1884 FFMV => { #PH (FinePix HS20EXR) 1885 Name => 'FujiFilmFFMV', 1886 SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::FFMV' }, 1887 }, 1888 MVTG => { #PH (FinePix HS20EXR) 1889 Name => 'FujiFilmMVTG', 1890 SubDirectory => { 1891 TagTable => 'Image::ExifTool::Exif::Main', 1892 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 1893 DirName => 'IFD0', 1894 Start => 16, 1895 Base => '$start', 1896 ByteOrder => 'LittleEndian', 1897 }, 1898 }, 1899 # ---- Garmin ---- (ref PH) 1900 uuid => [{ 1901 Name => 'GarminSoftware', # (NC) 1902 Condition => '$$valPt =~ /^VIRBactioncamera/', 1903 RawConv => 'substr($val, 16)', 1904 RawConvInv => '"VIRBactioncamera$val"', 1905 },{ 1906 # 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) 1907 Name => 'UUID-Unknown', 1908 Writable => 0, 1909 %unknownInfo, 1910 }], 1911 pmcc => { 1912 Name => 'GarminSettings', 1913 ValueConv => 'substr($val, 4)', 1914 ValueConvInv => '"\0\0\0\x01$val"', 1915 }, 1916 # hmtp - "\0\0\0\x01" followed by 408 bytes of zero 1917 # vrin - "\0\0\0\x01" followed by 8 bytes of zero 1918 # ---- GoPro ---- (ref PH) 1919 GoPr => 'GoProType', # (Hero3+) 1920 FIRM => { Name => 'FirmwareVersion', Avoid => 1 }, # (Hero4) 1921 LENS => 'LensSerialNumber', # (Hero4) 1922 CAME => { # (Hero4) 1923 Name => 'SerialNumberHash', 1924 Description => 'Camera Serial Number Hash', 1925 ValueConv => 'unpack("H*",$val)', 1926 ValueConvInv => 'pack("H*",$val)', 1927 }, 1928 # SETT? 12 bytes (Hero4) 1929 # MUID? 32 bytes (Hero4, starts with serial number hash) 1930 # HMMT? 404 bytes (Hero4, all zero) 1931 # BCID? 26 bytes (Hero5, all zero), 36 bytes GoPro Max 1932 # GUMI? 16 bytes (Hero5) 1933 "FOV\0" => 'FieldOfView', #forum8938 (Hero2) seen: "Wide" 1934 GPMF => { 1935 Name => 'GoProGPMF', 1936 SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' }, 1937 }, 1938 # free (all zero) 1939 "\xa9TSC" => 'StartTimeScale', # (Hero6) 1940 "\xa9TSZ" => 'StartTimeSampleSize', # (Hero6) 1941 "\xa9TIM" => 'StartTimecode', #PH (NC) 1942 # --- HTC ---- 1943 htcb => { 1944 Name => 'HTCBinary', 1945 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HTCBinary' }, 1946 }, 1947 # ---- Kodak ---- 1948 DcMD => { 1949 Name => 'KodakDcMD', 1950 SubDirectory => { TagTable => 'Image::ExifTool::Kodak::DcMD' }, 1951 }, 1952 SNum => { Name => 'SerialNumber', Avoid => 1, Groups => { 2 => 'Camera' } }, 1953 ptch => { Name => 'Pitch', Format => 'rational64s', Avoid => 1 }, # Units?? 1954 _yaw => { Name => 'Yaw', Format => 'rational64s', Avoid => 1 }, # Units?? 1955 roll => { Name => 'Roll', Format => 'rational64s', Avoid => 1 }, # Units?? 1956 _cx_ => { Name => 'CX', Format => 'rational64s', Unknown => 1 }, 1957 _cy_ => { Name => 'CY', Format => 'rational64s', Unknown => 1 }, 1958 rads => { Name => 'Rads', Format => 'rational64s', Unknown => 1 }, 1959 lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess) 1960 Lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess) 1961 pose => { Name => 'pose', SubDirectory => { TagTable => 'Image::ExifTool::Kodak::pose' } }, 1962 # AMBA => Ambarella AVC atom (unknown data written by Kodak Playsport video cam) 1963 # tmlp - 1 byte: 0 (PixPro SP360/4KVR360) 1964 # pivi - 72 bytes (PixPro SP360) 1965 # pive - 12 bytes (PixPro SP360) 1966 # loop - 4 bytes: 0 0 0 0 (PixPro 4KVR360) 1967 # m cm - 2 bytes: 0 0 (PixPro 4KVR360) 1968 # m ev - 2 bytes: 0 0 (PixPro SP360/4KVR360) (exposure comp?) 1969 # m vr - 2 bytes: 0 1 (PixPro 4KVR360) (virtual reality?) 1970 # m wb - 4 bytes: 0 0 0 0 (PixPro SP360/4KVR360) (white balance?) 1971 # mclr - 4 bytes: 0 0 0 0 (PixPro SP360/4KVR360) 1972 # mmtr - 4 bytes: 0,6 0 0 0 (PixPro SP360/4KVR360) 1973 # mflr - 4 bytes: 0 0 0 0 (PixPro SP360) 1974 # lvlm - 24 bytes (PixPro SP360) 1975 # Lvlm - 24 bytes (PixPro 4KVR360) 1976 # ufdm - 4 bytes: 0 0 0 1 (PixPro SP360) 1977 # mtdt - 1 byte: 0 (PixPro SP360/4KVR360) 1978 # gdta - 75240 bytes (PixPro SP360) 1979 # EIS1 - 4 bytes: 03 07 00 00 (PixPro 4KVR360) 1980 # EIS2 - 4 bytes: 04 97 00 00 (PixPro 4KVR360) 1981 # ---- LG ---- 1982 adzc => { Name => 'Unknown_adzc', Unknown => 1, Hidden => 1, %langText }, # "false\0/","true\0/" 1983 adze => { Name => 'Unknown_adze', Unknown => 1, Hidden => 1, %langText }, # "false\0/" 1984 adzm => { Name => 'Unknown_adzm', Unknown => 1, Hidden => 1, %langText }, # "\x0e\x04/","\x10\x06" 1985 # ---- Microsoft ---- 1986 Xtra => { #PH (microsoft) 1987 Name => 'MicrosoftXtra', 1988 SubDirectory => { TagTable => 'Image::ExifTool::Microsoft::Xtra' }, 1989 }, 1990 # ---- Minolta ---- 1991 MMA0 => { #PH (DiMage 7Hi) 1992 Name => 'MinoltaMMA0', 1993 SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' }, 1994 }, 1995 MMA1 => { #PH (Dimage A2) 1996 Name => 'MinoltaMMA1', 1997 SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' }, 1998 }, 1999 # ---- Nikon ---- 2000 NCDT => { #PH 2001 Name => 'NikonNCDT', 2002 SubDirectory => { TagTable => 'Image::ExifTool::Nikon::NCDT' }, 2003 }, 2004 # ---- Olympus ---- 2005 scrn => { #PH (TG-810) 2006 Name => 'OlympusPreview', 2007 Condition => '$$valPt =~ /^.{4}\xff\xd8\xff\xdb/s', 2008 SubDirectory => { TagTable => 'Image::ExifTool::Olympus::scrn' }, 2009 }, 2010 # ---- Panasonic/Leica ---- 2011 PANA => { #PH 2012 Name => 'PanasonicPANA', 2013 SubDirectory => { TagTable => 'Image::ExifTool::Panasonic::PANA' }, 2014 }, 2015 LEIC => { #PH 2016 Name => 'LeicaLEIC', 2017 SubDirectory => { TagTable => 'Image::ExifTool::Panasonic::PANA' }, 2018 }, 2019 # ---- Pentax ---- 2020 thmb => [ # (apparently defined by 3gpp, ref 16) 2021 { #PH (Pentax Q) 2022 Name => 'MakerNotePentax5a', 2023 Condition => '$$valPt =~ /^PENTAX \0II/', 2024 SubDirectory => { 2025 TagTable => 'Image::ExifTool::Pentax::Main', 2026 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 2027 Start => 10, 2028 Base => '$start - 10', 2029 ByteOrder => 'LittleEndian', 2030 }, 2031 },{ #PH (TG-810) 2032 Name => 'OlympusThumbnail', 2033 Condition => '$$valPt =~ /^.{4}\xff\xd8\xff\xdb/s', 2034 SubDirectory => { TagTable => 'Image::ExifTool::Olympus::thmb' }, 2035 },{ #17 (format is in bytes 3-7) 2036 Name => 'ThumbnailImage', 2037 Condition => '$$valPt =~ /^.{8}\xff\xd8\xff\xdb/s', 2038 Groups => { 2 => 'Preview' }, 2039 RawConv => 'substr($val, 8)', 2040 Binary => 1, 2041 },{ #17 (format is in bytes 3-7) 2042 Name => 'ThumbnailPNG', 2043 Condition => '$$valPt =~ /^.{8}\x89PNG\r\n\x1a\n/s', 2044 Groups => { 2 => 'Preview' }, 2045 RawConv => 'substr($val, 8)', 2046 Binary => 1, 2047 },{ 2048 Name => 'UnknownThumbnail', 2049 Groups => { 2 => 'Preview' }, 2050 Binary => 1, 2051 }, 2052 ], 2053 PENT => { #PH 2054 Name => 'PentaxPENT', 2055 SubDirectory => { 2056 TagTable => 'Image::ExifTool::Pentax::PENT', 2057 ByteOrder => 'LittleEndian', 2058 }, 2059 }, 2060 PXTH => { #PH (Pentax K-01) 2061 Name => 'PentaxPreview', 2062 SubDirectory => { TagTable => 'Image::ExifTool::Pentax::PXTH' }, 2063 }, 2064 PXMN => [{ #PH (Pentax K-01) 2065 Name => 'MakerNotePentax5b', 2066 Condition => '$$valPt =~ /^PENTAX \0MM/', 2067 SubDirectory => { 2068 TagTable => 'Image::ExifTool::Pentax::Main', 2069 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 2070 Start => 10, 2071 Base => '$start - 10', 2072 ByteOrder => 'BigEndian', 2073 }, 2074 },{ #PH (Pentax 645Z) 2075 Name => 'MakerNotePentax5c', 2076 Condition => '$$valPt =~ /^PENTAX \0II/', 2077 SubDirectory => { 2078 TagTable => 'Image::ExifTool::Pentax::Main', 2079 ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default) 2080 Start => 10, 2081 Base => '$start - 10', 2082 ByteOrder => 'LittleEndian', 2083 }, 2084 },{ 2085 Name => 'MakerNotePentaxUnknown', 2086 Binary => 1, 2087 }], 2088 # ---- Ricoh ---- 2089 RTHU => { #PH (GR) 2090 Name => 'PreviewImage', 2091 Groups => { 2 => 'Preview' }, 2092 RawConv => '$self->ValidateImage(\$val, $tag)', 2093 }, 2094 RMKN => { #PH (GR) 2095 Name => 'RicohRMKN', 2096 SubDirectory => { 2097 TagTable => 'Image::ExifTool::Exif::Main', 2098 ProcessProc => \&Image::ExifTool::ProcessTIFF, # (because ProcessMOV is default) 2099 }, 2100 }, 2101 '@mak' => { Name => 'Make', Avoid => 1 }, 2102 '@mod' => { Name => 'Model', Avoid => 1 }, 2103 '@swr' => { Name => 'SoftwareVersion', Avoid => 1 }, 2104 '@day' => { 2105 Name => 'ContentCreateDate', 2106 Notes => q{ 2107 some stupid Ricoh programmer used the '@' symbol instead of the copyright 2108 symbol in these tag ID's for the Ricoh Theta Z1 and maybe other models 2109 }, 2110 Groups => { 2 => 'Time' }, 2111 Shift => 'Time', 2112 Avoid => 1, 2113 # handle values in the form "2010-02-12T13:27:14-0800" 2114 ValueConv => q{ 2115 require Image::ExifTool::XMP; 2116 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 2117 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 2118 return $val; 2119 }, 2120 ValueConvInv => q{ 2121 require Image::ExifTool::XMP; 2122 my $tmp = Image::ExifTool::XMP::FormatXMPDate($val); 2123 ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon 2124 return $val; 2125 }, 2126 PrintConv => '$self->ConvertDateTime($val)', 2127 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 2128 }, 2129 '@xyz' => { #PH (iPhone 3GS) 2130 Name => 'GPSCoordinates', 2131 Groups => { 2 => 'Location' }, 2132 Avoid => 1, 2133 ValueConv => \&ConvertISO6709, 2134 ValueConvInv => \&ConvInvISO6709, 2135 PrintConv => \&PrintGPSCoordinates, 2136 PrintConvInv => \&PrintInvGPSCoordinates, 2137 }, 2138 # RDT1 - pairs of int32u_BE, starting at byte 8: "458275 471846" 2139 # RDT2 - pairs of int32u_BE, starting at byte 8: "472276 468526" 2140 # RDT3 - pairs of int32u_BE, starting at byte 8: "876603 482191" 2141 # RDT4 - pairs of int32u_BE, starting at byte 8: "1955 484612" 2142 # RDT6 - empty 2143 # RDT7 - empty 2144 # RDT8 - empty 2145 # RDT9 - only 16-byte header? 2146 # the boxes below all have a similar header (little-endian): 2147 # 0 int32u - number of records 2148 # 4 ? - "1e 00" 2149 # 6 int16u - record length in bytes 2150 # 8 ? - "23 01 00 00 00 00 00 00" 2151 # 16 - start of records (each record ends in an int64u timestamp in ns) 2152 # RDTA - float[4],ts: "-0.31289672 -0.2245330 11.303817 0 775.780" 2153 # RDTB - float[4],ts: "-0.04841613 -0.2166595 0.0724792 0 775.780" 2154 # RDTC - float[4],ts: "27.60925 -27.10037 -13.27285 0 775.829" 2155 # RDTD - int16s[3],ts: "353 -914 16354 0 775.829" 2156 # RDTG - ts: "775.825" 2157 # RDTI - float[4],ts: "0.00165951 0.005770059 0.06838259 0.1744695 775.862" 2158 # ---- Samsung ---- 2159 vndr => 'Vendor', #PH (Samsung PL70) 2160 SDLN => 'PlayMode', #PH (NC, Samsung ST80 "SEQ_PLAY") 2161 INFO => { 2162 Name => 'SamsungINFO', 2163 SubDirectory => { TagTable => 'Image::ExifTool::Samsung::INFO' }, 2164 }, 2165 '@sec' => { #PH (Samsung WB30F) 2166 Name => 'SamsungSec', 2167 SubDirectory => { TagTable => 'Image::ExifTool::Samsung::sec' }, 2168 }, 2169 'smta' => { #PH (Samsung SM-C101) 2170 Name => 'SamsungSmta', 2171 SubDirectory => { 2172 TagTable => 'Image::ExifTool::Samsung::smta', 2173 Start => 4, 2174 }, 2175 }, 2176 cver => 'CodeVersion', #PH (guess, Samsung MV900F) 2177 # ducp - 4 bytes all zero (Samsung ST96,WB750), 52 bytes all zero (Samsung WB30F) 2178 # edli - 52 bytes all zero (Samsung WB30F) 2179 # @etc - 4 bytes all zero (Samsung WB30F) 2180 # saut - 4 bytes all zero (Samsung SM-N900T) 2181 # smrd - string "TRUEBLUE" (Samsung SM-C101) 2182 # ---- TomTom Bandit Action Cam ---- 2183 TTMD => { 2184 Name => 'TomTomMetaData', 2185 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TomTom' }, 2186 }, 2187 # ---- Samsung Gear 360 ---- 2188 vrot => { 2189 Name => 'AccelerometerData', 2190 Notes => q{ 2191 accelerometer readings for each frame of the video, expressed as sets of 2192 yaw, pitch and roll angles in degrees 2193 }, 2194 Format => 'rational64s', 2195 ValueConv => '$val =~ s/^-?\d+ //; \$val', # (ignore leading version/size words) 2196 }, 2197 # m360 - 8 bytes "0 0 0 0 0 0 0 1" 2198 # opax - 164 bytes unknown (center and affine arrays? ref 26) 2199 # opai - 32 bytes (maybe contains a serial number starting at byte 16? - PH) (rgb gains, degamma, gamma? ref 26) 2200 # intv - 16 bytes all zero 2201 # ---- Unknown ---- 2202 # CDET - 128 bytes (unknown origin) 2203 # mtyp - 4 bytes all zero (some drone video) 2204 # kgrf - 8 bytes all zero ? (in udta inside trak atom) 2205 # kgcg - 128 bytes 0's and 1's 2206 # kgsi - 4 bytes "00 00 00 80" 2207 # FIEL - 18 bytes "FIEL\0\x01\0\0\0..." 2208# 2209# other 3rd-party tags 2210# (ref http://code.google.com/p/mp4parser/source/browse/trunk/isoparser/src/main/resources/isoparser-default.properties?r=814) 2211# 2212 ccid => 'ContentID', 2213 icnu => 'IconURI', 2214 infu => 'InfoURL', 2215 cdis => 'ContentDistributorID', 2216 albr => { Name => 'AlbumArtist', Groups => { 2 => 'Author' } }, 2217 cvru => 'CoverURI', 2218 lrcu => 'LyricsURI', 2219 2220 tags => { # found in Audible .m4b audio books (ref PH) 2221 Name => 'Audible_tags', 2222 SubDirectory => { TagTable => 'Image::ExifTool::Audible::tags' }, 2223 }, 2224); 2225 2226# Unknown information stored in HTC One (M8) videos - PH 2227%Image::ExifTool::QuickTime::HTCBinary = ( 2228 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2229 GROUPS => { 0 => 'MakerNotes', 1 => 'HTC', 2 => 'Video' }, 2230 TAG_PREFIX => 'HTCBinary', 2231 FORMAT => 'int32u', 2232 FIRST_ENTRY => 0, 2233 # 0 - values: 1 2234 # 1 - values: 0 2235 # 2 - values: 0 2236 # 3 - values: FileSize minus 12 (why?) 2237 # 4 - values: 12 2238); 2239 2240# TomTom Bandit Action Cam metadata (ref PH) 2241%Image::ExifTool::QuickTime::TomTom = ( 2242 PROCESS_PROC => \&ProcessMOV, 2243 GROUPS => { 2 => 'Video' }, 2244 NOTES => 'Tags found in TomTom Bandit Action Cam MP4 videos.', 2245 TTAD => { 2246 Name => 'TomTomAD', 2247 SubDirectory => { 2248 TagTable => 'Image::ExifTool::QuickTime::Stream', 2249 ProcessProc => \&Image::ExifTool::QuickTime::ProcessTTAD, 2250 }, 2251 }, 2252 TTHL => { Name => 'TomTomHL', Binary => 1, Unknown => 1 }, # (mostly zeros) 2253 # (TTID values are different for each video) 2254 TTID => { Name => 'TomTomID', ValueConv => 'unpack("x4H*",$val)' }, 2255 TTVI => { Name => 'TomTomVI', Format => 'int32u', Unknown => 1 }, # seen: "0 1 61 508 508" 2256 # TTVD seen: "normal 720p 60fps 60fps 16/9 wide 1x" 2257 TTVD => { Name => 'TomTomVD', ValueConv => 'my @a = ($val =~ /[\x20-\x7f]+/g); "@a"' }, 2258); 2259 2260# User-specific media data atoms (ref 11) 2261%Image::ExifTool::QuickTime::UserMedia = ( 2262 PROCESS_PROC => \&ProcessMOV, 2263 GROUPS => { 2 => 'Video' }, 2264 MTDT => { 2265 Name => 'MetaData', 2266 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MetaData' }, 2267 }, 2268); 2269 2270# User-specific media data atoms (ref 11) 2271%Image::ExifTool::QuickTime::MetaData = ( 2272 PROCESS_PROC => \&ProcessMetaData, 2273 GROUPS => { 2 => 'Video' }, 2274 TAG_PREFIX => 'MetaData', 2275 0x01 => 'Title', 2276 0x03 => { 2277 Name => 'ProductionDate', 2278 Groups => { 2 => 'Time' }, 2279 Shift => 'Time', 2280 Writable => 1, 2281 Permanent => 1, 2282 DelValue => '0000/00/00 00:00:00', 2283 # translate from format "YYYY/mm/dd HH:MM:SS" 2284 ValueConv => '$val=~tr{/}{:}; $val', 2285 ValueConvInv => '$val=~s[^(\d{4}):(\d{2}):][$1/$2/]; $val', 2286 PrintConv => '$self->ConvertDateTime($val)', 2287 PrintConvInv => '$self->InverseDateTime($val)', 2288 }, 2289 0x04 => 'Software', 2290 0x05 => 'Product', 2291 0x0a => { 2292 Name => 'TrackProperty', 2293 RawConv => 'my @a=unpack("Nnn",$val); "@a"', 2294 PrintConv => [ 2295 { 0 => 'No presentation', BITMASK => { 0 => 'Main track' } }, 2296 { 0 => 'No attributes', BITMASK => { 15 => 'Read only' } }, 2297 '"Priority $val"', 2298 ], 2299 }, 2300 0x0b => { 2301 Name => 'TimeZone', 2302 Groups => { 2 => 'Time' }, 2303 Writable => 1, 2304 Permanent => 1, 2305 DelValue => 0, 2306 RawConv => 'Get16s(\$val,0)', 2307 RawConvInv => 'Set16s($val)', 2308 PrintConv => 'TimeZoneString($val)', 2309 PrintConvInv => q{ 2310 return undef unless $val =~ /^([-+])(\d{1,2}):?(\d{2})$/' 2311 my $tzmin = $2 * 60 + $3; 2312 $tzmin = -$tzmin if $1 eq '-'; 2313 return $tzmin; 2314 } 2315 }, 2316 0x0c => { 2317 Name => 'ModifyDate', 2318 Groups => { 2 => 'Time' }, 2319 Shift => 'Time', 2320 Writable => 1, 2321 Permanent => 1, 2322 DelValue => '0000/00/00 00:00:00', 2323 # translate from format "YYYY/mm/dd HH:MM:SS" 2324 ValueConv => '$val=~tr{/}{:}; $val', 2325 ValueConvInv => '$val=~s[^(\d{4}):(\d{2}):][$1/$2/]; $val', 2326 PrintConv => '$self->ConvertDateTime($val)', 2327 PrintConvInv => '$self->InverseDateTime($val)', 2328 }, 2329); 2330 2331# compressed movie atoms (ref http://wiki.multimedia.cx/index.php?title=QuickTime_container#cmov) 2332%Image::ExifTool::QuickTime::CMovie = ( 2333 PROCESS_PROC => \&ProcessMOV, 2334 GROUPS => { 2 => 'Video' }, 2335 dcom => 'Compression', 2336 # cmvd - compressed moov atom data 2337); 2338 2339# Profile atoms (ref 11) 2340%Image::ExifTool::QuickTime::Profile = ( 2341 PROCESS_PROC => \&ProcessMOV, 2342 GROUPS => { 2 => 'Video' }, 2343 FPRF => { 2344 Name => 'FileGlobalProfile', 2345 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FileProf' }, 2346 }, 2347 APRF => { 2348 Name => 'AudioProfile', 2349 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AudioProf' }, 2350 }, 2351 VPRF => { 2352 Name => 'VideoProfile', 2353 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::VideoProf' }, 2354 }, 2355 OLYM => { #PH 2356 Name => 'OlympusOLYM', 2357 SubDirectory => { 2358 TagTable => 'Image::ExifTool::Olympus::OLYM', 2359 ByteOrder => 'BigEndian', 2360 }, 2361 }, 2362); 2363 2364# FPRF atom information (ref 11) 2365%Image::ExifTool::QuickTime::FileProf = ( 2366 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2367 GROUPS => { 2 => 'Video' }, 2368 FORMAT => 'int32u', 2369 0 => { Name => 'FileProfileVersion', Unknown => 1 }, # unknown = uninteresting 2370 1 => { 2371 Name => 'FileFunctionFlags', 2372 PrintConv => { BITMASK => { 2373 28 => 'Fragmented', 2374 29 => 'Additional tracks', 2375 30 => 'Edited', # (main AV track is edited) 2376 }}, 2377 }, 2378 # 2 - reserved 2379); 2380 2381# APRF atom information (ref 11) 2382%Image::ExifTool::QuickTime::AudioProf = ( 2383 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2384 GROUPS => { 2 => 'Audio' }, 2385 FORMAT => 'int32u', 2386 0 => { Name => 'AudioProfileVersion', Unknown => 1 }, 2387 1 => 'AudioTrackID', 2388 2 => { 2389 Name => 'AudioCodec', 2390 Format => 'undef[4]', 2391 }, 2392 3 => { 2393 Name => 'AudioCodecInfo', 2394 Unknown => 1, 2395 PrintConv => 'sprintf("0x%.4x", $val)', 2396 }, 2397 4 => { 2398 Name => 'AudioAttributes', 2399 PrintConv => { BITMASK => { 2400 0 => 'Encrypted', 2401 1 => 'Variable bitrate', 2402 2 => 'Dual mono', 2403 }}, 2404 }, 2405 5 => { 2406 Name => 'AudioAvgBitrate', 2407 ValueConv => '$val * 1000', 2408 PrintConv => 'ConvertBitrate($val)', 2409 }, 2410 6 => { 2411 Name => 'AudioMaxBitrate', 2412 ValueConv => '$val * 1000', 2413 PrintConv => 'ConvertBitrate($val)', 2414 }, 2415 7 => 'AudioSampleRate', 2416 8 => 'AudioChannels', 2417); 2418 2419# VPRF atom information (ref 11) 2420%Image::ExifTool::QuickTime::VideoProf = ( 2421 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2422 GROUPS => { 2 => 'Video' }, 2423 FORMAT => 'int32u', 2424 0 => { Name => 'VideoProfileVersion', Unknown => 1 }, 2425 1 => 'VideoTrackID', 2426 2 => { 2427 Name => 'VideoCodec', 2428 Format => 'undef[4]', 2429 }, 2430 3 => { 2431 Name => 'VideoCodecInfo', 2432 Unknown => 1, 2433 PrintConv => 'sprintf("0x%.4x", $val)', 2434 }, 2435 4 => { 2436 Name => 'VideoAttributes', 2437 PrintConv => { BITMASK => { 2438 0 => 'Encrypted', 2439 1 => 'Variable bitrate', 2440 2 => 'Variable frame rate', 2441 3 => 'Interlaced', 2442 }}, 2443 }, 2444 5 => { 2445 Name => 'VideoAvgBitrate', 2446 ValueConv => '$val * 1000', 2447 PrintConv => 'ConvertBitrate($val)', 2448 }, 2449 6 => { 2450 Name => 'VideoMaxBitrate', 2451 ValueConv => '$val * 1000', 2452 PrintConv => 'ConvertBitrate($val)', 2453 }, 2454 7 => { 2455 Name => 'VideoAvgFrameRate', 2456 Format => 'fixed32u', 2457 PrintConv => 'int($val * 1000 + 0.5) / 1000', 2458 }, 2459 8 => { 2460 Name => 'VideoMaxFrameRate', 2461 Format => 'fixed32u', 2462 PrintConv => 'int($val * 1000 + 0.5) / 1000', 2463 }, 2464 9 => { 2465 Name => 'VideoSize', 2466 Format => 'int16u[2]', 2467 PrintConv => '$val=~tr/ /x/; $val', 2468 }, 2469 10 => { 2470 Name => 'PixelAspectRatio', 2471 Format => 'int16u[2]', 2472 PrintConv => '$val=~tr/ /:/; $val', 2473 }, 2474); 2475 2476# meta atoms 2477%Image::ExifTool::QuickTime::Meta = ( 2478 PROCESS_PROC => \&ProcessMOV, 2479 WRITE_PROC => \&WriteQuickTime, 2480 GROUPS => { 1 => 'Meta', 2 => 'Video' }, 2481 ilst => { 2482 Name => 'ItemList', 2483 SubDirectory => { 2484 TagTable => 'Image::ExifTool::QuickTime::ItemList', 2485 HasData => 1, # process atoms as containers with 'data' elements 2486 }, 2487 }, 2488 # MP4 tags (ref 5) 2489 hdlr => { 2490 Name => 'Handler', 2491 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' }, 2492 }, 2493 dinf => { 2494 Name => 'DataInfo', # (don't change this name -- used to recognize directory when writing) 2495 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' }, 2496 }, 2497 ipmc => { 2498 Name => 'IPMPControl', 2499 Flags => ['Binary','Unknown'], 2500 }, 2501 iloc => { 2502 Name => 'ItemLocation', 2503 RawConv => \&ParseItemLocation, 2504 WriteHook => \&ParseItemLocation, 2505 Notes => 'parsed, but not extracted as a tag', 2506 }, 2507 ipro => { 2508 Name => 'ItemProtection', 2509 Flags => ['Binary','Unknown'], 2510 }, 2511 iinf => [{ 2512 Name => 'ItemInformation', 2513 Condition => '$$valPt =~ /^\0/', # (check for version 0) 2514 SubDirectory => { 2515 TagTable => 'Image::ExifTool::QuickTime::ItemInfo', 2516 Start => 6, # (4-byte version/flags + 2-byte count) 2517 }, 2518 },{ 2519 Name => 'ItemInformation', 2520 SubDirectory => { 2521 TagTable => 'Image::ExifTool::QuickTime::ItemInfo', 2522 Start => 8, # (4-byte version/flags + 4-byte count) 2523 }, 2524 }], 2525 'xml ' => { 2526 Name => 'XML', 2527 Flags => [ 'Binary', 'Protected' ], 2528 SubDirectory => { 2529 TagTable => 'Image::ExifTool::XMP::XML', 2530 IgnoreProp => { NonRealTimeMeta => 1 }, # ignore container for Sony 'nrtm' 2531 }, 2532 }, 2533 'keys' => { 2534 Name => 'Keys', 2535 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Keys' }, 2536 }, 2537 bxml => { 2538 Name => 'BinaryXML', 2539 Flags => ['Binary','Unknown'], 2540 }, 2541 pitm => [{ 2542 Name => 'PrimaryItemReference', 2543 Condition => '$$valPt =~ /^\0/', # (version 0?) 2544 RawConv => '$$self{PrimaryItem} = unpack("x4n",$val)', 2545 WriteHook => sub { my ($val,$et) = @_; $$et{PrimaryItem} = unpack("x4n",$val); }, 2546 },{ 2547 Name => 'PrimaryItemReference', 2548 RawConv => '$$self{PrimaryItem} = unpack("x4N",$val)', 2549 WriteHook => sub { my ($val,$et) = @_; $$et{PrimaryItem} = unpack("x4N",$val); }, 2550 }], 2551 free => { #PH 2552 Name => 'Free', 2553 Flags => ['Binary','Unknown'], 2554 }, 2555 iprp => { 2556 Name => 'ItemProperties', 2557 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemProp' }, 2558 }, 2559 iref => { 2560 Name => 'ItemReference', 2561 # the version is needed to parse some of the item references 2562 Condition => '$$self{ItemRefVersion} = ord($$valPt); 1', 2563 SubDirectory => { 2564 TagTable => 'Image::ExifTool::QuickTime::ItemRef', 2565 Start => 4, 2566 }, 2567 }, 2568 idat => { 2569 Name => 'MetaImageSize', #PH (NC) 2570 Format => 'int16u', 2571 # (don't know what the first two numbers are for) 2572 PrintConv => '$val =~ s/^(\d+) (\d+) (\d+) (\d+)/${3}x$4/; $val', 2573 }, 2574 uuid => [ 2575 { #PH (Canon R5/R6 HIF) 2576 Name => 'MetaVersion', # (NC) 2577 Condition => '$$valPt=~/^\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48/', 2578 RawConv => 'substr($val, 0x14)', 2579 }, 2580 { 2581 Name => 'UUID-Unknown', 2582 %unknownInfo, 2583 }, 2584 ], 2585); 2586 2587# additional metadata container (ref ISO14496-12:2015) 2588%Image::ExifTool::QuickTime::OtherMeta = ( 2589 PROCESS_PROC => \&ProcessMOV, 2590 WRITE_PROC => \&WriteQuickTime, 2591 GROUPS => { 2 => 'Video' }, 2592 mere => { 2593 Name => 'MetaRelation', 2594 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MetaRelation' }, 2595 }, 2596 meta => { 2597 Name => 'Meta', 2598 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, 2599 }, 2600); 2601 2602# metabox relation (ref ISO14496-12:2015) 2603%Image::ExifTool::QuickTime::MetaRelation = ( 2604 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2605 GROUPS => { 2 => 'Video' }, 2606 FORMAT => 'int32u', 2607 # 0 => 'MetaRelationVersion', 2608 # 1 => 'FirstMetaboxHandlerType', 2609 # 2 => 'FirstMetaboxHandlerType', 2610 # 3 => { Name => 'MetaboxRelation', Format => 'int8u' }, 2611); 2612 2613%Image::ExifTool::QuickTime::ItemProp = ( 2614 PROCESS_PROC => \&ProcessMOV, 2615 WRITE_PROC => \&WriteQuickTime, 2616 GROUPS => { 2 => 'Image' }, 2617 ipco => { 2618 Name => 'ItemPropertyContainer', 2619 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemPropCont' }, 2620 }, 2621 ipma => { 2622 Name => 'ItemPropertyAssociation', 2623 RawConv => \&ParseItemPropAssoc, 2624 WriteHook => \&ParseItemPropAssoc, 2625 Notes => 'parsed, but not extracted as a tag', 2626 }, 2627); 2628 2629%Image::ExifTool::QuickTime::ItemPropCont = ( 2630 PROCESS_PROC => \&ProcessMOV, 2631 WRITE_PROC => \&WriteQuickTime, 2632 PERMANENT => 1, # (can't be deleted) 2633 GROUPS => { 2 => 'Image' }, 2634 VARS => { START_INDEX => 1 }, # show verbose indices starting at 1 2635 colr => [{ 2636 Name => 'ICC_Profile', 2637 Condition => '$$valPt =~ /^(prof|rICC)/', 2638 SubDirectory => { 2639 TagTable => 'Image::ExifTool::ICC_Profile::Main', 2640 Start => 4, 2641 }, 2642 },{ 2643 Name => 'ColorRepresentation', 2644 ValueConv => 'join(" ", substr($val,0,4), unpack("x4n*",$val))', 2645 }], 2646 irot => { 2647 Name => 'Rotation', 2648 Format => 'int8u', 2649 Writable => 'int8u', 2650 Protected => 1, 2651 ValueConv => '$val * 90', 2652 ValueConvInv => 'int($val / 90 + 0.5)', 2653 }, 2654 ispe => { 2655 Name => 'ImageSpatialExtent', 2656 Condition => '$$valPt =~ /^\0{4}/', # (version/flags == 0/0) 2657 RawConv => q{ 2658 my @dim = unpack("x4N*", $val); 2659 return undef if @dim < 2; 2660 unless ($$self{DOC_NUM}) { 2661 $self->FoundTag(ImageWidth => $dim[0]); 2662 $self->FoundTag(ImageHeight => $dim[1]); 2663 } 2664 return join ' ', @dim; 2665 }, 2666 PrintConv => '$val =~ tr/ /x/; $val', 2667 }, 2668 pixi => { 2669 Name => 'ImagePixelDepth', 2670 Condition => '$$valPt =~ /^\0{4}./s', # (version/flags == 0/0 and count) 2671 RawConv => 'join " ", unpack("x5C*", $val)', 2672 }, 2673 auxC => { 2674 Name => 'AuxiliaryImageType', 2675 Format => 'undef', 2676 RawConv => '$val = substr($val, 4); $val =~ s/\0.*//s; $val', 2677 }, 2678 pasp => { 2679 Name => 'PixelAspectRatio', 2680 Format => 'int32u', 2681 Writable => 'int32u', 2682 Protected => 1, 2683 }, 2684 rloc => { 2685 Name => 'RelativeLocation', 2686 Format => 'int32u', 2687 RawConv => '$val =~ s/^\S+\s+//; $val', # remove version/flags 2688 }, 2689 clap => { 2690 Name => 'CleanAperture', 2691 Format => 'rational64s', 2692 Notes => '4 numbers: width, height, left and top', 2693 }, 2694 hvcC => { 2695 Name => 'HEVCConfiguration', 2696 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HEVCConfig' }, 2697 }, 2698 av1C => { 2699 Name => 'AV1Configuration', 2700 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AV1Config' }, 2701 }, 2702); 2703 2704# HEVC configuration (ref https://github.com/MPEGGroup/isobmff/blob/master/IsoLib/libisomediafile/src/HEVCConfigAtom.c) 2705%Image::ExifTool::QuickTime::HEVCConfig = ( 2706 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2707 GROUPS => { 2 => 'Video' }, 2708 FIRST_ENTRY => 0, 2709 0 => 'HEVCConfigurationVersion', 2710 1 => { 2711 Name => 'GeneralProfileSpace', 2712 Mask => 0xc0, 2713 PrintConv => { 0 => 'Conforming' }, 2714 }, 2715 1.1 => { 2716 Name => 'GeneralTierFlag', 2717 Mask => 0x20, 2718 PrintConv => { 2719 0 => 'Main Tier', 2720 1 => 'High Tier', 2721 }, 2722 }, 2723 1.2 => { 2724 Name => 'GeneralProfileIDC', 2725 Mask => 0x1f, 2726 PrintConv => { 2727 0 => 'No Profile', 2728 1 => 'Main', 2729 2 => 'Main 10', 2730 3 => 'Main Still Picture', 2731 4 => 'Format Range Extensions', 2732 5 => 'High Throughput', 2733 6 => 'Multiview Main', 2734 7 => 'Scalable Main', 2735 8 => '3D Main', 2736 9 => 'Screen Content Coding Extensions', 2737 10 => 'Scalable Format Range Extensions', 2738 11 => 'High Throughput Screen Content Coding Extensions', 2739 }, 2740 }, 2741 2 => { 2742 Name => 'GenProfileCompatibilityFlags', 2743 Format => 'int32u', 2744 PrintConv => { BITMASK => { 2745 31 => 'No Profile', # (bit 0 in stream) 2746 30 => 'Main', # (bit 1 in stream) 2747 29 => 'Main 10', # (bit 2 in stream) 2748 28 => 'Main Still Picture', # (bit 3 in stream) 2749 27 => 'Format Range Extensions',# (...) 2750 26 => 'High Throughput', 2751 25 => 'Multiview Main', 2752 24 => 'Scalable Main', 2753 23 => '3D Main', 2754 22 => 'Screen Content Coding Extensions', 2755 21 => 'Scalable Format Range Extensions', 2756 20 => 'High Throughput Screen Content Coding Extensions', 2757 }}, 2758 }, 2759 6 => { 2760 Name => 'ConstraintIndicatorFlags', 2761 Format => 'int8u[6]', 2762 }, 2763 12 => { 2764 Name => 'GeneralLevelIDC', 2765 PrintConv => 'sprintf("%d (level %.1f)", $val, $val/30)', 2766 }, 2767 13 => { 2768 Name => 'MinSpatialSegmentationIDC', 2769 Format => 'int16u', 2770 Mask => 0x0fff, 2771 }, 2772 15 => { 2773 Name => 'ParallelismType', 2774 Mask => 0x03, 2775 }, 2776 16 => { 2777 Name => 'ChromaFormat', 2778 Mask => 0x03, 2779 PrintConv => { 2780 0 => 'Monochrome', 2781 1 => '4:2:0', 2782 2 => '4:2:2', 2783 3 => '4:4:4', 2784 }, 2785 }, 2786 17 => { 2787 Name => 'BitDepthLuma', 2788 Mask => 0x07, 2789 ValueConv => '$val + 8', 2790 }, 2791 18 => { 2792 Name => 'BitDepthChroma', 2793 Mask => 0x07, 2794 ValueConv => '$val + 8', 2795 }, 2796 19 => { 2797 Name => 'AverageFrameRate', 2798 Format => 'int16u', 2799 ValueConv => '$val / 256', 2800 }, 2801 21 => { 2802 Name => 'ConstantFrameRate', 2803 Mask => 0xc0, 2804 PrintConv => { 2805 0 => 'Unknown', 2806 1 => 'Constant Frame Rate', 2807 2 => 'Each Temporal Layer is Constant Frame Rate', 2808 }, 2809 }, 2810 21.1 => { 2811 Name => 'NumTemporalLayers', 2812 Mask => 0x38, 2813 }, 2814 21.2 => { 2815 Name => 'TemporalIDNested', 2816 Mask => 0x04, 2817 PrintConv => { 0 => 'No', 1 => 'Yes' }, 2818 }, 2819 #21.3 => { 2820 # Name => 'NALUnitLengthSize', 2821 # Mask => 0x03, 2822 # ValueConv => '$val + 1', 2823 # PrintConv => { 1 => '8-bit', 2 => '16-bit', 4 => '32-bit' }, 2824 #}, 2825 #22 => 'NumberOfNALUnitArrays', 2826 # (don't decode the NAL unit arrays) 2827); 2828 2829# HEVC configuration (ref https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox) 2830%Image::ExifTool::QuickTime::AV1Config = ( 2831 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 2832 GROUPS => { 2 => 'Video' }, 2833 FIRST_ENTRY => 0, 2834 0 => { 2835 Name => 'AV1ConfigurationVersion', 2836 Mask => 0x7f, 2837 }, 2838 1.0 => { 2839 Name => 'SeqProfile', 2840 Mask => 0xe0, 2841 Unknown => 1, 2842 }, 2843 1.1 => { 2844 Name => 'SeqLevelIdx0', 2845 Mask => 0x1f, 2846 Unknown => 1, 2847 }, 2848 2.0 => { 2849 Name => 'SeqTier0', 2850 Mask => 0x80, 2851 Unknown => 1, 2852 }, 2853 2.1 => { 2854 Name => 'HighBitDepth', 2855 Mask => 0x40, 2856 Unknown => 1, 2857 }, 2858 2.2 => { 2859 Name => 'TwelveBit', 2860 Mask => 0x20, 2861 Unknown => 1, 2862 }, 2863 2.3 => { 2864 Name => 'ChromaFormat', # (Monochrome+SubSamplingX+SubSamplingY) 2865 Notes => 'bits: 0x04 = Monochrome, 0x02 = SubSamplingX, 0x01 = SubSamplingY', 2866 Mask => 0x1c, 2867 PrintConv => { 2868 0x00 => 'YUV 4:4:4', 2869 0x02 => 'YUV 4:2:2', 2870 0x03 => 'YUV 4:2:0', 2871 0x07 => 'Monochrome 4:0:0', 2872 }, 2873 }, 2874 2.4 => { 2875 Name => 'ChromaSamplePosition', 2876 Mask => 0x03, 2877 PrintConv => { 2878 0 => 'Unknown', 2879 1 => 'Vertical', 2880 2 => 'Colocated', 2881 3 => '(reserved)', 2882 }, 2883 }, 2884 3 => { 2885 Name => 'InitialDelaySamples', 2886 RawConv => '$val & 0x10 ? undef : ($val & 0x0f) + 1', 2887 Unknown => 1, 2888 }, 2889); 2890 2891%Image::ExifTool::QuickTime::ItemRef = ( 2892 PROCESS_PROC => \&ProcessMOV, 2893 WRITE_PROC => \&WriteQuickTime, 2894 GROUPS => { 2 => 'Image' }, 2895 # (Note: ExifTool's ItemRefVersion may be used to test the iref version number) 2896 NOTES => q{ 2897 The Item reference entries listed in the table below contain information about 2898 the associations between items in the file. This information is used by 2899 ExifTool, but these entries are not extracted as tags. 2900 }, 2901 dimg => { Name => 'DerivedImageRef', RawConv => 'undef' }, 2902 thmb => { Name => 'ThumbnailRef', RawConv => 'undef' }, 2903 auxl => { Name => 'AuxiliaryImageRef', RawConv => 'undef' }, 2904 cdsc => { 2905 Name => 'ContentDescribes', 2906 RawConv => \&ParseContentDescribes, 2907 WriteHook => \&ParseContentDescribes, 2908 }, 2909); 2910 2911%Image::ExifTool::QuickTime::ItemInfo = ( 2912 PROCESS_PROC => \&ProcessMOV, 2913 WRITE_PROC => \&WriteQuickTime, 2914 GROUPS => { 2 => 'Image' }, 2915 # avc1 - AVC image 2916 # hvc1 - HEVC image 2917 # lhv1 - L-HEVC image 2918 # infe - ItemInformationEntry 2919 # infe types: avc1,hvc1,lhv1,Exif,xml1,iovl(overlay image),grid,mime,hvt1(tile image) 2920 infe => { 2921 Name => 'ItemInfoEntry', 2922 RawConv => \&ParseItemInfoEntry, 2923 WriteHook => \&ParseItemInfoEntry, 2924 Notes => 'parsed, but not extracted as a tag', 2925 }, 2926); 2927 2928# track reference atoms 2929%Image::ExifTool::QuickTime::TrackRef = ( 2930 PROCESS_PROC => \&ProcessMOV, 2931 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 2932 chap => { Name => 'ChapterListTrackID', Format => 'int32u' }, 2933 tmcd => { Name => 'TimeCode', Format => 'int32u' }, 2934 mpod => { #PH (FLIR MP4) 2935 Name => 'ElementaryStreamTrack', 2936 Format => 'int32u', 2937 ValueConv => '$val =~ s/^1 //; $val', # (why 2 numbers? -- ignore the first if "1") 2938 }, 2939 # also: sync, scpt, ssrc, iTunesInfo 2940 cdsc => { 2941 Name => 'ContentDescribes', 2942 Format => 'int32u', 2943 PrintConv => '"Track $val"', 2944 }, 2945 # cdep (Structural Dependency QT tag?) 2946); 2947 2948# track aperture mode dimensions atoms 2949# (ref https://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap2/qtff2.html) 2950%Image::ExifTool::QuickTime::TrackAperture = ( 2951 PROCESS_PROC => \&ProcessMOV, 2952 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 2953 clef => { 2954 Name => 'CleanApertureDimensions', 2955 Format => 'fixed32u', 2956 Count => 3, 2957 ValueConv => '$val =~ s/^.*? //; $val', # remove flags word 2958 PrintConv => '$val =~ tr/ /x/; $val', 2959 }, 2960 prof => { 2961 Name => 'ProductionApertureDimensions', 2962 Format => 'fixed32u', 2963 Count => 3, 2964 ValueConv => '$val =~ s/^.*? //; $val', 2965 PrintConv => '$val =~ tr/ /x/; $val', 2966 }, 2967 enof => { 2968 Name => 'EncodedPixelsDimensions', 2969 Format => 'fixed32u', 2970 Count => 3, 2971 ValueConv => '$val =~ s/^.*? //; $val', 2972 PrintConv => '$val =~ tr/ /x/; $val', 2973 }, 2974); 2975 2976# item list atoms 2977# -> these atoms are unique, and contain one or more 'data' atoms 2978%Image::ExifTool::QuickTime::ItemList = ( 2979 PROCESS_PROC => \&ProcessMOV, 2980 WRITE_PROC => \&WriteQuickTime, 2981 CHECK_PROC => \&CheckQTValue, 2982 WRITABLE => 1, 2983 PREFERRED => 2, # (preferred over UserData and Keys tags when writing) 2984 FORMAT => 'string', 2985 GROUPS => { 1 => 'ItemList', 2 => 'Audio' }, 2986 WRITE_GROUP => 'ItemList', 2987 LANG_INFO => \&GetLangInfo, 2988 NOTES => q{ 2989 This is the preferred location for creating new QuickTime tags. Tags in 2990 this table support alternate languages which are accessed by adding a 2991 3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2 2992 country code to the tag name (eg. "ItemList:Title-fra" or 2993 "ItemList::Title-fra-FR"). When creating a new Meta box to contain the 2994 ItemList directory, by default ExifTool does not specify a 2995 L<Handler|Image::ExifTool::TagNames/QuickTime Handler Tags>, but the 2996 API L<QuickTimeHandler|../ExifTool.html#QuickTimeHandler> option may be used to include an 'mdir' Handler box. 2997 }, 2998 # in this table, binary 1 and 2-byte "data"-type tags are interpreted as 2999 # int8u and int16u. Multi-byte binary "data" tags are extracted as binary data. 3000 # (Note that the Preferred property is set to 0 for some tags to prevent them 3001 # from being created when a same-named tag already exists in the table) 3002 "\xa9ART" => 'Artist', 3003 "\xa9alb" => 'Album', 3004 "\xa9aut" => { Name => 'Author', Avoid => 1, Groups => { 2 => 'Author' } }, #forum10091 ('auth' is preferred) 3005 "\xa9cmt" => 'Comment', 3006 "\xa9com" => { Name => 'Composer', Avoid => 1, }, # ("\xa9wrt" is preferred in ItemList) 3007 "\xa9day" => { 3008 Name => 'ContentCreateDate', 3009 Groups => { 2 => 'Time' }, 3010 Shift => 'Time', 3011 # handle values in the form "2010-02-12T13:27:14-0800" 3012 ValueConv => q{ 3013 require Image::ExifTool::XMP; 3014 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 3015 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 3016 return $val; 3017 }, 3018 ValueConvInv => q{ 3019 require Image::ExifTool::XMP; 3020 $val = Image::ExifTool::XMP::FormatXMPDate($val); 3021 $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon 3022 return $val; 3023 }, 3024 PrintConv => '$self->ConvertDateTime($val)', 3025 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 3026 }, 3027 "\xa9des" => 'Description', #4 3028 "\xa9enc" => 'EncodedBy', #10 3029 "\xa9gen" => 'Genre', 3030 "\xa9grp" => 'Grouping', 3031 "\xa9lyr" => 'Lyrics', 3032 "\xa9nam" => 'Title', 3033 "\xa9too" => 'Encoder', 3034 "\xa9trk" => 'Track', 3035 "\xa9wrt" => 'Composer', 3036# 3037# the following tags written by AtomicParsley 0.9.6 3038# (ref https://exiftool.org/forum/index.php?topic=11455.0) 3039# 3040 "\xa9st3" => 'Subtitle', 3041 "\xa9con" => 'Conductor', 3042 "\xa9sol" => 'Soloist', 3043 "\xa9arg" => 'Arranger', 3044 "\xa9ope" => 'OriginalArtist', 3045 "\xa9dir" => 'Director', 3046 "\xa9ard" => 'ArtDirector', 3047 "\xa9sne" => 'SoundEngineer', 3048 "\xa9prd" => 'Producer', 3049 "\xa9xpd" => 'ExecutiveProducer', 3050 sdes => 'StoreDescription', 3051# 3052 '----' => { 3053 Name => 'iTunesInfo', 3054 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::iTunesInfo' }, 3055 }, 3056 aART => { Name => 'AlbumArtist', Groups => { 2 => 'Author' } }, 3057 covr => { Name => 'CoverArt', Groups => { 2 => 'Preview' } }, 3058 cpil => { #10 3059 Name => 'Compilation', 3060 Format => 'int8u', #27 (ref 23 contradicts what AtomicParsley actually writes, which is int8s) 3061 Writable => 'int8s', 3062 PrintConv => { 0 => 'No', 1 => 'Yes' }, 3063 }, 3064 disk => { 3065 Name => 'DiskNumber', 3066 Format => 'undef', # (necessary to prevent decoding as string!) 3067 ValueConv => q{ 3068 return \$val unless length($val) >= 6; 3069 my @a = unpack 'x2nn', $val; 3070 return $a[1] ? join(' of ', @a) : $a[0]; 3071 }, 3072 ValueConvInv => q{ 3073 my @a = $val =~ /\d+/g; 3074 return undef if @a == 0 or @a > 2; 3075 push @a, 0 if @a == 1; 3076 return pack('n3', 0, @a); 3077 }, 3078 }, 3079 pgap => { #10 3080 Name => 'PlayGap', 3081 Format => 'int8u', #23 3082 Writable => 'int8s', #27 3083 PrintConv => { 3084 0 => 'Insert Gap', 3085 1 => 'No Gap', 3086 }, 3087 }, 3088 tmpo => { 3089 Name => 'BeatsPerMinute', 3090 # marked as boolean but really int16u in my sample 3091 # (but written as int16s by iTunes and AtomicParsley, ref forum11506) 3092 Format => 'int16u', 3093 Writable => 'int16s', 3094 }, 3095 trkn => { 3096 Name => 'TrackNumber', 3097 Format => 'undef', # (necessary to prevent decoding as string!) 3098 ValueConv => q{ 3099 return \$val unless length($val) >= 6; 3100 my @a = unpack 'x2nn', $val; 3101 return $a[1] ? join(' of ', @a) : $a[0]; 3102 }, 3103 # (see forum11501 for discussion about the format used) 3104 ValueConvInv => q{ 3105 my @a = $val =~ /\d+/g; 3106 return undef if @a == 0 or @a > 2; 3107 push @a, 0 if @a == 1; 3108 return pack('n4', 0, @a, 0); 3109 }, 3110 }, 3111# 3112# Note: it is possible that the tags below are not being decoded properly 3113# because I don't have samples to verify many of these - PH 3114# 3115 akID => { #10 3116 Name => 'AppleStoreAccountType', 3117 Format => 'int8u', #24 3118 Writable => 'int8s', #27 3119 PrintConv => { 3120 0 => 'iTunes', 3121 1 => 'AOL', 3122 }, 3123 }, 3124 albm => { Name => 'Album', Avoid => 1 }, #(ffmpeg source) 3125 apID => 'AppleStoreAccount', 3126 atID => { #10 (or TV series) 3127 Name => 'AlbumTitleID', 3128 Format => 'int32u', 3129 Writable => 'int32s', #27 3130 }, 3131 auth => { Name => 'Author', Groups => { 2 => 'Author' } }, 3132 catg => 'Category', #7 3133 cnID => { #10 3134 Name => 'AppleStoreCatalogID', 3135 Format => 'int32u', 3136 Writable => 'int32s', #27 3137 }, 3138 cprt => { Name => 'Copyright', Groups => { 2 => 'Author' } }, 3139 dscp => { Name => 'Description', Avoid => 1 }, 3140 desc => { Name => 'Description', Avoid => 1 }, #7 3141 gnre => { #10 3142 Name => 'Genre', 3143 Avoid => 1, 3144 # (Note: see https://exiftool.org/forum/index.php?topic=11537.0) 3145 Format => 'undef', 3146 ValueConv => 'unpack("n",$val)', 3147 ValueConvInv => '$val =~ /^\d+$/ ? pack("n",$val) : undef', 3148 PrintConv => q{ 3149 return $val unless $val =~ /^\d+$/; 3150 require Image::ExifTool::ID3; 3151 Image::ExifTool::ID3::PrintGenre($val - 1); # note the "- 1" 3152 }, 3153 PrintConvInv => q{ 3154 return $val if $val =~ /^[0-9]+$/; 3155 require Image::ExifTool::ID3; 3156 my $id = Image::ExifTool::ID3::GetGenreID($val); 3157 return unless defined $id and $id =~ /^\d+$/; 3158 return $id + 1; 3159 }, 3160 }, 3161 egid => 'EpisodeGlobalUniqueID', #7 3162 geID => { #10 3163 Name => 'GenreID', 3164 Format => 'int32u', 3165 Writable => 'int32s', #27 3166 SeparateTable => 1, 3167 # the following lookup is based on http://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/genres 3168 # (see scripts/parse_genre to parse genre JSON file from above) 3169 PrintConv => { #21/PH 3170 2 => 'Music|Blues', 3171 3 => 'Music|Comedy', 3172 4 => "Music|Children's Music", 3173 5 => 'Music|Classical', 3174 6 => 'Music|Country', 3175 7 => 'Music|Electronic', 3176 8 => 'Music|Holiday', 3177 9 => 'Music|Classical|Opera', 3178 10 => 'Music|Singer/Songwriter', 3179 11 => 'Music|Jazz', 3180 12 => 'Music|Latino', 3181 13 => 'Music|New Age', 3182 14 => 'Music|Pop', 3183 15 => 'Music|R&B/Soul', 3184 16 => 'Music|Soundtrack', 3185 17 => 'Music|Dance', 3186 18 => 'Music|Hip-Hop/Rap', 3187 19 => 'Music|World', 3188 20 => 'Music|Alternative', 3189 21 => 'Music|Rock', 3190 22 => 'Music|Christian & Gospel', 3191 23 => 'Music|Vocal', 3192 24 => 'Music|Reggae', 3193 25 => 'Music|Easy Listening', 3194 26 => 'Podcasts', 3195 27 => 'Music|J-Pop', 3196 28 => 'Music|Enka', 3197 29 => 'Music|Anime', 3198 30 => 'Music|Kayokyoku', 3199 31 => 'Music Videos', 3200 32 => 'TV Shows', 3201 33 => 'Movies', 3202 34 => 'Music', 3203 35 => 'iPod Games', 3204 36 => 'App Store', 3205 37 => 'Tones', 3206 38 => 'Books', 3207 39 => 'Mac App Store', 3208 40 => 'Textbooks', 3209 50 => 'Music|Fitness & Workout', 3210 51 => 'Music|Pop|K-Pop', 3211 52 => 'Music|Karaoke', 3212 53 => 'Music|Instrumental', 3213 74 => 'Audiobooks|News', 3214 75 => 'Audiobooks|Programs & Performances', 3215 500 => 'Fitness Music', 3216 501 => 'Fitness Music|Pop', 3217 502 => 'Fitness Music|Dance', 3218 503 => 'Fitness Music|Hip-Hop', 3219 504 => 'Fitness Music|Rock', 3220 505 => 'Fitness Music|Alt/Indie', 3221 506 => 'Fitness Music|Latino', 3222 507 => 'Fitness Music|Country', 3223 508 => 'Fitness Music|World', 3224 509 => 'Fitness Music|New Age', 3225 510 => 'Fitness Music|Classical', 3226 1001 => 'Music|Alternative|College Rock', 3227 1002 => 'Music|Alternative|Goth Rock', 3228 1003 => 'Music|Alternative|Grunge', 3229 1004 => 'Music|Alternative|Indie Rock', 3230 1005 => 'Music|Alternative|New Wave', 3231 1006 => 'Music|Alternative|Punk', 3232 1007 => 'Music|Blues|Chicago Blues', 3233 1009 => 'Music|Blues|Classic Blues', 3234 1010 => 'Music|Blues|Contemporary Blues', 3235 1011 => 'Music|Blues|Country Blues', 3236 1012 => 'Music|Blues|Delta Blues', 3237 1013 => 'Music|Blues|Electric Blues', 3238 1014 => "Music|Children's Music|Lullabies", 3239 1015 => "Music|Children's Music|Sing-Along", 3240 1016 => "Music|Children's Music|Stories", 3241 1017 => 'Music|Classical|Avant-Garde', 3242 1018 => 'Music|Classical|Baroque Era', 3243 1019 => 'Music|Classical|Chamber Music', 3244 1020 => 'Music|Classical|Chant', 3245 1021 => 'Music|Classical|Choral', 3246 1022 => 'Music|Classical|Classical Crossover', 3247 1023 => 'Music|Classical|Early Music', 3248 1024 => 'Music|Classical|Impressionist', 3249 1025 => 'Music|Classical|Medieval Era', 3250 1026 => 'Music|Classical|Minimalism', 3251 1027 => 'Music|Classical|Modern Era', 3252 1028 => 'Music|Classical|Opera', 3253 1029 => 'Music|Classical|Orchestral', 3254 1030 => 'Music|Classical|Renaissance', 3255 1031 => 'Music|Classical|Romantic Era', 3256 1032 => 'Music|Classical|Wedding Music', 3257 1033 => 'Music|Country|Alternative Country', 3258 1034 => 'Music|Country|Americana', 3259 1035 => 'Music|Country|Bluegrass', 3260 1036 => 'Music|Country|Contemporary Bluegrass', 3261 1037 => 'Music|Country|Contemporary Country', 3262 1038 => 'Music|Country|Country Gospel', 3263 1039 => 'Music|Country|Honky Tonk', 3264 1040 => 'Music|Country|Outlaw Country', 3265 1041 => 'Music|Country|Traditional Bluegrass', 3266 1042 => 'Music|Country|Traditional Country', 3267 1043 => 'Music|Country|Urban Cowboy', 3268 1044 => 'Music|Dance|Breakbeat', 3269 1045 => 'Music|Dance|Exercise', 3270 1046 => 'Music|Dance|Garage', 3271 1047 => 'Music|Dance|Hardcore', 3272 1048 => 'Music|Dance|House', 3273 1049 => "Music|Dance|Jungle/Drum'n'bass", 3274 1050 => 'Music|Dance|Techno', 3275 1051 => 'Music|Dance|Trance', 3276 1052 => 'Music|Jazz|Big Band', 3277 1053 => 'Music|Jazz|Bop', 3278 1054 => 'Music|Easy Listening|Lounge', 3279 1055 => 'Music|Easy Listening|Swing', 3280 1056 => 'Music|Electronic|Ambient', 3281 1057 => 'Music|Electronic|Downtempo', 3282 1058 => 'Music|Electronic|Electronica', 3283 1060 => 'Music|Electronic|IDM/Experimental', 3284 1061 => 'Music|Electronic|Industrial', 3285 1062 => 'Music|Singer/Songwriter|Alternative Folk', 3286 1063 => 'Music|Singer/Songwriter|Contemporary Folk', 3287 1064 => 'Music|Singer/Songwriter|Contemporary Singer/Songwriter', 3288 1065 => 'Music|Singer/Songwriter|Folk-Rock', 3289 1066 => 'Music|Singer/Songwriter|New Acoustic', 3290 1067 => 'Music|Singer/Songwriter|Traditional Folk', 3291 1068 => 'Music|Hip-Hop/Rap|Alternative Rap', 3292 1069 => 'Music|Hip-Hop/Rap|Dirty South', 3293 1070 => 'Music|Hip-Hop/Rap|East Coast Rap', 3294 1071 => 'Music|Hip-Hop/Rap|Gangsta Rap', 3295 1072 => 'Music|Hip-Hop/Rap|Hardcore Rap', 3296 1073 => 'Music|Hip-Hop/Rap|Hip-Hop', 3297 1074 => 'Music|Hip-Hop/Rap|Latin Rap', 3298 1075 => 'Music|Hip-Hop/Rap|Old School Rap', 3299 1076 => 'Music|Hip-Hop/Rap|Rap', 3300 1077 => 'Music|Hip-Hop/Rap|Underground Rap', 3301 1078 => 'Music|Hip-Hop/Rap|West Coast Rap', 3302 1079 => 'Music|Holiday|Chanukah', 3303 1080 => 'Music|Holiday|Christmas', 3304 1081 => "Music|Holiday|Christmas: Children's", 3305 1082 => 'Music|Holiday|Christmas: Classic', 3306 1083 => 'Music|Holiday|Christmas: Classical', 3307 1084 => 'Music|Holiday|Christmas: Jazz', 3308 1085 => 'Music|Holiday|Christmas: Modern', 3309 1086 => 'Music|Holiday|Christmas: Pop', 3310 1087 => 'Music|Holiday|Christmas: R&B', 3311 1088 => 'Music|Holiday|Christmas: Religious', 3312 1089 => 'Music|Holiday|Christmas: Rock', 3313 1090 => 'Music|Holiday|Easter', 3314 1091 => 'Music|Holiday|Halloween', 3315 1092 => 'Music|Holiday|Holiday: Other', 3316 1093 => 'Music|Holiday|Thanksgiving', 3317 1094 => 'Music|Christian & Gospel|CCM', 3318 1095 => 'Music|Christian & Gospel|Christian Metal', 3319 1096 => 'Music|Christian & Gospel|Christian Pop', 3320 1097 => 'Music|Christian & Gospel|Christian Rap', 3321 1098 => 'Music|Christian & Gospel|Christian Rock', 3322 1099 => 'Music|Christian & Gospel|Classic Christian', 3323 1100 => 'Music|Christian & Gospel|Contemporary Gospel', 3324 1101 => 'Music|Christian & Gospel|Gospel', 3325 1103 => 'Music|Christian & Gospel|Praise & Worship', 3326 1104 => 'Music|Christian & Gospel|Southern Gospel', 3327 1105 => 'Music|Christian & Gospel|Traditional Gospel', 3328 1106 => 'Music|Jazz|Avant-Garde Jazz', 3329 1107 => 'Music|Jazz|Contemporary Jazz', 3330 1108 => 'Music|Jazz|Crossover Jazz', 3331 1109 => 'Music|Jazz|Dixieland', 3332 1110 => 'Music|Jazz|Fusion', 3333 1111 => 'Music|Jazz|Latin Jazz', 3334 1112 => 'Music|Jazz|Mainstream Jazz', 3335 1113 => 'Music|Jazz|Ragtime', 3336 1114 => 'Music|Jazz|Smooth Jazz', 3337 1115 => 'Music|Latino|Latin Jazz', 3338 1116 => 'Music|Latino|Contemporary Latin', 3339 1117 => 'Music|Latino|Pop Latino', 3340 1118 => 'Music|Latino|Raices', # (Raíces) 3341 1119 => 'Music|Latino|Urbano latino', 3342 1120 => 'Music|Latino|Baladas y Boleros', 3343 1121 => 'Music|Latino|Rock y Alternativo', 3344 1122 => 'Music|Brazilian', 3345 1123 => 'Music|Latino|Musica Mexicana', # (Música Mexicana) 3346 1124 => 'Music|Latino|Musica tropical', # (Música tropical) 3347 1125 => 'Music|New Age|Environmental', 3348 1126 => 'Music|New Age|Healing', 3349 1127 => 'Music|New Age|Meditation', 3350 1128 => 'Music|New Age|Nature', 3351 1129 => 'Music|New Age|Relaxation', 3352 1130 => 'Music|New Age|Travel', 3353 1131 => 'Music|Pop|Adult Contemporary', 3354 1132 => 'Music|Pop|Britpop', 3355 1133 => 'Music|Pop|Pop/Rock', 3356 1134 => 'Music|Pop|Soft Rock', 3357 1135 => 'Music|Pop|Teen Pop', 3358 1136 => 'Music|R&B/Soul|Contemporary R&B', 3359 1137 => 'Music|R&B/Soul|Disco', 3360 1138 => 'Music|R&B/Soul|Doo Wop', 3361 1139 => 'Music|R&B/Soul|Funk', 3362 1140 => 'Music|R&B/Soul|Motown', 3363 1141 => 'Music|R&B/Soul|Neo-Soul', 3364 1142 => 'Music|R&B/Soul|Quiet Storm', 3365 1143 => 'Music|R&B/Soul|Soul', 3366 1144 => 'Music|Rock|Adult Alternative', 3367 1145 => 'Music|Rock|American Trad Rock', 3368 1146 => 'Music|Rock|Arena Rock', 3369 1147 => 'Music|Rock|Blues-Rock', 3370 1148 => 'Music|Rock|British Invasion', 3371 1149 => 'Music|Rock|Death Metal/Black Metal', 3372 1150 => 'Music|Rock|Glam Rock', 3373 1151 => 'Music|Rock|Hair Metal', 3374 1152 => 'Music|Rock|Hard Rock', 3375 1153 => 'Music|Rock|Metal', 3376 1154 => 'Music|Rock|Jam Bands', 3377 1155 => 'Music|Rock|Prog-Rock/Art Rock', 3378 1156 => 'Music|Rock|Psychedelic', 3379 1157 => 'Music|Rock|Rock & Roll', 3380 1158 => 'Music|Rock|Rockabilly', 3381 1159 => 'Music|Rock|Roots Rock', 3382 1160 => 'Music|Rock|Singer/Songwriter', 3383 1161 => 'Music|Rock|Southern Rock', 3384 1162 => 'Music|Rock|Surf', 3385 1163 => 'Music|Rock|Tex-Mex', 3386 1165 => 'Music|Soundtrack|Foreign Cinema', 3387 1166 => 'Music|Soundtrack|Musicals', 3388 1167 => 'Music|Comedy|Novelty', 3389 1168 => 'Music|Soundtrack|Original Score', 3390 1169 => 'Music|Soundtrack|Soundtrack', 3391 1171 => 'Music|Comedy|Standup Comedy', 3392 1172 => 'Music|Soundtrack|TV Soundtrack', 3393 1173 => 'Music|Vocal|Standards', 3394 1174 => 'Music|Vocal|Traditional Pop', 3395 1175 => 'Music|Jazz|Vocal Jazz', 3396 1176 => 'Music|Vocal|Vocal Pop', 3397 1177 => 'Music|African|Afro-Beat', 3398 1178 => 'Music|African|Afro-Pop', 3399 1179 => 'Music|World|Cajun', 3400 1180 => 'Music|World|Celtic', 3401 1181 => 'Music|World|Celtic Folk', 3402 1182 => 'Music|World|Contemporary Celtic', 3403 1183 => 'Music|Reggae|Modern Dancehall', 3404 1184 => 'Music|World|Drinking Songs', 3405 1185 => 'Music|Indian|Indian Pop', 3406 1186 => 'Music|World|Japanese Pop', 3407 1187 => 'Music|World|Klezmer', 3408 1188 => 'Music|World|Polka', 3409 1189 => 'Music|World|Traditional Celtic', 3410 1190 => 'Music|World|Worldbeat', 3411 1191 => 'Music|World|Zydeco', 3412 1192 => 'Music|Reggae|Roots Reggae', 3413 1193 => 'Music|Reggae|Dub', 3414 1194 => 'Music|Reggae|Ska', 3415 1195 => 'Music|World|Caribbean', 3416 1196 => 'Music|World|South America', 3417 1197 => 'Music|Arabic', 3418 1198 => 'Music|World|North America', 3419 1199 => 'Music|World|Hawaii', 3420 1200 => 'Music|World|Australia', 3421 1201 => 'Music|World|Japan', 3422 1202 => 'Music|World|France', 3423 1203 => 'Music|African', 3424 1204 => 'Music|World|Asia', 3425 1205 => 'Music|World|Europe', 3426 1206 => 'Music|World|South Africa', 3427 1207 => 'Music|Jazz|Hard Bop', 3428 1208 => 'Music|Jazz|Trad Jazz', 3429 1209 => 'Music|Jazz|Cool Jazz', 3430 1210 => 'Music|Blues|Acoustic Blues', 3431 1211 => 'Music|Classical|High Classical', 3432 1220 => 'Music|Brazilian|Axe', # (Axé) 3433 1221 => 'Music|Brazilian|Bossa Nova', 3434 1222 => 'Music|Brazilian|Choro', 3435 1223 => 'Music|Brazilian|Forro', # (Forró) 3436 1224 => 'Music|Brazilian|Frevo', 3437 1225 => 'Music|Brazilian|MPB', 3438 1226 => 'Music|Brazilian|Pagode', 3439 1227 => 'Music|Brazilian|Samba', 3440 1228 => 'Music|Brazilian|Sertanejo', 3441 1229 => 'Music|Brazilian|Baile Funk', 3442 1230 => 'Music|Alternative|Chinese Alt', 3443 1231 => 'Music|Alternative|Korean Indie', 3444 1232 => 'Music|Chinese', 3445 1233 => 'Music|Chinese|Chinese Classical', 3446 1234 => 'Music|Chinese|Chinese Flute', 3447 1235 => 'Music|Chinese|Chinese Opera', 3448 1236 => 'Music|Chinese|Chinese Orchestral', 3449 1237 => 'Music|Chinese|Chinese Regional Folk', 3450 1238 => 'Music|Chinese|Chinese Strings', 3451 1239 => 'Music|Chinese|Taiwanese Folk', 3452 1240 => 'Music|Chinese|Tibetan Native Music', 3453 1241 => 'Music|Hip-Hop/Rap|Chinese Hip-Hop', 3454 1242 => 'Music|Hip-Hop/Rap|Korean Hip-Hop', 3455 1243 => 'Music|Korean', 3456 1244 => 'Music|Korean|Korean Classical', 3457 1245 => 'Music|Korean|Korean Trad Song', 3458 1246 => 'Music|Korean|Korean Trad Instrumental', 3459 1247 => 'Music|Korean|Korean Trad Theater', 3460 1248 => 'Music|Rock|Chinese Rock', 3461 1249 => 'Music|Rock|Korean Rock', 3462 1250 => 'Music|Pop|C-Pop', 3463 1251 => 'Music|Pop|Cantopop/HK-Pop', 3464 1252 => 'Music|Pop|Korean Folk-Pop', 3465 1253 => 'Music|Pop|Mandopop', 3466 1254 => 'Music|Pop|Tai-Pop', 3467 1255 => 'Music|Pop|Malaysian Pop', 3468 1256 => 'Music|Pop|Pinoy Pop', 3469 1257 => 'Music|Pop|Original Pilipino Music', 3470 1258 => 'Music|Pop|Manilla Sound', 3471 1259 => 'Music|Pop|Indo Pop', 3472 1260 => 'Music|Pop|Thai Pop', 3473 1261 => 'Music|Vocal|Trot', 3474 1262 => 'Music|Indian', 3475 1263 => 'Music|Indian|Bollywood', 3476 1264 => 'Music|Indian|Regional Indian|Tamil', 3477 1265 => 'Music|Indian|Regional Indian|Telugu', 3478 1266 => 'Music|Indian|Regional Indian', 3479 1267 => 'Music|Indian|Devotional & Spiritual', 3480 1268 => 'Music|Indian|Sufi', 3481 1269 => 'Music|Indian|Indian Classical', 3482 1270 => 'Music|Russian|Russian Chanson', 3483 1271 => 'Music|World|Dini', 3484 1272 => 'Music|Turkish|Halk', 3485 1273 => 'Music|Turkish|Sanat', 3486 1274 => 'Music|World|Dangdut', 3487 1275 => 'Music|World|Indonesian Religious', 3488 1276 => 'Music|World|Calypso', 3489 1277 => 'Music|World|Soca', 3490 1278 => 'Music|Indian|Ghazals', 3491 1279 => 'Music|Indian|Indian Folk', 3492 1280 => 'Music|Turkish|Arabesque', 3493 1281 => 'Music|African|Afrikaans', 3494 1282 => 'Music|World|Farsi', 3495 1283 => 'Music|World|Israeli', 3496 1284 => 'Music|Arabic|Khaleeji', 3497 1285 => 'Music|Arabic|North African', 3498 1286 => 'Music|Arabic|Arabic Pop', 3499 1287 => 'Music|Arabic|Islamic', 3500 1288 => 'Music|Soundtrack|Sound Effects', 3501 1289 => 'Music|Folk', 3502 1290 => 'Music|Orchestral', 3503 1291 => 'Music|Marching', 3504 1293 => 'Music|Pop|Oldies', 3505 1294 => 'Music|Country|Thai Country', 3506 1295 => 'Music|World|Flamenco', 3507 1296 => 'Music|World|Tango', 3508 1297 => 'Music|World|Fado', 3509 1298 => 'Music|World|Iberia', 3510 1299 => 'Music|Russian', 3511 1300 => 'Music|Turkish', 3512 1301 => 'Podcasts|Arts', 3513 1302 => 'Podcasts|Society & Culture|Personal Journals', 3514 1303 => 'Podcasts|Comedy', 3515 1304 => 'Podcasts|Education', 3516 1305 => 'Podcasts|Kids & Family', 3517 1306 => 'Podcasts|Arts|Food', 3518 1307 => 'Podcasts|Health', 3519 1309 => 'Podcasts|TV & Film', 3520 1310 => 'Podcasts|Music', 3521 1311 => 'Podcasts|News & Politics', 3522 1314 => 'Podcasts|Religion & Spirituality', 3523 1315 => 'Podcasts|Science & Medicine', 3524 1316 => 'Podcasts|Sports & Recreation', 3525 1318 => 'Podcasts|Technology', 3526 1320 => 'Podcasts|Society & Culture|Places & Travel', 3527 1321 => 'Podcasts|Business', 3528 1323 => 'Podcasts|Games & Hobbies', 3529 1324 => 'Podcasts|Society & Culture', 3530 1325 => 'Podcasts|Government & Organizations', 3531 1337 => 'Music Videos|Classical|Piano', 3532 1401 => 'Podcasts|Arts|Literature', 3533 1402 => 'Podcasts|Arts|Design', 3534 1404 => 'Podcasts|Games & Hobbies|Video Games', 3535 1405 => 'Podcasts|Arts|Performing Arts', 3536 1406 => 'Podcasts|Arts|Visual Arts', 3537 1410 => 'Podcasts|Business|Careers', 3538 1412 => 'Podcasts|Business|Investing', 3539 1413 => 'Podcasts|Business|Management & Marketing', 3540 1415 => 'Podcasts|Education|K-12', 3541 1416 => 'Podcasts|Education|Higher Education', 3542 1417 => 'Podcasts|Health|Fitness & Nutrition', 3543 1420 => 'Podcasts|Health|Self-Help', 3544 1421 => 'Podcasts|Health|Sexuality', 3545 1438 => 'Podcasts|Religion & Spirituality|Buddhism', 3546 1439 => 'Podcasts|Religion & Spirituality|Christianity', 3547 1440 => 'Podcasts|Religion & Spirituality|Islam', 3548 1441 => 'Podcasts|Religion & Spirituality|Judaism', 3549 1443 => 'Podcasts|Society & Culture|Philosophy', 3550 1444 => 'Podcasts|Religion & Spirituality|Spirituality', 3551 1446 => 'Podcasts|Technology|Gadgets', 3552 1448 => 'Podcasts|Technology|Tech News', 3553 1450 => 'Podcasts|Technology|Podcasting', 3554 1454 => 'Podcasts|Games & Hobbies|Automotive', 3555 1455 => 'Podcasts|Games & Hobbies|Aviation', 3556 1456 => 'Podcasts|Sports & Recreation|Outdoor', 3557 1459 => 'Podcasts|Arts|Fashion & Beauty', 3558 1460 => 'Podcasts|Games & Hobbies|Hobbies', 3559 1461 => 'Podcasts|Games & Hobbies|Other Games', 3560 1462 => 'Podcasts|Society & Culture|History', 3561 1463 => 'Podcasts|Religion & Spirituality|Hinduism', 3562 1464 => 'Podcasts|Religion & Spirituality|Other', 3563 1465 => 'Podcasts|Sports & Recreation|Professional', 3564 1466 => 'Podcasts|Sports & Recreation|College & High School', 3565 1467 => 'Podcasts|Sports & Recreation|Amateur', 3566 1468 => 'Podcasts|Education|Educational Technology', 3567 1469 => 'Podcasts|Education|Language Courses', 3568 1470 => 'Podcasts|Education|Training', 3569 1471 => 'Podcasts|Business|Business News', 3570 1472 => 'Podcasts|Business|Shopping', 3571 1473 => 'Podcasts|Government & Organizations|National', 3572 1474 => 'Podcasts|Government & Organizations|Regional', 3573 1475 => 'Podcasts|Government & Organizations|Local', 3574 1476 => 'Podcasts|Government & Organizations|Non-Profit', 3575 1477 => 'Podcasts|Science & Medicine|Natural Sciences', 3576 1478 => 'Podcasts|Science & Medicine|Medicine', 3577 1479 => 'Podcasts|Science & Medicine|Social Sciences', 3578 1480 => 'Podcasts|Technology|Software How-To', 3579 1481 => 'Podcasts|Health|Alternative Health', 3580 1482 => 'Podcasts|Arts|Books', 3581 1483 => 'Podcasts|Fiction', 3582 1484 => 'Podcasts|Fiction|Drama', 3583 1485 => 'Podcasts|Fiction|Science Fiction', 3584 1486 => 'Podcasts|Fiction|Comedy Fiction', 3585 1487 => 'Podcasts|History', 3586 1488 => 'Podcasts|True Crime', 3587 1489 => 'Podcasts|News', 3588 1490 => 'Podcasts|News|Business News', 3589 1491 => 'Podcasts|Business|Management', 3590 1492 => 'Podcasts|Business|Marketing', 3591 1493 => 'Podcasts|Business|Entrepreneurship', 3592 1494 => 'Podcasts|Business|Non-Profit', 3593 1495 => 'Podcasts|Comedy|Improv', 3594 1496 => 'Podcasts|Comedy|Comedy Interviews', 3595 1497 => 'Podcasts|Comedy|Stand-Up', 3596 1498 => 'Podcasts|Education|Language Learning', 3597 1499 => 'Podcasts|Education|How To', 3598 1500 => 'Podcasts|Education|Self-Improvement', 3599 1501 => 'Podcasts|Education|Courses', 3600 1502 => 'Podcasts|Leisure', 3601 1503 => 'Podcasts|Leisure|Automotive', 3602 1504 => 'Podcasts|Leisure|Aviation', 3603 1505 => 'Podcasts|Leisure|Hobbies', 3604 1506 => 'Podcasts|Leisure|Crafts', 3605 1507 => 'Podcasts|Leisure|Games', 3606 1508 => 'Podcasts|Leisure|Home & Garden', 3607 1509 => 'Podcasts|Leisure|Video Games', 3608 1510 => 'Podcasts|Leisure|Animation & Manga', 3609 1511 => 'Podcasts|Government', 3610 1512 => 'Podcasts|Health & Fitness', 3611 1513 => 'Podcasts|Health & Fitness|Alternative Health', 3612 1514 => 'Podcasts|Health & Fitness|Fitness', 3613 1515 => 'Podcasts|Health & Fitness|Nutrition', 3614 1516 => 'Podcasts|Health & Fitness|Sexuality', 3615 1517 => 'Podcasts|Health & Fitness|Mental Health', 3616 1518 => 'Podcasts|Health & Fitness|Medicine', 3617 1519 => 'Podcasts|Kids & Family|Education for Kids', 3618 1520 => 'Podcasts|Kids & Family|Stories for Kids', 3619 1521 => 'Podcasts|Kids & Family|Parenting', 3620 1522 => 'Podcasts|Kids & Family|Pets & Animals', 3621 1523 => 'Podcasts|Music|Music Commentary', 3622 1524 => 'Podcasts|Music|Music History', 3623 1525 => 'Podcasts|Music|Music Interviews', 3624 1526 => 'Podcasts|News|Daily News', 3625 1527 => 'Podcasts|News|Politics', 3626 1528 => 'Podcasts|News|Tech News', 3627 1529 => 'Podcasts|News|Sports News', 3628 1530 => 'Podcasts|News|News Commentary', 3629 1531 => 'Podcasts|News|Entertainment News', 3630 1532 => 'Podcasts|Religion & Spirituality|Religion', 3631 1533 => 'Podcasts|Science', 3632 1534 => 'Podcasts|Science|Natural Sciences', 3633 1535 => 'Podcasts|Science|Social Sciences', 3634 1536 => 'Podcasts|Science|Mathematics', 3635 1537 => 'Podcasts|Science|Nature', 3636 1538 => 'Podcasts|Science|Astronomy', 3637 1539 => 'Podcasts|Science|Chemistry', 3638 1540 => 'Podcasts|Science|Earth Sciences', 3639 1541 => 'Podcasts|Science|Life Sciences', 3640 1542 => 'Podcasts|Science|Physics', 3641 1543 => 'Podcasts|Society & Culture|Documentary', 3642 1544 => 'Podcasts|Society & Culture|Relationships', 3643 1545 => 'Podcasts|Sports', 3644 1546 => 'Podcasts|Sports|Soccer', 3645 1547 => 'Podcasts|Sports|Football', 3646 1548 => 'Podcasts|Sports|Basketball', 3647 1549 => 'Podcasts|Sports|Baseball', 3648 1550 => 'Podcasts|Sports|Hockey', 3649 1551 => 'Podcasts|Sports|Running', 3650 1552 => 'Podcasts|Sports|Rugby', 3651 1553 => 'Podcasts|Sports|Golf', 3652 1554 => 'Podcasts|Sports|Cricket', 3653 1555 => 'Podcasts|Sports|Wrestling', 3654 1556 => 'Podcasts|Sports|Tennis', 3655 1557 => 'Podcasts|Sports|Volleyball', 3656 1558 => 'Podcasts|Sports|Swimming', 3657 1559 => 'Podcasts|Sports|Wilderness', 3658 1560 => 'Podcasts|Sports|Fantasy Sports', 3659 1561 => 'Podcasts|TV & Film|TV Reviews', 3660 1562 => 'Podcasts|TV & Film|After Shows', 3661 1563 => 'Podcasts|TV & Film|Film Reviews', 3662 1564 => 'Podcasts|TV & Film|Film History', 3663 1565 => 'Podcasts|TV & Film|Film Interviews', 3664 1602 => 'Music Videos|Blues', 3665 1603 => 'Music Videos|Comedy', 3666 1604 => "Music Videos|Children's Music", 3667 1605 => 'Music Videos|Classical', 3668 1606 => 'Music Videos|Country', 3669 1607 => 'Music Videos|Electronic', 3670 1608 => 'Music Videos|Holiday', 3671 1609 => 'Music Videos|Classical|Opera', 3672 1610 => 'Music Videos|Singer/Songwriter', 3673 1611 => 'Music Videos|Jazz', 3674 1612 => 'Music Videos|Latin', 3675 1613 => 'Music Videos|New Age', 3676 1614 => 'Music Videos|Pop', 3677 1615 => 'Music Videos|R&B/Soul', 3678 1616 => 'Music Videos|Soundtrack', 3679 1617 => 'Music Videos|Dance', 3680 1618 => 'Music Videos|Hip-Hop/Rap', 3681 1619 => 'Music Videos|World', 3682 1620 => 'Music Videos|Alternative', 3683 1621 => 'Music Videos|Rock', 3684 1622 => 'Music Videos|Christian & Gospel', 3685 1623 => 'Music Videos|Vocal', 3686 1624 => 'Music Videos|Reggae', 3687 1625 => 'Music Videos|Easy Listening', 3688 1626 => 'Music Videos|Podcasts', 3689 1627 => 'Music Videos|J-Pop', 3690 1628 => 'Music Videos|Enka', 3691 1629 => 'Music Videos|Anime', 3692 1630 => 'Music Videos|Kayokyoku', 3693 1631 => 'Music Videos|Disney', 3694 1632 => 'Music Videos|French Pop', 3695 1633 => 'Music Videos|German Pop', 3696 1634 => 'Music Videos|German Folk', 3697 1635 => 'Music Videos|Alternative|Chinese Alt', 3698 1636 => 'Music Videos|Alternative|Korean Indie', 3699 1637 => 'Music Videos|Chinese', 3700 1638 => 'Music Videos|Chinese|Chinese Classical', 3701 1639 => 'Music Videos|Chinese|Chinese Flute', 3702 1640 => 'Music Videos|Chinese|Chinese Opera', 3703 1641 => 'Music Videos|Chinese|Chinese Orchestral', 3704 1642 => 'Music Videos|Chinese|Chinese Regional Folk', 3705 1643 => 'Music Videos|Chinese|Chinese Strings', 3706 1644 => 'Music Videos|Chinese|Taiwanese Folk', 3707 1645 => 'Music Videos|Chinese|Tibetan Native Music', 3708 1646 => 'Music Videos|Hip-Hop/Rap|Chinese Hip-Hop', 3709 1647 => 'Music Videos|Hip-Hop/Rap|Korean Hip-Hop', 3710 1648 => 'Music Videos|Korean', 3711 1649 => 'Music Videos|Korean|Korean Classical', 3712 1650 => 'Music Videos|Korean|Korean Trad Song', 3713 1651 => 'Music Videos|Korean|Korean Trad Instrumental', 3714 1652 => 'Music Videos|Korean|Korean Trad Theater', 3715 1653 => 'Music Videos|Rock|Chinese Rock', 3716 1654 => 'Music Videos|Rock|Korean Rock', 3717 1655 => 'Music Videos|Pop|C-Pop', 3718 1656 => 'Music Videos|Pop|Cantopop/HK-Pop', 3719 1657 => 'Music Videos|Pop|Korean Folk-Pop', 3720 1658 => 'Music Videos|Pop|Mandopop', 3721 1659 => 'Music Videos|Pop|Tai-Pop', 3722 1660 => 'Music Videos|Pop|Malaysian Pop', 3723 1661 => 'Music Videos|Pop|Pinoy Pop', 3724 1662 => 'Music Videos|Pop|Original Pilipino Music', 3725 1663 => 'Music Videos|Pop|Manilla Sound', 3726 1664 => 'Music Videos|Pop|Indo Pop', 3727 1665 => 'Music Videos|Pop|Thai Pop', 3728 1666 => 'Music Videos|Vocal|Trot', 3729 1671 => 'Music Videos|Brazilian', 3730 1672 => 'Music Videos|Brazilian|Axe', # (Axé) 3731 1673 => 'Music Videos|Brazilian|Baile Funk', 3732 1674 => 'Music Videos|Brazilian|Bossa Nova', 3733 1675 => 'Music Videos|Brazilian|Choro', 3734 1676 => 'Music Videos|Brazilian|Forro', 3735 1677 => 'Music Videos|Brazilian|Frevo', 3736 1678 => 'Music Videos|Brazilian|MPB', 3737 1679 => 'Music Videos|Brazilian|Pagode', 3738 1680 => 'Music Videos|Brazilian|Samba', 3739 1681 => 'Music Videos|Brazilian|Sertanejo', 3740 1682 => 'Music Videos|Classical|High Classical', 3741 1683 => 'Music Videos|Fitness & Workout', 3742 1684 => 'Music Videos|Instrumental', 3743 1685 => 'Music Videos|Jazz|Big Band', 3744 1686 => 'Music Videos|Pop|K-Pop', 3745 1687 => 'Music Videos|Karaoke', 3746 1688 => 'Music Videos|Rock|Heavy Metal', 3747 1689 => 'Music Videos|Spoken Word', 3748 1690 => 'Music Videos|Indian', 3749 1691 => 'Music Videos|Indian|Bollywood', 3750 1692 => 'Music Videos|Indian|Regional Indian|Tamil', 3751 1693 => 'Music Videos|Indian|Regional Indian|Telugu', 3752 1694 => 'Music Videos|Indian|Regional Indian', 3753 1695 => 'Music Videos|Indian|Devotional & Spiritual', 3754 1696 => 'Music Videos|Indian|Sufi', 3755 1697 => 'Music Videos|Indian|Indian Classical', 3756 1698 => 'Music Videos|Russian|Russian Chanson', 3757 1699 => 'Music Videos|World|Dini', 3758 1700 => 'Music Videos|Turkish|Halk', 3759 1701 => 'Music Videos|Turkish|Sanat', 3760 1702 => 'Music Videos|World|Dangdut', 3761 1703 => 'Music Videos|World|Indonesian Religious', 3762 1704 => 'Music Videos|Indian|Indian Pop', 3763 1705 => 'Music Videos|World|Calypso', 3764 1706 => 'Music Videos|World|Soca', 3765 1707 => 'Music Videos|Indian|Ghazals', 3766 1708 => 'Music Videos|Indian|Indian Folk', 3767 1709 => 'Music Videos|Turkish|Arabesque', 3768 1710 => 'Music Videos|African|Afrikaans', 3769 1711 => 'Music Videos|World|Farsi', 3770 1712 => 'Music Videos|World|Israeli', 3771 1713 => 'Music Videos|Arabic', 3772 1714 => 'Music Videos|Arabic|Khaleeji', 3773 1715 => 'Music Videos|Arabic|North African', 3774 1716 => 'Music Videos|Arabic|Arabic Pop', 3775 1717 => 'Music Videos|Arabic|Islamic', 3776 1718 => 'Music Videos|Soundtrack|Sound Effects', 3777 1719 => 'Music Videos|Folk', 3778 1720 => 'Music Videos|Orchestral', 3779 1721 => 'Music Videos|Marching', 3780 1723 => 'Music Videos|Pop|Oldies', 3781 1724 => 'Music Videos|Country|Thai Country', 3782 1725 => 'Music Videos|World|Flamenco', 3783 1726 => 'Music Videos|World|Tango', 3784 1727 => 'Music Videos|World|Fado', 3785 1728 => 'Music Videos|World|Iberia', 3786 1729 => 'Music Videos|Russian', 3787 1730 => 'Music Videos|Turkish', 3788 1731 => 'Music Videos|Alternative|College Rock', 3789 1732 => 'Music Videos|Alternative|Goth Rock', 3790 1733 => 'Music Videos|Alternative|Grunge', 3791 1734 => 'Music Videos|Alternative|Indie Rock', 3792 1735 => 'Music Videos|Alternative|New Wave', 3793 1736 => 'Music Videos|Alternative|Punk', 3794 1737 => 'Music Videos|Blues|Acoustic Blues', 3795 1738 => 'Music Videos|Blues|Chicago Blues', 3796 1739 => 'Music Videos|Blues|Classic Blues', 3797 1740 => 'Music Videos|Blues|Contemporary Blues', 3798 1741 => 'Music Videos|Blues|Country Blues', 3799 1742 => 'Music Videos|Blues|Delta Blues', 3800 1743 => 'Music Videos|Blues|Electric Blues', 3801 1744 => "Music Videos|Children's Music|Lullabies", 3802 1745 => "Music Videos|Children's Music|Sing-Along", 3803 1746 => "Music Videos|Children's Music|Stories", 3804 1747 => 'Music Videos|Christian & Gospel|CCM', 3805 1748 => 'Music Videos|Christian & Gospel|Christian Metal', 3806 1749 => 'Music Videos|Christian & Gospel|Christian Pop', 3807 1750 => 'Music Videos|Christian & Gospel|Christian Rap', 3808 1751 => 'Music Videos|Christian & Gospel|Christian Rock', 3809 1752 => 'Music Videos|Christian & Gospel|Classic Christian', 3810 1753 => 'Music Videos|Christian & Gospel|Contemporary Gospel', 3811 1754 => 'Music Videos|Christian & Gospel|Gospel', 3812 1755 => 'Music Videos|Christian & Gospel|Praise & Worship', 3813 1756 => 'Music Videos|Christian & Gospel|Southern Gospel', 3814 1757 => 'Music Videos|Christian & Gospel|Traditional Gospel', 3815 1758 => 'Music Videos|Classical|Avant-Garde', 3816 1759 => 'Music Videos|Classical|Baroque Era', 3817 1760 => 'Music Videos|Classical|Chamber Music', 3818 1761 => 'Music Videos|Classical|Chant', 3819 1762 => 'Music Videos|Classical|Choral', 3820 1763 => 'Music Videos|Classical|Classical Crossover', 3821 1764 => 'Music Videos|Classical|Early Music', 3822 1765 => 'Music Videos|Classical|Impressionist', 3823 1766 => 'Music Videos|Classical|Medieval Era', 3824 1767 => 'Music Videos|Classical|Minimalism', 3825 1768 => 'Music Videos|Classical|Modern Era', 3826 1769 => 'Music Videos|Classical|Orchestral', 3827 1770 => 'Music Videos|Classical|Renaissance', 3828 1771 => 'Music Videos|Classical|Romantic Era', 3829 1772 => 'Music Videos|Classical|Wedding Music', 3830 1773 => 'Music Videos|Comedy|Novelty', 3831 1774 => 'Music Videos|Comedy|Standup Comedy', 3832 1775 => 'Music Videos|Country|Alternative Country', 3833 1776 => 'Music Videos|Country|Americana', 3834 1777 => 'Music Videos|Country|Bluegrass', 3835 1778 => 'Music Videos|Country|Contemporary Bluegrass', 3836 1779 => 'Music Videos|Country|Contemporary Country', 3837 1780 => 'Music Videos|Country|Country Gospel', 3838 1781 => 'Music Videos|Country|Honky Tonk', 3839 1782 => 'Music Videos|Country|Outlaw Country', 3840 1783 => 'Music Videos|Country|Traditional Bluegrass', 3841 1784 => 'Music Videos|Country|Traditional Country', 3842 1785 => 'Music Videos|Country|Urban Cowboy', 3843 1786 => 'Music Videos|Dance|Breakbeat', 3844 1787 => 'Music Videos|Dance|Exercise', 3845 1788 => 'Music Videos|Dance|Garage', 3846 1789 => 'Music Videos|Dance|Hardcore', 3847 1790 => 'Music Videos|Dance|House', 3848 1791 => "Music Videos|Dance|Jungle/Drum'n'bass", 3849 1792 => 'Music Videos|Dance|Techno', 3850 1793 => 'Music Videos|Dance|Trance', 3851 1794 => 'Music Videos|Easy Listening|Lounge', 3852 1795 => 'Music Videos|Easy Listening|Swing', 3853 1796 => 'Music Videos|Electronic|Ambient', 3854 1797 => 'Music Videos|Electronic|Downtempo', 3855 1798 => 'Music Videos|Electronic|Electronica', 3856 1799 => 'Music Videos|Electronic|IDM/Experimental', 3857 1800 => 'Music Videos|Electronic|Industrial', 3858 1801 => 'Music Videos|Hip-Hop/Rap|Alternative Rap', 3859 1802 => 'Music Videos|Hip-Hop/Rap|Dirty South', 3860 1803 => 'Music Videos|Hip-Hop/Rap|East Coast Rap', 3861 1804 => 'Music Videos|Hip-Hop/Rap|Gangsta Rap', 3862 1805 => 'Music Videos|Hip-Hop/Rap|Hardcore Rap', 3863 1806 => 'Music Videos|Hip-Hop/Rap|Hip-Hop', 3864 1807 => 'Music Videos|Hip-Hop/Rap|Latin Rap', 3865 1808 => 'Music Videos|Hip-Hop/Rap|Old School Rap', 3866 1809 => 'Music Videos|Hip-Hop/Rap|Rap', 3867 1810 => 'Music Videos|Hip-Hop/Rap|Underground Rap', 3868 1811 => 'Music Videos|Hip-Hop/Rap|West Coast Rap', 3869 1812 => 'Music Videos|Holiday|Chanukah', 3870 1813 => 'Music Videos|Holiday|Christmas', 3871 1814 => "Music Videos|Holiday|Christmas: Children's", 3872 1815 => 'Music Videos|Holiday|Christmas: Classic', 3873 1816 => 'Music Videos|Holiday|Christmas: Classical', 3874 1817 => 'Music Videos|Holiday|Christmas: Jazz', 3875 1818 => 'Music Videos|Holiday|Christmas: Modern', 3876 1819 => 'Music Videos|Holiday|Christmas: Pop', 3877 1820 => 'Music Videos|Holiday|Christmas: R&B', 3878 1821 => 'Music Videos|Holiday|Christmas: Religious', 3879 1822 => 'Music Videos|Holiday|Christmas: Rock', 3880 1823 => 'Music Videos|Holiday|Easter', 3881 1824 => 'Music Videos|Holiday|Halloween', 3882 1825 => 'Music Videos|Holiday|Thanksgiving', 3883 1826 => 'Music Videos|Jazz|Avant-Garde Jazz', 3884 1828 => 'Music Videos|Jazz|Bop', 3885 1829 => 'Music Videos|Jazz|Contemporary Jazz', 3886 1830 => 'Music Videos|Jazz|Cool Jazz', 3887 1831 => 'Music Videos|Jazz|Crossover Jazz', 3888 1832 => 'Music Videos|Jazz|Dixieland', 3889 1833 => 'Music Videos|Jazz|Fusion', 3890 1834 => 'Music Videos|Jazz|Hard Bop', 3891 1835 => 'Music Videos|Jazz|Latin Jazz', 3892 1836 => 'Music Videos|Jazz|Mainstream Jazz', 3893 1837 => 'Music Videos|Jazz|Ragtime', 3894 1838 => 'Music Videos|Jazz|Smooth Jazz', 3895 1839 => 'Music Videos|Jazz|Trad Jazz', 3896 1840 => 'Music Videos|Latin|Alternative & Rock in Spanish', 3897 1841 => 'Music Videos|Latin|Baladas y Boleros', 3898 1842 => 'Music Videos|Latin|Contemporary Latin', 3899 1843 => 'Music Videos|Latin|Latin Jazz', 3900 1844 => 'Music Videos|Latin|Latin Urban', 3901 1845 => 'Music Videos|Latin|Pop in Spanish', 3902 1846 => 'Music Videos|Latin|Raices', 3903 1847 => 'Music Videos|Latin|Musica Mexicana', # (Música Mexicana) 3904 1848 => 'Music Videos|Latin|Salsa y Tropical', 3905 1849 => 'Music Videos|New Age|Healing', 3906 1850 => 'Music Videos|New Age|Meditation', 3907 1851 => 'Music Videos|New Age|Nature', 3908 1852 => 'Music Videos|New Age|Relaxation', 3909 1853 => 'Music Videos|New Age|Travel', 3910 1854 => 'Music Videos|Pop|Adult Contemporary', 3911 1855 => 'Music Videos|Pop|Britpop', 3912 1856 => 'Music Videos|Pop|Pop/Rock', 3913 1857 => 'Music Videos|Pop|Soft Rock', 3914 1858 => 'Music Videos|Pop|Teen Pop', 3915 1859 => 'Music Videos|R&B/Soul|Contemporary R&B', 3916 1860 => 'Music Videos|R&B/Soul|Disco', 3917 1861 => 'Music Videos|R&B/Soul|Doo Wop', 3918 1862 => 'Music Videos|R&B/Soul|Funk', 3919 1863 => 'Music Videos|R&B/Soul|Motown', 3920 1864 => 'Music Videos|R&B/Soul|Neo-Soul', 3921 1865 => 'Music Videos|R&B/Soul|Soul', 3922 1866 => 'Music Videos|Reggae|Modern Dancehall', 3923 1867 => 'Music Videos|Reggae|Dub', 3924 1868 => 'Music Videos|Reggae|Roots Reggae', 3925 1869 => 'Music Videos|Reggae|Ska', 3926 1870 => 'Music Videos|Rock|Adult Alternative', 3927 1871 => 'Music Videos|Rock|American Trad Rock', 3928 1872 => 'Music Videos|Rock|Arena Rock', 3929 1873 => 'Music Videos|Rock|Blues-Rock', 3930 1874 => 'Music Videos|Rock|British Invasion', 3931 1875 => 'Music Videos|Rock|Death Metal/Black Metal', 3932 1876 => 'Music Videos|Rock|Glam Rock', 3933 1877 => 'Music Videos|Rock|Hair Metal', 3934 1878 => 'Music Videos|Rock|Hard Rock', 3935 1879 => 'Music Videos|Rock|Jam Bands', 3936 1880 => 'Music Videos|Rock|Prog-Rock/Art Rock', 3937 1881 => 'Music Videos|Rock|Psychedelic', 3938 1882 => 'Music Videos|Rock|Rock & Roll', 3939 1883 => 'Music Videos|Rock|Rockabilly', 3940 1884 => 'Music Videos|Rock|Roots Rock', 3941 1885 => 'Music Videos|Rock|Singer/Songwriter', 3942 1886 => 'Music Videos|Rock|Southern Rock', 3943 1887 => 'Music Videos|Rock|Surf', 3944 1888 => 'Music Videos|Rock|Tex-Mex', 3945 1889 => 'Music Videos|Singer/Songwriter|Alternative Folk', 3946 1890 => 'Music Videos|Singer/Songwriter|Contemporary Folk', 3947 1891 => 'Music Videos|Singer/Songwriter|Contemporary Singer/Songwriter', 3948 1892 => 'Music Videos|Singer/Songwriter|Folk-Rock', 3949 1893 => 'Music Videos|Singer/Songwriter|New Acoustic', 3950 1894 => 'Music Videos|Singer/Songwriter|Traditional Folk', 3951 1895 => 'Music Videos|Soundtrack|Foreign Cinema', 3952 1896 => 'Music Videos|Soundtrack|Musicals', 3953 1897 => 'Music Videos|Soundtrack|Original Score', 3954 1898 => 'Music Videos|Soundtrack|Soundtrack', 3955 1899 => 'Music Videos|Soundtrack|TV Soundtrack', 3956 1900 => 'Music Videos|Vocal|Standards', 3957 1901 => 'Music Videos|Vocal|Traditional Pop', 3958 1902 => 'Music Videos|Jazz|Vocal Jazz', 3959 1903 => 'Music Videos|Vocal|Vocal Pop', 3960 1904 => 'Music Videos|African', 3961 1905 => 'Music Videos|African|Afro-Beat', 3962 1906 => 'Music Videos|African|Afro-Pop', 3963 1907 => 'Music Videos|World|Asia', 3964 1908 => 'Music Videos|World|Australia', 3965 1909 => 'Music Videos|World|Cajun', 3966 1910 => 'Music Videos|World|Caribbean', 3967 1911 => 'Music Videos|World|Celtic', 3968 1912 => 'Music Videos|World|Celtic Folk', 3969 1913 => 'Music Videos|World|Contemporary Celtic', 3970 1914 => 'Music Videos|World|Europe', 3971 1915 => 'Music Videos|World|France', 3972 1916 => 'Music Videos|World|Hawaii', 3973 1917 => 'Music Videos|World|Japan', 3974 1918 => 'Music Videos|World|Klezmer', 3975 1919 => 'Music Videos|World|North America', 3976 1920 => 'Music Videos|World|Polka', 3977 1921 => 'Music Videos|World|South Africa', 3978 1922 => 'Music Videos|World|South America', 3979 1923 => 'Music Videos|World|Traditional Celtic', 3980 1924 => 'Music Videos|World|Worldbeat', 3981 1925 => 'Music Videos|World|Zydeco', 3982 1926 => 'Music Videos|Christian & Gospel', 3983 1928 => 'Music Videos|Classical|Art Song', 3984 1929 => 'Music Videos|Classical|Brass & Woodwinds', 3985 1930 => 'Music Videos|Classical|Solo Instrumental', 3986 1931 => 'Music Videos|Classical|Contemporary Era', 3987 1932 => 'Music Videos|Classical|Oratorio', 3988 1933 => 'Music Videos|Classical|Cantata', 3989 1934 => 'Music Videos|Classical|Electronic', 3990 1935 => 'Music Videos|Classical|Sacred', 3991 1936 => 'Music Videos|Classical|Guitar', 3992 1938 => 'Music Videos|Classical|Violin', 3993 1939 => 'Music Videos|Classical|Cello', 3994 1940 => 'Music Videos|Classical|Percussion', 3995 1941 => 'Music Videos|Electronic|Dubstep', 3996 1942 => 'Music Videos|Electronic|Bass', 3997 1943 => 'Music Videos|Hip-Hop/Rap|UK Hip-Hop', 3998 1944 => 'Music Videos|Reggae|Lovers Rock', 3999 1945 => 'Music Videos|Alternative|EMO', 4000 1946 => 'Music Videos|Alternative|Pop Punk', 4001 1947 => 'Music Videos|Alternative|Indie Pop', 4002 1948 => 'Music Videos|New Age|Yoga', 4003 1949 => 'Music Videos|Pop|Tribute', 4004 1950 => 'Music Videos|Pop|Shows', 4005 1951 => 'Music Videos|Cuban', 4006 1952 => 'Music Videos|Cuban|Mambo', 4007 1953 => 'Music Videos|Cuban|Chachacha', 4008 1954 => 'Music Videos|Cuban|Guajira', 4009 1955 => 'Music Videos|Cuban|Son', 4010 1956 => 'Music Videos|Cuban|Bolero', 4011 1957 => 'Music Videos|Cuban|Guaracha', 4012 1958 => 'Music Videos|Cuban|Timba', 4013 1959 => 'Music Videos|Soundtrack|Video Game', 4014 1960 => 'Music Videos|Indian|Regional Indian|Punjabi|Punjabi Pop', 4015 1961 => 'Music Videos|Indian|Regional Indian|Bengali|Rabindra Sangeet', 4016 1962 => 'Music Videos|Indian|Regional Indian|Malayalam', 4017 1963 => 'Music Videos|Indian|Regional Indian|Kannada', 4018 1964 => 'Music Videos|Indian|Regional Indian|Marathi', 4019 1965 => 'Music Videos|Indian|Regional Indian|Gujarati', 4020 1966 => 'Music Videos|Indian|Regional Indian|Assamese', 4021 1967 => 'Music Videos|Indian|Regional Indian|Bhojpuri', 4022 1968 => 'Music Videos|Indian|Regional Indian|Haryanvi', 4023 1969 => 'Music Videos|Indian|Regional Indian|Odia', 4024 1970 => 'Music Videos|Indian|Regional Indian|Rajasthani', 4025 1971 => 'Music Videos|Indian|Regional Indian|Urdu', 4026 1972 => 'Music Videos|Indian|Regional Indian|Punjabi', 4027 1973 => 'Music Videos|Indian|Regional Indian|Bengali', 4028 1974 => 'Music Videos|Indian|Indian Classical|Carnatic Classical', 4029 1975 => 'Music Videos|Indian|Indian Classical|Hindustani Classical', 4030 1976 => 'Music Videos|African|Afro House', 4031 1977 => 'Music Videos|African|Afro Soul', 4032 1978 => 'Music Videos|African|Afrobeats', 4033 1979 => 'Music Videos|African|Benga', 4034 1980 => 'Music Videos|African|Bongo-Flava', 4035 1981 => 'Music Videos|African|Coupe-Decale', 4036 1982 => 'Music Videos|African|Gqom', 4037 1983 => 'Music Videos|African|Highlife', 4038 1984 => 'Music Videos|African|Kuduro', 4039 1985 => 'Music Videos|African|Kizomba', 4040 1986 => 'Music Videos|African|Kwaito', 4041 1987 => 'Music Videos|African|Mbalax', 4042 1988 => 'Music Videos|African|Ndombolo', 4043 1989 => 'Music Videos|African|Shangaan Electro', 4044 1990 => 'Music Videos|African|Soukous', 4045 1991 => 'Music Videos|African|Taarab', 4046 1992 => 'Music Videos|African|Zouglou', 4047 1993 => 'Music Videos|Turkish|Ozgun', 4048 1994 => 'Music Videos|Turkish|Fantezi', 4049 1995 => 'Music Videos|Turkish|Religious', 4050 1996 => 'Music Videos|Pop|Turkish Pop', 4051 1997 => 'Music Videos|Rock|Turkish Rock', 4052 1998 => 'Music Videos|Alternative|Turkish Alternative', 4053 1999 => 'Music Videos|Hip-Hop/Rap|Turkish Hip-Hop/Rap', 4054 2000 => 'Music Videos|African|Maskandi', 4055 2001 => 'Music Videos|Russian|Russian Romance', 4056 2002 => 'Music Videos|Russian|Russian Bard', 4057 2003 => 'Music Videos|Russian|Russian Pop', 4058 2004 => 'Music Videos|Russian|Russian Rock', 4059 2005 => 'Music Videos|Russian|Russian Hip-Hop', 4060 2006 => 'Music Videos|Arabic|Levant', 4061 2007 => 'Music Videos|Arabic|Levant|Dabke', 4062 2008 => 'Music Videos|Arabic|Maghreb Rai', 4063 2009 => 'Music Videos|Arabic|Khaleeji|Khaleeji Jalsat', 4064 2010 => 'Music Videos|Arabic|Khaleeji|Khaleeji Shailat', 4065 2011 => 'Music Videos|Tarab', 4066 2012 => 'Music Videos|Tarab|Iraqi Tarab', 4067 2013 => 'Music Videos|Tarab|Egyptian Tarab', 4068 2014 => 'Music Videos|Tarab|Khaleeji Tarab', 4069 2015 => 'Music Videos|Pop|Levant Pop', 4070 2016 => 'Music Videos|Pop|Iraqi Pop', 4071 2017 => 'Music Videos|Pop|Egyptian Pop', 4072 2018 => 'Music Videos|Pop|Maghreb Pop', 4073 2019 => 'Music Videos|Pop|Khaleeji Pop', 4074 2020 => 'Music Videos|Hip-Hop/Rap|Levant Hip-Hop', 4075 2021 => 'Music Videos|Hip-Hop/Rap|Egyptian Hip-Hop', 4076 2022 => 'Music Videos|Hip-Hop/Rap|Maghreb Hip-Hop', 4077 2023 => 'Music Videos|Hip-Hop/Rap|Khaleeji Hip-Hop', 4078 2024 => 'Music Videos|Alternative|Indie Levant', 4079 2025 => 'Music Videos|Alternative|Indie Egyptian', 4080 2026 => 'Music Videos|Alternative|Indie Maghreb', 4081 2027 => 'Music Videos|Electronic|Levant Electronic', 4082 2028 => "Music Videos|Electronic|Electro-Cha'abi", 4083 2029 => 'Music Videos|Electronic|Maghreb Electronic', 4084 2030 => 'Music Videos|Folk|Iraqi Folk', 4085 2031 => 'Music Videos|Folk|Khaleeji Folk', 4086 2032 => 'Music Videos|Dance|Maghreb Dance', 4087 4000 => 'TV Shows|Comedy', 4088 4001 => 'TV Shows|Drama', 4089 4002 => 'TV Shows|Animation', 4090 4003 => 'TV Shows|Action & Adventure', 4091 4004 => 'TV Shows|Classics', 4092 4005 => 'TV Shows|Kids & Family', 4093 4006 => 'TV Shows|Nonfiction', 4094 4007 => 'TV Shows|Reality TV', 4095 4008 => 'TV Shows|Sci-Fi & Fantasy', 4096 4009 => 'TV Shows|Sports', 4097 4010 => 'TV Shows|Teens', 4098 4011 => 'TV Shows|Latino TV', 4099 4401 => 'Movies|Action & Adventure', 4100 4402 => 'Movies|Anime', 4101 4403 => 'Movies|Classics', 4102 4404 => 'Movies|Comedy', 4103 4405 => 'Movies|Documentary', 4104 4406 => 'Movies|Drama', 4105 4407 => 'Movies|Foreign', 4106 4408 => 'Movies|Horror', 4107 4409 => 'Movies|Independent', 4108 4410 => 'Movies|Kids & Family', 4109 4411 => 'Movies|Musicals', 4110 4412 => 'Movies|Romance', 4111 4413 => 'Movies|Sci-Fi & Fantasy', 4112 4414 => 'Movies|Short Films', 4113 4415 => 'Movies|Special Interest', 4114 4416 => 'Movies|Thriller', 4115 4417 => 'Movies|Sports', 4116 4418 => 'Movies|Western', 4117 4419 => 'Movies|Urban', 4118 4420 => 'Movies|Holiday', 4119 4421 => 'Movies|Made for TV', 4120 4422 => 'Movies|Concert Films', 4121 4423 => 'Movies|Music Documentaries', 4122 4424 => 'Movies|Music Feature Films', 4123 4425 => 'Movies|Japanese Cinema', 4124 4426 => 'Movies|Jidaigeki', 4125 4427 => 'Movies|Tokusatsu', 4126 4428 => 'Movies|Korean Cinema', 4127 4429 => 'Movies|Russian', 4128 4430 => 'Movies|Turkish', 4129 4431 => 'Movies|Bollywood', 4130 4432 => 'Movies|Regional Indian', 4131 4433 => 'Movies|Middle Eastern', 4132 4434 => 'Movies|African', 4133 6000 => 'App Store|Business', 4134 6001 => 'App Store|Weather', 4135 6002 => 'App Store|Utilities', 4136 6003 => 'App Store|Travel', 4137 6004 => 'App Store|Sports', 4138 6005 => 'App Store|Social Networking', 4139 6006 => 'App Store|Reference', 4140 6007 => 'App Store|Productivity', 4141 6008 => 'App Store|Photo & Video', 4142 6009 => 'App Store|News', 4143 6010 => 'App Store|Navigation', 4144 6011 => 'App Store|Music', 4145 6012 => 'App Store|Lifestyle', 4146 6013 => 'App Store|Health & Fitness', 4147 6014 => 'App Store|Games', 4148 6015 => 'App Store|Finance', 4149 6016 => 'App Store|Entertainment', 4150 6017 => 'App Store|Education', 4151 6018 => 'App Store|Books', 4152 6020 => 'App Store|Medical', 4153 6021 => 'App Store|Magazines & Newspapers', 4154 6022 => 'App Store|Catalogs', 4155 6023 => 'App Store|Food & Drink', 4156 6024 => 'App Store|Shopping', 4157 6025 => 'App Store|Stickers', 4158 6026 => 'App Store|Developer Tools', 4159 6027 => 'App Store|Graphics & Design', 4160 7001 => 'App Store|Games|Action', 4161 7002 => 'App Store|Games|Adventure', 4162 7003 => 'App Store|Games|Casual', 4163 7004 => 'App Store|Games|Board', 4164 7005 => 'App Store|Games|Card', 4165 7006 => 'App Store|Games|Casino', 4166 7007 => 'App Store|Games|Dice', 4167 7008 => 'App Store|Games|Educational', 4168 7009 => 'App Store|Games|Family', 4169 7011 => 'App Store|Games|Music', 4170 7012 => 'App Store|Games|Puzzle', 4171 7013 => 'App Store|Games|Racing', 4172 7014 => 'App Store|Games|Role Playing', 4173 7015 => 'App Store|Games|Simulation', 4174 7016 => 'App Store|Games|Sports', 4175 7017 => 'App Store|Games|Strategy', 4176 7018 => 'App Store|Games|Trivia', 4177 7019 => 'App Store|Games|Word', 4178 8001 => 'Tones|Ringtones|Alternative', 4179 8002 => 'Tones|Ringtones|Blues', 4180 8003 => "Tones|Ringtones|Children's Music", 4181 8004 => 'Tones|Ringtones|Classical', 4182 8005 => 'Tones|Ringtones|Comedy', 4183 8006 => 'Tones|Ringtones|Country', 4184 8007 => 'Tones|Ringtones|Dance', 4185 8008 => 'Tones|Ringtones|Electronic', 4186 8009 => 'Tones|Ringtones|Enka', 4187 8010 => 'Tones|Ringtones|French Pop', 4188 8011 => 'Tones|Ringtones|German Folk', 4189 8012 => 'Tones|Ringtones|German Pop', 4190 8013 => 'Tones|Ringtones|Hip-Hop/Rap', 4191 8014 => 'Tones|Ringtones|Holiday', 4192 8015 => 'Tones|Ringtones|Inspirational', 4193 8016 => 'Tones|Ringtones|J-Pop', 4194 8017 => 'Tones|Ringtones|Jazz', 4195 8018 => 'Tones|Ringtones|Kayokyoku', 4196 8019 => 'Tones|Ringtones|Latin', 4197 8020 => 'Tones|Ringtones|New Age', 4198 8021 => 'Tones|Ringtones|Classical|Opera', 4199 8022 => 'Tones|Ringtones|Pop', 4200 8023 => 'Tones|Ringtones|R&B/Soul', 4201 8024 => 'Tones|Ringtones|Reggae', 4202 8025 => 'Tones|Ringtones|Rock', 4203 8026 => 'Tones|Ringtones|Singer/Songwriter', 4204 8027 => 'Tones|Ringtones|Soundtrack', 4205 8028 => 'Tones|Ringtones|Spoken Word', 4206 8029 => 'Tones|Ringtones|Vocal', 4207 8030 => 'Tones|Ringtones|World', 4208 8050 => 'Tones|Alert Tones|Sound Effects', 4209 8051 => 'Tones|Alert Tones|Dialogue', 4210 8052 => 'Tones|Alert Tones|Music', 4211 8053 => 'Tones|Ringtones', 4212 8054 => 'Tones|Alert Tones', 4213 8055 => 'Tones|Ringtones|Alternative|Chinese Alt', 4214 8056 => 'Tones|Ringtones|Alternative|College Rock', 4215 8057 => 'Tones|Ringtones|Alternative|Goth Rock', 4216 8058 => 'Tones|Ringtones|Alternative|Grunge', 4217 8059 => 'Tones|Ringtones|Alternative|Indie Rock', 4218 8060 => 'Tones|Ringtones|Alternative|Korean Indie', 4219 8061 => 'Tones|Ringtones|Alternative|New Wave', 4220 8062 => 'Tones|Ringtones|Alternative|Punk', 4221 8063 => 'Tones|Ringtones|Anime', 4222 8064 => 'Tones|Ringtones|Arabic', 4223 8065 => 'Tones|Ringtones|Arabic|Arabic Pop', 4224 8066 => 'Tones|Ringtones|Arabic|Islamic', 4225 8067 => 'Tones|Ringtones|Arabic|Khaleeji', 4226 8068 => 'Tones|Ringtones|Arabic|North African', 4227 8069 => 'Tones|Ringtones|Blues|Acoustic Blues', 4228 8070 => 'Tones|Ringtones|Blues|Chicago Blues', 4229 8071 => 'Tones|Ringtones|Blues|Classic Blues', 4230 8072 => 'Tones|Ringtones|Blues|Contemporary Blues', 4231 8073 => 'Tones|Ringtones|Blues|Country Blues', 4232 8074 => 'Tones|Ringtones|Blues|Delta Blues', 4233 8075 => 'Tones|Ringtones|Blues|Electric Blues', 4234 8076 => 'Tones|Ringtones|Brazilian', 4235 8077 => 'Tones|Ringtones|Brazilian|Axe', # (Axé) 4236 8078 => 'Tones|Ringtones|Brazilian|Baile Funk', 4237 8079 => 'Tones|Ringtones|Brazilian|Bossa Nova', 4238 8080 => 'Tones|Ringtones|Brazilian|Choro', 4239 8081 => 'Tones|Ringtones|Brazilian|Forro', # (Forró) 4240 8082 => 'Tones|Ringtones|Brazilian|Frevo', 4241 8083 => 'Tones|Ringtones|Brazilian|MPB', 4242 8084 => 'Tones|Ringtones|Brazilian|Pagode', 4243 8085 => 'Tones|Ringtones|Brazilian|Samba', 4244 8086 => 'Tones|Ringtones|Brazilian|Sertanejo', 4245 8087 => "Tones|Ringtones|Children's Music|Lullabies", 4246 8088 => "Tones|Ringtones|Children's Music|Sing-Along", 4247 8089 => "Tones|Ringtones|Children's Music|Stories", 4248 8090 => 'Tones|Ringtones|Chinese', 4249 8091 => 'Tones|Ringtones|Chinese|Chinese Classical', 4250 8092 => 'Tones|Ringtones|Chinese|Chinese Flute', 4251 8093 => 'Tones|Ringtones|Chinese|Chinese Opera', 4252 8094 => 'Tones|Ringtones|Chinese|Chinese Orchestral', 4253 8095 => 'Tones|Ringtones|Chinese|Chinese Regional Folk', 4254 8096 => 'Tones|Ringtones|Chinese|Chinese Strings', 4255 8097 => 'Tones|Ringtones|Chinese|Taiwanese Folk', 4256 8098 => 'Tones|Ringtones|Chinese|Tibetan Native Music', 4257 8099 => 'Tones|Ringtones|Christian & Gospel', 4258 8100 => 'Tones|Ringtones|Christian & Gospel|CCM', 4259 8101 => 'Tones|Ringtones|Christian & Gospel|Christian Metal', 4260 8102 => 'Tones|Ringtones|Christian & Gospel|Christian Pop', 4261 8103 => 'Tones|Ringtones|Christian & Gospel|Christian Rap', 4262 8104 => 'Tones|Ringtones|Christian & Gospel|Christian Rock', 4263 8105 => 'Tones|Ringtones|Christian & Gospel|Classic Christian', 4264 8106 => 'Tones|Ringtones|Christian & Gospel|Contemporary Gospel', 4265 8107 => 'Tones|Ringtones|Christian & Gospel|Gospel', 4266 8108 => 'Tones|Ringtones|Christian & Gospel|Praise & Worship', 4267 8109 => 'Tones|Ringtones|Christian & Gospel|Southern Gospel', 4268 8110 => 'Tones|Ringtones|Christian & Gospel|Traditional Gospel', 4269 8111 => 'Tones|Ringtones|Classical|Avant-Garde', 4270 8112 => 'Tones|Ringtones|Classical|Baroque Era', 4271 8113 => 'Tones|Ringtones|Classical|Chamber Music', 4272 8114 => 'Tones|Ringtones|Classical|Chant', 4273 8115 => 'Tones|Ringtones|Classical|Choral', 4274 8116 => 'Tones|Ringtones|Classical|Classical Crossover', 4275 8117 => 'Tones|Ringtones|Classical|Early Music', 4276 8118 => 'Tones|Ringtones|Classical|High Classical', 4277 8119 => 'Tones|Ringtones|Classical|Impressionist', 4278 8120 => 'Tones|Ringtones|Classical|Medieval Era', 4279 8121 => 'Tones|Ringtones|Classical|Minimalism', 4280 8122 => 'Tones|Ringtones|Classical|Modern Era', 4281 8123 => 'Tones|Ringtones|Classical|Orchestral', 4282 8124 => 'Tones|Ringtones|Classical|Renaissance', 4283 8125 => 'Tones|Ringtones|Classical|Romantic Era', 4284 8126 => 'Tones|Ringtones|Classical|Wedding Music', 4285 8127 => 'Tones|Ringtones|Comedy|Novelty', 4286 8128 => 'Tones|Ringtones|Comedy|Standup Comedy', 4287 8129 => 'Tones|Ringtones|Country|Alternative Country', 4288 8130 => 'Tones|Ringtones|Country|Americana', 4289 8131 => 'Tones|Ringtones|Country|Bluegrass', 4290 8132 => 'Tones|Ringtones|Country|Contemporary Bluegrass', 4291 8133 => 'Tones|Ringtones|Country|Contemporary Country', 4292 8134 => 'Tones|Ringtones|Country|Country Gospel', 4293 8135 => 'Tones|Ringtones|Country|Honky Tonk', 4294 8136 => 'Tones|Ringtones|Country|Outlaw Country', 4295 8137 => 'Tones|Ringtones|Country|Thai Country', 4296 8138 => 'Tones|Ringtones|Country|Traditional Bluegrass', 4297 8139 => 'Tones|Ringtones|Country|Traditional Country', 4298 8140 => 'Tones|Ringtones|Country|Urban Cowboy', 4299 8141 => 'Tones|Ringtones|Dance|Breakbeat', 4300 8142 => 'Tones|Ringtones|Dance|Exercise', 4301 8143 => 'Tones|Ringtones|Dance|Garage', 4302 8144 => 'Tones|Ringtones|Dance|Hardcore', 4303 8145 => 'Tones|Ringtones|Dance|House', 4304 8146 => "Tones|Ringtones|Dance|Jungle/Drum'n'bass", 4305 8147 => 'Tones|Ringtones|Dance|Techno', 4306 8148 => 'Tones|Ringtones|Dance|Trance', 4307 8149 => 'Tones|Ringtones|Disney', 4308 8150 => 'Tones|Ringtones|Easy Listening', 4309 8151 => 'Tones|Ringtones|Easy Listening|Lounge', 4310 8152 => 'Tones|Ringtones|Easy Listening|Swing', 4311 8153 => 'Tones|Ringtones|Electronic|Ambient', 4312 8154 => 'Tones|Ringtones|Electronic|Downtempo', 4313 8155 => 'Tones|Ringtones|Electronic|Electronica', 4314 8156 => 'Tones|Ringtones|Electronic|IDM/Experimental', 4315 8157 => 'Tones|Ringtones|Electronic|Industrial', 4316 8158 => 'Tones|Ringtones|Fitness & Workout', 4317 8159 => 'Tones|Ringtones|Folk', 4318 8160 => 'Tones|Ringtones|Hip-Hop/Rap|Alternative Rap', 4319 8161 => 'Tones|Ringtones|Hip-Hop/Rap|Chinese Hip-Hop', 4320 8162 => 'Tones|Ringtones|Hip-Hop/Rap|Dirty South', 4321 8163 => 'Tones|Ringtones|Hip-Hop/Rap|East Coast Rap', 4322 8164 => 'Tones|Ringtones|Hip-Hop/Rap|Gangsta Rap', 4323 8165 => 'Tones|Ringtones|Hip-Hop/Rap|Hardcore Rap', 4324 8166 => 'Tones|Ringtones|Hip-Hop/Rap|Hip-Hop', 4325 8167 => 'Tones|Ringtones|Hip-Hop/Rap|Korean Hip-Hop', 4326 8168 => 'Tones|Ringtones|Hip-Hop/Rap|Latin Rap', 4327 8169 => 'Tones|Ringtones|Hip-Hop/Rap|Old School Rap', 4328 8170 => 'Tones|Ringtones|Hip-Hop/Rap|Rap', 4329 8171 => 'Tones|Ringtones|Hip-Hop/Rap|Underground Rap', 4330 8172 => 'Tones|Ringtones|Hip-Hop/Rap|West Coast Rap', 4331 8173 => 'Tones|Ringtones|Holiday|Chanukah', 4332 8174 => 'Tones|Ringtones|Holiday|Christmas', 4333 8175 => "Tones|Ringtones|Holiday|Christmas: Children's", 4334 8176 => 'Tones|Ringtones|Holiday|Christmas: Classic', 4335 8177 => 'Tones|Ringtones|Holiday|Christmas: Classical', 4336 8178 => 'Tones|Ringtones|Holiday|Christmas: Jazz', 4337 8179 => 'Tones|Ringtones|Holiday|Christmas: Modern', 4338 8180 => 'Tones|Ringtones|Holiday|Christmas: Pop', 4339 8181 => 'Tones|Ringtones|Holiday|Christmas: R&B', 4340 8182 => 'Tones|Ringtones|Holiday|Christmas: Religious', 4341 8183 => 'Tones|Ringtones|Holiday|Christmas: Rock', 4342 8184 => 'Tones|Ringtones|Holiday|Easter', 4343 8185 => 'Tones|Ringtones|Holiday|Halloween', 4344 8186 => 'Tones|Ringtones|Holiday|Thanksgiving', 4345 8187 => 'Tones|Ringtones|Indian', 4346 8188 => 'Tones|Ringtones|Indian|Bollywood', 4347 8189 => 'Tones|Ringtones|Indian|Devotional & Spiritual', 4348 8190 => 'Tones|Ringtones|Indian|Ghazals', 4349 8191 => 'Tones|Ringtones|Indian|Indian Classical', 4350 8192 => 'Tones|Ringtones|Indian|Indian Folk', 4351 8193 => 'Tones|Ringtones|Indian|Indian Pop', 4352 8194 => 'Tones|Ringtones|Indian|Regional Indian', 4353 8195 => 'Tones|Ringtones|Indian|Sufi', 4354 8196 => 'Tones|Ringtones|Indian|Regional Indian|Tamil', 4355 8197 => 'Tones|Ringtones|Indian|Regional Indian|Telugu', 4356 8198 => 'Tones|Ringtones|Instrumental', 4357 8199 => 'Tones|Ringtones|Jazz|Avant-Garde Jazz', 4358 8201 => 'Tones|Ringtones|Jazz|Big Band', 4359 8202 => 'Tones|Ringtones|Jazz|Bop', 4360 8203 => 'Tones|Ringtones|Jazz|Contemporary Jazz', 4361 8204 => 'Tones|Ringtones|Jazz|Cool Jazz', 4362 8205 => 'Tones|Ringtones|Jazz|Crossover Jazz', 4363 8206 => 'Tones|Ringtones|Jazz|Dixieland', 4364 8207 => 'Tones|Ringtones|Jazz|Fusion', 4365 8208 => 'Tones|Ringtones|Jazz|Hard Bop', 4366 8209 => 'Tones|Ringtones|Jazz|Latin Jazz', 4367 8210 => 'Tones|Ringtones|Jazz|Mainstream Jazz', 4368 8211 => 'Tones|Ringtones|Jazz|Ragtime', 4369 8212 => 'Tones|Ringtones|Jazz|Smooth Jazz', 4370 8213 => 'Tones|Ringtones|Jazz|Trad Jazz', 4371 8214 => 'Tones|Ringtones|Pop|K-Pop', 4372 8215 => 'Tones|Ringtones|Karaoke', 4373 8216 => 'Tones|Ringtones|Korean', 4374 8217 => 'Tones|Ringtones|Korean|Korean Classical', 4375 8218 => 'Tones|Ringtones|Korean|Korean Trad Instrumental', 4376 8219 => 'Tones|Ringtones|Korean|Korean Trad Song', 4377 8220 => 'Tones|Ringtones|Korean|Korean Trad Theater', 4378 8221 => 'Tones|Ringtones|Latin|Alternative & Rock in Spanish', 4379 8222 => 'Tones|Ringtones|Latin|Baladas y Boleros', 4380 8223 => 'Tones|Ringtones|Latin|Contemporary Latin', 4381 8224 => 'Tones|Ringtones|Latin|Latin Jazz', 4382 8225 => 'Tones|Ringtones|Latin|Latin Urban', 4383 8226 => 'Tones|Ringtones|Latin|Pop in Spanish', 4384 8227 => 'Tones|Ringtones|Latin|Raices', 4385 8228 => 'Tones|Ringtones|Latin|Musica Mexicana', # (Música Mexicana) 4386 8229 => 'Tones|Ringtones|Latin|Salsa y Tropical', 4387 8230 => 'Tones|Ringtones|Marching Bands', 4388 8231 => 'Tones|Ringtones|New Age|Healing', 4389 8232 => 'Tones|Ringtones|New Age|Meditation', 4390 8233 => 'Tones|Ringtones|New Age|Nature', 4391 8234 => 'Tones|Ringtones|New Age|Relaxation', 4392 8235 => 'Tones|Ringtones|New Age|Travel', 4393 8236 => 'Tones|Ringtones|Orchestral', 4394 8237 => 'Tones|Ringtones|Pop|Adult Contemporary', 4395 8238 => 'Tones|Ringtones|Pop|Britpop', 4396 8239 => 'Tones|Ringtones|Pop|C-Pop', 4397 8240 => 'Tones|Ringtones|Pop|Cantopop/HK-Pop', 4398 8241 => 'Tones|Ringtones|Pop|Indo Pop', 4399 8242 => 'Tones|Ringtones|Pop|Korean Folk-Pop', 4400 8243 => 'Tones|Ringtones|Pop|Malaysian Pop', 4401 8244 => 'Tones|Ringtones|Pop|Mandopop', 4402 8245 => 'Tones|Ringtones|Pop|Manilla Sound', 4403 8246 => 'Tones|Ringtones|Pop|Oldies', 4404 8247 => 'Tones|Ringtones|Pop|Original Pilipino Music', 4405 8248 => 'Tones|Ringtones|Pop|Pinoy Pop', 4406 8249 => 'Tones|Ringtones|Pop|Pop/Rock', 4407 8250 => 'Tones|Ringtones|Pop|Soft Rock', 4408 8251 => 'Tones|Ringtones|Pop|Tai-Pop', 4409 8252 => 'Tones|Ringtones|Pop|Teen Pop', 4410 8253 => 'Tones|Ringtones|Pop|Thai Pop', 4411 8254 => 'Tones|Ringtones|R&B/Soul|Contemporary R&B', 4412 8255 => 'Tones|Ringtones|R&B/Soul|Disco', 4413 8256 => 'Tones|Ringtones|R&B/Soul|Doo Wop', 4414 8257 => 'Tones|Ringtones|R&B/Soul|Funk', 4415 8258 => 'Tones|Ringtones|R&B/Soul|Motown', 4416 8259 => 'Tones|Ringtones|R&B/Soul|Neo-Soul', 4417 8260 => 'Tones|Ringtones|R&B/Soul|Soul', 4418 8261 => 'Tones|Ringtones|Reggae|Modern Dancehall', 4419 8262 => 'Tones|Ringtones|Reggae|Dub', 4420 8263 => 'Tones|Ringtones|Reggae|Roots Reggae', 4421 8264 => 'Tones|Ringtones|Reggae|Ska', 4422 8265 => 'Tones|Ringtones|Rock|Adult Alternative', 4423 8266 => 'Tones|Ringtones|Rock|American Trad Rock', 4424 8267 => 'Tones|Ringtones|Rock|Arena Rock', 4425 8268 => 'Tones|Ringtones|Rock|Blues-Rock', 4426 8269 => 'Tones|Ringtones|Rock|British Invasion', 4427 8270 => 'Tones|Ringtones|Rock|Chinese Rock', 4428 8271 => 'Tones|Ringtones|Rock|Death Metal/Black Metal', 4429 8272 => 'Tones|Ringtones|Rock|Glam Rock', 4430 8273 => 'Tones|Ringtones|Rock|Hair Metal', 4431 8274 => 'Tones|Ringtones|Rock|Hard Rock', 4432 8275 => 'Tones|Ringtones|Rock|Metal', 4433 8276 => 'Tones|Ringtones|Rock|Jam Bands', 4434 8277 => 'Tones|Ringtones|Rock|Korean Rock', 4435 8278 => 'Tones|Ringtones|Rock|Prog-Rock/Art Rock', 4436 8279 => 'Tones|Ringtones|Rock|Psychedelic', 4437 8280 => 'Tones|Ringtones|Rock|Rock & Roll', 4438 8281 => 'Tones|Ringtones|Rock|Rockabilly', 4439 8282 => 'Tones|Ringtones|Rock|Roots Rock', 4440 8283 => 'Tones|Ringtones|Rock|Singer/Songwriter', 4441 8284 => 'Tones|Ringtones|Rock|Southern Rock', 4442 8285 => 'Tones|Ringtones|Rock|Surf', 4443 8286 => 'Tones|Ringtones|Rock|Tex-Mex', 4444 8287 => 'Tones|Ringtones|Singer/Songwriter|Alternative Folk', 4445 8288 => 'Tones|Ringtones|Singer/Songwriter|Contemporary Folk', 4446 8289 => 'Tones|Ringtones|Singer/Songwriter|Contemporary Singer/Songwriter', 4447 8290 => 'Tones|Ringtones|Singer/Songwriter|Folk-Rock', 4448 8291 => 'Tones|Ringtones|Singer/Songwriter|New Acoustic', 4449 8292 => 'Tones|Ringtones|Singer/Songwriter|Traditional Folk', 4450 8293 => 'Tones|Ringtones|Soundtrack|Foreign Cinema', 4451 8294 => 'Tones|Ringtones|Soundtrack|Musicals', 4452 8295 => 'Tones|Ringtones|Soundtrack|Original Score', 4453 8296 => 'Tones|Ringtones|Soundtrack|Sound Effects', 4454 8297 => 'Tones|Ringtones|Soundtrack|Soundtrack', 4455 8298 => 'Tones|Ringtones|Soundtrack|TV Soundtrack', 4456 8299 => 'Tones|Ringtones|Vocal|Standards', 4457 8300 => 'Tones|Ringtones|Vocal|Traditional Pop', 4458 8301 => 'Tones|Ringtones|Vocal|Trot', 4459 8302 => 'Tones|Ringtones|Jazz|Vocal Jazz', 4460 8303 => 'Tones|Ringtones|Vocal|Vocal Pop', 4461 8304 => 'Tones|Ringtones|African', 4462 8305 => 'Tones|Ringtones|African|Afrikaans', 4463 8306 => 'Tones|Ringtones|African|Afro-Beat', 4464 8307 => 'Tones|Ringtones|African|Afro-Pop', 4465 8308 => 'Tones|Ringtones|Turkish|Arabesque', 4466 8309 => 'Tones|Ringtones|World|Asia', 4467 8310 => 'Tones|Ringtones|World|Australia', 4468 8311 => 'Tones|Ringtones|World|Cajun', 4469 8312 => 'Tones|Ringtones|World|Calypso', 4470 8313 => 'Tones|Ringtones|World|Caribbean', 4471 8314 => 'Tones|Ringtones|World|Celtic', 4472 8315 => 'Tones|Ringtones|World|Celtic Folk', 4473 8316 => 'Tones|Ringtones|World|Contemporary Celtic', 4474 8317 => 'Tones|Ringtones|World|Dangdut', 4475 8318 => 'Tones|Ringtones|World|Dini', 4476 8319 => 'Tones|Ringtones|World|Europe', 4477 8320 => 'Tones|Ringtones|World|Fado', 4478 8321 => 'Tones|Ringtones|World|Farsi', 4479 8322 => 'Tones|Ringtones|World|Flamenco', 4480 8323 => 'Tones|Ringtones|World|France', 4481 8324 => 'Tones|Ringtones|Turkish|Halk', 4482 8325 => 'Tones|Ringtones|World|Hawaii', 4483 8326 => 'Tones|Ringtones|World|Iberia', 4484 8327 => 'Tones|Ringtones|World|Indonesian Religious', 4485 8328 => 'Tones|Ringtones|World|Israeli', 4486 8329 => 'Tones|Ringtones|World|Japan', 4487 8330 => 'Tones|Ringtones|World|Klezmer', 4488 8331 => 'Tones|Ringtones|World|North America', 4489 8332 => 'Tones|Ringtones|World|Polka', 4490 8333 => 'Tones|Ringtones|Russian', 4491 8334 => 'Tones|Ringtones|Russian|Russian Chanson', 4492 8335 => 'Tones|Ringtones|Turkish|Sanat', 4493 8336 => 'Tones|Ringtones|World|Soca', 4494 8337 => 'Tones|Ringtones|World|South Africa', 4495 8338 => 'Tones|Ringtones|World|South America', 4496 8339 => 'Tones|Ringtones|World|Tango', 4497 8340 => 'Tones|Ringtones|World|Traditional Celtic', 4498 8341 => 'Tones|Ringtones|Turkish', 4499 8342 => 'Tones|Ringtones|World|Worldbeat', 4500 8343 => 'Tones|Ringtones|World|Zydeco', 4501 8345 => 'Tones|Ringtones|Classical|Art Song', 4502 8346 => 'Tones|Ringtones|Classical|Brass & Woodwinds', 4503 8347 => 'Tones|Ringtones|Classical|Solo Instrumental', 4504 8348 => 'Tones|Ringtones|Classical|Contemporary Era', 4505 8349 => 'Tones|Ringtones|Classical|Oratorio', 4506 8350 => 'Tones|Ringtones|Classical|Cantata', 4507 8351 => 'Tones|Ringtones|Classical|Electronic', 4508 8352 => 'Tones|Ringtones|Classical|Sacred', 4509 8353 => 'Tones|Ringtones|Classical|Guitar', 4510 8354 => 'Tones|Ringtones|Classical|Piano', 4511 8355 => 'Tones|Ringtones|Classical|Violin', 4512 8356 => 'Tones|Ringtones|Classical|Cello', 4513 8357 => 'Tones|Ringtones|Classical|Percussion', 4514 8358 => 'Tones|Ringtones|Electronic|Dubstep', 4515 8359 => 'Tones|Ringtones|Electronic|Bass', 4516 8360 => 'Tones|Ringtones|Hip-Hop/Rap|UK Hip Hop', 4517 8361 => 'Tones|Ringtones|Reggae|Lovers Rock', 4518 8362 => 'Tones|Ringtones|Alternative|EMO', 4519 8363 => 'Tones|Ringtones|Alternative|Pop Punk', 4520 8364 => 'Tones|Ringtones|Alternative|Indie Pop', 4521 8365 => 'Tones|Ringtones|New Age|Yoga', 4522 8366 => 'Tones|Ringtones|Pop|Tribute', 4523 8367 => 'Tones|Ringtones|Pop|Shows', 4524 8368 => 'Tones|Ringtones|Cuban', 4525 8369 => 'Tones|Ringtones|Cuban|Mambo', 4526 8370 => 'Tones|Ringtones|Cuban|Chachacha', 4527 8371 => 'Tones|Ringtones|Cuban|Guajira', 4528 8372 => 'Tones|Ringtones|Cuban|Son', 4529 8373 => 'Tones|Ringtones|Cuban|Bolero', 4530 8374 => 'Tones|Ringtones|Cuban|Guaracha', 4531 8375 => 'Tones|Ringtones|Cuban|Timba', 4532 8376 => 'Tones|Ringtones|Soundtrack|Video Game', 4533 8377 => 'Tones|Ringtones|Indian|Regional Indian|Punjabi|Punjabi Pop', 4534 8378 => 'Tones|Ringtones|Indian|Regional Indian|Bengali|Rabindra Sangeet', 4535 8379 => 'Tones|Ringtones|Indian|Regional Indian|Malayalam', 4536 8380 => 'Tones|Ringtones|Indian|Regional Indian|Kannada', 4537 8381 => 'Tones|Ringtones|Indian|Regional Indian|Marathi', 4538 8382 => 'Tones|Ringtones|Indian|Regional Indian|Gujarati', 4539 8383 => 'Tones|Ringtones|Indian|Regional Indian|Assamese', 4540 8384 => 'Tones|Ringtones|Indian|Regional Indian|Bhojpuri', 4541 8385 => 'Tones|Ringtones|Indian|Regional Indian|Haryanvi', 4542 8386 => 'Tones|Ringtones|Indian|Regional Indian|Odia', 4543 8387 => 'Tones|Ringtones|Indian|Regional Indian|Rajasthani', 4544 8388 => 'Tones|Ringtones|Indian|Regional Indian|Urdu', 4545 8389 => 'Tones|Ringtones|Indian|Regional Indian|Punjabi', 4546 8390 => 'Tones|Ringtones|Indian|Regional Indian|Bengali', 4547 8391 => 'Tones|Ringtones|Indian|Indian Classical|Carnatic Classical', 4548 8392 => 'Tones|Ringtones|Indian|Indian Classical|Hindustani Classical', 4549 8393 => 'Tones|Ringtones|African|Afro House', 4550 8394 => 'Tones|Ringtones|African|Afro Soul', 4551 8395 => 'Tones|Ringtones|African|Afrobeats', 4552 8396 => 'Tones|Ringtones|African|Benga', 4553 8397 => 'Tones|Ringtones|African|Bongo-Flava', 4554 8398 => 'Tones|Ringtones|African|Coupe-Decale', 4555 8399 => 'Tones|Ringtones|African|Gqom', 4556 8400 => 'Tones|Ringtones|African|Highlife', 4557 8401 => 'Tones|Ringtones|African|Kuduro', 4558 8402 => 'Tones|Ringtones|African|Kizomba', 4559 8403 => 'Tones|Ringtones|African|Kwaito', 4560 8404 => 'Tones|Ringtones|African|Mbalax', 4561 8405 => 'Tones|Ringtones|African|Ndombolo', 4562 8406 => 'Tones|Ringtones|African|Shangaan Electro', 4563 8407 => 'Tones|Ringtones|African|Soukous', 4564 8408 => 'Tones|Ringtones|African|Taarab', 4565 8409 => 'Tones|Ringtones|African|Zouglou', 4566 8410 => 'Tones|Ringtones|Turkish|Ozgun', 4567 8411 => 'Tones|Ringtones|Turkish|Fantezi', 4568 8412 => 'Tones|Ringtones|Turkish|Religious', 4569 8413 => 'Tones|Ringtones|Pop|Turkish Pop', 4570 8414 => 'Tones|Ringtones|Rock|Turkish Rock', 4571 8415 => 'Tones|Ringtones|Alternative|Turkish Alternative', 4572 8416 => 'Tones|Ringtones|Hip-Hop/Rap|Turkish Hip-Hop/Rap', 4573 8417 => 'Tones|Ringtones|African|Maskandi', 4574 8418 => 'Tones|Ringtones|Russian|Russian Romance', 4575 8419 => 'Tones|Ringtones|Russian|Russian Bard', 4576 8420 => 'Tones|Ringtones|Russian|Russian Pop', 4577 8421 => 'Tones|Ringtones|Russian|Russian Rock', 4578 8422 => 'Tones|Ringtones|Russian|Russian Hip-Hop', 4579 8423 => 'Tones|Ringtones|Arabic|Levant', 4580 8424 => 'Tones|Ringtones|Arabic|Levant|Dabke', 4581 8425 => 'Tones|Ringtones|Arabic|Maghreb Rai', 4582 8426 => 'Tones|Ringtones|Arabic|Khaleeji|Khaleeji Jalsat', 4583 8427 => 'Tones|Ringtones|Arabic|Khaleeji|Khaleeji Shailat', 4584 8428 => 'Tones|Ringtones|Tarab', 4585 8429 => 'Tones|Ringtones|Tarab|Iraqi Tarab', 4586 8430 => 'Tones|Ringtones|Tarab|Egyptian Tarab', 4587 8431 => 'Tones|Ringtones|Tarab|Khaleeji Tarab', 4588 8432 => 'Tones|Ringtones|Pop|Levant Pop', 4589 8433 => 'Tones|Ringtones|Pop|Iraqi Pop', 4590 8434 => 'Tones|Ringtones|Pop|Egyptian Pop', 4591 8435 => 'Tones|Ringtones|Pop|Maghreb Pop', 4592 8436 => 'Tones|Ringtones|Pop|Khaleeji Pop', 4593 8437 => 'Tones|Ringtones|Hip-Hop/Rap|Levant Hip-Hop', 4594 8438 => 'Tones|Ringtones|Hip-Hop/Rap|Egyptian Hip-Hop', 4595 8439 => 'Tones|Ringtones|Hip-Hop/Rap|Maghreb Hip-Hop', 4596 8440 => 'Tones|Ringtones|Hip-Hop/Rap|Khaleeji Hip-Hop', 4597 8441 => 'Tones|Ringtones|Alternative|Indie Levant', 4598 8442 => 'Tones|Ringtones|Alternative|Indie Egyptian', 4599 8443 => 'Tones|Ringtones|Alternative|Indie Maghreb', 4600 8444 => 'Tones|Ringtones|Electronic|Levant Electronic', 4601 8445 => "Tones|Ringtones|Electronic|Electro-Cha'abi", 4602 8446 => 'Tones|Ringtones|Electronic|Maghreb Electronic', 4603 8447 => 'Tones|Ringtones|Folk|Iraqi Folk', 4604 8448 => 'Tones|Ringtones|Folk|Khaleeji Folk', 4605 8449 => 'Tones|Ringtones|Dance|Maghreb Dance', 4606 9002 => 'Books|Nonfiction', 4607 9003 => 'Books|Romance', 4608 9004 => 'Books|Travel & Adventure', 4609 9007 => 'Books|Arts & Entertainment', 4610 9008 => 'Books|Biographies & Memoirs', 4611 9009 => 'Books|Business & Personal Finance', 4612 9010 => 'Books|Children & Teens', 4613 9012 => 'Books|Humor', 4614 9015 => 'Books|History', 4615 9018 => 'Books|Religion & Spirituality', 4616 9019 => 'Books|Science & Nature', 4617 9020 => 'Books|Sci-Fi & Fantasy', 4618 9024 => 'Books|Lifestyle & Home', 4619 9025 => 'Books|Self-Development', 4620 9026 => 'Books|Comics & Graphic Novels', 4621 9027 => 'Books|Computers & Internet', 4622 9028 => 'Books|Cookbooks, Food & Wine', 4623 9029 => 'Books|Professional & Technical', 4624 9030 => 'Books|Parenting', 4625 9031 => 'Books|Fiction & Literature', 4626 9032 => 'Books|Mysteries & Thrillers', 4627 9033 => 'Books|Reference', 4628 9034 => 'Books|Politics & Current Events', 4629 9035 => 'Books|Sports & Outdoors', 4630 10001 => 'Books|Lifestyle & Home|Antiques & Collectibles', 4631 10002 => 'Books|Arts & Entertainment|Art & Architecture', 4632 10003 => 'Books|Religion & Spirituality|Bibles', 4633 10004 => 'Books|Self-Development|Spirituality', 4634 10005 => 'Books|Business & Personal Finance|Industries & Professions', 4635 10006 => 'Books|Business & Personal Finance|Marketing & Sales', 4636 10007 => 'Books|Business & Personal Finance|Small Business & Entrepreneurship', 4637 10008 => 'Books|Business & Personal Finance|Personal Finance', 4638 10009 => 'Books|Business & Personal Finance|Reference', 4639 10010 => 'Books|Business & Personal Finance|Careers', 4640 10011 => 'Books|Business & Personal Finance|Economics', 4641 10012 => 'Books|Business & Personal Finance|Investing', 4642 10013 => 'Books|Business & Personal Finance|Finance', 4643 10014 => 'Books|Business & Personal Finance|Management & Leadership', 4644 10015 => 'Books|Comics & Graphic Novels|Graphic Novels', 4645 10016 => 'Books|Comics & Graphic Novels|Manga', 4646 10017 => 'Books|Computers & Internet|Computers', 4647 10018 => 'Books|Computers & Internet|Databases', 4648 10019 => 'Books|Computers & Internet|Digital Media', 4649 10020 => 'Books|Computers & Internet|Internet', 4650 10021 => 'Books|Computers & Internet|Network', 4651 10022 => 'Books|Computers & Internet|Operating Systems', 4652 10023 => 'Books|Computers & Internet|Programming', 4653 10024 => 'Books|Computers & Internet|Software', 4654 10025 => 'Books|Computers & Internet|System Administration', 4655 10026 => 'Books|Cookbooks, Food & Wine|Beverages', 4656 10027 => 'Books|Cookbooks, Food & Wine|Courses & Dishes', 4657 10028 => 'Books|Cookbooks, Food & Wine|Special Diet', 4658 10029 => 'Books|Cookbooks, Food & Wine|Special Occasions', 4659 10030 => 'Books|Cookbooks, Food & Wine|Methods', 4660 10031 => 'Books|Cookbooks, Food & Wine|Reference', 4661 10032 => 'Books|Cookbooks, Food & Wine|Regional & Ethnic', 4662 10033 => 'Books|Cookbooks, Food & Wine|Specific Ingredients', 4663 10034 => 'Books|Lifestyle & Home|Crafts & Hobbies', 4664 10035 => 'Books|Professional & Technical|Design', 4665 10036 => 'Books|Arts & Entertainment|Theater', 4666 10037 => 'Books|Professional & Technical|Education', 4667 10038 => 'Books|Nonfiction|Family & Relationships', 4668 10039 => 'Books|Fiction & Literature|Action & Adventure', 4669 10040 => 'Books|Fiction & Literature|African American', 4670 10041 => 'Books|Fiction & Literature|Religious', 4671 10042 => 'Books|Fiction & Literature|Classics', 4672 10043 => 'Books|Fiction & Literature|Erotica', 4673 10044 => 'Books|Sci-Fi & Fantasy|Fantasy', 4674 10045 => 'Books|Fiction & Literature|Gay', 4675 10046 => 'Books|Fiction & Literature|Ghost', 4676 10047 => 'Books|Fiction & Literature|Historical', 4677 10048 => 'Books|Fiction & Literature|Horror', 4678 10049 => 'Books|Fiction & Literature|Literary', 4679 10050 => 'Books|Mysteries & Thrillers|Hard-Boiled', 4680 10051 => 'Books|Mysteries & Thrillers|Historical', 4681 10052 => 'Books|Mysteries & Thrillers|Police Procedural', 4682 10053 => 'Books|Mysteries & Thrillers|Short Stories', 4683 10054 => 'Books|Mysteries & Thrillers|British Detectives', 4684 10055 => 'Books|Mysteries & Thrillers|Women Sleuths', 4685 10056 => 'Books|Romance|Erotic Romance', 4686 10057 => 'Books|Romance|Contemporary', 4687 10058 => 'Books|Romance|Paranormal', 4688 10059 => 'Books|Romance|Historical', 4689 10060 => 'Books|Romance|Short Stories', 4690 10061 => 'Books|Romance|Suspense', 4691 10062 => 'Books|Romance|Western', 4692 10063 => 'Books|Sci-Fi & Fantasy|Science Fiction', 4693 10064 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature', 4694 10065 => 'Books|Fiction & Literature|Short Stories', 4695 10066 => 'Books|Reference|Foreign Languages', 4696 10067 => 'Books|Arts & Entertainment|Games', 4697 10068 => 'Books|Lifestyle & Home|Gardening', 4698 10069 => 'Books|Self-Development|Health & Fitness', 4699 10070 => 'Books|History|Africa', 4700 10071 => 'Books|History|Americas', 4701 10072 => 'Books|History|Ancient', 4702 10073 => 'Books|History|Asia', 4703 10074 => 'Books|History|Australia & Oceania', 4704 10075 => 'Books|History|Europe', 4705 10076 => 'Books|History|Latin America', 4706 10077 => 'Books|History|Middle East', 4707 10078 => 'Books|History|Military', 4708 10079 => 'Books|History|United States', 4709 10080 => 'Books|History|World', 4710 10081 => "Books|Children & Teens|Children's Fiction", 4711 10082 => "Books|Children & Teens|Children's Nonfiction", 4712 10083 => 'Books|Professional & Technical|Law', 4713 10084 => 'Books|Fiction & Literature|Literary Criticism', 4714 10085 => 'Books|Science & Nature|Mathematics', 4715 10086 => 'Books|Professional & Technical|Medical', 4716 10087 => 'Books|Arts & Entertainment|Music', 4717 10088 => 'Books|Science & Nature|Nature', 4718 10089 => 'Books|Arts & Entertainment|Performing Arts', 4719 10090 => 'Books|Lifestyle & Home|Pets', 4720 10091 => 'Books|Nonfiction|Philosophy', 4721 10092 => 'Books|Arts & Entertainment|Photography', 4722 10093 => 'Books|Fiction & Literature|Poetry', 4723 10094 => 'Books|Self-Development|Psychology', 4724 10095 => 'Books|Reference|Almanacs & Yearbooks', 4725 10096 => 'Books|Reference|Atlases & Maps', 4726 10097 => 'Books|Reference|Catalogs & Directories', 4727 10098 => 'Books|Reference|Consumer Guides', 4728 10099 => 'Books|Reference|Dictionaries & Thesauruses', 4729 10100 => 'Books|Reference|Encyclopedias', 4730 10101 => 'Books|Reference|Etiquette', 4731 10102 => 'Books|Reference|Quotations', 4732 10103 => 'Books|Reference|Words & Language', 4733 10104 => 'Books|Reference|Writing', 4734 10105 => 'Books|Religion & Spirituality|Bible Studies', 4735 10106 => 'Books|Religion & Spirituality|Buddhism', 4736 10107 => 'Books|Religion & Spirituality|Christianity', 4737 10108 => 'Books|Religion & Spirituality|Hinduism', 4738 10109 => 'Books|Religion & Spirituality|Islam', 4739 10110 => 'Books|Religion & Spirituality|Judaism', 4740 10111 => 'Books|Science & Nature|Astronomy', 4741 10112 => 'Books|Science & Nature|Chemistry', 4742 10113 => 'Books|Science & Nature|Earth Sciences', 4743 10114 => 'Books|Science & Nature|Essays', 4744 10115 => 'Books|Science & Nature|History', 4745 10116 => 'Books|Science & Nature|Life Sciences', 4746 10117 => 'Books|Science & Nature|Physics', 4747 10118 => 'Books|Science & Nature|Reference', 4748 10119 => 'Books|Self-Development|Self-Improvement', 4749 10120 => 'Books|Nonfiction|Social Science', 4750 10121 => 'Books|Sports & Outdoors|Baseball', 4751 10122 => 'Books|Sports & Outdoors|Basketball', 4752 10123 => 'Books|Sports & Outdoors|Coaching', 4753 10124 => 'Books|Sports & Outdoors|Extreme Sports', 4754 10125 => 'Books|Sports & Outdoors|Football', 4755 10126 => 'Books|Sports & Outdoors|Golf', 4756 10127 => 'Books|Sports & Outdoors|Hockey', 4757 10128 => 'Books|Sports & Outdoors|Mountaineering', 4758 10129 => 'Books|Sports & Outdoors|Outdoors', 4759 10130 => 'Books|Sports & Outdoors|Racket Sports', 4760 10131 => 'Books|Sports & Outdoors|Reference', 4761 10132 => 'Books|Sports & Outdoors|Soccer', 4762 10133 => 'Books|Sports & Outdoors|Training', 4763 10134 => 'Books|Sports & Outdoors|Water Sports', 4764 10135 => 'Books|Sports & Outdoors|Winter Sports', 4765 10136 => 'Books|Reference|Study Aids', 4766 10137 => 'Books|Professional & Technical|Engineering', 4767 10138 => 'Books|Nonfiction|Transportation', 4768 10139 => 'Books|Travel & Adventure|Africa', 4769 10140 => 'Books|Travel & Adventure|Asia', 4770 10141 => 'Books|Travel & Adventure|Specialty Travel', 4771 10142 => 'Books|Travel & Adventure|Canada', 4772 10143 => 'Books|Travel & Adventure|Caribbean', 4773 10144 => 'Books|Travel & Adventure|Latin America', 4774 10145 => 'Books|Travel & Adventure|Essays & Memoirs', 4775 10146 => 'Books|Travel & Adventure|Europe', 4776 10147 => 'Books|Travel & Adventure|Middle East', 4777 10148 => 'Books|Travel & Adventure|United States', 4778 10149 => 'Books|Nonfiction|True Crime', 4779 11001 => 'Books|Sci-Fi & Fantasy|Fantasy|Contemporary', 4780 11002 => 'Books|Sci-Fi & Fantasy|Fantasy|Epic', 4781 11003 => 'Books|Sci-Fi & Fantasy|Fantasy|Historical', 4782 11004 => 'Books|Sci-Fi & Fantasy|Fantasy|Paranormal', 4783 11005 => 'Books|Sci-Fi & Fantasy|Fantasy|Short Stories', 4784 11006 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|Adventure', 4785 11007 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|High Tech', 4786 11008 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|Short Stories', 4787 11009 => 'Books|Professional & Technical|Education|Language Arts & Disciplines', 4788 11010 => 'Books|Communications & Media', 4789 11011 => 'Books|Communications & Media|Broadcasting', 4790 11012 => 'Books|Communications & Media|Digital Media', 4791 11013 => 'Books|Communications & Media|Journalism', 4792 11014 => 'Books|Communications & Media|Photojournalism', 4793 11015 => 'Books|Communications & Media|Print', 4794 11016 => 'Books|Communications & Media|Speech', 4795 11017 => 'Books|Communications & Media|Writing', 4796 11018 => 'Books|Arts & Entertainment|Art & Architecture|Urban Planning', 4797 11019 => 'Books|Arts & Entertainment|Dance', 4798 11020 => 'Books|Arts & Entertainment|Fashion', 4799 11021 => 'Books|Arts & Entertainment|Film', 4800 11022 => 'Books|Arts & Entertainment|Interior Design', 4801 11023 => 'Books|Arts & Entertainment|Media Arts', 4802 11024 => 'Books|Arts & Entertainment|Radio', 4803 11025 => 'Books|Arts & Entertainment|TV', 4804 11026 => 'Books|Arts & Entertainment|Visual Arts', 4805 11027 => 'Books|Biographies & Memoirs|Arts & Entertainment', 4806 11028 => 'Books|Biographies & Memoirs|Business', 4807 11029 => 'Books|Biographies & Memoirs|Culinary', 4808 11030 => 'Books|Biographies & Memoirs|Gay & Lesbian', 4809 11031 => 'Books|Biographies & Memoirs|Historical', 4810 11032 => 'Books|Biographies & Memoirs|Literary', 4811 11033 => 'Books|Biographies & Memoirs|Media & Journalism', 4812 11034 => 'Books|Biographies & Memoirs|Military', 4813 11035 => 'Books|Biographies & Memoirs|Politics', 4814 11036 => 'Books|Biographies & Memoirs|Religious', 4815 11037 => 'Books|Biographies & Memoirs|Science & Technology', 4816 11038 => 'Books|Biographies & Memoirs|Sports', 4817 11039 => 'Books|Biographies & Memoirs|Women', 4818 11040 => 'Books|Romance|New Adult', 4819 11042 => 'Books|Romance|Romantic Comedy', 4820 11043 => 'Books|Romance|Gay & Lesbian', 4821 11044 => 'Books|Fiction & Literature|Essays', 4822 11045 => 'Books|Fiction & Literature|Anthologies', 4823 11046 => 'Books|Fiction & Literature|Comparative Literature', 4824 11047 => 'Books|Fiction & Literature|Drama', 4825 11049 => 'Books|Fiction & Literature|Fairy Tales, Myths & Fables', 4826 11050 => 'Books|Fiction & Literature|Family', 4827 11051 => 'Books|Comics & Graphic Novels|Manga|School Drama', 4828 11052 => 'Books|Comics & Graphic Novels|Manga|Human Drama', 4829 11053 => 'Books|Comics & Graphic Novels|Manga|Family Drama', 4830 11054 => 'Books|Sports & Outdoors|Boxing', 4831 11055 => 'Books|Sports & Outdoors|Cricket', 4832 11056 => 'Books|Sports & Outdoors|Cycling', 4833 11057 => 'Books|Sports & Outdoors|Equestrian', 4834 11058 => 'Books|Sports & Outdoors|Martial Arts & Self Defense', 4835 11059 => 'Books|Sports & Outdoors|Motor Sports', 4836 11060 => 'Books|Sports & Outdoors|Rugby', 4837 11061 => 'Books|Sports & Outdoors|Running', 4838 11062 => 'Books|Self-Development|Diet & Nutrition', 4839 11063 => 'Books|Science & Nature|Agriculture', 4840 11064 => 'Books|Science & Nature|Atmosphere', 4841 11065 => 'Books|Science & Nature|Biology', 4842 11066 => 'Books|Science & Nature|Ecology', 4843 11067 => 'Books|Science & Nature|Environment', 4844 11068 => 'Books|Science & Nature|Geography', 4845 11069 => 'Books|Science & Nature|Geology', 4846 11070 => 'Books|Nonfiction|Social Science|Anthropology', 4847 11071 => 'Books|Nonfiction|Social Science|Archaeology', 4848 11072 => 'Books|Nonfiction|Social Science|Civics', 4849 11073 => 'Books|Nonfiction|Social Science|Government', 4850 11074 => 'Books|Nonfiction|Social Science|Social Studies', 4851 11075 => 'Books|Nonfiction|Social Science|Social Welfare', 4852 11076 => 'Books|Nonfiction|Social Science|Society', 4853 11077 => 'Books|Nonfiction|Philosophy|Aesthetics', 4854 11078 => 'Books|Nonfiction|Philosophy|Epistemology', 4855 11079 => 'Books|Nonfiction|Philosophy|Ethics', 4856 11080 => 'Books|Nonfiction|Philosophy|Language', 4857 11081 => 'Books|Nonfiction|Philosophy|Logic', 4858 11082 => 'Books|Nonfiction|Philosophy|Metaphysics', 4859 11083 => 'Books|Nonfiction|Philosophy|Political', 4860 11084 => 'Books|Nonfiction|Philosophy|Religion', 4861 11085 => 'Books|Reference|Manuals', 4862 11086 => 'Books|Kids', 4863 11087 => 'Books|Kids|Animals', 4864 11088 => 'Books|Kids|Basic Concepts', 4865 11089 => 'Books|Kids|Basic Concepts|Alphabet', 4866 11090 => 'Books|Kids|Basic Concepts|Body', 4867 11091 => 'Books|Kids|Basic Concepts|Colors', 4868 11092 => 'Books|Kids|Basic Concepts|Counting & Numbers', 4869 11093 => 'Books|Kids|Basic Concepts|Date & Time', 4870 11094 => 'Books|Kids|Basic Concepts|General', 4871 11095 => 'Books|Kids|Basic Concepts|Money', 4872 11096 => 'Books|Kids|Basic Concepts|Opposites', 4873 11097 => 'Books|Kids|Basic Concepts|Seasons', 4874 11098 => 'Books|Kids|Basic Concepts|Senses & Sensation', 4875 11099 => 'Books|Kids|Basic Concepts|Size & Shape', 4876 11100 => 'Books|Kids|Basic Concepts|Sounds', 4877 11101 => 'Books|Kids|Basic Concepts|Words', 4878 11102 => 'Books|Kids|Biography', 4879 11103 => 'Books|Kids|Careers & Occupations', 4880 11104 => 'Books|Kids|Computers & Technology', 4881 11105 => 'Books|Kids|Cooking & Food', 4882 11106 => 'Books|Kids|Arts & Entertainment', 4883 11107 => 'Books|Kids|Arts & Entertainment|Art', 4884 11108 => 'Books|Kids|Arts & Entertainment|Crafts', 4885 11109 => 'Books|Kids|Arts & Entertainment|Music', 4886 11110 => 'Books|Kids|Arts & Entertainment|Performing Arts', 4887 11111 => 'Books|Kids|Family', 4888 11112 => 'Books|Kids|Fiction', 4889 11113 => 'Books|Kids|Fiction|Action & Adventure', 4890 11114 => 'Books|Kids|Fiction|Animals', 4891 11115 => 'Books|Kids|Fiction|Classics', 4892 11116 => 'Books|Kids|Fiction|Comics & Graphic Novels', 4893 11117 => 'Books|Kids|Fiction|Culture, Places & People', 4894 11118 => 'Books|Kids|Fiction|Family & Relationships', 4895 11119 => 'Books|Kids|Fiction|Fantasy', 4896 11120 => 'Books|Kids|Fiction|Fairy Tales, Myths & Fables', 4897 11121 => 'Books|Kids|Fiction|Favorite Characters', 4898 11122 => 'Books|Kids|Fiction|Historical', 4899 11123 => 'Books|Kids|Fiction|Holidays & Celebrations', 4900 11124 => 'Books|Kids|Fiction|Monsters & Ghosts', 4901 11125 => 'Books|Kids|Fiction|Mysteries', 4902 11126 => 'Books|Kids|Fiction|Nature', 4903 11127 => 'Books|Kids|Fiction|Religion', 4904 11128 => 'Books|Kids|Fiction|Sci-Fi', 4905 11129 => 'Books|Kids|Fiction|Social Issues', 4906 11130 => 'Books|Kids|Fiction|Sports & Recreation', 4907 11131 => 'Books|Kids|Fiction|Transportation', 4908 11132 => 'Books|Kids|Games & Activities', 4909 11133 => 'Books|Kids|General Nonfiction', 4910 11134 => 'Books|Kids|Health', 4911 11135 => 'Books|Kids|History', 4912 11136 => 'Books|Kids|Holidays & Celebrations', 4913 11137 => 'Books|Kids|Holidays & Celebrations|Birthdays', 4914 11138 => 'Books|Kids|Holidays & Celebrations|Christmas & Advent', 4915 11139 => 'Books|Kids|Holidays & Celebrations|Easter & Lent', 4916 11140 => 'Books|Kids|Holidays & Celebrations|General', 4917 11141 => 'Books|Kids|Holidays & Celebrations|Halloween', 4918 11142 => 'Books|Kids|Holidays & Celebrations|Hanukkah', 4919 11143 => 'Books|Kids|Holidays & Celebrations|Other', 4920 11144 => 'Books|Kids|Holidays & Celebrations|Passover', 4921 11145 => 'Books|Kids|Holidays & Celebrations|Patriotic Holidays', 4922 11146 => 'Books|Kids|Holidays & Celebrations|Ramadan', 4923 11147 => 'Books|Kids|Holidays & Celebrations|Thanksgiving', 4924 11148 => "Books|Kids|Holidays & Celebrations|Valentine's Day", 4925 11149 => 'Books|Kids|Humor', 4926 11150 => 'Books|Kids|Humor|Jokes & Riddles', 4927 11151 => 'Books|Kids|Poetry', 4928 11152 => 'Books|Kids|Learning to Read', 4929 11153 => 'Books|Kids|Learning to Read|Chapter Books', 4930 11154 => 'Books|Kids|Learning to Read|Early Readers', 4931 11155 => 'Books|Kids|Learning to Read|Intermediate Readers', 4932 11156 => 'Books|Kids|Nursery Rhymes', 4933 11157 => 'Books|Kids|Government', 4934 11158 => 'Books|Kids|Reference', 4935 11159 => 'Books|Kids|Religion', 4936 11160 => 'Books|Kids|Science & Nature', 4937 11161 => 'Books|Kids|Social Issues', 4938 11162 => 'Books|Kids|Social Studies', 4939 11163 => 'Books|Kids|Sports & Recreation', 4940 11164 => 'Books|Kids|Transportation', 4941 11165 => 'Books|Young Adult', 4942 11166 => 'Books|Young Adult|Animals', 4943 11167 => 'Books|Young Adult|Biography', 4944 11168 => 'Books|Young Adult|Careers & Occupations', 4945 11169 => 'Books|Young Adult|Computers & Technology', 4946 11170 => 'Books|Young Adult|Cooking & Food', 4947 11171 => 'Books|Young Adult|Arts & Entertainment', 4948 11172 => 'Books|Young Adult|Arts & Entertainment|Art', 4949 11173 => 'Books|Young Adult|Arts & Entertainment|Crafts', 4950 11174 => 'Books|Young Adult|Arts & Entertainment|Music', 4951 11175 => 'Books|Young Adult|Arts & Entertainment|Performing Arts', 4952 11176 => 'Books|Young Adult|Family', 4953 11177 => 'Books|Young Adult|Fiction', 4954 11178 => 'Books|Young Adult|Fiction|Action & Adventure', 4955 11179 => 'Books|Young Adult|Fiction|Animals', 4956 11180 => 'Books|Young Adult|Fiction|Classics', 4957 11181 => 'Books|Young Adult|Fiction|Comics & Graphic Novels', 4958 11182 => 'Books|Young Adult|Fiction|Culture, Places & People', 4959 11183 => 'Books|Young Adult|Fiction|Dystopian', 4960 11184 => 'Books|Young Adult|Fiction|Family & Relationships', 4961 11185 => 'Books|Young Adult|Fiction|Fantasy', 4962 11186 => 'Books|Young Adult|Fiction|Fairy Tales, Myths & Fables', 4963 11187 => 'Books|Young Adult|Fiction|Favorite Characters', 4964 11188 => 'Books|Young Adult|Fiction|Historical', 4965 11189 => 'Books|Young Adult|Fiction|Holidays & Celebrations', 4966 11190 => 'Books|Young Adult|Fiction|Horror, Monsters & Ghosts', 4967 11191 => 'Books|Young Adult|Fiction|Crime & Mystery', 4968 11192 => 'Books|Young Adult|Fiction|Nature', 4969 11193 => 'Books|Young Adult|Fiction|Religion', 4970 11194 => 'Books|Young Adult|Fiction|Romance', 4971 11195 => 'Books|Young Adult|Fiction|Sci-Fi', 4972 11196 => 'Books|Young Adult|Fiction|Coming of Age', 4973 11197 => 'Books|Young Adult|Fiction|Sports & Recreation', 4974 11198 => 'Books|Young Adult|Fiction|Transportation', 4975 11199 => 'Books|Young Adult|Games & Activities', 4976 11200 => 'Books|Young Adult|General Nonfiction', 4977 11201 => 'Books|Young Adult|Health', 4978 11202 => 'Books|Young Adult|History', 4979 11203 => 'Books|Young Adult|Holidays & Celebrations', 4980 11204 => 'Books|Young Adult|Holidays & Celebrations|Birthdays', 4981 11205 => 'Books|Young Adult|Holidays & Celebrations|Christmas & Advent', 4982 11206 => 'Books|Young Adult|Holidays & Celebrations|Easter & Lent', 4983 11207 => 'Books|Young Adult|Holidays & Celebrations|General', 4984 11208 => 'Books|Young Adult|Holidays & Celebrations|Halloween', 4985 11209 => 'Books|Young Adult|Holidays & Celebrations|Hanukkah', 4986 11210 => 'Books|Young Adult|Holidays & Celebrations|Other', 4987 11211 => 'Books|Young Adult|Holidays & Celebrations|Passover', 4988 11212 => 'Books|Young Adult|Holidays & Celebrations|Patriotic Holidays', 4989 11213 => 'Books|Young Adult|Holidays & Celebrations|Ramadan', 4990 11214 => 'Books|Young Adult|Holidays & Celebrations|Thanksgiving', 4991 11215 => "Books|Young Adult|Holidays & Celebrations|Valentine's Day", 4992 11216 => 'Books|Young Adult|Humor', 4993 11217 => 'Books|Young Adult|Humor|Jokes & Riddles', 4994 11218 => 'Books|Young Adult|Poetry', 4995 11219 => 'Books|Young Adult|Politics & Government', 4996 11220 => 'Books|Young Adult|Reference', 4997 11221 => 'Books|Young Adult|Religion', 4998 11222 => 'Books|Young Adult|Science & Nature', 4999 11223 => 'Books|Young Adult|Coming of Age', 5000 11224 => 'Books|Young Adult|Social Studies', 5001 11225 => 'Books|Young Adult|Sports & Recreation', 5002 11226 => 'Books|Young Adult|Transportation', 5003 11227 => 'Books|Communications & Media', 5004 11228 => 'Books|Military & Warfare', 5005 11229 => 'Books|Romance|Inspirational', 5006 11231 => 'Books|Romance|Holiday', 5007 11232 => 'Books|Romance|Wholesome', 5008 11233 => 'Books|Romance|Military', 5009 11234 => 'Books|Arts & Entertainment|Art History', 5010 11236 => 'Books|Arts & Entertainment|Design', 5011 11243 => 'Books|Business & Personal Finance|Accounting', 5012 11244 => 'Books|Business & Personal Finance|Hospitality', 5013 11245 => 'Books|Business & Personal Finance|Real Estate', 5014 11246 => 'Books|Humor|Jokes & Riddles', 5015 11247 => 'Books|Religion & Spirituality|Comparative Religion', 5016 11255 => 'Books|Cookbooks, Food & Wine|Culinary Arts', 5017 11259 => 'Books|Mysteries & Thrillers|Cozy', 5018 11260 => 'Books|Politics & Current Events|Current Events', 5019 11261 => 'Books|Politics & Current Events|Foreign Policy & International Relations', 5020 11262 => 'Books|Politics & Current Events|Local Government', 5021 11263 => 'Books|Politics & Current Events|National Government', 5022 11264 => 'Books|Politics & Current Events|Political Science', 5023 11265 => 'Books|Politics & Current Events|Public Administration', 5024 11266 => 'Books|Politics & Current Events|World Affairs', 5025 11273 => 'Books|Nonfiction|Family & Relationships|Family & Childcare', 5026 11274 => 'Books|Nonfiction|Family & Relationships|Love & Romance', 5027 11275 => 'Books|Sci-Fi & Fantasy|Fantasy|Urban', 5028 11276 => 'Books|Reference|Foreign Languages|Arabic', 5029 11277 => 'Books|Reference|Foreign Languages|Bilingual Editions', 5030 11278 => 'Books|Reference|Foreign Languages|African Languages', 5031 11279 => 'Books|Reference|Foreign Languages|Ancient Languages', 5032 11280 => 'Books|Reference|Foreign Languages|Chinese', 5033 11281 => 'Books|Reference|Foreign Languages|English', 5034 11282 => 'Books|Reference|Foreign Languages|French', 5035 11283 => 'Books|Reference|Foreign Languages|German', 5036 11284 => 'Books|Reference|Foreign Languages|Hebrew', 5037 11285 => 'Books|Reference|Foreign Languages|Hindi', 5038 11286 => 'Books|Reference|Foreign Languages|Italian', 5039 11287 => 'Books|Reference|Foreign Languages|Japanese', 5040 11288 => 'Books|Reference|Foreign Languages|Korean', 5041 11289 => 'Books|Reference|Foreign Languages|Linguistics', 5042 11290 => 'Books|Reference|Foreign Languages|Other Languages', 5043 11291 => 'Books|Reference|Foreign Languages|Portuguese', 5044 11292 => 'Books|Reference|Foreign Languages|Russian', 5045 11293 => 'Books|Reference|Foreign Languages|Spanish', 5046 11294 => 'Books|Reference|Foreign Languages|Speech Pathology', 5047 11295 => 'Books|Science & Nature|Mathematics|Advanced Mathematics', 5048 11296 => 'Books|Science & Nature|Mathematics|Algebra', 5049 11297 => 'Books|Science & Nature|Mathematics|Arithmetic', 5050 11298 => 'Books|Science & Nature|Mathematics|Calculus', 5051 11299 => 'Books|Science & Nature|Mathematics|Geometry', 5052 11300 => 'Books|Science & Nature|Mathematics|Statistics', 5053 11301 => 'Books|Professional & Technical|Medical|Veterinary', 5054 11302 => 'Books|Professional & Technical|Medical|Neuroscience', 5055 11303 => 'Books|Professional & Technical|Medical|Immunology', 5056 11304 => 'Books|Professional & Technical|Medical|Nursing', 5057 11305 => 'Books|Professional & Technical|Medical|Pharmacology & Toxicology', 5058 11306 => 'Books|Professional & Technical|Medical|Anatomy & Physiology', 5059 11307 => 'Books|Professional & Technical|Medical|Dentistry', 5060 11308 => 'Books|Professional & Technical|Medical|Emergency Medicine', 5061 11309 => 'Books|Professional & Technical|Medical|Genetics', 5062 11310 => 'Books|Professional & Technical|Medical|Psychiatry', 5063 11311 => 'Books|Professional & Technical|Medical|Radiology', 5064 11312 => 'Books|Professional & Technical|Medical|Alternative Medicine', 5065 11317 => 'Books|Nonfiction|Philosophy|Political Philosophy', 5066 11319 => 'Books|Nonfiction|Philosophy|Philosophy of Language', 5067 11320 => 'Books|Nonfiction|Philosophy|Philosophy of Religion', 5068 11327 => 'Books|Nonfiction|Social Science|Sociology', 5069 11329 => 'Books|Professional & Technical|Engineering|Aeronautics', 5070 11330 => 'Books|Professional & Technical|Engineering|Chemical & Petroleum Engineering', 5071 11331 => 'Books|Professional & Technical|Engineering|Civil Engineering', 5072 11332 => 'Books|Professional & Technical|Engineering|Computer Science', 5073 11333 => 'Books|Professional & Technical|Engineering|Electrical Engineering', 5074 11334 => 'Books|Professional & Technical|Engineering|Environmental Engineering', 5075 11335 => 'Books|Professional & Technical|Engineering|Mechanical Engineering', 5076 11336 => 'Books|Professional & Technical|Engineering|Power Resources', 5077 11337 => 'Books|Comics & Graphic Novels|Manga|Boys', 5078 11338 => 'Books|Comics & Graphic Novels|Manga|Men', 5079 11339 => 'Books|Comics & Graphic Novels|Manga|Girls', 5080 11340 => 'Books|Comics & Graphic Novels|Manga|Women', 5081 11341 => 'Books|Comics & Graphic Novels|Manga|Other', 5082 11342 => 'Books|Comics & Graphic Novels|Manga|Yaoi', 5083 11343 => 'Books|Comics & Graphic Novels|Manga|Comic Essays', 5084 12001 => 'Mac App Store|Business', 5085 12002 => 'Mac App Store|Developer Tools', 5086 12003 => 'Mac App Store|Education', 5087 12004 => 'Mac App Store|Entertainment', 5088 12005 => 'Mac App Store|Finance', 5089 12006 => 'Mac App Store|Games', 5090 12007 => 'Mac App Store|Health & Fitness', 5091 12008 => 'Mac App Store|Lifestyle', 5092 12010 => 'Mac App Store|Medical', 5093 12011 => 'Mac App Store|Music', 5094 12012 => 'Mac App Store|News', 5095 12013 => 'Mac App Store|Photography', 5096 12014 => 'Mac App Store|Productivity', 5097 12015 => 'Mac App Store|Reference', 5098 12016 => 'Mac App Store|Social Networking', 5099 12017 => 'Mac App Store|Sports', 5100 12018 => 'Mac App Store|Travel', 5101 12019 => 'Mac App Store|Utilities', 5102 12020 => 'Mac App Store|Video', 5103 12021 => 'Mac App Store|Weather', 5104 12022 => 'Mac App Store|Graphics & Design', 5105 12201 => 'Mac App Store|Games|Action', 5106 12202 => 'Mac App Store|Games|Adventure', 5107 12203 => 'Mac App Store|Games|Casual', 5108 12204 => 'Mac App Store|Games|Board', 5109 12205 => 'Mac App Store|Games|Card', 5110 12206 => 'Mac App Store|Games|Casino', 5111 12207 => 'Mac App Store|Games|Dice', 5112 12208 => 'Mac App Store|Games|Educational', 5113 12209 => 'Mac App Store|Games|Family', 5114 12210 => 'Mac App Store|Games|Kids', 5115 12211 => 'Mac App Store|Games|Music', 5116 12212 => 'Mac App Store|Games|Puzzle', 5117 12213 => 'Mac App Store|Games|Racing', 5118 12214 => 'Mac App Store|Games|Role Playing', 5119 12215 => 'Mac App Store|Games|Simulation', 5120 12216 => 'Mac App Store|Games|Sports', 5121 12217 => 'Mac App Store|Games|Strategy', 5122 12218 => 'Mac App Store|Games|Trivia', 5123 12219 => 'Mac App Store|Games|Word', 5124 13001 => 'App Store|Magazines & Newspapers|News & Politics', 5125 13002 => 'App Store|Magazines & Newspapers|Fashion & Style', 5126 13003 => 'App Store|Magazines & Newspapers|Home & Garden', 5127 13004 => 'App Store|Magazines & Newspapers|Outdoors & Nature', 5128 13005 => 'App Store|Magazines & Newspapers|Sports & Leisure', 5129 13006 => 'App Store|Magazines & Newspapers|Automotive', 5130 13007 => 'App Store|Magazines & Newspapers|Arts & Photography', 5131 13008 => 'App Store|Magazines & Newspapers|Brides & Weddings', 5132 13009 => 'App Store|Magazines & Newspapers|Business & Investing', 5133 13010 => "App Store|Magazines & Newspapers|Children's Magazines", 5134 13011 => 'App Store|Magazines & Newspapers|Computers & Internet', 5135 13012 => 'App Store|Magazines & Newspapers|Cooking, Food & Drink', 5136 13013 => 'App Store|Magazines & Newspapers|Crafts & Hobbies', 5137 13014 => 'App Store|Magazines & Newspapers|Electronics & Audio', 5138 13015 => 'App Store|Magazines & Newspapers|Entertainment', 5139 13017 => 'App Store|Magazines & Newspapers|Health, Mind & Body', 5140 13018 => 'App Store|Magazines & Newspapers|History', 5141 13019 => 'App Store|Magazines & Newspapers|Literary Magazines & Journals', 5142 13020 => "App Store|Magazines & Newspapers|Men's Interest", 5143 13021 => 'App Store|Magazines & Newspapers|Movies & Music', 5144 13023 => 'App Store|Magazines & Newspapers|Parenting & Family', 5145 13024 => 'App Store|Magazines & Newspapers|Pets', 5146 13025 => 'App Store|Magazines & Newspapers|Professional & Trade', 5147 13026 => 'App Store|Magazines & Newspapers|Regional News', 5148 13027 => 'App Store|Magazines & Newspapers|Science', 5149 13028 => 'App Store|Magazines & Newspapers|Teens', 5150 13029 => 'App Store|Magazines & Newspapers|Travel & Regional', 5151 13030 => "App Store|Magazines & Newspapers|Women's Interest", 5152 15000 => 'Textbooks|Arts & Entertainment', 5153 15001 => 'Textbooks|Arts & Entertainment|Art & Architecture', 5154 15002 => 'Textbooks|Arts & Entertainment|Art & Architecture|Urban Planning', 5155 15003 => 'Textbooks|Arts & Entertainment|Art History', 5156 15004 => 'Textbooks|Arts & Entertainment|Dance', 5157 15005 => 'Textbooks|Arts & Entertainment|Design', 5158 15006 => 'Textbooks|Arts & Entertainment|Fashion', 5159 15007 => 'Textbooks|Arts & Entertainment|Film', 5160 15008 => 'Textbooks|Arts & Entertainment|Games', 5161 15009 => 'Textbooks|Arts & Entertainment|Interior Design', 5162 15010 => 'Textbooks|Arts & Entertainment|Media Arts', 5163 15011 => 'Textbooks|Arts & Entertainment|Music', 5164 15012 => 'Textbooks|Arts & Entertainment|Performing Arts', 5165 15013 => 'Textbooks|Arts & Entertainment|Photography', 5166 15014 => 'Textbooks|Arts & Entertainment|Theater', 5167 15015 => 'Textbooks|Arts & Entertainment|TV', 5168 15016 => 'Textbooks|Arts & Entertainment|Visual Arts', 5169 15017 => 'Textbooks|Biographies & Memoirs', 5170 15018 => 'Textbooks|Business & Personal Finance', 5171 15019 => 'Textbooks|Business & Personal Finance|Accounting', 5172 15020 => 'Textbooks|Business & Personal Finance|Careers', 5173 15021 => 'Textbooks|Business & Personal Finance|Economics', 5174 15022 => 'Textbooks|Business & Personal Finance|Finance', 5175 15023 => 'Textbooks|Business & Personal Finance|Hospitality', 5176 15024 => 'Textbooks|Business & Personal Finance|Industries & Professions', 5177 15025 => 'Textbooks|Business & Personal Finance|Investing', 5178 15026 => 'Textbooks|Business & Personal Finance|Management & Leadership', 5179 15027 => 'Textbooks|Business & Personal Finance|Marketing & Sales', 5180 15028 => 'Textbooks|Business & Personal Finance|Personal Finance', 5181 15029 => 'Textbooks|Business & Personal Finance|Real Estate', 5182 15030 => 'Textbooks|Business & Personal Finance|Reference', 5183 15031 => 'Textbooks|Business & Personal Finance|Small Business & Entrepreneurship', 5184 15032 => 'Textbooks|Children & Teens', 5185 15033 => 'Textbooks|Children & Teens|Fiction', 5186 15034 => 'Textbooks|Children & Teens|Nonfiction', 5187 15035 => 'Textbooks|Comics & Graphic Novels', 5188 15036 => 'Textbooks|Comics & Graphic Novels|Graphic Novels', 5189 15037 => 'Textbooks|Comics & Graphic Novels|Manga', 5190 15038 => 'Textbooks|Communications & Media', 5191 15039 => 'Textbooks|Communications & Media|Broadcasting', 5192 15040 => 'Textbooks|Communications & Media|Digital Media', 5193 15041 => 'Textbooks|Communications & Media|Journalism', 5194 15042 => 'Textbooks|Communications & Media|Photojournalism', 5195 15043 => 'Textbooks|Communications & Media|Print', 5196 15044 => 'Textbooks|Communications & Media|Speech', 5197 15045 => 'Textbooks|Communications & Media|Writing', 5198 15046 => 'Textbooks|Computers & Internet', 5199 15047 => 'Textbooks|Computers & Internet|Computers', 5200 15048 => 'Textbooks|Computers & Internet|Databases', 5201 15049 => 'Textbooks|Computers & Internet|Digital Media', 5202 15050 => 'Textbooks|Computers & Internet|Internet', 5203 15051 => 'Textbooks|Computers & Internet|Network', 5204 15052 => 'Textbooks|Computers & Internet|Operating Systems', 5205 15053 => 'Textbooks|Computers & Internet|Programming', 5206 15054 => 'Textbooks|Computers & Internet|Software', 5207 15055 => 'Textbooks|Computers & Internet|System Administration', 5208 15056 => 'Textbooks|Cookbooks, Food & Wine', 5209 15057 => 'Textbooks|Cookbooks, Food & Wine|Beverages', 5210 15058 => 'Textbooks|Cookbooks, Food & Wine|Courses & Dishes', 5211 15059 => 'Textbooks|Cookbooks, Food & Wine|Culinary Arts', 5212 15060 => 'Textbooks|Cookbooks, Food & Wine|Methods', 5213 15061 => 'Textbooks|Cookbooks, Food & Wine|Reference', 5214 15062 => 'Textbooks|Cookbooks, Food & Wine|Regional & Ethnic', 5215 15063 => 'Textbooks|Cookbooks, Food & Wine|Special Diet', 5216 15064 => 'Textbooks|Cookbooks, Food & Wine|Special Occasions', 5217 15065 => 'Textbooks|Cookbooks, Food & Wine|Specific Ingredients', 5218 15066 => 'Textbooks|Engineering', 5219 15067 => 'Textbooks|Engineering|Aeronautics', 5220 15068 => 'Textbooks|Engineering|Chemical & Petroleum Engineering', 5221 15069 => 'Textbooks|Engineering|Civil Engineering', 5222 15070 => 'Textbooks|Engineering|Computer Science', 5223 15071 => 'Textbooks|Engineering|Electrical Engineering', 5224 15072 => 'Textbooks|Engineering|Environmental Engineering', 5225 15073 => 'Textbooks|Engineering|Mechanical Engineering', 5226 15074 => 'Textbooks|Engineering|Power Resources', 5227 15075 => 'Textbooks|Fiction & Literature', 5228 15076 => 'Textbooks|Fiction & Literature|Latino', 5229 15077 => 'Textbooks|Fiction & Literature|Action & Adventure', 5230 15078 => 'Textbooks|Fiction & Literature|African American', 5231 15079 => 'Textbooks|Fiction & Literature|Anthologies', 5232 15080 => 'Textbooks|Fiction & Literature|Classics', 5233 15081 => 'Textbooks|Fiction & Literature|Comparative Literature', 5234 15082 => 'Textbooks|Fiction & Literature|Erotica', 5235 15083 => 'Textbooks|Fiction & Literature|Gay', 5236 15084 => 'Textbooks|Fiction & Literature|Ghost', 5237 15085 => 'Textbooks|Fiction & Literature|Historical', 5238 15086 => 'Textbooks|Fiction & Literature|Horror', 5239 15087 => 'Textbooks|Fiction & Literature|Literary', 5240 15088 => 'Textbooks|Fiction & Literature|Literary Criticism', 5241 15089 => 'Textbooks|Fiction & Literature|Poetry', 5242 15090 => 'Textbooks|Fiction & Literature|Religious', 5243 15091 => 'Textbooks|Fiction & Literature|Short Stories', 5244 15092 => 'Textbooks|Health, Mind & Body', 5245 15093 => 'Textbooks|Health, Mind & Body|Fitness', 5246 15094 => 'Textbooks|Health, Mind & Body|Self-Improvement', 5247 15095 => 'Textbooks|History', 5248 15096 => 'Textbooks|History|Africa', 5249 15097 => 'Textbooks|History|Americas', 5250 15098 => 'Textbooks|History|Americas|Canada', 5251 15099 => 'Textbooks|History|Americas|Latin America', 5252 15100 => 'Textbooks|History|Americas|United States', 5253 15101 => 'Textbooks|History|Ancient', 5254 15102 => 'Textbooks|History|Asia', 5255 15103 => 'Textbooks|History|Australia & Oceania', 5256 15104 => 'Textbooks|History|Europe', 5257 15105 => 'Textbooks|History|Middle East', 5258 15106 => 'Textbooks|History|Military', 5259 15107 => 'Textbooks|History|World', 5260 15108 => 'Textbooks|Humor', 5261 15109 => 'Textbooks|Language Studies', 5262 15110 => 'Textbooks|Language Studies|African Languages', 5263 15111 => 'Textbooks|Language Studies|Ancient Languages', 5264 15112 => 'Textbooks|Language Studies|Arabic', 5265 15113 => 'Textbooks|Language Studies|Bilingual Editions', 5266 15114 => 'Textbooks|Language Studies|Chinese', 5267 15115 => 'Textbooks|Language Studies|English', 5268 15116 => 'Textbooks|Language Studies|French', 5269 15117 => 'Textbooks|Language Studies|German', 5270 15118 => 'Textbooks|Language Studies|Hebrew', 5271 15119 => 'Textbooks|Language Studies|Hindi', 5272 15120 => 'Textbooks|Language Studies|Indigenous Languages', 5273 15121 => 'Textbooks|Language Studies|Italian', 5274 15122 => 'Textbooks|Language Studies|Japanese', 5275 15123 => 'Textbooks|Language Studies|Korean', 5276 15124 => 'Textbooks|Language Studies|Linguistics', 5277 15125 => 'Textbooks|Language Studies|Other Language', 5278 15126 => 'Textbooks|Language Studies|Portuguese', 5279 15127 => 'Textbooks|Language Studies|Russian', 5280 15128 => 'Textbooks|Language Studies|Spanish', 5281 15129 => 'Textbooks|Language Studies|Speech Pathology', 5282 15130 => 'Textbooks|Lifestyle & Home', 5283 15131 => 'Textbooks|Lifestyle & Home|Antiques & Collectibles', 5284 15132 => 'Textbooks|Lifestyle & Home|Crafts & Hobbies', 5285 15133 => 'Textbooks|Lifestyle & Home|Gardening', 5286 15134 => 'Textbooks|Lifestyle & Home|Pets', 5287 15135 => 'Textbooks|Mathematics', 5288 15136 => 'Textbooks|Mathematics|Advanced Mathematics', 5289 15137 => 'Textbooks|Mathematics|Algebra', 5290 15138 => 'Textbooks|Mathematics|Arithmetic', 5291 15139 => 'Textbooks|Mathematics|Calculus', 5292 15140 => 'Textbooks|Mathematics|Geometry', 5293 15141 => 'Textbooks|Mathematics|Statistics', 5294 15142 => 'Textbooks|Medicine', 5295 15143 => 'Textbooks|Medicine|Anatomy & Physiology', 5296 15144 => 'Textbooks|Medicine|Dentistry', 5297 15145 => 'Textbooks|Medicine|Emergency Medicine', 5298 15146 => 'Textbooks|Medicine|Genetics', 5299 15147 => 'Textbooks|Medicine|Immunology', 5300 15148 => 'Textbooks|Medicine|Neuroscience', 5301 15149 => 'Textbooks|Medicine|Nursing', 5302 15150 => 'Textbooks|Medicine|Pharmacology & Toxicology', 5303 15151 => 'Textbooks|Medicine|Psychiatry', 5304 15152 => 'Textbooks|Medicine|Psychology', 5305 15153 => 'Textbooks|Medicine|Radiology', 5306 15154 => 'Textbooks|Medicine|Veterinary', 5307 15155 => 'Textbooks|Mysteries & Thrillers', 5308 15156 => 'Textbooks|Mysteries & Thrillers|British Detectives', 5309 15157 => 'Textbooks|Mysteries & Thrillers|Hard-Boiled', 5310 15158 => 'Textbooks|Mysteries & Thrillers|Historical', 5311 15159 => 'Textbooks|Mysteries & Thrillers|Police Procedural', 5312 15160 => 'Textbooks|Mysteries & Thrillers|Short Stories', 5313 15161 => 'Textbooks|Mysteries & Thrillers|Women Sleuths', 5314 15162 => 'Textbooks|Nonfiction', 5315 15163 => 'Textbooks|Nonfiction|Family & Relationships', 5316 15164 => 'Textbooks|Nonfiction|Transportation', 5317 15165 => 'Textbooks|Nonfiction|True Crime', 5318 15166 => 'Textbooks|Parenting', 5319 15167 => 'Textbooks|Philosophy', 5320 15168 => 'Textbooks|Philosophy|Aesthetics', 5321 15169 => 'Textbooks|Philosophy|Epistemology', 5322 15170 => 'Textbooks|Philosophy|Ethics', 5323 15171 => 'Textbooks|Philosophy|Philosophy of Language', 5324 15172 => 'Textbooks|Philosophy|Logic', 5325 15173 => 'Textbooks|Philosophy|Metaphysics', 5326 15174 => 'Textbooks|Philosophy|Political Philosophy', 5327 15175 => 'Textbooks|Philosophy|Philosophy of Religion', 5328 15176 => 'Textbooks|Politics & Current Events', 5329 15177 => 'Textbooks|Politics & Current Events|Current Events', 5330 15178 => 'Textbooks|Politics & Current Events|Foreign Policy & International Relations', 5331 15179 => 'Textbooks|Politics & Current Events|Local Governments', 5332 15180 => 'Textbooks|Politics & Current Events|National Governments', 5333 15181 => 'Textbooks|Politics & Current Events|Political Science', 5334 15182 => 'Textbooks|Politics & Current Events|Public Administration', 5335 15183 => 'Textbooks|Politics & Current Events|World Affairs', 5336 15184 => 'Textbooks|Professional & Technical', 5337 15185 => 'Textbooks|Professional & Technical|Design', 5338 15186 => 'Textbooks|Professional & Technical|Language Arts & Disciplines', 5339 15187 => 'Textbooks|Professional & Technical|Engineering', 5340 15188 => 'Textbooks|Professional & Technical|Law', 5341 15189 => 'Textbooks|Professional & Technical|Medical', 5342 15190 => 'Textbooks|Reference', 5343 15191 => 'Textbooks|Reference|Almanacs & Yearbooks', 5344 15192 => 'Textbooks|Reference|Atlases & Maps', 5345 15193 => 'Textbooks|Reference|Catalogs & Directories', 5346 15194 => 'Textbooks|Reference|Consumer Guides', 5347 15195 => 'Textbooks|Reference|Dictionaries & Thesauruses', 5348 15196 => 'Textbooks|Reference|Encyclopedias', 5349 15197 => 'Textbooks|Reference|Etiquette', 5350 15198 => 'Textbooks|Reference|Quotations', 5351 15199 => 'Textbooks|Reference|Study Aids', 5352 15200 => 'Textbooks|Reference|Words & Language', 5353 15201 => 'Textbooks|Reference|Writing', 5354 15202 => 'Textbooks|Religion & Spirituality', 5355 15203 => 'Textbooks|Religion & Spirituality|Bible Studies', 5356 15204 => 'Textbooks|Religion & Spirituality|Bibles', 5357 15205 => 'Textbooks|Religion & Spirituality|Buddhism', 5358 15206 => 'Textbooks|Religion & Spirituality|Christianity', 5359 15207 => 'Textbooks|Religion & Spirituality|Comparative Religion', 5360 15208 => 'Textbooks|Religion & Spirituality|Hinduism', 5361 15209 => 'Textbooks|Religion & Spirituality|Islam', 5362 15210 => 'Textbooks|Religion & Spirituality|Judaism', 5363 15211 => 'Textbooks|Religion & Spirituality|Spirituality', 5364 15212 => 'Textbooks|Romance', 5365 15213 => 'Textbooks|Romance|Contemporary', 5366 15214 => 'Textbooks|Romance|Erotic Romance', 5367 15215 => 'Textbooks|Romance|Paranormal', 5368 15216 => 'Textbooks|Romance|Historical', 5369 15217 => 'Textbooks|Romance|Short Stories', 5370 15218 => 'Textbooks|Romance|Suspense', 5371 15219 => 'Textbooks|Romance|Western', 5372 15220 => 'Textbooks|Sci-Fi & Fantasy', 5373 15221 => 'Textbooks|Sci-Fi & Fantasy|Fantasy', 5374 15222 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Contemporary', 5375 15223 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Epic', 5376 15224 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Historical', 5377 15225 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Paranormal', 5378 15226 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Short Stories', 5379 15227 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction', 5380 15228 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature', 5381 15229 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|Adventure', 5382 15230 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|High Tech', 5383 15231 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|Short Stories', 5384 15232 => 'Textbooks|Science & Nature', 5385 15233 => 'Textbooks|Science & Nature|Agriculture', 5386 15234 => 'Textbooks|Science & Nature|Astronomy', 5387 15235 => 'Textbooks|Science & Nature|Atmosphere', 5388 15236 => 'Textbooks|Science & Nature|Biology', 5389 15237 => 'Textbooks|Science & Nature|Chemistry', 5390 15238 => 'Textbooks|Science & Nature|Earth Sciences', 5391 15239 => 'Textbooks|Science & Nature|Ecology', 5392 15240 => 'Textbooks|Science & Nature|Environment', 5393 15241 => 'Textbooks|Science & Nature|Essays', 5394 15242 => 'Textbooks|Science & Nature|Geography', 5395 15243 => 'Textbooks|Science & Nature|Geology', 5396 15244 => 'Textbooks|Science & Nature|History', 5397 15245 => 'Textbooks|Science & Nature|Life Sciences', 5398 15246 => 'Textbooks|Science & Nature|Nature', 5399 15247 => 'Textbooks|Science & Nature|Physics', 5400 15248 => 'Textbooks|Science & Nature|Reference', 5401 15249 => 'Textbooks|Social Science', 5402 15250 => 'Textbooks|Social Science|Anthropology', 5403 15251 => 'Textbooks|Social Science|Archaeology', 5404 15252 => 'Textbooks|Social Science|Civics', 5405 15253 => 'Textbooks|Social Science|Government', 5406 15254 => 'Textbooks|Social Science|Social Studies', 5407 15255 => 'Textbooks|Social Science|Social Welfare', 5408 15256 => 'Textbooks|Social Science|Society', 5409 15257 => 'Textbooks|Social Science|Society|African Studies', 5410 15258 => 'Textbooks|Social Science|Society|American Studies', 5411 15259 => 'Textbooks|Social Science|Society|Asia Pacific Studies', 5412 15260 => 'Textbooks|Social Science|Society|Cross-Cultural Studies', 5413 15261 => 'Textbooks|Social Science|Society|European Studies', 5414 15262 => 'Textbooks|Social Science|Society|Immigration & Emigration', 5415 15263 => 'Textbooks|Social Science|Society|Indigenous Studies', 5416 15264 => 'Textbooks|Social Science|Society|Latin & Caribbean Studies', 5417 15265 => 'Textbooks|Social Science|Society|Middle Eastern Studies', 5418 15266 => 'Textbooks|Social Science|Society|Race & Ethnicity Studies', 5419 15267 => 'Textbooks|Social Science|Society|Sexuality Studies', 5420 15268 => "Textbooks|Social Science|Society|Women's Studies", 5421 15269 => 'Textbooks|Social Science|Sociology', 5422 15270 => 'Textbooks|Sports & Outdoors', 5423 15271 => 'Textbooks|Sports & Outdoors|Baseball', 5424 15272 => 'Textbooks|Sports & Outdoors|Basketball', 5425 15273 => 'Textbooks|Sports & Outdoors|Coaching', 5426 15274 => 'Textbooks|Sports & Outdoors|Equestrian', 5427 15275 => 'Textbooks|Sports & Outdoors|Extreme Sports', 5428 15276 => 'Textbooks|Sports & Outdoors|Football', 5429 15277 => 'Textbooks|Sports & Outdoors|Golf', 5430 15278 => 'Textbooks|Sports & Outdoors|Hockey', 5431 15279 => 'Textbooks|Sports & Outdoors|Motor Sports', 5432 15280 => 'Textbooks|Sports & Outdoors|Mountaineering', 5433 15281 => 'Textbooks|Sports & Outdoors|Outdoors', 5434 15282 => 'Textbooks|Sports & Outdoors|Racket Sports', 5435 15283 => 'Textbooks|Sports & Outdoors|Reference', 5436 15284 => 'Textbooks|Sports & Outdoors|Soccer', 5437 15285 => 'Textbooks|Sports & Outdoors|Training', 5438 15286 => 'Textbooks|Sports & Outdoors|Water Sports', 5439 15287 => 'Textbooks|Sports & Outdoors|Winter Sports', 5440 15288 => 'Textbooks|Teaching & Learning', 5441 15289 => 'Textbooks|Teaching & Learning|Adult Education', 5442 15290 => 'Textbooks|Teaching & Learning|Curriculum & Teaching', 5443 15291 => 'Textbooks|Teaching & Learning|Educational Leadership', 5444 15292 => 'Textbooks|Teaching & Learning|Educational Technology', 5445 15293 => 'Textbooks|Teaching & Learning|Family & Childcare', 5446 15294 => 'Textbooks|Teaching & Learning|Information & Library Science', 5447 15295 => 'Textbooks|Teaching & Learning|Learning Resources', 5448 15296 => 'Textbooks|Teaching & Learning|Psychology & Research', 5449 15297 => 'Textbooks|Teaching & Learning|Special Education', 5450 15298 => 'Textbooks|Travel & Adventure', 5451 15299 => 'Textbooks|Travel & Adventure|Africa', 5452 15300 => 'Textbooks|Travel & Adventure|Americas', 5453 15301 => 'Textbooks|Travel & Adventure|Americas|Canada', 5454 15302 => 'Textbooks|Travel & Adventure|Americas|Latin America', 5455 15303 => 'Textbooks|Travel & Adventure|Americas|United States', 5456 15304 => 'Textbooks|Travel & Adventure|Asia', 5457 15305 => 'Textbooks|Travel & Adventure|Caribbean', 5458 15306 => 'Textbooks|Travel & Adventure|Essays & Memoirs', 5459 15307 => 'Textbooks|Travel & Adventure|Europe', 5460 15308 => 'Textbooks|Travel & Adventure|Middle East', 5461 15309 => 'Textbooks|Travel & Adventure|Oceania', 5462 15310 => 'Textbooks|Travel & Adventure|Specialty Travel', 5463 15311 => 'Textbooks|Comics & Graphic Novels|Comics', 5464 15312 => 'Textbooks|Reference|Manuals', 5465 16001 => 'App Store|Stickers|Emoji & Expressions', 5466 16003 => 'App Store|Stickers|Animals & Nature', 5467 16005 => 'App Store|Stickers|Art', 5468 16006 => 'App Store|Stickers|Celebrations', 5469 16007 => 'App Store|Stickers|Celebrities', 5470 16008 => 'App Store|Stickers|Comics & Cartoons', 5471 16009 => 'App Store|Stickers|Eating & Drinking', 5472 16010 => 'App Store|Stickers|Gaming', 5473 16014 => 'App Store|Stickers|Movies & TV', 5474 16015 => 'App Store|Stickers|Music', 5475 16017 => 'App Store|Stickers|People', 5476 16019 => 'App Store|Stickers|Places & Objects', 5477 16021 => 'App Store|Stickers|Sports & Activities', 5478 16025 => 'App Store|Stickers|Kids & Family', 5479 16026 => 'App Store|Stickers|Fashion', 5480 100000 => 'Music|Christian & Gospel', 5481 100001 => 'Music|Classical|Art Song', 5482 100002 => 'Music|Classical|Brass & Woodwinds', 5483 100003 => 'Music|Classical|Solo Instrumental', 5484 100004 => 'Music|Classical|Contemporary Era', 5485 100005 => 'Music|Classical|Oratorio', 5486 100006 => 'Music|Classical|Cantata', 5487 100007 => 'Music|Classical|Electronic', 5488 100008 => 'Music|Classical|Sacred', 5489 100009 => 'Music|Classical|Guitar', 5490 100010 => 'Music|Classical|Piano', 5491 100011 => 'Music|Classical|Violin', 5492 100012 => 'Music|Classical|Cello', 5493 100013 => 'Music|Classical|Percussion', 5494 100014 => 'Music|Electronic|Dubstep', 5495 100015 => 'Music|Electronic|Bass', 5496 100016 => 'Music|Hip-Hop/Rap|UK Hip-Hop', 5497 100017 => 'Music|Reggae|Lovers Rock', 5498 100018 => 'Music|Alternative|EMO', 5499 100019 => 'Music|Alternative|Pop Punk', 5500 100020 => 'Music|Alternative|Indie Pop', 5501 100021 => 'Music|New Age|Yoga', 5502 100022 => 'Music|Pop|Tribute', 5503 100023 => 'Music|Pop|Shows', 5504 100024 => 'Music|Cuban', 5505 100025 => 'Music|Cuban|Mambo', 5506 100026 => 'Music|Cuban|Chachacha', 5507 100027 => 'Music|Cuban|Guajira', 5508 100028 => 'Music|Cuban|Son', 5509 100029 => 'Music|Cuban|Bolero', 5510 100030 => 'Music|Cuban|Guaracha', 5511 100031 => 'Music|Cuban|Timba', 5512 100032 => 'Music|Soundtrack|Video Game', 5513 100033 => 'Music|Indian|Regional Indian|Punjabi|Punjabi Pop', 5514 100034 => 'Music|Indian|Regional Indian|Bengali|Rabindra Sangeet', 5515 100035 => 'Music|Indian|Regional Indian|Malayalam', 5516 100036 => 'Music|Indian|Regional Indian|Kannada', 5517 100037 => 'Music|Indian|Regional Indian|Marathi', 5518 100038 => 'Music|Indian|Regional Indian|Gujarati', 5519 100039 => 'Music|Indian|Regional Indian|Assamese', 5520 100040 => 'Music|Indian|Regional Indian|Bhojpuri', 5521 100041 => 'Music|Indian|Regional Indian|Haryanvi', 5522 100042 => 'Music|Indian|Regional Indian|Odia', 5523 100043 => 'Music|Indian|Regional Indian|Rajasthani', 5524 100044 => 'Music|Indian|Regional Indian|Urdu', 5525 100045 => 'Music|Indian|Regional Indian|Punjabi', 5526 100046 => 'Music|Indian|Regional Indian|Bengali', 5527 100047 => 'Music|Indian|Indian Classical|Carnatic Classical', 5528 100048 => 'Music|Indian|Indian Classical|Hindustani Classical', 5529 100049 => 'Music|African|Afro House', 5530 100050 => 'Music|African|Afro Soul', 5531 100051 => 'Music|African|Afrobeats', 5532 100052 => 'Music|African|Benga', 5533 100053 => 'Music|African|Bongo-Flava', 5534 100054 => 'Music|African|Coupe-Decale', 5535 100055 => 'Music|African|Gqom', 5536 100056 => 'Music|African|Highlife', 5537 100057 => 'Music|African|Kuduro', 5538 100058 => 'Music|African|Kizomba', 5539 100059 => 'Music|African|Kwaito', 5540 100060 => 'Music|African|Mbalax', 5541 100061 => 'Music|African|Ndombolo', 5542 100062 => 'Music|African|Shangaan Electro', 5543 100063 => 'Music|African|Soukous', 5544 100064 => 'Music|African|Taarab', 5545 100065 => 'Music|African|Zouglou', 5546 100066 => 'Music|Turkish|Ozgun', 5547 100067 => 'Music|Turkish|Fantezi', 5548 100068 => 'Music|Turkish|Religious', 5549 100069 => 'Music|Pop|Turkish Pop', 5550 100070 => 'Music|Rock|Turkish Rock', 5551 100071 => 'Music|Alternative|Turkish Alternative', 5552 100072 => 'Music|Hip-Hop/Rap|Turkish Hip-Hop/Rap', 5553 100073 => 'Music|African|Maskandi', 5554 100074 => 'Music|Russian|Russian Romance', 5555 100075 => 'Music|Russian|Russian Bard', 5556 100076 => 'Music|Russian|Russian Pop', 5557 100077 => 'Music|Russian|Russian Rock', 5558 100078 => 'Music|Russian|Russian Hip-Hop', 5559 100079 => 'Music|Arabic|Levant', 5560 100080 => 'Music|Arabic|Levant|Dabke', 5561 100081 => 'Music|Arabic|Maghreb Rai', 5562 100082 => 'Music|Arabic|Khaleeji|Khaleeji Jalsat', 5563 100083 => 'Music|Arabic|Khaleeji|Khaleeji Shailat', 5564 100084 => 'Music|Tarab', 5565 100085 => 'Music|Tarab|Iraqi Tarab', 5566 100086 => 'Music|Tarab|Egyptian Tarab', 5567 100087 => 'Music|Tarab|Khaleeji Tarab', 5568 100088 => 'Music|Pop|Levant Pop', 5569 100089 => 'Music|Pop|Iraqi Pop', 5570 100090 => 'Music|Pop|Egyptian Pop', 5571 100091 => 'Music|Pop|Maghreb Pop', 5572 100092 => 'Music|Pop|Khaleeji Pop', 5573 100093 => 'Music|Hip-Hop/Rap|Levant Hip-Hop', 5574 100094 => 'Music|Hip-Hop/Rap|Egyptian Hip-Hop', 5575 100095 => 'Music|Hip-Hop/Rap|Maghreb Hip-Hop', 5576 100096 => 'Music|Hip-Hop/Rap|Khaleeji Hip-Hop', 5577 100097 => 'Music|Alternative|Indie Levant', 5578 100098 => 'Music|Alternative|Indie Egyptian', 5579 100099 => 'Music|Alternative|Indie Maghreb', 5580 100100 => 'Music|Electronic|Levant Electronic', 5581 100101 => "Music|Electronic|Electro-Cha'abi", 5582 100102 => 'Music|Electronic|Maghreb Electronic', 5583 100103 => 'Music|Folk|Iraqi Folk', 5584 100104 => 'Music|Folk|Khaleeji Folk', 5585 100105 => 'Music|Dance|Maghreb Dance', 5586 40000000 => 'iTunes U', 5587 40000001 => 'iTunes U|Business & Economics', 5588 40000002 => 'iTunes U|Business & Economics|Economics', 5589 40000003 => 'iTunes U|Business & Economics|Finance', 5590 40000004 => 'iTunes U|Business & Economics|Hospitality', 5591 40000005 => 'iTunes U|Business & Economics|Management', 5592 40000006 => 'iTunes U|Business & Economics|Marketing', 5593 40000007 => 'iTunes U|Business & Economics|Personal Finance', 5594 40000008 => 'iTunes U|Business & Economics|Real Estate', 5595 40000009 => 'iTunes U|Engineering', 5596 40000010 => 'iTunes U|Engineering|Chemical & Petroleum Engineering', 5597 40000011 => 'iTunes U|Engineering|Civil Engineering', 5598 40000012 => 'iTunes U|Engineering|Computer Science', 5599 40000013 => 'iTunes U|Engineering|Electrical Engineering', 5600 40000014 => 'iTunes U|Engineering|Environmental Engineering', 5601 40000015 => 'iTunes U|Engineering|Mechanical Engineering', 5602 40000016 => 'iTunes U|Music, Art, & Design', 5603 40000017 => 'iTunes U|Music, Art, & Design|Architecture', 5604 40000019 => 'iTunes U|Music, Art, & Design|Art History', 5605 40000020 => 'iTunes U|Music, Art, & Design|Dance', 5606 40000021 => 'iTunes U|Music, Art, & Design|Film', 5607 40000022 => 'iTunes U|Music, Art, & Design|Design', 5608 40000023 => 'iTunes U|Music, Art, & Design|Interior Design', 5609 40000024 => 'iTunes U|Music, Art, & Design|Music', 5610 40000025 => 'iTunes U|Music, Art, & Design|Theater', 5611 40000026 => 'iTunes U|Health & Medicine', 5612 40000027 => 'iTunes U|Health & Medicine|Anatomy & Physiology', 5613 40000028 => 'iTunes U|Health & Medicine|Behavioral Science', 5614 40000029 => 'iTunes U|Health & Medicine|Dentistry', 5615 40000030 => 'iTunes U|Health & Medicine|Diet & Nutrition', 5616 40000031 => 'iTunes U|Health & Medicine|Emergency Medicine', 5617 40000032 => 'iTunes U|Health & Medicine|Genetics', 5618 40000033 => 'iTunes U|Health & Medicine|Gerontology', 5619 40000034 => 'iTunes U|Health & Medicine|Health & Exercise Science', 5620 40000035 => 'iTunes U|Health & Medicine|Immunology', 5621 40000036 => 'iTunes U|Health & Medicine|Neuroscience', 5622 40000037 => 'iTunes U|Health & Medicine|Pharmacology & Toxicology', 5623 40000038 => 'iTunes U|Health & Medicine|Psychiatry', 5624 40000039 => 'iTunes U|Health & Medicine|Global Health', 5625 40000040 => 'iTunes U|Health & Medicine|Radiology', 5626 40000041 => 'iTunes U|History', 5627 40000042 => 'iTunes U|History|Ancient History', 5628 40000043 => 'iTunes U|History|Medieval History', 5629 40000044 => 'iTunes U|History|Military History', 5630 40000045 => 'iTunes U|History|Modern History', 5631 40000046 => 'iTunes U|History|African History', 5632 40000047 => 'iTunes U|History|Asia-Pacific History', 5633 40000048 => 'iTunes U|History|European History', 5634 40000049 => 'iTunes U|History|Middle Eastern History', 5635 40000050 => 'iTunes U|History|North American History', 5636 40000051 => 'iTunes U|History|South American History', 5637 40000053 => 'iTunes U|Communications & Journalism', 5638 40000054 => 'iTunes U|Philosophy', 5639 40000055 => 'iTunes U|Religion & Spirituality', 5640 40000056 => 'iTunes U|Languages', 5641 40000057 => 'iTunes U|Languages|African Languages', 5642 40000058 => 'iTunes U|Languages|Ancient Languages', 5643 40000061 => 'iTunes U|Languages|English', 5644 40000063 => 'iTunes U|Languages|French', 5645 40000064 => 'iTunes U|Languages|German', 5646 40000065 => 'iTunes U|Languages|Italian', 5647 40000066 => 'iTunes U|Languages|Linguistics', 5648 40000068 => 'iTunes U|Languages|Spanish', 5649 40000069 => 'iTunes U|Languages|Speech Pathology', 5650 40000070 => 'iTunes U|Writing & Literature', 5651 40000071 => 'iTunes U|Writing & Literature|Anthologies', 5652 40000072 => 'iTunes U|Writing & Literature|Biography', 5653 40000073 => 'iTunes U|Writing & Literature|Classics', 5654 40000074 => 'iTunes U|Writing & Literature|Literary Criticism', 5655 40000075 => 'iTunes U|Writing & Literature|Fiction', 5656 40000076 => 'iTunes U|Writing & Literature|Poetry', 5657 40000077 => 'iTunes U|Mathematics', 5658 40000078 => 'iTunes U|Mathematics|Advanced Mathematics', 5659 40000079 => 'iTunes U|Mathematics|Algebra', 5660 40000080 => 'iTunes U|Mathematics|Arithmetic', 5661 40000081 => 'iTunes U|Mathematics|Calculus', 5662 40000082 => 'iTunes U|Mathematics|Geometry', 5663 40000083 => 'iTunes U|Mathematics|Statistics', 5664 40000084 => 'iTunes U|Science', 5665 40000085 => 'iTunes U|Science|Agricultural', 5666 40000086 => 'iTunes U|Science|Astronomy', 5667 40000087 => 'iTunes U|Science|Atmosphere', 5668 40000088 => 'iTunes U|Science|Biology', 5669 40000089 => 'iTunes U|Science|Chemistry', 5670 40000090 => 'iTunes U|Science|Ecology', 5671 40000091 => 'iTunes U|Science|Geography', 5672 40000092 => 'iTunes U|Science|Geology', 5673 40000093 => 'iTunes U|Science|Physics', 5674 40000094 => 'iTunes U|Social Science', 5675 40000095 => 'iTunes U|Law & Politics|Law', 5676 40000096 => 'iTunes U|Law & Politics|Political Science', 5677 40000097 => 'iTunes U|Law & Politics|Public Administration', 5678 40000098 => 'iTunes U|Social Science|Psychology', 5679 40000099 => 'iTunes U|Social Science|Social Welfare', 5680 40000100 => 'iTunes U|Social Science|Sociology', 5681 40000101 => 'iTunes U|Society', 5682 40000103 => 'iTunes U|Society|Asia Pacific Studies', 5683 40000104 => 'iTunes U|Society|European Studies', 5684 40000105 => 'iTunes U|Society|Indigenous Studies', 5685 40000106 => 'iTunes U|Society|Latin & Caribbean Studies', 5686 40000107 => 'iTunes U|Society|Middle Eastern Studies', 5687 40000108 => "iTunes U|Society|Women's Studies", 5688 40000109 => 'iTunes U|Teaching & Learning', 5689 40000110 => 'iTunes U|Teaching & Learning|Curriculum & Teaching', 5690 40000111 => 'iTunes U|Teaching & Learning|Educational Leadership', 5691 40000112 => 'iTunes U|Teaching & Learning|Family & Childcare', 5692 40000113 => 'iTunes U|Teaching & Learning|Learning Resources', 5693 40000114 => 'iTunes U|Teaching & Learning|Psychology & Research', 5694 40000115 => 'iTunes U|Teaching & Learning|Special Education', 5695 40000116 => 'iTunes U|Music, Art, & Design|Culinary Arts', 5696 40000117 => 'iTunes U|Music, Art, & Design|Fashion', 5697 40000118 => 'iTunes U|Music, Art, & Design|Media Arts', 5698 40000119 => 'iTunes U|Music, Art, & Design|Photography', 5699 40000120 => 'iTunes U|Music, Art, & Design|Visual Art', 5700 40000121 => 'iTunes U|Business & Economics|Entrepreneurship', 5701 40000122 => 'iTunes U|Communications & Journalism|Broadcasting', 5702 40000123 => 'iTunes U|Communications & Journalism|Digital Media', 5703 40000124 => 'iTunes U|Communications & Journalism|Journalism', 5704 40000125 => 'iTunes U|Communications & Journalism|Photojournalism', 5705 40000126 => 'iTunes U|Communications & Journalism|Print', 5706 40000127 => 'iTunes U|Communications & Journalism|Speech', 5707 40000128 => 'iTunes U|Communications & Journalism|Writing', 5708 40000129 => 'iTunes U|Health & Medicine|Nursing', 5709 40000130 => 'iTunes U|Languages|Arabic', 5710 40000131 => 'iTunes U|Languages|Chinese', 5711 40000132 => 'iTunes U|Languages|Hebrew', 5712 40000133 => 'iTunes U|Languages|Hindi', 5713 40000134 => 'iTunes U|Languages|Indigenous Languages', 5714 40000135 => 'iTunes U|Languages|Japanese', 5715 40000136 => 'iTunes U|Languages|Korean', 5716 40000137 => 'iTunes U|Languages|Other Languages', 5717 40000138 => 'iTunes U|Languages|Portuguese', 5718 40000139 => 'iTunes U|Languages|Russian', 5719 40000140 => 'iTunes U|Law & Politics', 5720 40000141 => 'iTunes U|Law & Politics|Foreign Policy & International Relations', 5721 40000142 => 'iTunes U|Law & Politics|Local Governments', 5722 40000143 => 'iTunes U|Law & Politics|National Governments', 5723 40000144 => 'iTunes U|Law & Politics|World Affairs', 5724 40000145 => 'iTunes U|Writing & Literature|Comparative Literature', 5725 40000146 => 'iTunes U|Philosophy|Aesthetics', 5726 40000147 => 'iTunes U|Philosophy|Epistemology', 5727 40000148 => 'iTunes U|Philosophy|Ethics', 5728 40000149 => 'iTunes U|Philosophy|Metaphysics', 5729 40000150 => 'iTunes U|Philosophy|Political Philosophy', 5730 40000151 => 'iTunes U|Philosophy|Logic', 5731 40000152 => 'iTunes U|Philosophy|Philosophy of Language', 5732 40000153 => 'iTunes U|Philosophy|Philosophy of Religion', 5733 40000154 => 'iTunes U|Social Science|Archaeology', 5734 40000155 => 'iTunes U|Social Science|Anthropology', 5735 40000156 => 'iTunes U|Religion & Spirituality|Buddhism', 5736 40000157 => 'iTunes U|Religion & Spirituality|Christianity', 5737 40000158 => 'iTunes U|Religion & Spirituality|Comparative Religion', 5738 40000159 => 'iTunes U|Religion & Spirituality|Hinduism', 5739 40000160 => 'iTunes U|Religion & Spirituality|Islam', 5740 40000161 => 'iTunes U|Religion & Spirituality|Judaism', 5741 40000162 => 'iTunes U|Religion & Spirituality|Other Religions', 5742 40000163 => 'iTunes U|Religion & Spirituality|Spirituality', 5743 40000164 => 'iTunes U|Science|Environment', 5744 40000165 => 'iTunes U|Society|African Studies', 5745 40000166 => 'iTunes U|Society|American Studies', 5746 40000167 => 'iTunes U|Society|Cross-cultural Studies', 5747 40000168 => 'iTunes U|Society|Immigration & Emigration', 5748 40000169 => 'iTunes U|Society|Race & Ethnicity Studies', 5749 40000170 => 'iTunes U|Society|Sexuality Studies', 5750 40000171 => 'iTunes U|Teaching & Learning|Educational Technology', 5751 40000172 => 'iTunes U|Teaching & Learning|Information/Library Science', 5752 40000173 => 'iTunes U|Languages|Dutch', 5753 40000174 => 'iTunes U|Languages|Luxembourgish', 5754 40000175 => 'iTunes U|Languages|Swedish', 5755 40000176 => 'iTunes U|Languages|Norwegian', 5756 40000177 => 'iTunes U|Languages|Finnish', 5757 40000178 => 'iTunes U|Languages|Danish', 5758 40000179 => 'iTunes U|Languages|Polish', 5759 40000180 => 'iTunes U|Languages|Turkish', 5760 40000181 => 'iTunes U|Languages|Flemish', 5761 50000024 => 'Audiobooks', 5762 50000040 => 'Audiobooks|Fiction', 5763 50000041 => 'Audiobooks|Arts & Entertainment', 5764 50000042 => 'Audiobooks|Biographies & Memoirs', 5765 50000043 => 'Audiobooks|Business & Personal Finance', 5766 50000044 => 'Audiobooks|Kids & Young Adults', 5767 50000045 => 'Audiobooks|Classics', 5768 50000046 => 'Audiobooks|Comedy', 5769 50000047 => 'Audiobooks|Drama & Poetry', 5770 50000048 => 'Audiobooks|Speakers & Storytellers', 5771 50000049 => 'Audiobooks|History', 5772 50000050 => 'Audiobooks|Languages', 5773 50000051 => 'Audiobooks|Mysteries & Thrillers', 5774 50000052 => 'Audiobooks|Nonfiction', 5775 50000053 => 'Audiobooks|Religion & Spirituality', 5776 50000054 => 'Audiobooks|Science & Nature', 5777 50000055 => 'Audiobooks|Sci Fi & Fantasy', 5778 50000056 => 'Audiobooks|Self-Development', 5779 50000057 => 'Audiobooks|Sports & Outdoors', 5780 50000058 => 'Audiobooks|Technology', 5781 50000059 => 'Audiobooks|Travel & Adventure', 5782 50000061 => 'Music|Spoken Word', 5783 50000063 => 'Music|Disney', 5784 50000064 => 'Music|French Pop', 5785 50000066 => 'Music|German Pop', 5786 50000068 => 'Music|German Folk', 5787 50000069 => 'Audiobooks|Romance', 5788 50000070 => 'Audiobooks|Audiobooks Latino', 5789 50000071 => 'Books|Comics & Graphic Novels|Manga|Action', 5790 50000072 => 'Books|Comics & Graphic Novels|Manga|Comedy', 5791 50000073 => 'Books|Comics & Graphic Novels|Manga|Erotica', 5792 50000074 => 'Books|Comics & Graphic Novels|Manga|Fantasy', 5793 50000075 => 'Books|Comics & Graphic Novels|Manga|Four Cell Manga', 5794 50000076 => 'Books|Comics & Graphic Novels|Manga|Gay & Lesbian', 5795 50000077 => 'Books|Comics & Graphic Novels|Manga|Hard-Boiled', 5796 50000078 => 'Books|Comics & Graphic Novels|Manga|Heroes', 5797 50000079 => 'Books|Comics & Graphic Novels|Manga|Historical Fiction', 5798 50000080 => 'Books|Comics & Graphic Novels|Manga|Mecha', 5799 50000081 => 'Books|Comics & Graphic Novels|Manga|Mystery', 5800 50000082 => 'Books|Comics & Graphic Novels|Manga|Nonfiction', 5801 50000083 => 'Books|Comics & Graphic Novels|Manga|Religious', 5802 50000084 => 'Books|Comics & Graphic Novels|Manga|Romance', 5803 50000085 => 'Books|Comics & Graphic Novels|Manga|Romantic Comedy', 5804 50000086 => 'Books|Comics & Graphic Novels|Manga|Science Fiction', 5805 50000087 => 'Books|Comics & Graphic Novels|Manga|Sports', 5806 50000088 => 'Books|Fiction & Literature|Light Novels', 5807 50000089 => 'Books|Comics & Graphic Novels|Manga|Horror', 5808 50000090 => 'Books|Comics & Graphic Novels|Comics', 5809 50000091 => 'Books|Romance|Multicultural', 5810 50000092 => 'Audiobooks|Erotica', 5811 50000093 => 'Audiobooks|Light Novels', 5812 }, 5813 }, 5814 grup => { Name => 'Grouping', Avoid => 1 }, #10 5815 hdvd => { #10 5816 Name => 'HDVideo', 5817 Format => 'int8u', #24 5818 Writable => 'int8s', #27 5819 PrintConv => { 0 => 'No', 1 => 'Yes' }, 5820 }, 5821 keyw => 'Keyword', #7 5822 ldes => 'LongDescription', #10 5823 pcst => { #7 5824 Name => 'Podcast', 5825 Format => 'int8u', #23 5826 Writable => 'int8s', #27 5827 PrintConv => { 0 => 'No', 1 => 'Yes' }, 5828 }, 5829 perf => 'Performer', 5830 plID => { #10 (or TV season) 5831 Name => 'PlayListID', 5832 Format => 'int8u', # actually int64u, but split it up 5833 Writable => 'int32s', #27 5834 }, 5835 purd => 'PurchaseDate', #7 5836 purl => 'PodcastURL', #7 5837 rtng => { #10 5838 Name => 'Rating', 5839 Format => 'int8u', #23 5840 Writable => 'int8s', #27 5841 PrintConv => { 5842 0 => 'none', 5843 1 => 'Explicit', 5844 2 => 'Clean', 5845 4 => 'Explicit (old)', 5846 }, 5847 }, 5848 sfID => { #10 5849 Name => 'AppleStoreCountry', 5850 Format => 'int32u', 5851 Writable => 'int32s', #27 5852 SeparateTable => 1, 5853 PrintConv => { #21 5854 143441 => 'United States', # US 5855 143442 => 'France', # FR 5856 143443 => 'Germany', # DE 5857 143444 => 'United Kingdom', # GB 5858 143445 => 'Austria', # AT 5859 143446 => 'Belgium', # BE 5860 143447 => 'Finland', # FI 5861 143448 => 'Greece', # GR 5862 143449 => 'Ireland', # IE 5863 143450 => 'Italy', # IT 5864 143451 => 'Luxembourg', # LU 5865 143452 => 'Netherlands', # NL 5866 143453 => 'Portugal', # PT 5867 143454 => 'Spain', # ES 5868 143455 => 'Canada', # CA 5869 143456 => 'Sweden', # SE 5870 143457 => 'Norway', # NO 5871 143458 => 'Denmark', # DK 5872 143459 => 'Switzerland', # CH 5873 143460 => 'Australia', # AU 5874 143461 => 'New Zealand', # NZ 5875 143462 => 'Japan', # JP 5876 143463 => 'Hong Kong', # HK 5877 143464 => 'Singapore', # SG 5878 143465 => 'China', # CN 5879 143466 => 'Republic of Korea', # KR 5880 143467 => 'India', # IN 5881 143468 => 'Mexico', # MX 5882 143469 => 'Russia', # RU 5883 143470 => 'Taiwan', # TW 5884 143471 => 'Vietnam', # VN 5885 143472 => 'South Africa', # ZA 5886 143473 => 'Malaysia', # MY 5887 143474 => 'Philippines', # PH 5888 143475 => 'Thailand', # TH 5889 143476 => 'Indonesia', # ID 5890 143477 => 'Pakistan', # PK 5891 143478 => 'Poland', # PL 5892 143479 => 'Saudi Arabia', # SA 5893 143480 => 'Turkey', # TR 5894 143481 => 'United Arab Emirates', # AE 5895 143482 => 'Hungary', # HU 5896 143483 => 'Chile', # CL 5897 143484 => 'Nepal', # NP 5898 143485 => 'Panama', # PA 5899 143486 => 'Sri Lanka', # LK 5900 143487 => 'Romania', # RO 5901 143489 => 'Czech Republic', # CZ 5902 143491 => 'Israel', # IL 5903 143492 => 'Ukraine', # UA 5904 143493 => 'Kuwait', # KW 5905 143494 => 'Croatia', # HR 5906 143495 => 'Costa Rica', # CR 5907 143496 => 'Slovakia', # SK 5908 143497 => 'Lebanon', # LB 5909 143498 => 'Qatar', # QA 5910 143499 => 'Slovenia', # SI 5911 143501 => 'Colombia', # CO 5912 143502 => 'Venezuela', # VE 5913 143503 => 'Brazil', # BR 5914 143504 => 'Guatemala', # GT 5915 143505 => 'Argentina', # AR 5916 143506 => 'El Salvador', # SV 5917 143507 => 'Peru', # PE 5918 143508 => 'Dominican Republic', # DO 5919 143509 => 'Ecuador', # EC 5920 143510 => 'Honduras', # HN 5921 143511 => 'Jamaica', # JM 5922 143512 => 'Nicaragua', # NI 5923 143513 => 'Paraguay', # PY 5924 143514 => 'Uruguay', # UY 5925 143515 => 'Macau', # MO 5926 143516 => 'Egypt', # EG 5927 143517 => 'Kazakhstan', # KZ 5928 143518 => 'Estonia', # EE 5929 143519 => 'Latvia', # LV 5930 143520 => 'Lithuania', # LT 5931 143521 => 'Malta', # MT 5932 143523 => 'Moldova', # MD 5933 143524 => 'Armenia', # AM 5934 143525 => 'Botswana', # BW 5935 143526 => 'Bulgaria', # BG 5936 143528 => 'Jordan', # JO 5937 143529 => 'Kenya', # KE 5938 143530 => 'Macedonia', # MK 5939 143531 => 'Madagascar', # MG 5940 143532 => 'Mali', # ML 5941 143533 => 'Mauritius', # MU 5942 143534 => 'Niger', # NE 5943 143535 => 'Senegal', # SN 5944 143536 => 'Tunisia', # TN 5945 143537 => 'Uganda', # UG 5946 143538 => 'Anguilla', # AI 5947 143539 => 'Bahamas', # BS 5948 143540 => 'Antigua and Barbuda', # AG 5949 143541 => 'Barbados', # BB 5950 143542 => 'Bermuda', # BM 5951 143543 => 'British Virgin Islands', # VG 5952 143544 => 'Cayman Islands', # KY 5953 143545 => 'Dominica', # DM 5954 143546 => 'Grenada', # GD 5955 143547 => 'Montserrat', # MS 5956 143548 => 'St. Kitts and Nevis', # KN 5957 143549 => 'St. Lucia', # LC 5958 143550 => 'St. Vincent and The Grenadines', # VC 5959 143551 => 'Trinidad and Tobago', # TT 5960 143552 => 'Turks and Caicos', # TC 5961 143553 => 'Guyana', # GY 5962 143554 => 'Suriname', # SR 5963 143555 => 'Belize', # BZ 5964 143556 => 'Bolivia', # BO 5965 143557 => 'Cyprus', # CY 5966 143558 => 'Iceland', # IS 5967 143559 => 'Bahrain', # BH 5968 143560 => 'Brunei Darussalam', # BN 5969 143561 => 'Nigeria', # NG 5970 143562 => 'Oman', # OM 5971 143563 => 'Algeria', # DZ 5972 143564 => 'Angola', # AO 5973 143565 => 'Belarus', # BY 5974 143566 => 'Uzbekistan', # UZ 5975 143568 => 'Azerbaijan', # AZ 5976 143571 => 'Yemen', # YE 5977 143572 => 'Tanzania', # TZ 5978 143573 => 'Ghana', # GH 5979 143575 => 'Albania', # AL 5980 143576 => 'Benin', # BJ 5981 143577 => 'Bhutan', # BT 5982 143578 => 'Burkina Faso', # BF 5983 143579 => 'Cambodia', # KH 5984 143580 => 'Cape Verde', # CV 5985 143581 => 'Chad', # TD 5986 143582 => 'Republic of the Congo', # CG 5987 143583 => 'Fiji', # FJ 5988 143584 => 'Gambia', # GM 5989 143585 => 'Guinea-Bissau', # GW 5990 143586 => 'Kyrgyzstan', # KG 5991 143587 => "Lao People's Democratic Republic", # LA 5992 143588 => 'Liberia', # LR 5993 143589 => 'Malawi', # MW 5994 143590 => 'Mauritania', # MR 5995 143591 => 'Federated States of Micronesia', # FM 5996 143592 => 'Mongolia', # MN 5997 143593 => 'Mozambique', # MZ 5998 143594 => 'Namibia', # NA 5999 143595 => 'Palau', # PW 6000 143597 => 'Papua New Guinea', # PG 6001 143598 => 'Sao Tome and Principe', # ST (São Tomé and Príncipe) 6002 143599 => 'Seychelles', # SC 6003 143600 => 'Sierra Leone', # SL 6004 143601 => 'Solomon Islands', # SB 6005 143602 => 'Swaziland', # SZ 6006 143603 => 'Tajikistan', # TJ 6007 143604 => 'Turkmenistan', # TM 6008 143605 => 'Zimbabwe', # ZW 6009 }, 6010 }, 6011 soaa => 'SortAlbumArtist', #10 6012 soal => 'SortAlbum', #10 6013 soar => 'SortArtist', #10 6014 soco => 'SortComposer', #10 6015 sonm => 'SortName', #10 6016 sosn => 'SortShow', #10 6017 stik => { #10 6018 Name => 'MediaType', 6019 Format => 'int8u', #23 6020 Writable => 'int8s', #27 6021 PrintConvColumns => 2, 6022 PrintConv => { #(http://weblog.xanga.com/gryphondwb/615474010/iphone-ringtones---what-did-itunes-741-really-do.html) 6023 0 => 'Movie (old)', #forum9059 (was Movie) 6024 1 => 'Normal (Music)', 6025 2 => 'Audiobook', 6026 5 => 'Whacked Bookmark', 6027 6 => 'Music Video', 6028 9 => 'Movie', #forum9059 (was Short Film) 6029 10 => 'TV Show', 6030 11 => 'Booklet', 6031 14 => 'Ringtone', 6032 21 => 'Podcast', #15 6033 23 => 'iTunes U', #forum9059 6034 }, 6035 }, 6036 rate => 'RatingPercent', #PH 6037 titl => { Name => 'Title', Avoid => 1 }, 6038 tven => 'TVEpisodeID', #7 6039 tves => { #7/10 6040 Name => 'TVEpisode', 6041 Format => 'int32u', 6042 Writable => 'int32s', #27 6043 }, 6044 tvnn => 'TVNetworkName', #7 6045 tvsh => 'TVShow', #10 6046 tvsn => { #7/10 6047 Name => 'TVSeason', 6048 Format => 'int32u', 6049 }, 6050 yrrc => 'Year', #(ffmpeg source) 6051 itnu => { #PH (iTunes 10.5) 6052 Name => 'iTunesU', 6053 Format => 'int8u', #27 6054 Writable => 'int8s', #27 6055 Description => 'iTunes U', 6056 PrintConv => { 0 => 'No', 1 => 'Yes' }, 6057 }, 6058 #https://github.com/communitymedia/mediautilities/blob/master/src/net/sourceforge/jaad/mp4/boxes/BoxTypes.java 6059 gshh => { Name => 'GoogleHostHeader', Format => 'string' }, 6060 gspm => { Name => 'GooglePingMessage', Format => 'string' }, 6061 gspu => { Name => 'GooglePingURL', Format => 'string' }, 6062 gssd => { Name => 'GoogleSourceData', Format => 'string' }, 6063 gsst => { Name => 'GoogleStartTime', Format => 'string' }, 6064 gstd => { 6065 Name => 'GoogleTrackDuration', 6066 Format => 'string', 6067 ValueConv => '$val / 1000', 6068 ValueConvInv => '$val * 1000', 6069 PrintConv => 'ConvertDuration($val)', 6070 PrintConvInv => q{ 6071 $val =~ s/ s$//; 6072 my @a = split /(:| days )/, $val; 6073 my $sign = ($val =~ s/^-//) ? -1 : 1; 6074 $a[0] += shift(@a) * 24 if @a == 4; 6075 $a[0] += shift(@a) * 60 while @a > 1; 6076 return $a[0] * $sign; 6077 }, 6078 }, 6079 6080 # atoms observed in AAX audiobooks (ref PH) 6081 "\xa9cpy" => { Name => 'Copyright', Avoid => 1, Groups => { 2 => 'Author' } }, 6082 "\xa9pub" => 'Publisher', 6083 "\xa9nrt" => 'Narrator', 6084 '@pti' => 'ParentTitle', # (guess -- same as "\xa9nam") 6085 '@PST' => 'ParentShortTitle', # (guess -- same as "\xa9nam") 6086 '@ppi' => 'ParentProductID', # (guess -- same as 'prID') 6087 '@sti' => 'ShortTitle', # (guess -- same as "\xa9nam") 6088 prID => 'ProductID', 6089 rldt => { Name => 'ReleaseDate', Groups => { 2 => 'Time' }}, 6090 CDEK => { Name => 'Unknown_CDEK', Unknown => 1 }, # eg: "B004ZMTFEG" - used in URL's ("asin=") 6091 CDET => { Name => 'Unknown_CDET', Unknown => 1 }, # eg: "ADBL" 6092 VERS => 'ProductVersion', 6093 GUID => 'GUID', 6094 AACR => { Name => 'Unknown_AACR', Unknown => 1 }, # eg: "CR!1T1H1QH6WX7T714G2BMFX3E9MC4S" 6095 # ausr - 30 bytes (User Alias?) 6096 "\xa9xyz" => { #PH (written by Google Photos) 6097 Name => 'GPSCoordinates', 6098 Groups => { 2 => 'Location' }, 6099 ValueConv => \&ConvertISO6709, 6100 ValueConvInv => \&ConvInvISO6709, 6101 PrintConv => \&PrintGPSCoordinates, 6102 PrintConvInv => \&PrintInvGPSCoordinates, 6103 }, 6104 # the following tags written by iTunes 12.5.1.21 6105 # (ref https://www.ventismedia.com/mantis/view.php?id=14963 6106 # https://community.mp3tag.de/t/x-mp4-new-tag-problems/19488) 6107 "\xa9wrk" => 'Work', #PH 6108 "\xa9mvn" => 'MovementName', #PH 6109 "\xa9mvi" => { #PH 6110 Name => 'MovementNumber', 6111 Format => 'int16u', #27 6112 Writable => 'int16s', #27 6113 }, 6114 "\xa9mvc" => { #PH 6115 Name => 'MovementCount', 6116 Format => 'int16u', #27 6117 Writable => 'int16s', #27 6118 }, 6119 shwm => { #PH 6120 Name => 'ShowMovement', 6121 Format => 'int8u', #27 6122 Writable => 'int8s', #27 6123 PrintConv => { 0 => 'No', 1 => 'Yes' }, 6124 }, 6125); 6126 6127# tag decoded from timed face records 6128%Image::ExifTool::QuickTime::FaceInfo = ( 6129 PROCESS_PROC => \&ProcessMOV, 6130 GROUPS => { 2 => 'Video' }, 6131 crec => { 6132 Name => 'FaceRec', 6133 SubDirectory => { 6134 TagTable => 'Image::ExifTool::QuickTime::FaceRec', 6135 }, 6136 }, 6137); 6138 6139# tag decoded from timed face records 6140%Image::ExifTool::QuickTime::FaceRec = ( 6141 PROCESS_PROC => \&ProcessMOV, 6142 GROUPS => { 2 => 'Video' }, 6143 cits => { 6144 Name => 'FaceItem', 6145 SubDirectory => { 6146 TagTable => 'Image::ExifTool::QuickTime::Keys', 6147 ProcessProc => \&Process_mebx, 6148 }, 6149 }, 6150); 6151 6152# item list keys (ref PH) 6153%Image::ExifTool::QuickTime::Keys = ( 6154 PROCESS_PROC => \&ProcessKeys, 6155 WRITE_PROC => \&WriteKeys, 6156 CHECK_PROC => \&CheckQTValue, 6157 VARS => { LONG_TAGS => 3 }, 6158 WRITABLE => 1, 6159 # (not PREFERRED when writing) 6160 GROUPS => { 1 => 'Keys' }, 6161 WRITE_GROUP => 'Keys', 6162 LANG_INFO => \&GetLangInfo, 6163 FORMAT => 'string', 6164 NOTES => q{ 6165 This directory contains a list of key names which are used to decode tags 6166 written by the "mdta" handler. Also in this table are a few tags found in 6167 timed metadata that are not yet writable by ExifTool. The prefix of 6168 "com.apple.quicktime." has been removed from the TagID's below. These tags 6169 support alternate languages in the same way as the 6170 L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags. Note 6171 that by default, 6172 L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> and 6173 L<UserData|Image::ExifTool::TagNames/QuickTime UserData Tags> tags are 6174 preferred when writing, so to create a tag when a same-named tag exists in 6175 either of these tables, either the "Keys" location must be specified (eg. 6176 C<-Keys:Author=Phil> on the command line), or the PREFERRED level must be 6177 changed via L<the config file|../config.html#PREF>. 6178 }, 6179 version => 'Version', 6180 album => 'Album', 6181 artist => { }, 6182 artwork => { }, 6183 author => { Name => 'Author', Groups => { 2 => 'Author' } }, 6184 comment => { }, 6185 copyright => { Name => 'Copyright', Groups => { 2 => 'Author' } }, 6186 creationdate=> { 6187 Name => 'CreationDate', 6188 Groups => { 2 => 'Time' }, 6189 Shift => 'Time', 6190 ValueConv => q{ 6191 require Image::ExifTool::XMP; 6192 $val = Image::ExifTool::XMP::ConvertXMPDate($val,1); 6193 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 6194 return $val; 6195 }, 6196 ValueConvInv => q{ 6197 require Image::ExifTool::XMP; 6198 $val = Image::ExifTool::XMP::FormatXMPDate($val); 6199 $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon 6200 return $val; 6201 }, 6202 PrintConv => '$self->ConvertDateTime($val)', 6203 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 6204 }, 6205 description => { }, 6206 director => { }, 6207 displayname => { Name => 'DisplayName' }, 6208 title => { }, #22 6209 genre => { }, 6210 information => { }, 6211 keywords => { }, 6212 producer => { }, #22 6213 make => { Name => 'Make', Groups => { 2 => 'Camera' } }, 6214 model => { Name => 'Model', Groups => { 2 => 'Camera' } }, 6215 publisher => { }, 6216 software => { }, 6217 year => { Groups => { 2 => 'Time' } }, 6218 'camera.identifier' => 'CameraIdentifier', # (iPhone 4) 6219 'camera.framereadouttimeinmicroseconds' => { # (iPhone 4) 6220 Name => 'FrameReadoutTime', 6221 ValueConv => '$val * 1e-6', 6222 ValueConvInv => 'int($val * 1e6 + 0.5)', 6223 PrintConv => '$val * 1e6 . " microseconds"', 6224 PrintConvInv => '$val =~ s/ .*//; $val * 1e-6', 6225 }, 6226 'location.ISO6709' => { 6227 Name => 'GPSCoordinates', 6228 Groups => { 2 => 'Location' }, 6229 ValueConv => \&ConvertISO6709, 6230 ValueConvInv => \&ConvInvISO6709, 6231 PrintConv => \&PrintGPSCoordinates, 6232 PrintConvInv => \&PrintInvGPSCoordinates, 6233 }, 6234 'location.name' => { Name => 'LocationName', Groups => { 2 => 'Location' } }, 6235 'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } }, 6236 'location.note' => { Name => 'LocationNote', Groups => { 2 => 'Location' } }, 6237 'location.role' => { 6238 Name => 'LocationRole', 6239 Groups => { 2 => 'Location' }, 6240 PrintConv => { 6241 0 => 'Shooting Location', 6242 1 => 'Real Location', 6243 2 => 'Fictional Location', 6244 }, 6245 }, 6246 'location.date' => { 6247 Name => 'LocationDate', 6248 Groups => { 2 => 'Time' }, 6249 Shift => 'Time', 6250 ValueConv => q{ 6251 require Image::ExifTool::XMP; 6252 $val = Image::ExifTool::XMP::ConvertXMPDate($val); 6253 $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary 6254 return $val; 6255 }, 6256 ValueConvInv => q{ 6257 require Image::ExifTool::XMP; 6258 $val = Image::ExifTool::XMP::FormatXMPDate($val); 6259 $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon 6260 return $val; 6261 }, 6262 PrintConv => '$self->ConvertDateTime($val)', 6263 PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) 6264 }, 6265 'direction.facing' => { Name => 'CameraDirection', Groups => { 2 => 'Location' } }, 6266 'direction.motion' => { Name => 'CameraMotion', Groups => { 2 => 'Location' } }, 6267 'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } }, 6268 'player.version' => 'PlayerVersion', 6269 'player.movie.visual.brightness'=> 'Brightness', 6270 'player.movie.visual.color' => 'Color', 6271 'player.movie.visual.tint' => 'Tint', 6272 'player.movie.visual.contrast' => 'Contrast', 6273 'player.movie.audio.gain' => 'AudioGain', 6274 'player.movie.audio.treble' => 'Trebel', 6275 'player.movie.audio.bass' => 'Bass', 6276 'player.movie.audio.balance' => 'Balance', 6277 'player.movie.audio.pitchshift' => 'PitchShift', 6278 'player.movie.audio.mute' => { 6279 Name => 'Mute', 6280 Format => 'int8u', 6281 PrintConv => { 0 => 'Off', 1 => 'On' }, 6282 }, 6283 'rating.user' => 'UserRating', # (Canon ELPH 510 HS) 6284 'collection.user' => 'UserCollection', #22 6285 'Encoded_With' => 'EncodedWith', 6286# 6287# the following tags aren't in the com.apple.quicktime namespace: 6288# 6289 'com.apple.photos.captureMode' => 'CaptureMode', 6290 'com.android.version' => 'AndroidVersion', 6291# 6292# also seen 6293# 6294 # com.divergentmedia.clipwrap.model ('NEX-FS700EK') 6295 # com.divergentmedia.clipwrap.model1 ('49') 6296 # com.divergentmedia.clipwrap.model2 ('0') 6297 # com.divergentmedia.clipwrap.manufacturer ('Sony') 6298 # com.divergentmedia.clipwrap.originalDateTime ('2013/2/6 10:30:40+0200') 6299# 6300# seen in timed metadata (mebx), and added dynamically to the table 6301# via SaveMetaKeys(). NOTE: these tags are not writable! 6302# 6303 # (mdta)com.apple.quicktime.video-orientation (dtyp=66, int16s) 6304 'video-orientation' => { Name => 'VideoOrientation', Writable => 0 }, 6305 # (mdta)com.apple.quicktime.live-photo-info (dtyp=com.apple.quicktime.com.apple.quicktime.live-photo-info) 6306 'live-photo-info' => { 6307 Name => 'LivePhotoInfo', 6308 Writable => 0, 6309 # not sure what these values mean, but unpack them anyway - PH 6310 # (ignore the fact that the "f" and "l" unpacks won't work on a big-endian machine) 6311 ValueConv => 'join " ",unpack "VfVVf6c4lCCcclf4Vvv", $val', 6312 }, 6313 # (mdta)com.apple.quicktime.still-image-time (dtyp=65, int8s) 6314 'still-image-time' => { # (found in live photo) 6315 Name => 'StillImageTime', 6316 Writable => 0, 6317 Notes => q{ 6318 this tag always has a value of -1; the time of the still image is obtained 6319 from the associated SampleTime 6320 }, 6321 }, 6322 # (mdta)com.apple.quicktime.detected-face (dtyp='com.apple.quicktime.detected-face') 6323 'detected-face' => { 6324 Name => 'FaceInfo', 6325 Writable => 0, 6326 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FaceInfo' }, 6327 }, 6328 # ---- detected-face fields ( ---- 6329 # --> back here after a round trip through FaceInfo -> FaceRec -> FaceItem 6330 # (fiel)com.apple.quicktime.detected-face.bounds (dtyp=80, float[8]) 6331 'detected-face.bounds' => { 6332 Name => 'DetectedFaceBounds', 6333 Writable => 0, 6334 # round to a reasonable number of decimal places 6335 PrintConv => 'my @a=split " ",$val;$_=int($_*1e6+.5)/1e6 foreach @a;join " ",@a', 6336 PrintConvInv => '$val', 6337 }, 6338 # (fiel)com.apple.quicktime.detected-face.face-id (dtyp=77, int32u) 6339 'detected-face.face-id' => { Name => 'DetectedFaceID', Writable => 0 }, 6340 # (fiel)com.apple.quicktime.detected-face.roll-angle (dtyp=23, float) 6341 'detected-face.roll-angle' => { Name => 'DetectedFaceRollAngle', Writable => 0 }, 6342 # (fiel)com.apple.quicktime.detected-face.yaw-angle (dtyp=23, float) 6343 'detected-face.yaw-angle' => { Name => 'DetectedFaceYawAngle', Writable => 0 }, 6344# 6345# seen in Apple ProRes RAW file 6346# 6347 # (mdta)com.apple.proapps.manufacturer (eg. "Sony") 6348 # (mdta)com.apple.proapps.exif.{Exif}.FNumber (float, eg. 1.0) 6349 # (mdta)org.smpte.rdd18.lens.irisfnumber (eg. "F1.0") 6350 # (mdta)com.apple.proapps.exif.{Exif}.ShutterSpeedValue (float, eg. 1.006) 6351 # (mdta)org.smpte.rdd18.camera.shutterspeed_angle (eg. "179.2deg") 6352 # (mdta)org.smpte.rdd18.camera.neutraldensityfilterwheelsetting (eg. "ND1") 6353 # (mdta)org.smpte.rdd18.camera.whitebalance (eg. "4300K") 6354 # (mdta)com.apple.proapps.exif.{Exif}.ExposureIndex (float, eg. 4000) 6355 # (mdta)org.smpte.rdd18.camera.isosensitivity (eg. "4000") 6356 # (mdta)com.apple.proapps.image.{TIFF}.Make (eg. "Atmos") 6357 # (mdta)com.apple.proapps.image.{TIFF}.Model (eg. "ShogunInferno") 6358 # (mdta)com.apple.proapps.image.{TIFF}.Software (eg. "9.0") 6359); 6360 6361# iTunes info ('----') atoms 6362%Image::ExifTool::QuickTime::iTunesInfo = ( 6363 PROCESS_PROC => \&ProcessMOV, 6364 GROUPS => { 2 => 'Audio' }, 6365 NOTES => q{ 6366 ExifTool will extract any iTunesInfo tags that exist, even if they are not 6367 defined in this table. 6368 }, 6369 # 'mean'/'name'/'data' atoms form a triplet, but unfortunately 6370 # I haven't been able to find any documentation on this. 6371 # 'mean' is normally 'com.apple.iTunes' 6372 mean => { 6373 Name => 'Mean', 6374 # the 'Triplet' flag tells ProcessMOV() to generate 6375 # a single tag from the mean/name/data triplet 6376 Triplet => 1, 6377 Hidden => 1, 6378 }, 6379 name => { 6380 Name => 'Name', 6381 Triplet => 1, 6382 Hidden => 1, 6383 }, 6384 data => { 6385 Name => 'Data', 6386 Triplet => 1, 6387 Hidden => 1, 6388 }, 6389 # the tag ID's below are composed from "mean/name", 6390 # but "mean/" is omitted if it is "com.apple.iTunes/": 6391 'iTunMOVI' => { 6392 Name => 'iTunMOVI', 6393 SubDirectory => { TagTable => 'Image::ExifTool::PLIST::Main' }, 6394 }, 6395 'tool' => { 6396 Name => 'iTunTool', 6397 Description => 'iTunTool', 6398 Format => 'int32u', 6399 PrintConv => 'sprintf("0x%.8x",$val)', 6400 }, 6401 'iTunEXTC' => { 6402 Name => 'ContentRating', 6403 Notes => 'standard | rating | score | reasons', 6404 # eg. 'us-tv|TV-14|500|V', 'mpaa|PG-13|300|For violence and sexuality' 6405 # (see http://shadowofged.blogspot.ca/2008/06/itunes-content-ratings.html) 6406 }, 6407 'iTunNORM' => { 6408 Name => 'VolumeNormalization', 6409 PrintConv => '$val=~s/ 0+(\w)/ $1/g; $val=~s/^\s+//; $val', 6410 }, 6411 'iTunSMPB' => { 6412 Name => 'iTunSMPB', 6413 Description => 'iTunSMPB', 6414 # hex format, similar to iTunNORM, but 12 words instead of 10, 6415 # and 4th word is 16 hex digits (all others are 8) 6416 # (gives AAC encoder delay, ref http://code.google.com/p/l-smash/issues/detail?id=1) 6417 PrintConv => '$val=~s/ 0+(\w)/ $1/g; $val=~s/^\s+//; $val', 6418 }, 6419 # (CDDB = Compact Disc DataBase) 6420 # iTunes_CDDB_1 = <CDDB1 disk ID>+<# tracks>+<logical block address for each track>... 6421 'iTunes_CDDB_1' => 'CDDB1Info', 6422 'iTunes_CDDB_TrackNumber' => 'CDDBTrackNumber', 6423 'Encoding Params' => { 6424 Name => 'EncodingParams', 6425 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::EncodingParams' }, 6426 }, 6427 # also heard about 'iTunPGAP', but I haven't seen a sample 6428 DISCNUMBER => 'DiscNumber', #PH 6429 TRACKNUMBER => 'TrackNumber', #PH 6430 popularimeter => 'Popularimeter', #PH 6431); 6432 6433# iTunes audio encoding parameters 6434# ref https://developer.apple.com/library/mac/#documentation/MusicAudio/Reference/AudioCodecServicesRef/Reference/reference.html 6435%Image::ExifTool::QuickTime::EncodingParams = ( 6436 PROCESS_PROC => \&ProcessEncodingParams, 6437 GROUPS => { 2 => 'Audio' }, 6438 # (I have commented out the ones that don't have integer values because they 6439 # probably don't appear, and definitely wouldn't work with current decoding - PH) 6440 6441 # global codec properties 6442 #'lnam' => 'AudioCodecName', 6443 #'lmak' => 'AudioCodecManufacturer', 6444 #'lfor' => 'AudioCodecFormat', 6445 'vpk?' => 'AudioHasVariablePacketByteSizes', 6446 #'ifm#' => 'AudioSupportedInputFormats', 6447 #'ofm#' => 'AudioSupportedOutputFormats', 6448 #'aisr' => 'AudioAvailableInputSampleRates', 6449 #'aosr' => 'AudioAvailableOutputSampleRates', 6450 'abrt' => 'AudioAvailableBitRateRange', 6451 'mnip' => 'AudioMinimumNumberInputPackets', 6452 'mnop' => 'AudioMinimumNumberOutputPackets', 6453 'cmnc' => 'AudioAvailableNumberChannels', 6454 'lmrc' => 'AudioDoesSampleRateConversion', 6455 #'aicl' => 'AudioAvailableInputChannelLayoutTags', 6456 #'aocl' => 'AudioAvailableOutputChannelLayoutTags', 6457 #'if4o' => 'AudioInputFormatsForOutputFormat', 6458 #'of4i' => 'AudioOutputFormatsForInputFormat', 6459 #'acfi' => 'AudioFormatInfo', 6460 6461 # instance codec properties 6462 'tbuf' => 'AudioInputBufferSize', 6463 'pakf' => 'AudioPacketFrameSize', 6464 'pakb' => 'AudioMaximumPacketByteSize', 6465 #'ifmt' => 'AudioCurrentInputFormat', 6466 #'ofmt' => 'AudioCurrentOutputFormat', 6467 #'kuki' => 'AudioMagicCookie', 6468 'ubuf' => 'AudioUsedInputBufferSize', 6469 'init' => 'AudioIsInitialized', 6470 'brat' => 'AudioCurrentTargetBitRate', 6471 #'cisr' => 'AudioCurrentInputSampleRate', 6472 #'cosr' => 'AudioCurrentOutputSampleRate', 6473 'srcq' => 'AudioQualitySetting', 6474 #'brta' => 'AudioApplicableBitRateRange', 6475 #'isra' => 'AudioApplicableInputSampleRates', 6476 #'osra' => 'AudioApplicableOutputSampleRates', 6477 'pad0' => 'AudioZeroFramesPadded', 6478 'prmm' => 'AudioCodecPrimeMethod', 6479 #'prim' => 'AudioCodecPrimeInfo', 6480 #'icl ' => 'AudioInputChannelLayout', 6481 #'ocl ' => 'AudioOutputChannelLayout', 6482 #'acs ' => 'AudioCodecSettings', 6483 #'acfl' => 'AudioCodecFormatList', 6484 'acbf' => 'AudioBitRateControlMode', 6485 'vbrq' => 'AudioVBRQuality', 6486 'mdel' => 'AudioMinimumDelayMode', 6487 6488 # deprecated 6489 'pakd' => 'AudioRequiresPacketDescription', 6490 #'brt#' => 'AudioAvailableBitRates', 6491 'acef' => 'AudioExtendFrequencies', 6492 'ursr' => 'AudioUseRecommendedSampleRate', 6493 'oppr' => 'AudioOutputPrecedence', 6494 #'loud' => 'AudioCurrentLoudnessStatistics', 6495 6496 # others 6497 'vers' => 'AudioEncodingParamsVersion', #PH 6498 'cdcv' => { #PH 6499 Name => 'AudioComponentVersion', 6500 ValueConv => 'join ".", unpack("ncc", pack("N",$val))', 6501 }, 6502); 6503 6504# print to video data block 6505%Image::ExifTool::QuickTime::Video = ( 6506 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6507 GROUPS => { 2 => 'Video' }, 6508 0 => { 6509 Name => 'DisplaySize', 6510 PrintConv => { 6511 0 => 'Normal', 6512 1 => 'Double Size', 6513 2 => 'Half Size', 6514 3 => 'Full Screen', 6515 4 => 'Current Size', 6516 }, 6517 }, 6518 6 => { 6519 Name => 'SlideShow', 6520 PrintConv => { 6521 0 => 'No', 6522 1 => 'Yes', 6523 }, 6524 }, 6525); 6526 6527# 'hnti' atoms 6528%Image::ExifTool::QuickTime::HintInfo = ( 6529 PROCESS_PROC => \&ProcessMOV, 6530 GROUPS => { 2 => 'Video' }, 6531 'rtp ' => { 6532 Name => 'RealtimeStreamingProtocol', 6533 PrintConv => '$val=~s/^sdp /(SDP) /; $val', 6534 }, 6535 'sdp ' => 'StreamingDataProtocol', 6536); 6537 6538# 'hinf' atoms 6539%Image::ExifTool::QuickTime::HintTrackInfo = ( 6540 PROCESS_PROC => \&ProcessMOV, 6541 GROUPS => { 2 => 'Video' }, 6542 trpY => { Name => 'TotalBytes', Format => 'int64u' }, #(documented) 6543 trpy => { Name => 'TotalBytes', Format => 'int64u' }, #(observed) 6544 totl => { Name => 'TotalBytes', Format => 'int32u' }, 6545 nump => { Name => 'NumPackets', Format => 'int64u' }, 6546 npck => { Name => 'NumPackets', Format => 'int32u' }, 6547 tpyl => { Name => 'TotalBytesNoRTPHeaders', Format => 'int64u' }, 6548 tpaY => { Name => 'TotalBytesNoRTPHeaders', Format => 'int32u' }, #(documented) 6549 tpay => { Name => 'TotalBytesNoRTPHeaders', Format => 'int32u' }, #(observed) 6550 maxr => { 6551 Name => 'MaxDataRate', 6552 Format => 'int32u', 6553 Count => 2, 6554 PrintConv => 'my @a=split(" ",$val);sprintf("%d bytes in %.3f s",$a[1],$a[0]/1000)', 6555 }, 6556 dmed => { Name => 'MediaTrackBytes', Format => 'int64u' }, 6557 dimm => { Name => 'ImmediateDataBytes', Format => 'int64u' }, 6558 drep => { Name => 'RepeatedDataBytes', Format => 'int64u' }, 6559 tmin => { 6560 Name => 'MinTransmissionTime', 6561 Format => 'int32u', 6562 PrintConv => 'sprintf("%.3f s",$val/1000)', 6563 }, 6564 tmax => { 6565 Name => 'MaxTransmissionTime', 6566 Format => 'int32u', 6567 PrintConv => 'sprintf("%.3f s",$val/1000)', 6568 }, 6569 pmax => { Name => 'LargestPacketSize', Format => 'int32u' }, 6570 dmax => { 6571 Name => 'LargestPacketDuration', 6572 Format => 'int32u', 6573 PrintConv => 'sprintf("%.3f s",$val/1000)', 6574 }, 6575 payt => { 6576 Name => 'PayloadType', 6577 Format => 'undef', # (necessary to prevent decoding as string!) 6578 ValueConv => 'unpack("N",$val) . " " . substr($val, 5)', 6579 PrintConv => '$val=~s/ /, /;$val', 6580 }, 6581); 6582 6583# MP4 media box (ref 5) 6584%Image::ExifTool::QuickTime::Media = ( 6585 PROCESS_PROC => \&ProcessMOV, 6586 WRITE_PROC => \&WriteQuickTime, 6587 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 6588 NOTES => 'MP4 media box.', 6589 mdhd => { 6590 Name => 'MediaHeader', 6591 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MediaHeader' }, 6592 }, 6593 hdlr => { 6594 Name => 'Handler', 6595 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' }, 6596 }, 6597 minf => { 6598 Name => 'MediaInfo', 6599 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MediaInfo' }, 6600 }, 6601); 6602 6603# MP4 media header box (ref 5) 6604%Image::ExifTool::QuickTime::MediaHeader = ( 6605 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6606 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 6607 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 6608 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 6609 FORMAT => 'int32u', 6610 DATAMEMBER => [ 0, 1, 2, 3, 4 ], 6611 0 => { 6612 Name => 'MediaHeaderVersion', 6613 RawConv => '$$self{MediaHeaderVersion} = $val', 6614 }, 6615 1 => { 6616 Name => 'MediaCreateDate', 6617 Groups => { 2 => 'Time' }, 6618 %timeInfo, 6619 # this is int64u if MediaHeaderVersion == 1 (ref 5/13) 6620 Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4', 6621 }, 6622 2 => { 6623 Name => 'MediaModifyDate', 6624 Groups => { 2 => 'Time' }, 6625 %timeInfo, 6626 # this is int64u if MediaHeaderVersion == 1 (ref 5/13) 6627 Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4', 6628 }, 6629 3 => { 6630 Name => 'MediaTimeScale', 6631 RawConv => '$$self{MediaTS} = $val', 6632 }, 6633 4 => { 6634 Name => 'MediaDuration', 6635 RawConv => '$$self{MediaTS} ? $val / $$self{MediaTS} : $val', 6636 PrintConv => '$$self{MediaTS} ? ConvertDuration($val) : $val', 6637 # this is int64u if MediaHeaderVersion == 1 (ref 5/13) 6638 Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4', 6639 }, 6640 5 => { 6641 Name => 'MediaLanguageCode', 6642 Format => 'int16u', 6643 RawConv => '$val ? $val : undef', 6644 # allow both Macintosh (for MOV files) and ISO (for MP4 files) language codes 6645 ValueConv => '($val < 0x400 or $val == 0x7fff) ? $val : pack "C*", map { (($val>>$_)&0x1f)+0x60 } 10, 5, 0', 6646 PrintConv => q{ 6647 return $val unless $val =~ /^\d+$/; 6648 require Image::ExifTool::Font; 6649 return $Image::ExifTool::Font::ttLang{Macintosh}{$val} || "Unknown ($val)"; 6650 }, 6651 }, 6652); 6653 6654# MP4 media information box (ref 5) 6655%Image::ExifTool::QuickTime::MediaInfo = ( 6656 PROCESS_PROC => \&ProcessMOV, 6657 WRITE_PROC => \&WriteQuickTime, 6658 GROUPS => { 1 => 'Track#', 2 => 'Video' }, 6659 NOTES => 'MP4 media info box.', 6660 vmhd => { 6661 Name => 'VideoHeader', 6662 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::VideoHeader' }, 6663 }, 6664 smhd => { 6665 Name => 'AudioHeader', 6666 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AudioHeader' }, 6667 }, 6668 hmhd => { 6669 Name => 'HintHeader', 6670 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintHeader' }, 6671 }, 6672 nmhd => { 6673 Name => 'NullMediaHeader', 6674 Flags => ['Binary','Unknown'], 6675 }, 6676 dinf => { 6677 Name => 'DataInfo', # (don't change this name -- used to recognize directory when writing) 6678 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' }, 6679 }, 6680 gmhd => { 6681 Name => 'GenMediaHeader', 6682 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::GenMediaHeader' }, 6683 }, 6684 hdlr => { #PH 6685 Name => 'Handler', 6686 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' }, 6687 }, 6688 stbl => { 6689 Name => 'SampleTable', 6690 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SampleTable' }, 6691 }, 6692); 6693 6694# MP4 video media header (ref 5) 6695%Image::ExifTool::QuickTime::VideoHeader = ( 6696 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6697 GROUPS => { 2 => 'Video' }, 6698 NOTES => 'MP4 video media header.', 6699 FORMAT => 'int16u', 6700 2 => { 6701 Name => 'GraphicsMode', 6702 PrintHex => 1, 6703 SeparateTable => 'GraphicsMode', 6704 PrintConv => \%graphicsMode, 6705 }, 6706 3 => { Name => 'OpColor', Format => 'int16u[3]' }, 6707); 6708 6709# MP4 audio media header (ref 5) 6710%Image::ExifTool::QuickTime::AudioHeader = ( 6711 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6712 GROUPS => { 2 => 'Audio' }, 6713 NOTES => 'MP4 audio media header.', 6714 FORMAT => 'int16u', 6715 2 => { Name => 'Balance', Format => 'fixed16s' }, 6716); 6717 6718# MP4 hint media header (ref 5) 6719%Image::ExifTool::QuickTime::HintHeader = ( 6720 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6721 NOTES => 'MP4 hint media header.', 6722 FORMAT => 'int16u', 6723 2 => 'MaxPDUSize', 6724 3 => 'AvgPDUSize', 6725 4 => { Name => 'MaxBitrate', Format => 'int32u', PrintConv => 'ConvertBitrate($val)' }, 6726 6 => { Name => 'AvgBitrate', Format => 'int32u', PrintConv => 'ConvertBitrate($val)' }, 6727); 6728 6729# MP4 sample table box (ref 5) 6730%Image::ExifTool::QuickTime::SampleTable = ( 6731 PROCESS_PROC => \&ProcessMOV, 6732 WRITE_PROC => \&WriteQuickTime, 6733 GROUPS => { 2 => 'Video' }, 6734 NOTES => 'MP4 sample table box.', 6735 stsd => [ 6736 { 6737 Name => 'AudioSampleDesc', 6738 Condition => '$$self{HandlerType} and $$self{HandlerType} eq "soun"', 6739 SubDirectory => { 6740 TagTable => 'Image::ExifTool::QuickTime::AudioSampleDesc', 6741 ProcessProc => \&ProcessSampleDesc, 6742 }, 6743 },{ 6744 Name => 'VideoSampleDesc', 6745 Condition => '$$self{HandlerType} and $$self{HandlerType} eq "vide"', 6746 SubDirectory => { 6747 TagTable => 'Image::ExifTool::QuickTime::ImageDesc', 6748 ProcessProc => \&ProcessSampleDesc, 6749 }, 6750 },{ 6751 Name => 'HintSampleDesc', 6752 Condition => '$$self{HandlerType} and $$self{HandlerType} eq "hint"', 6753 SubDirectory => { 6754 TagTable => 'Image::ExifTool::QuickTime::HintSampleDesc', 6755 ProcessProc => \&ProcessSampleDesc, 6756 }, 6757 },{ 6758 Name => 'MetaSampleDesc', 6759 Condition => '$$self{HandlerType} and $$self{HandlerType} eq "meta"', 6760 SubDirectory => { 6761 TagTable => 'Image::ExifTool::QuickTime::MetaSampleDesc', 6762 ProcessProc => \&ProcessSampleDesc, 6763 }, 6764 },{ 6765 Name => 'OtherSampleDesc', 6766 SubDirectory => { 6767 TagTable => 'Image::ExifTool::QuickTime::OtherSampleDesc', 6768 ProcessProc => \&ProcessSampleDesc, 6769 }, 6770 }, 6771 # (Note: "alis" HandlerType handled by the parent audio or video handler) 6772 ], 6773 stts => [ # decoding time-to-sample table 6774 { 6775 Name => 'VideoFrameRate', 6776 Notes => 'average rate calculated from time-to-sample table for video media', 6777 Condition => '$$self{HandlerType} and $$self{HandlerType} eq "vide"', 6778 Format => 'undef', # (necessary to prevent decoding as string!) 6779 # (must be RawConv so appropriate MediaTS is used in calculation) 6780 RawConv => 'Image::ExifTool::QuickTime::CalcSampleRate($self, \$val)', 6781 PrintConv => 'int($val * 1000 + 0.5) / 1000', 6782 }, 6783 { 6784 Name => 'TimeToSampleTable', 6785 Flags => ['Binary','Unknown'], 6786 }, 6787 ], 6788 ctts => { 6789 Name => 'CompositionTimeToSample', 6790 Flags => ['Binary','Unknown'], 6791 }, 6792 stsc => { 6793 Name => 'SampleToChunk', 6794 Flags => ['Binary','Unknown'], 6795 }, 6796 stsz => { 6797 Name => 'SampleSizes', 6798 Flags => ['Binary','Unknown'], 6799 }, 6800 stz2 => { 6801 Name => 'CompactSampleSizes', 6802 Flags => ['Binary','Unknown'], 6803 }, 6804 stco => { 6805 Name => 'ChunkOffset', 6806 Flags => ['Binary','Unknown'], 6807 }, 6808 co64 => { 6809 Name => 'ChunkOffset64', 6810 Flags => ['Binary','Unknown'], 6811 }, 6812 stss => { 6813 Name => 'SyncSampleTable', 6814 Flags => ['Binary','Unknown'], 6815 }, 6816 stsh => { 6817 Name => 'ShadowSyncSampleTable', 6818 Flags => ['Binary','Unknown'], 6819 }, 6820 padb => { 6821 Name => 'SamplePaddingBits', 6822 Flags => ['Binary','Unknown'], 6823 }, 6824 stdp => { 6825 Name => 'SampleDegradationPriority', 6826 Flags => ['Binary','Unknown'], 6827 }, 6828 sdtp => { 6829 Name => 'IdependentAndDisposableSamples', 6830 Flags => ['Binary','Unknown'], 6831 }, 6832 sbgp => { 6833 Name => 'SampleToGroup', 6834 Flags => ['Binary','Unknown'], 6835 }, 6836 sgpd => { 6837 Name => 'SampleGroupDescription', 6838 Flags => ['Binary','Unknown'], 6839 # bytes 4-7 give grouping type (ref ISO/IEC 14496-15:2014) 6840 # tsas - temporal sublayer sample 6841 # stsa - step-wise temporal layer access 6842 # avss - AVC sample 6843 # tscl - temporal layer scalability 6844 # sync - sync sample 6845 }, 6846 subs => { 6847 Name => 'Sub-sampleInformation', 6848 Flags => ['Binary','Unknown'], 6849 }, 6850 cslg => { 6851 Name => 'CompositionToDecodeTimelineMapping', 6852 Flags => ['Binary','Unknown'], 6853 }, 6854 stps => { 6855 Name => 'PartialSyncSamples', 6856 ValueConv => 'join " ",unpack("x8N*",$val)', 6857 }, 6858 # mark - 8 bytes all zero (GoPro) 6859); 6860 6861# MP4 audio sample description box (ref 5/AtomicParsley 0.9.4 parsley.cpp) 6862%Image::ExifTool::QuickTime::AudioSampleDesc = ( 6863 PROCESS_PROC => \&ProcessHybrid, 6864 VARS => { ID_LABEL => 'ID/Index' }, 6865 GROUPS => { 2 => 'Audio' }, 6866 NOTES => q{ 6867 MP4 audio sample description. This hybrid atom contains both data and child 6868 atoms. 6869 }, 6870 4 => { 6871 Name => 'AudioFormat', 6872 Format => 'undef[4]', 6873 RawConv => q{ 6874 $$self{AudioFormat} = $val; 6875 return undef unless $val =~ /^[\w ]{4}$/i; 6876 # check for protected audio format 6877 $self->OverrideFileType('M4P') if $val eq 'drms' and $$self{VALUE}{FileType} eq 'M4A'; 6878 return $val; 6879 }, 6880 # see this link for print conversions (not complete): 6881 # https://github.com/yannickcr/brooser/blob/master/php/librairies/getid3/module.audio-video.quicktime.php 6882 }, 6883 20 => { #PH 6884 Name => 'AudioVendorID', 6885 Condition => '$$self{AudioFormat} ne "mp4s"', 6886 Format => 'undef[4]', 6887 RawConv => '$val eq "\0\0\0\0" ? undef : $val', 6888 PrintConv => \%vendorID, 6889 SeparateTable => 'VendorID', 6890 }, 6891 24 => { Name => 'AudioChannels', Format => 'int16u' }, 6892 26 => { Name => 'AudioBitsPerSample', Format => 'int16u' }, 6893 32 => { Name => 'AudioSampleRate', Format => 'fixed32u' }, 6894# 6895# Observed offsets for child atoms of various AudioFormat types: 6896# 6897# AudioFormat Offset Child atoms 6898# ----------- ------ ---------------- 6899# mp4a 52 * wave, chan, esds, SA3D(Insta360 spherical video params?,also GoPro Max) 6900# in24 52 wave, chan 6901# "ms\0\x11" 52 wave 6902# sowt 52 chan 6903# mp4a 36 * esds, pinf 6904# drms 36 esds, sinf 6905# samr 36 damr 6906# alac 36 alac 6907# ac-3 36 dac3 6908# 6909# (* child atoms found at different offsets in mp4a) 6910# 6911 pinf => { 6912 Name => 'PurchaseInfo', 6913 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ProtectionInfo' }, 6914 }, 6915 sinf => { # "protection scheme information" 6916 Name => 'ProtectionInfo', #3 6917 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ProtectionInfo' }, 6918 }, 6919 # f - 16/36 bytes 6920 # esds - 31/40/42/43 bytes - ES descriptor (ref 3) 6921 damr => { #3 6922 Name => 'DecodeConfig', 6923 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DecodeConfig' }, 6924 }, 6925 wave => { 6926 Name => 'Wave', 6927 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Wave' }, 6928 }, 6929 chan => { 6930 Name => 'AudioChannelLayout', 6931 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ChannelLayout' }, 6932 } 6933 # alac - 28 bytes 6934 # adrm - AAX DRM atom? 148 bytes 6935 # aabd - AAX unknown 17kB (contains 'aavd' strings) 6936 # SA3D - written by Garmin VIRB360 6937); 6938 6939# AMR decode config box (ref 3) 6940%Image::ExifTool::QuickTime::DecodeConfig = ( 6941 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6942 GROUPS => { 2 => 'Audio' }, 6943 0 => { 6944 Name => 'EncoderVendor', 6945 Format => 'undef[4]', 6946 }, 6947 4 => 'EncoderVersion', 6948 # 5 - int16u - packet modes 6949 # 7 - int8u - number of packet mode changes 6950 # 8 - int8u - bytes per packet 6951); 6952 6953%Image::ExifTool::QuickTime::ProtectionInfo = ( 6954 PROCESS_PROC => \&ProcessMOV, 6955 GROUPS => { 2 => 'Audio' }, 6956 NOTES => 'Child atoms found in "sinf" and/or "pinf" atoms.', 6957 frma => 'OriginalFormat', 6958 # imif - IPMP information 6959 schm => { 6960 Name => 'SchemeType', 6961 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeType' }, 6962 }, 6963 schi => { 6964 Name => 'SchemeInfo', 6965 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeInfo' }, 6966 }, 6967 enda => { 6968 Name => 'Endianness', 6969 Format => 'int16u', 6970 PrintConv => { 6971 0 => 'Big-endian (Motorola, MM)', 6972 1 => 'Little-endian (Intel, II)', 6973 }, 6974 }, 6975 # skcr 6976); 6977 6978%Image::ExifTool::QuickTime::Wave = ( 6979 PROCESS_PROC => \&ProcessMOV, 6980 frma => 'PurchaseFileFormat', 6981 enda => { 6982 Name => 'Endianness', 6983 Format => 'int16u', 6984 PrintConv => { 6985 0 => 'Big-endian (Motorola, MM)', 6986 1 => 'Little-endian (Intel, II)', 6987 }, 6988 }, 6989 # "ms\0\x11" - 20 bytes 6990); 6991 6992# audio channel layout (ref CoreAudioTypes.h) 6993%Image::ExifTool::QuickTime::ChannelLayout = ( 6994 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 6995 GROUPS => { 2 => 'Audio' }, 6996 DATAMEMBER => [ 0, 8 ], 6997 NOTES => 'Audio channel layout.', 6998 # 0 - version and flags 6999 4 => { 7000 Name => 'LayoutFlags', 7001 Format => 'int16u', 7002 RawConv => '$$self{LayoutFlags} = $val', 7003 PrintConvColumns => 2, 7004 PrintConv => { 7005 0 => 'UseDescriptions', 7006 1 => 'UseBitmap', 7007 100 => 'Mono', 7008 101 => 'Stereo', 7009 102 => 'StereoHeadphones', 7010 100 => 'Mono', 7011 101 => 'Stereo', 7012 102 => 'StereoHeadphones', 7013 103 => 'MatrixStereo', 7014 104 => 'MidSide', 7015 105 => 'XY', 7016 106 => 'Binaural', 7017 107 => 'Ambisonic_B_Format', 7018 108 => 'Quadraphonic', 7019 109 => 'Pentagonal', 7020 110 => 'Hexagonal', 7021 111 => 'Octagonal', 7022 112 => 'Cube', 7023 113 => 'MPEG_3_0_A', 7024 114 => 'MPEG_3_0_B', 7025 115 => 'MPEG_4_0_A', 7026 116 => 'MPEG_4_0_B', 7027 117 => 'MPEG_5_0_A', 7028 118 => 'MPEG_5_0_B', 7029 119 => 'MPEG_5_0_C', 7030 120 => 'MPEG_5_0_D', 7031 121 => 'MPEG_5_1_A', 7032 122 => 'MPEG_5_1_B', 7033 123 => 'MPEG_5_1_C', 7034 124 => 'MPEG_5_1_D', 7035 125 => 'MPEG_6_1_A', 7036 126 => 'MPEG_7_1_A', 7037 127 => 'MPEG_7_1_B', 7038 128 => 'MPEG_7_1_C', 7039 129 => 'Emagic_Default_7_1', 7040 130 => 'SMPTE_DTV', 7041 131 => 'ITU_2_1', 7042 132 => 'ITU_2_2', 7043 133 => 'DVD_4', 7044 134 => 'DVD_5', 7045 135 => 'DVD_6', 7046 136 => 'DVD_10', 7047 137 => 'DVD_11', 7048 138 => 'DVD_18', 7049 139 => 'AudioUnit_6_0', 7050 140 => 'AudioUnit_7_0', 7051 141 => 'AAC_6_0', 7052 142 => 'AAC_6_1', 7053 143 => 'AAC_7_0', 7054 144 => 'AAC_Octagonal', 7055 145 => 'TMH_10_2_std', 7056 146 => 'TMH_10_2_full', 7057 147 => 'DiscreteInOrder', 7058 148 => 'AudioUnit_7_0_Front', 7059 149 => 'AC3_1_0_1', 7060 150 => 'AC3_3_0', 7061 151 => 'AC3_3_1', 7062 152 => 'AC3_3_0_1', 7063 153 => 'AC3_2_1_1', 7064 154 => 'AC3_3_1_1', 7065 155 => 'EAC_6_0_A', 7066 156 => 'EAC_7_0_A', 7067 157 => 'EAC3_6_1_A', 7068 158 => 'EAC3_6_1_B', 7069 159 => 'EAC3_6_1_C', 7070 160 => 'EAC3_7_1_A', 7071 161 => 'EAC3_7_1_B', 7072 162 => 'EAC3_7_1_C', 7073 163 => 'EAC3_7_1_D', 7074 164 => 'EAC3_7_1_E', 7075 165 => 'EAC3_7_1_F', 7076 166 => 'EAC3_7_1_G', 7077 167 => 'EAC3_7_1_H', 7078 168 => 'DTS_3_1', 7079 169 => 'DTS_4_1', 7080 170 => 'DTS_6_0_A', 7081 171 => 'DTS_6_0_B', 7082 172 => 'DTS_6_0_C', 7083 173 => 'DTS_6_1_A', 7084 174 => 'DTS_6_1_B', 7085 175 => 'DTS_6_1_C', 7086 176 => 'DTS_7_0', 7087 177 => 'DTS_7_1', 7088 178 => 'DTS_8_0_A', 7089 179 => 'DTS_8_0_B', 7090 180 => 'DTS_8_1_A', 7091 181 => 'DTS_8_1_B', 7092 182 => 'DTS_6_1_D', 7093 183 => 'AAC_7_1_B', 7094 0xffff => 'Unknown', 7095 }, 7096 }, 7097 6 => { 7098 Name => 'AudioChannels', 7099 Condition => '$$self{LayoutFlags} != 0 and $$self{LayoutFlags} != 1', 7100 Format => 'int16u', 7101 }, 7102 8 => { 7103 Name => 'AudioChannelTypes', 7104 Condition => '$$self{LayoutFlags} == 1', 7105 Format => 'int32u', 7106 PrintConv => { BITMASK => { 7107 0 => 'Left', 7108 1 => 'Right', 7109 2 => 'Center', 7110 3 => 'LFEScreen', 7111 4 => 'LeftSurround', 7112 5 => 'RightSurround', 7113 6 => 'LeftCenter', 7114 7 => 'RightCenter', 7115 8 => 'CenterSurround', 7116 9 => 'LeftSurroundDirect', 7117 10 => 'RightSurroundDirect', 7118 11 => 'TopCenterSurround', 7119 12 => 'VerticalHeightLeft', 7120 13 => 'VerticalHeightCenter', 7121 14 => 'VerticalHeightRight', 7122 15 => 'TopBackLeft', 7123 16 => 'TopBackCenter', 7124 17 => 'TopBackRight', 7125 }}, 7126 }, 7127 12 => { 7128 Name => 'NumChannelDescriptions', 7129 Condition => '$$self{LayoutFlags} == 1', 7130 Format => 'int32u', 7131 RawConv => '$$self{NumChannelDescriptions} = $val', 7132 }, 7133 16 => { 7134 Name => 'Channel1Label', 7135 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0', 7136 Format => 'int32u', 7137 SeparateTable => 'ChannelLabel', 7138 PrintConv => \%channelLabel, 7139 }, 7140 20 => { 7141 Name => 'Channel1Flags', 7142 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0', 7143 Format => 'int32u', 7144 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7145 }, 7146 24 => { 7147 Name => 'Channel1Coordinates', 7148 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0', 7149 Notes => q{ 7150 3 numbers: for rectangular coordinates left/right, back/front, down/up; for 7151 spherical coordinates left/right degrees, down/up degrees, distance 7152 }, 7153 Format => 'float[3]', 7154 }, 7155 36 => { 7156 Name => 'Channel2Label', 7157 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1', 7158 Format => 'int32u', 7159 SeparateTable => 'ChannelLabel', 7160 PrintConv => \%channelLabel, 7161 }, 7162 40 => { 7163 Name => 'Channel2Flags', 7164 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1', 7165 Format => 'int32u', 7166 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7167 }, 7168 44 => { 7169 Name => 'Channel2Coordinates', 7170 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1', 7171 Format => 'float[3]', 7172 }, 7173 56 => { 7174 Name => 'Channel3Label', 7175 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2', 7176 Format => 'int32u', 7177 SeparateTable => 'ChannelLabel', 7178 PrintConv => \%channelLabel, 7179 }, 7180 60 => { 7181 Name => 'Channel3Flags', 7182 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2', 7183 Format => 'int32u', 7184 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7185 }, 7186 64 => { 7187 Name => 'Channel3Coordinates', 7188 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2', 7189 Format => 'float[3]', 7190 }, 7191 76 => { 7192 Name => 'Channel4Label', 7193 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3', 7194 Format => 'int32u', 7195 SeparateTable => 'ChannelLabel', 7196 PrintConv => \%channelLabel, 7197 }, 7198 80 => { 7199 Name => 'Channel4Flags', 7200 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3', 7201 Format => 'int32u', 7202 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7203 }, 7204 84 => { 7205 Name => 'Channel4Coordinates', 7206 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3', 7207 Format => 'float[3]', 7208 }, 7209 96 => { 7210 Name => 'Channel5Label', 7211 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4', 7212 Format => 'int32u', 7213 SeparateTable => 'ChannelLabel', 7214 PrintConv => \%channelLabel, 7215 }, 7216 100 => { 7217 Name => 'Channel5Flags', 7218 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4', 7219 Format => 'int32u', 7220 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7221 }, 7222 104 => { 7223 Name => 'Channel5Coordinates', 7224 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4', 7225 Format => 'float[3]', 7226 }, 7227 116 => { 7228 Name => 'Channel6Label', 7229 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5', 7230 Format => 'int32u', 7231 SeparateTable => 'ChannelLabel', 7232 PrintConv => \%channelLabel, 7233 }, 7234 120 => { 7235 Name => 'Channel6Flags', 7236 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5', 7237 Format => 'int32u', 7238 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7239 }, 7240 124 => { 7241 Name => 'Channel6Coordinates', 7242 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5', 7243 Format => 'float[3]', 7244 }, 7245 136 => { 7246 Name => 'Channel7Label', 7247 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6', 7248 Format => 'int32u', 7249 SeparateTable => 'ChannelLabel', 7250 PrintConv => \%channelLabel, 7251 }, 7252 140 => { 7253 Name => 'Channel7Flags', 7254 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6', 7255 Format => 'int32u', 7256 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7257 }, 7258 144 => { 7259 Name => 'Channel7Coordinates', 7260 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6', 7261 Format => 'float[3]', 7262 }, 7263 156 => { 7264 Name => 'Channel8Label', 7265 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7', 7266 Format => 'int32u', 7267 SeparateTable => 'ChannelLabel', 7268 PrintConv => \%channelLabel, 7269 }, 7270 160 => { 7271 Name => 'Channel8Flags', 7272 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7', 7273 Format => 'int32u', 7274 PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }}, 7275 }, 7276 164 => { 7277 Name => 'Channel8Coordinates', 7278 Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7', 7279 Format => 'float[3]', 7280 }, 7281 # (arbitrarily decode only first 8 channels) 7282); 7283 7284# scheme type atom 7285# ref http://xhelmboyx.tripod.com/formats/mp4-layout.txt 7286%Image::ExifTool::QuickTime::SchemeType = ( 7287 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7288 GROUPS => { 2 => 'Audio' }, 7289 # 0 - 4 bytes version 7290 4 => { Name => 'SchemeType', Format => 'undef[4]' }, 7291 8 => { Name => 'SchemeVersion', Format => 'int16u' }, 7292 10 => { Name => 'SchemeURL', Format => 'string[$size-10]' }, 7293); 7294 7295%Image::ExifTool::QuickTime::SchemeInfo = ( 7296 PROCESS_PROC => \&ProcessMOV, 7297 GROUPS => { 2 => 'Audio' }, 7298 user => { 7299 Name => 'UserID', 7300 Groups => { 2 => 'Author' }, 7301 ValueConv => '"0x" . unpack("H*",$val)', 7302 }, 7303 cert => { # ref http://www.onvif.org/specs/stream/ONVIF-ExportFileFormat-Spec-v100.pdf 7304 Name => 'Certificate', 7305 ValueConv => '"0x" . unpack("H*",$val)', 7306 }, 7307 'key ' => { 7308 Name => 'KeyID', 7309 ValueConv => '"0x" . unpack("H*",$val)', 7310 }, 7311 iviv => { 7312 Name => 'InitializationVector', 7313 ValueConv => 'unpack("H*",$val)', 7314 }, 7315 righ => { 7316 Name => 'Rights', 7317 Groups => { 2 => 'Author' }, 7318 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Rights' }, 7319 }, 7320 name => { Name => 'UserName', Groups => { 2 => 'Author' } }, 7321 # chtb 7322 # priv - private data 7323 # sign 7324 # adkm - Adobe DRM key management system (ref http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf) 7325 # iKMS 7326 # iSFM 7327 # iSLT 7328); 7329 7330%Image::ExifTool::QuickTime::Rights = ( 7331 PROCESS_PROC => \&ProcessRights, 7332 GROUPS => { 2 => 'Audio' }, 7333 veID => 'ItemVendorID', #PH ("VendorID" ref 19) 7334 plat => 'Platform', #18? 7335 aver => 'VersionRestrictions', #19 ("appversion?" ref 18) 7336 tran => 'TransactionID', #18 7337 song => 'ItemID', #19 ("appid" ref 18) 7338 tool => { 7339 Name => 'ItemTool', #PH (guess) ("itunes build?" ref 18) 7340 Format => 'string', 7341 }, 7342 medi => 'MediaFlags', #PH (?) 7343 mode => 'ModeFlags', #PH (?) 0x04 is HD flag (https://compilr.com/heksesang/requiem-mac/UnDrm.java) 7344); 7345 7346# MP4 hint sample description box (ref 5) 7347# (ref https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-SW1) 7348%Image::ExifTool::QuickTime::HintSampleDesc = ( 7349 PROCESS_PROC => \&ProcessHybrid, 7350 VARS => { ID_LABEL => 'ID/Index' }, 7351 NOTES => 'MP4 hint sample description.', 7352 4 => { Name => 'HintFormat', Format => 'undef[4]' }, 7353 # 14 - int16u DataReferenceIndex 7354 16 => { Name => 'HintTrackVersion', Format => 'int16u' }, 7355 # 18 - int16u LastCompatibleHintTrackVersion 7356 20 => { Name => 'MaxPacketSize', Format => 'int32u' }, 7357# 7358# Observed offsets for child atoms of various HintFormat types: 7359# 7360# HintFormat Offset Child atoms 7361# ----------- ------ ---------------- 7362# "rtp " 24 tims 7363# 7364 tims => { Name => 'RTPTimeScale', Format => 'int32u' }, 7365 tsro => { Name => 'TimestampRandomOffset', Format => 'int32u' }, 7366 snro => { Name => 'SequenceNumberRandomOffset', Format => 'int32u' }, 7367); 7368 7369# MP4 metadata sample description box 7370%Image::ExifTool::QuickTime::MetaSampleDesc = ( 7371 PROCESS_PROC => \&ProcessHybrid, 7372 NOTES => 'MP4 metadata sample description.', 7373 4 => { 7374 Name => 'MetaFormat', 7375 Format => 'undef[4]', 7376 RawConv => '$$self{MetaFormat} = $val', 7377 }, 7378# 7379# Observed offsets for child atoms of various MetaFormat types: 7380# 7381# MetaFormat Offset Child atoms 7382# ----------- ------ ---------------- 7383# mebx 24 keys,btrt,lidp,lidl 7384# fdsc - - 7385# gpmd - - 7386# rtmd - - 7387# CTMD - - 7388# 7389 'keys' => { #PH (iPhone7+ hevc) 7390 Name => 'Keys', 7391 SubDirectory => { 7392 TagTable => 'Image::ExifTool::QuickTime::Keys', 7393 ProcessProc => \&ProcessMetaKeys, 7394 }, 7395 }, 7396 btrt => { 7397 Name => 'BitrateInfo', 7398 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Bitrate' }, 7399 }, 7400); 7401 7402# MP4 generic sample description box 7403%Image::ExifTool::QuickTime::OtherSampleDesc = ( 7404 PROCESS_PROC => \&ProcessHybrid, 7405 4 => { 7406 Name => 'OtherFormat', 7407 Format => 'undef[4]', 7408 RawConv => '$$self{MetaFormat} = $val', # (yes, use MetaFormat for this too) 7409 }, 7410# 7411# Observed offsets for child atoms of various OtherFormat types: 7412# 7413# OtherFormat Offset Child atoms 7414# ----------- ------ ---------------- 7415# avc1 86 avcC 7416# mp4a 36 esds 7417# mp4s 16 esds 7418# tmcd 34 name 7419# data - - 7420# 7421 ftab => { Name => 'FontTable', Format => 'undef', ValueConv => 'substr($val, 5)' }, 7422 name => { Name => 'OtherName', Format => 'undef', ValueConv => 'substr($val, 4)' }, 7423 # mrlh = GM header? 7424 # mrlv = GM data 7425 # mrld = GM data (448-byte records): 7426 # 0 - int32u count 7427 # 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=% 7428 # 8 - int32u ? (0,1,3,4,5) 7429 # 12 - string[64] units 7430 # 76 - int32u ? (1,3,7,15) 7431 # 80 - int32u 0 7432 # 84 - undef[4] ? 7433 # 88 - int16u[6] ? 7434 # 100 - undef[32] ? 7435 # 132 - string[64] measurement name 7436 # 196 - string[64] measurement name 7437); 7438 7439# MP4 data information box (ref 5) 7440%Image::ExifTool::QuickTime::DataInfo = ( 7441 PROCESS_PROC => \&ProcessMOV, 7442 WRITE_PROC => \&WriteQuickTime, # (necessary to parse dref even though we don't change it) 7443 NOTES => 'MP4 data information box.', 7444 dref => { 7445 Name => 'DataRef', 7446 SubDirectory => { 7447 TagTable => 'Image::ExifTool::QuickTime::DataRef', 7448 Start => 8, 7449 }, 7450 }, 7451); 7452 7453# Generic media header 7454%Image::ExifTool::QuickTime::GenMediaHeader = ( 7455 PROCESS_PROC => \&ProcessMOV, 7456 gmin => { 7457 Name => 'GenMediaInfo', 7458 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::GenMediaInfo' }, 7459 }, 7460 text => { 7461 Name => 'Text', 7462 Flags => ['Binary','Unknown'], 7463 }, 7464 tmcd => { 7465 Name => 'TimeCode', 7466 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TimeCode' }, 7467 }, 7468); 7469 7470# TimeCode header 7471%Image::ExifTool::QuickTime::TimeCode = ( 7472 PROCESS_PROC => \&ProcessMOV, 7473 tcmi => { 7474 Name => 'TCMediaInfo', 7475 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TCMediaInfo' }, 7476 }, 7477); 7478 7479# TimeCode media info (ref 12) 7480%Image::ExifTool::QuickTime::TCMediaInfo = ( 7481 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7482 GROUPS => { 2 => 'Video' }, 7483 4 => { 7484 Name => 'TextFont', 7485 Format => 'int16u', 7486 PrintConv => { 0 => 'System' }, 7487 }, 7488 6 => { 7489 Name => 'TextFace', 7490 Format => 'int16u', 7491 PrintConv => { 7492 0 => 'Plain', 7493 BITMASK => { 7494 0 => 'Bold', 7495 1 => 'Italic', 7496 2 => 'Underline', 7497 3 => 'Outline', 7498 4 => 'Shadow', 7499 5 => 'Condense', 7500 6 => 'Extend', 7501 }, 7502 }, 7503 }, 7504 8 => { 7505 Name => 'TextSize', 7506 Format => 'int16u', 7507 }, 7508 # 10 - reserved 7509 12 => { 7510 Name => 'TextColor', 7511 Format => 'int16u[3]', 7512 }, 7513 18 => { 7514 Name => 'BackgroundColor', 7515 Format => 'int16u[3]', 7516 }, 7517 24 => { 7518 Name => 'FontName', 7519 Format => 'pstring', 7520 ValueConv => '$self->Decode($val, $self->Options("CharsetQuickTime"))', 7521 }, 7522); 7523 7524# Generic media info (ref http://sourceforge.jp/cvs/view/ntvrec/ntvrec/libqtime/gmin.h?view=co) 7525%Image::ExifTool::QuickTime::GenMediaInfo = ( 7526 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7527 GROUPS => { 2 => 'Video' }, 7528 0 => 'GenMediaVersion', 7529 1 => { Name => 'GenFlags', Format => 'int8u[3]' }, 7530 4 => { Name => 'GenGraphicsMode', 7531 Format => 'int16u', 7532 PrintHex => 1, 7533 SeparateTable => 'GraphicsMode', 7534 PrintConv => \%graphicsMode, 7535 }, 7536 6 => { Name => 'GenOpColor', Format => 'int16u[3]' }, 7537 12 => { Name => 'GenBalance', Format => 'fixed16s' }, 7538); 7539 7540# MP4 data reference box (ref 5) 7541%Image::ExifTool::QuickTime::DataRef = ( 7542 PROCESS_PROC => \&ProcessMOV, 7543 WRITE_PROC => \&WriteQuickTime, # (necessary to parse dref even though we don't change it) 7544 NOTES => 'MP4 data reference box.', 7545 'url ' => { 7546 Name => 'URL', 7547 Format => 'undef', # (necessary to prevent decoding as string!) 7548 RawConv => q{ 7549 # ignore if self-contained (flags bit 0 set) 7550 return undef if unpack("N",$val) & 0x01; 7551 $_ = substr($val,4); s/\0.*//s; $_; 7552 }, 7553 }, 7554 "url\0" => { # (written by GoPro) 7555 Name => 'URL', 7556 Format => 'undef', # (necessary to prevent decoding as string!) 7557 RawConv => q{ 7558 # ignore if self-contained (flags bit 0 set) 7559 return undef if unpack("N",$val) & 0x01; 7560 $_ = substr($val,4); s/\0.*//s; $_; 7561 }, 7562 }, 7563 'urn ' => { 7564 Name => 'URN', 7565 Format => 'undef', # (necessary to prevent decoding as string!) 7566 RawConv => q{ 7567 return undef if unpack("N",$val) & 0x01; 7568 $_ = substr($val,4); s/\0+/; /; s/\0.*//s; $_; 7569 }, 7570 }, 7571); 7572 7573# MP4 handler box (ref 5) 7574%Image::ExifTool::QuickTime::Handler = ( 7575 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7576 GROUPS => { 2 => 'Video' }, 7577 4 => { #PH 7578 Name => 'HandlerClass', 7579 Format => 'undef[4]', 7580 RawConv => '$val eq "\0\0\0\0" ? undef : $val', 7581 PrintConv => { 7582 mhlr => 'Media Handler', 7583 dhlr => 'Data Handler', 7584 }, 7585 }, 7586 8 => { 7587 Name => 'HandlerType', 7588 Format => 'undef[4]', 7589 RawConv => '$$self{HandlerType} = $val unless $val eq "alis" or $val eq "url "; $val', 7590 PrintConvColumns => 2, 7591 PrintConv => { 7592 alis => 'Alias Data', #PH 7593 crsm => 'Clock Reference', #3 7594 hint => 'Hint Track', 7595 ipsm => 'IPMP', #3 7596 m7sm => 'MPEG-7 Stream', #3 7597 meta => 'NRT Metadata', #PH 7598 mdir => 'Metadata', #3 7599 mdta => 'Metadata Tags', #PH 7600 mjsm => 'MPEG-J', #3 7601 ocsm => 'Object Content', #3 7602 odsm => 'Object Descriptor', #3 7603 priv => 'Private', #PH 7604 sdsm => 'Scene Description', #3 7605 soun => 'Audio Track', 7606 text => 'Text', #PH (but what type? subtitle?) 7607 tmcd => 'Time Code', #PH 7608 'url '=> 'URL', #3 7609 vide => 'Video Track', 7610 subp => 'Subpicture', #http://www.google.nl/patents/US7778526 7611 nrtm => 'Non-Real Time Metadata', #PH (Sony ILCE-7S) [how is this different from "meta"?] 7612 pict => 'Picture', # (HEIC images) 7613 camm => 'Camera Metadata', # (Insta360 MP4) 7614 psmd => 'Panasonic Static Metadata', #PH (Leica C-Lux CAM-DC25) 7615 data => 'Data', #PH (GPS and G-sensor data from DataKam) 7616 sbtl => 'Subtitle', #PH (TomTom Bandit Action Cam) 7617 }, 7618 }, 7619 12 => { #PH 7620 Name => 'HandlerVendorID', 7621 Format => 'undef[4]', 7622 RawConv => '$val eq "\0\0\0\0" ? undef : $val', 7623 PrintConv => \%vendorID, 7624 SeparateTable => 'VendorID', 7625 }, 7626 24 => { 7627 Name => 'HandlerDescription', 7628 Format => 'string', 7629 # (sometimes this is a Pascal string, and sometimes it is a C string) 7630 RawConv => q{ 7631 $val=substr($val,1,ord($1)) if $val=~/^([\0-\x1f])/ and ord($1)<length($val); 7632 length $val ? $val : undef; 7633 }, 7634 }, 7635); 7636 7637# Flip uuid data (ref PH) 7638%Image::ExifTool::QuickTime::Flip = ( 7639 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 7640 FORMAT => 'int32u', 7641 FIRST_ENTRY => 0, 7642 NOTES => 'Found in MP4 files from Flip Video cameras.', 7643 GROUPS => { 1 => 'MakerNotes', 2 => 'Image' }, 7644 1 => 'PreviewImageWidth', 7645 2 => 'PreviewImageHeight', 7646 13 => 'PreviewImageLength', 7647 14 => { # (confirmed for FlipVideoMinoHD) 7648 Name => 'SerialNumber', 7649 Groups => { 2 => 'Camera' }, 7650 Format => 'string[16]', 7651 }, 7652 28 => { 7653 Name => 'PreviewImage', 7654 Groups => { 2 => 'Preview' }, 7655 Format => 'undef[$val{13}]', 7656 RawConv => '$self->ValidateImage(\$val, $tag)', 7657 }, 7658); 7659 7660# atoms in Pittasoft "free" atom 7661%Image::ExifTool::QuickTime::Pittasoft = ( 7662 PROCESS_PROC => \&ProcessMOV, 7663 NOTES => 'Tags found in Pittasoft Blackvue dashcam "free" data.', 7664 cprt => 'Copyright', 7665 thum => { 7666 Name => 'PreviewImage', 7667 Groups => { 2 => 'Preview' }, 7668 Binary => 1, 7669 RawConv => q{ 7670 return undef unless length $val > 4; 7671 my $len = unpack('N', $val); 7672 return undef unless length $val >= 4 + $len; 7673 return substr($val, 4, $len); 7674 }, 7675 }, 7676 ptnm => { 7677 Name => 'OriginalFileName', 7678 ValueConv => 'substr($val, 4, -1)', 7679 }, 7680 ptrh => { 7681 SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' }, 7682 # contains these atoms: 7683 # ptvi - 27 bytes: '..avc1...' 7684 # ptso - 16 bytes: '..mp4a...' 7685 }, 7686 'gps ' => { 7687 Name => 'GPSLog', 7688 Binary => 1, # (ASCII NMEA track log with leading timestamps) 7689 Notes => 'parsed to extract GPS separately when ExtractEmbedded is used', 7690 RawConv => q{ 7691 $val =~ s/\0+$//; # remove trailing nulls 7692 if (length $val and $$self{OPTIONS}{ExtractEmbedded}) { 7693 my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); 7694 Image::ExifTool::QuickTime::ProcessNMEA($self, { DataPt => \$val }, $tagTbl); 7695 } 7696 return $val; 7697 }, 7698 }, 7699 '3gf ' => { 7700 Name => 'AccelData', 7701 SubDirectory => { 7702 TagTable => 'Image::ExifTool::QuickTime::Stream', 7703 ProcessProc => \&Process_3gf, 7704 }, 7705 }, 7706 sttm => { 7707 Name => 'StartTime', 7708 Format => 'int64u', 7709 Groups => { 2 => 'Time' }, 7710 RawConv => '$$self{StartTime} = $val', 7711 # (ms since Jan 1, 1970, in local time zone - PH) 7712 ValueConv => q{ 7713 my $secs = int($val / 1000); 7714 return ConvertUnixTime($secs) . sprintf(".%03d",$val - $secs * 1000); 7715 }, 7716 PrintConv => '$self->ConvertDateTime($val)', 7717 }, 7718); 7719 7720# QuickTime composite tags 7721%Image::ExifTool::QuickTime::Composite = ( 7722 GROUPS => { 2 => 'Video' }, 7723 Rotation => { 7724 Notes => q{ 7725 writing this tag updates QuickTime MatrixStructure for all tracks with a 7726 non-zero image size 7727 }, 7728 Require => { 7729 0 => 'QuickTime:MatrixStructure', 7730 1 => 'QuickTime:HandlerType', 7731 }, 7732 Writable => 1, 7733 Protected => 1, 7734 WriteAlso => { 7735 MatrixStructure => 'Image::ExifTool::QuickTime::GetRotationMatrix($val)', 7736 }, 7737 ValueConv => 'Image::ExifTool::QuickTime::CalcRotation($self)', 7738 ValueConvInv => '$val', 7739 }, 7740 AvgBitrate => { 7741 Priority => 0, # let QuickTime::AvgBitrate take priority 7742 Require => { 7743 0 => 'QuickTime::MediaDataSize', 7744 1 => 'QuickTime::Duration', 7745 }, 7746 RawConv => q{ 7747 return undef unless $val[1]; 7748 $val[1] /= $$self{TimeScale} if $$self{TimeScale}; 7749 my $key = 'MediaDataSize'; 7750 my $size = $val[0]; 7751 for (;;) { 7752 $key = $self->NextTagKey($key) or last; 7753 $size += $self->GetValue($key, 'ValueConv'); 7754 } 7755 return int($size * 8 / $val[1] + 0.5); 7756 }, 7757 PrintConv => 'ConvertBitrate($val)', 7758 }, 7759 GPSLatitude => { 7760 Require => 'QuickTime:GPSCoordinates', 7761 Groups => { 2 => 'Location' }, 7762 ValueConv => 'my @c = split " ", $val; $c[0]', 7763 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', 7764 }, 7765 GPSLongitude => { 7766 Require => 'QuickTime:GPSCoordinates', 7767 Groups => { 2 => 'Location' }, 7768 ValueConv => 'my @c = split " ", $val; $c[1]', 7769 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', 7770 }, 7771 # split altitude into GPSAltitude/GPSAltitudeRef like EXIF and XMP 7772 GPSAltitude => { 7773 Require => 'QuickTime:GPSCoordinates', 7774 Groups => { 2 => 'Location' }, 7775 Priority => 0, # (because it may not exist) 7776 ValueConv => 'my @c = split " ", $val; defined $c[2] ? abs($c[2]) : undef', 7777 PrintConv => '"$val m"', 7778 }, 7779 GPSAltitudeRef => { 7780 Require => 'QuickTime:GPSCoordinates', 7781 Groups => { 2 => 'Location' }, 7782 Priority => 0, # (because altitude information may not exist) 7783 ValueConv => 'my @c = split " ", $val; defined $c[2] ? ($c[2] < 0 ? 1 : 0) : undef', 7784 PrintConv => { 7785 0 => 'Above Sea Level', 7786 1 => 'Below Sea Level', 7787 }, 7788 }, 7789 GPSLatitude2 => { 7790 Name => 'GPSLatitude', 7791 Require => 'QuickTime:LocationInformation', 7792 Groups => { 2 => 'Location' }, 7793 ValueConv => '$val =~ /Lat=([-+.\d]+)/; $1', 7794 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', 7795 }, 7796 GPSLongitude2 => { 7797 Name => 'GPSLongitude', 7798 Require => 'QuickTime:LocationInformation', 7799 Groups => { 2 => 'Location' }, 7800 ValueConv => '$val =~ /Lon=([-+.\d]+)/; $1', 7801 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', 7802 }, 7803 GPSAltitude2 => { 7804 Name => 'GPSAltitude', 7805 Require => 'QuickTime:LocationInformation', 7806 Groups => { 2 => 'Location' }, 7807 ValueConv => '$val =~ /Alt=([-+.\d]+)/; abs($1)', 7808 PrintConv => '"$val m"', 7809 }, 7810 GPSAltitudeRef2 => { 7811 Name => 'GPSAltitudeRef', 7812 Require => 'QuickTime:LocationInformation', 7813 Groups => { 2 => 'Location' }, 7814 ValueConv => '$val =~ /Alt=([-+.\d]+)/; $1 < 0 ? 1 : 0', 7815 PrintConv => { 7816 0 => 'Above Sea Level', 7817 1 => 'Below Sea Level', 7818 }, 7819 }, 7820 CDDBDiscPlayTime => { 7821 Require => 'CDDB1Info', 7822 Groups => { 2 => 'Audio' }, 7823 ValueConv => '$val =~ /^..([a-z0-9]{4})/i ? hex($1) : undef', 7824 PrintConv => 'ConvertDuration($val)', 7825 }, 7826 CDDBDiscTracks => { 7827 Require => 'CDDB1Info', 7828 Groups => { 2 => 'Audio' }, 7829 ValueConv => '$val =~ /^.{6}([a-z0-9]{2})/i ? hex($1) : undef', 7830 }, 7831); 7832 7833# add our composite tags 7834Image::ExifTool::AddCompositeTags('Image::ExifTool::QuickTime'); 7835 7836 7837#------------------------------------------------------------------------------ 7838# AutoLoad our routines when necessary 7839# 7840sub AUTOLOAD 7841{ 7842 # (Note: no need to autoload routines in QuickTimeStream that use Stream table) 7843 if ($AUTOLOAD eq 'Image::ExifTool::QuickTime::Process_mebx') { 7844 require 'Image/ExifTool/QuickTimeStream.pl'; 7845 no strict 'refs'; 7846 return &$AUTOLOAD(@_); 7847 } else { 7848 return Image::ExifTool::DoAutoLoad($AUTOLOAD, @_); 7849 } 7850} 7851 7852#------------------------------------------------------------------------------ 7853# Get rotation matrix 7854# Inputs: 0) angle in degrees 7855# Returns: 9-element rotation matrix as a string (with 0 x/y offsets) 7856sub GetRotationMatrix($) 7857{ 7858 my $ang = 3.1415926536 * shift() / 180; 7859 my $cos = cos $ang; 7860 my $sin = sin $ang; 7861 my $msn = -$sin; 7862 return "$cos $sin 0 $msn $cos 0 0 0 1"; 7863} 7864 7865#------------------------------------------------------------------------------ 7866# Get rotation angle from a matrix 7867# Inputs: 0) rotation matrix as a string 7868# Return: positive rotation angle in degrees rounded to 3 decimal points, 7869# or undef on error 7870sub GetRotationAngle($) 7871{ 7872 my $rotMatrix = shift; 7873 my @a = split ' ', $rotMatrix; 7874 return undef if $a[0]==0 and $a[1]==0; 7875 # calculate the rotation angle (assume uniform rotation) 7876 my $angle = atan2($a[1], $a[0]) * 180 / 3.14159; 7877 $angle += 360 if $angle < 0; 7878 return int($angle * 1000 + 0.5) / 1000; 7879} 7880 7881#------------------------------------------------------------------------------ 7882# Calculate rotation of video track 7883# Inputs: 0) ExifTool object ref 7884# Returns: rotation angle or undef 7885sub CalcRotation($) 7886{ 7887 my $et = shift; 7888 my $value = $$et{VALUE}; 7889 my ($i, $track); 7890 # get the video track family 1 group (eg. "Track1"); 7891 for ($i=0; ; ++$i) { 7892 my $idx = $i ? " ($i)" : ''; 7893 my $tag = "HandlerType$idx"; 7894 last unless $$value{$tag}; 7895 next unless $$value{$tag} eq 'vide'; 7896 $track = $et->GetGroup($tag, 1); 7897 last; 7898 } 7899 return undef unless $track; 7900 # get the video track matrix 7901 for ($i=0; ; ++$i) { 7902 my $idx = $i ? " ($i)" : ''; 7903 my $tag = "MatrixStructure$idx"; 7904 last unless $$value{$tag}; 7905 next unless $et->GetGroup($tag, 1) eq $track; 7906 return GetRotationAngle($$value{$tag}); 7907 } 7908 return undef; 7909} 7910 7911#------------------------------------------------------------------------------ 7912# Get MatrixStructure for a given rotation angle 7913# Inputs: 0) rotation angle (deg), 1) ExifTool ref 7914# Returns: matrix structure as a string, or undef if it can't be rotated 7915# - requires ImageSizeLookahead to determine the video image size, and doesn't 7916# rotate matrix unless image size is valid 7917sub GetMatrixStructure($$) 7918{ 7919 my ($val, $et) = @_; 7920 my @a = split ' ', $val; 7921 # pass straight through if it already has an offset 7922 return $val unless $a[6] == 0 and $a[7] == 0; 7923 my @s = split ' ', $$et{ImageSizeLookahead}; 7924 my ($w, $h) = @s[12,13]; 7925 return undef unless $w and $h; # don't rotate 0-sized track 7926 $_ = Image::ExifTool::QuickTime::FixWrongFormat($_) foreach $w,$h; 7927 # apply necessary offsets for the standard rotations 7928 my $angle = GetRotationAngle($val); 7929 return undef unless defined $angle; 7930 if ($angle == 90) { 7931 @a[6,7] = ($h, 0); 7932 } elsif ($angle == 180) { 7933 @a[6,7] = ($w, $h); 7934 } elsif ($angle == 270) { 7935 @a[6,7] = (0, $w); 7936 } 7937 return "@a"; 7938} 7939 7940#------------------------------------------------------------------------------ 7941# Determine the average sample rate from a time-to-sample table 7942# Inputs: 0) ExifTool object ref, 1) time-to-sample table data ref 7943# Returns: average sample rate (in Hz) 7944sub CalcSampleRate($$) 7945{ 7946 my ($et, $valPt) = @_; 7947 my @dat = unpack('N*', $$valPt); 7948 my ($num, $dur) = (0, 0); 7949 my $i; 7950 for ($i=2; $i<@dat-1; $i+=2) { 7951 $num += $dat[$i]; # total number of samples 7952 $dur += $dat[$i] * $dat[$i+1]; # total sample duration 7953 } 7954 return undef unless $num and $dur and $$et{MediaTS}; 7955 return $num * $$et{MediaTS} / $dur; 7956} 7957 7958#------------------------------------------------------------------------------ 7959# Fix incorrect format for ImageWidth/Height as written by Pentax 7960sub FixWrongFormat($) 7961{ 7962 my $val = shift; 7963 return undef unless $val; 7964 return $val & 0xfff00000 ? unpack('n',pack('N',$val)) : $val; 7965} 7966 7967#------------------------------------------------------------------------------ 7968# Convert ISO 6709 string to standard lag/lon format 7969# Inputs: 0) ISO 6709 string (lat, lon, and optional alt) 7970# Returns: position in decimal degrees with altitude if available 7971# Notes: Wikipedia indicates altitude may be in feet -- how is this specified? 7972sub ConvertISO6709($) 7973{ 7974 my $val = shift; 7975 if ($val =~ /^([-+]\d{1,2}(?:\.\d*)?)([-+]\d{1,3}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) { 7976 # +DD.DDD+DDD.DDD+AA.AAA 7977 $val = ($1 + 0) . ' ' . ($2 + 0); 7978 $val .= ' ' . ($3 + 0) if $3; 7979 } elsif ($val =~ /^([-+])(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) { 7980 # +DDMM.MMM+DDDMM.MMM+AA.AAA 7981 my $lat = $2 + $3 / 60; 7982 $lat = -$lat if $1 eq '-'; 7983 my $lon = $5 + $6 / 60; 7984 $lon = -$lon if $4 eq '-'; 7985 $val = "$lat $lon"; 7986 $val .= ' ' . ($7 + 0) if $7; 7987 } elsif ($val =~ /^([-+])(\d{2})(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2})(\d{2}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) { 7988 # +DDMMSS.SSS+DDDMMSS.SSS+AA.AAA 7989 my $lat = $2 + $3 / 60 + $4 / 3600; 7990 $lat = -$lat if $1 eq '-'; 7991 my $lon = $6 + $7 / 60 + $8 / 3600; 7992 $lon = -$lon if $5 eq '-'; 7993 $val = "$lat $lon"; 7994 $val .= ' ' . ($9 + 0) if $9; 7995 } 7996 return $val; 7997} 7998 7999#------------------------------------------------------------------------------ 8000# Convert Nero chapter list (ref ffmpeg libavformat/movenc.c) 8001# Inputs: 0) binary chpl data 8002# Returns: chapter list 8003sub ConvertChapterList($) 8004{ 8005 my $val = shift; 8006 my $size = length $val; 8007 return '<invalid>' if $size < 9; 8008 my $num = Get8u(\$val, 8); 8009 my ($i, @chapters); 8010 my $pos = 9; 8011 for ($i=0; $i<$num; ++$i) { 8012 last if $pos + 9 > $size; 8013 my $dur = Get64u(\$val, $pos) / 10000000; 8014 my $len = Get8u(\$val, $pos + 8); 8015 last if $pos + 9 + $len > $size; 8016 my $title = substr($val, $pos + 9, $len); 8017 $pos += 9 + $len; 8018 push @chapters, "$dur $title"; 8019 } 8020 return \@chapters; # return as a list 8021} 8022 8023#------------------------------------------------------------------------------ 8024# Print conversion for a Nero chapter list item 8025# Inputs: 0) ValueConv chapter string 8026# Returns: formatted chapter string 8027sub PrintChapter($) 8028{ 8029 my $val = shift; 8030 $val =~ /^(\S+) (.*)/ or return $val; 8031 my ($dur, $title) = ($1, $2); 8032 my $h = int($dur / 3600); 8033 $dur -= $h * 3600; 8034 my $m = int($dur / 60); 8035 my $s = $dur - $m * 60; 8036 my $ss = sprintf('%06.3f', $s); 8037 if ($ss >= 60) { 8038 $ss = '00.000'; 8039 ++$m >= 60 and $m -= 60, ++$h; 8040 } 8041 return sprintf("[%d:%.2d:%s] %s",$h,$m,$ss,$title); 8042} 8043 8044#------------------------------------------------------------------------------ 8045# Format GPSCoordinates for printing 8046# Inputs: 0) string with numerical lat, lon and optional alt, separated by spaces 8047# 1) ExifTool object reference 8048# Returns: PrintConv value 8049sub PrintGPSCoordinates($) 8050{ 8051 my ($val, $et) = @_; 8052 my @v = split ' ', $val; 8053 my $prt = Image::ExifTool::GPS::ToDMS($et, $v[0], 1, "N") . ', ' . 8054 Image::ExifTool::GPS::ToDMS($et, $v[1], 1, "E"); 8055 if (defined $v[2]) { 8056 $prt .= ', ' . ($v[2] < 0 ? -$v[2] . ' m Below' : $v[2] . ' m Above') . ' Sea Level'; 8057 } 8058 return $prt; 8059} 8060 8061#------------------------------------------------------------------------------ 8062# Unpack packed ISO 639/T language code 8063# Inputs: 0) packed language code (or undef/0), 1) true to not treat 'und' and 'eng' as default 8064# Returns: language code, or undef/0 for default language, or 'err' for format error 8065sub UnpackLang($;$) 8066{ 8067 my ($lang, $noDef) = @_; 8068 if ($lang) { 8069 # language code is packed in 5-bit characters 8070 $lang = pack 'C*', map { (($lang>>$_)&0x1f)+0x60 } 10, 5, 0; 8071 # validate language code 8072 if ($lang =~ /^[a-z]+$/) { 8073 # treat 'eng' or 'und' as the default language 8074 undef $lang if ($lang eq 'und' or $lang eq 'eng') and not $noDef; 8075 } else { 8076 $lang = 'err'; # invalid language code 8077 } 8078 } 8079 return $lang; 8080} 8081 8082#------------------------------------------------------------------------------ 8083# Get language code string given QuickTime language and country codes 8084# Inputs: 0) numerical language code, 1) numerical country code, 2) no defaults 8085# Returns: language code string (ie. "fra-FR") or undef for default language 8086sub GetLangCode($;$$) 8087{ 8088 my ($lang, $ctry, $noDef) = @_; 8089 # ignore country ('ctry') and language lists ('lang') for now 8090 undef $ctry if $ctry and $ctry <= 255; 8091 undef $lang if $lang and $lang <= 255; 8092 $lang = UnpackLang($lang, $noDef); 8093 # add country code if specified 8094 if ($ctry) { 8095 $ctry = unpack('a2',pack('n',$ctry)); # unpack as ISO 3166-1 8096 # treat 'ZZ' like a default country (see ref 12) 8097 undef $ctry if $ctry eq 'ZZ'; 8098 if ($ctry and $ctry =~ /^[A-Z]{2}$/) { 8099 $lang or $lang = 'und'; 8100 $lang .= "-$ctry"; 8101 } 8102 } 8103 return $lang; 8104} 8105 8106#------------------------------------------------------------------------------ 8107# Get langInfo hash and save details about alt-lang tags 8108# Inputs: 0) ExifTool ref, 1) tagInfo hash ref, 2) locale code 8109# Returns: new tagInfo hash ref, or undef if invalid 8110sub GetLangInfoQT($$$) 8111{ 8112 my ($et, $tagInfo, $langCode) = @_; 8113 my $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $langCode); 8114 if ($langInfo) { 8115 $$et{QTLang} or $$et{QTLang} = [ ]; 8116 push @{$$et{QTLang}}, $$langInfo{Name}; 8117 } 8118 return $langInfo; 8119} 8120 8121#------------------------------------------------------------------------------ 8122# Get variable-length integer from data (used by ParseItemLocation) 8123# Inputs: 0) data ref, 1) start position, 2) integer size in bytes (0, 4 or 8), 8124# 3) default value 8125# Returns: integer value, and updates current position 8126sub GetVarInt($$$;$) 8127{ 8128 my ($dataPt, $pos, $n, $default) = @_; 8129 my $len = length $$dataPt; 8130 $_[1] = $pos + $n; # update current position 8131 return undef if $pos + $n > $len; 8132 if ($n == 0) { 8133 return $default || 0; 8134 } elsif ($n == 4) { 8135 return Get32u($dataPt, $pos); 8136 } elsif ($n == 8) { 8137 return Get64u($dataPt, $pos); 8138 } 8139 return undef; 8140} 8141 8142#------------------------------------------------------------------------------ 8143# Get null-terminated string from binary data (used by ParseItemInfoEntry) 8144# Inputs: 0) data ref, 1) start position 8145# Returns: string, and updates current position 8146sub GetString($$) 8147{ 8148 my ($dataPt, $pos) = @_; 8149 my $len = length $$dataPt; 8150 my $str = ''; 8151 while ($pos < $len) { 8152 my $ch = substr($$dataPt, $pos, 1); 8153 ++$pos; 8154 last if ord($ch) == 0; 8155 $str .= $ch; 8156 } 8157 $_[1] = $pos; # update current position 8158 return $str; 8159} 8160 8161#------------------------------------------------------------------------------ 8162# Get a printable version of the tag ID 8163# Inputs: 0) tag ID, 1) Flag: 0x01 - print as 4- or 8-digit hex value if necessary 8164# 0x02 - put leading backslash before escaped character 8165# Returns: Printable tag ID 8166sub PrintableTagID($;$) 8167{ 8168 my $tag = $_[0]; 8169 my $n = ($tag =~ s/([\x00-\x1f\x7f-\xff])/'x'.unpack('H*',$1)/eg); 8170 if ($n and $_[1]) { 8171 if ($n > 2 and $_[1] & 0x01) { 8172 $tag = '0x' . unpack('H8', $_[0]); 8173 $tag =~ s/^0x0000/0x/; 8174 } elsif ($_[1] & 0x02) { 8175 ($tag = $_[0]) =~ s/([\x00-\x1f\x7f-\xff])/'\\x'.unpack('H*',$1)/eg; 8176 } 8177 } 8178 return $tag; 8179} 8180 8181#============================================================================== 8182# The following ParseXxx routines parse various boxes to extract this 8183# information about embedded items in a $$et{ItemInfo} hash, keyed by item ID: 8184# 8185# iloc: 8186# ConstructionMethod - offset type: 0=file, 1=idat, 2=item 8187# DataReferenceIndex - 0 for "this file", otherwise index in dref box 8188# BaseOffset - base for file offsets 8189# Extents - list of details for data in file: 8190# 0) index (extent_index) 8191# 1) offset (extent_offset) 8192# 2) length (extent_length) 8193# 3) nlen (length_size) 8194# 4) lenPt (pointer to length word) 8195# infe: 8196# ProtectionIndex - index if item is protected (0 for unprotected) 8197# Name - item name 8198# ContentType - mime type of item 8199# ContentEncoding - item encoding 8200# URI - URI of a 'uri '-type item 8201# ipma: 8202# Association - list of associated properties in the ipco container 8203# Essential - list of "essential" flags for the associated properties 8204# cdsc: 8205# RefersTo - hash lookup of flags based on referred item ID 8206# other: 8207# DocNum - exiftool document number for this item 8208# 8209#------------------------------------------------------------------------------ 8210# Parse item location (iloc) box (ref ISO 14496-12:2015 pg.79) 8211# Inputs: 0) iloc data, 1) ExifTool ref 8212# Returns: undef, and fills in ExifTool ItemInfo hash 8213# Notes: see also Handle_iloc() in WriteQuickTime.pl 8214sub ParseItemLocation($$) 8215{ 8216 my ($val, $et) = @_; 8217 my ($i, $j, $num, $pos, $id); 8218 my ($extent_index, $extent_offset, $extent_length); 8219 8220 my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose'); 8221 my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { }); 8222 my $len = length $val; 8223 return undef if $len < 8; 8224 my $ver = Get8u(\$val, 0); 8225 my $siz = Get16u(\$val, 4); 8226 my $noff = ($siz >> 12); 8227 my $nlen = ($siz >> 8) & 0x0f; 8228 my $nbas = ($siz >> 4) & 0x0f; 8229 my $nind = $siz & 0x0f; 8230 if ($ver < 2) { 8231 $num = Get16u(\$val, 6); 8232 $pos = 8; 8233 } else { 8234 return undef if $len < 10; 8235 $num = Get32u(\$val, 6); 8236 $pos = 10; 8237 } 8238 for ($i=0; $i<$num; ++$i) { 8239 if ($ver < 2) { 8240 return undef if $pos + 2 > $len; 8241 $id = Get16u(\$val, $pos); 8242 $pos += 2; 8243 } else { 8244 return undef if $pos + 4 > $len; 8245 $id = Get32u(\$val, $pos); 8246 $pos += 4; 8247 } 8248 if ($ver == 1 or $ver == 2) { 8249 return undef if $pos + 2 > $len; 8250 $$items{$id}{ConstructionMethod} = Get16u(\$val, $pos) & 0x0f; 8251 $pos += 2; 8252 } 8253 return undef if $pos + 2 > $len; 8254 $$items{$id}{DataReferenceIndex} = Get16u(\$val, $pos); 8255 $pos += 2; 8256 $$items{$id}{BaseOffset} = GetVarInt(\$val, $pos, $nbas); 8257 return undef if $pos + 2 > $len; 8258 my $ext_num = Get16u(\$val, $pos); 8259 $pos += 2; 8260 my @extents; 8261 for ($j=0; $j<$ext_num; ++$j) { 8262 if ($ver == 1 or $ver == 2) { 8263 $extent_index = GetVarInt(\$val, $pos, $nind, 1); 8264 } 8265 $extent_offset = GetVarInt(\$val, $pos, $noff); 8266 $extent_length = GetVarInt(\$val, $pos, $nlen); 8267 return undef unless defined $extent_length; 8268 $et->VPrint(1, "$$et{INDENT} Item $id: const_meth=", 8269 defined $$items{$id}{ConstructionMethod} ? $$items{$id}{ConstructionMethod} : '', 8270 sprintf(" base=0x%x offset=0x%x len=0x%x\n", $$items{$id}{BaseOffset}, 8271 $extent_offset, $extent_length)) if $verbose; 8272 push @extents, [ $extent_index, $extent_offset, $extent_length, $nlen, $pos-$nlen ]; 8273 } 8274 # save item location information keyed on 1-based item ID: 8275 $$items{$id}{Extents} = \@extents; 8276 } 8277 return undef; 8278} 8279 8280#------------------------------------------------------------------------------ 8281# Parse content describes entry (cdsc) box 8282# Inputs: 0) cdsc data, 1) ExifTool ref 8283# Returns: undef, and fills in ExifTool ItemInfo hash 8284sub ParseContentDescribes($$) 8285{ 8286 my ($val, $et) = @_; 8287 my ($id, $count, @to); 8288 if ($$et{ItemRefVersion}) { 8289 return undef if length $val < 10; 8290 ($id, $count, @to) = unpack('NnN*', $val); 8291 } else { 8292 return undef if length $val < 6; 8293 ($id, $count, @to) = unpack('nnn*', $val); 8294 } 8295 if ($count > @to) { 8296 my $str = 'Missing values in ContentDescribes box'; 8297 $$et{IsWriting} ? $et->Error($str) : $et->Warn($str); 8298 } elsif ($count < @to) { 8299 $et->Warn('Ignored extra values in ContentDescribes box', 1); 8300 @to = $count; 8301 } 8302 # add all referenced item ID's to a "RefersTo" lookup 8303 $$et{ItemInfo}{$id}{RefersTo}{$_} = 1 foreach @to; 8304 return undef; 8305} 8306 8307#------------------------------------------------------------------------------ 8308# Parse item information entry (infe) box (ref ISO 14496-12:2015 pg.82) 8309# Inputs: 0) infe data, 1) ExifTool ref 8310# Returns: undef, and fills in ExifTool ItemInfo hash 8311sub ParseItemInfoEntry($$) 8312{ 8313 my ($val, $et) = @_; 8314 my $id; 8315 8316 my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose'); 8317 my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { }); 8318 my $len = length $val; 8319 return undef if $len < 4; 8320 my $ver = Get8u(\$val, 0); 8321 my $pos = 4; 8322 return undef if $pos + 4 > $len; 8323 if ($ver == 0 or $ver == 1) { 8324 $id = Get16u(\$val, $pos); 8325 $$items{$id}{ProtectionIndex} = Get16u(\$val, $pos + 2); 8326 $pos += 4; 8327 $$items{$id}{Name} = GetString(\$val, $pos); 8328 $$items{$id}{ContentType} = GetString(\$val, $pos); 8329 $$items{$id}{ContentEncoding} = GetString(\$val, $pos); 8330 } else { 8331 if ($ver == 2) { 8332 $id = Get16u(\$val, $pos); 8333 $pos += 2; 8334 } elsif ($ver == 3) { 8335 $id = Get32u(\$val, $pos); 8336 $pos += 4; 8337 } 8338 return undef if $pos + 6 > $len; 8339 $$items{$id}{ProtectionIndex} = Get16u(\$val, $pos); 8340 my $type = substr($val, $pos + 2, 4); 8341 $$items{$id}{Type} = $type; 8342 $pos += 6; 8343 $$items{$id}{Name} = GetString(\$val, $pos); 8344 if ($type eq 'mime') { 8345 $$items{$id}{ContentType} = GetString(\$val, $pos); 8346 $$items{$id}{ContentEncoding} = GetString(\$val, $pos); 8347 } elsif ($type eq 'uri ') { 8348 $$items{$id}{URI} = GetString(\$val, $pos); 8349 } 8350 } 8351 $et->VPrint(1, "$$et{INDENT} Item $id: Type=", $$items{$id}{Type} || '', 8352 ' Name=', $$items{$id}{Name} || '', 8353 ' ContentType=', $$items{$id}{ContentType} || '', 8354 "\n") if $verbose > 1; 8355 return undef; 8356} 8357 8358#------------------------------------------------------------------------------ 8359# Parse item property association (ipma) box (ref https://github.com/gpac/gpac/blob/master/src/isomedia/iff.c) 8360# Inputs: 0) ipma data, 1) ExifTool ref 8361# Returns: undef, and fills in ExifTool ItemInfo hash 8362sub ParseItemPropAssoc($$) 8363{ 8364 my ($val, $et) = @_; 8365 my ($i, $j, $id); 8366 8367 my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose'); 8368 my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { }); 8369 my $len = length $val; 8370 return undef if $len < 8; 8371 my $ver = Get8u(\$val, 0); 8372 my $flg = Get32u(\$val, 0); 8373 my $num = Get32u(\$val, 4); 8374 my $pos = 8; 8375 for ($i=0; $i<$num; ++$i) { 8376 if ($ver == 0) { 8377 return undef if $pos + 3 > $len; 8378 $id = Get16u(\$val, $pos); 8379 $pos += 2; 8380 } else { 8381 return undef if $pos + 5 > $len; 8382 $id = Get32u(\$val, $pos); 8383 $pos += 4; 8384 } 8385 my $n = Get8u(\$val, $pos++); 8386 my (@association, @essential); 8387 if ($flg & 0x01) { 8388 return undef if $pos + $n * 2 > $len; 8389 for ($j=0; $j<$n; ++$j) { 8390 my $tmp = Get16u(\$val, $pos + $j * 2); 8391 push @association, $tmp & 0x7fff; 8392 push @essential, ($tmp & 0x8000) ? 1 : 0; 8393 } 8394 $pos += $n * 2; 8395 } else { 8396 return undef if $pos + $n > $len; 8397 for ($j=0; $j<$n; ++$j) { 8398 my $tmp = Get8u(\$val, $pos + $j); 8399 push @association, $tmp & 0x7f; 8400 push @essential, ($tmp & 0x80) ? 1 : 0; 8401 } 8402 $pos += $n; 8403 } 8404 $$items{$id}{Association} = \@association; 8405 $$items{$id}{Essential} = \@essential; 8406 $et->VPrint(1, "$$et{INDENT} Item $id properties: @association\n") if $verbose > 1; 8407 } 8408 return undef; 8409} 8410 8411#------------------------------------------------------------------------------ 8412# Process item information now 8413# Inputs: 0) ExifTool ref 8414sub HandleItemInfo($) 8415{ 8416 my $et = shift; 8417 my $raf = $$et{RAF}; 8418 my $items = $$et{ItemInfo}; 8419 my $verbose = $et->Options('Verbose'); 8420 my $buff; 8421 8422 # extract information from EXIF/XMP metadata items 8423 if ($items and $raf) { 8424 push @{$$et{PATH}}, 'ItemInformation'; 8425 my $curPos = $raf->Tell(); 8426 my $primary = $$et{PrimaryItem}; 8427 my $id; 8428 $et->VerboseDir('Processing items from ItemInformation', scalar(keys %$items)); 8429 foreach $id (sort { $a <=> $b } keys %$items) { 8430 my $item = $$items{$id}; 8431 my $type = $$item{ContentType} || $$item{Type} || next; 8432 if ($verbose) { 8433 # add up total length of this item for the verbose output 8434 my $len = 0; 8435 if ($$item{Extents} and @{$$item{Extents}}) { 8436 $len += $$_[2] foreach @{$$item{Extents}}; 8437 } 8438 $et->VPrint(0, "$$et{INDENT}Item $id) '${type}' ($len bytes)\n"); 8439 } 8440 # get ExifTool name for this item 8441 my $name = { Exif => 'EXIF', 'application/rdf+xml' => 'XMP' }->{$type} || ''; 8442 my ($warn, $extent); 8443 $warn = "Can't currently decode encoded $type metadata" if $$item{ContentEncoding}; 8444 $warn = "Can't currently decode protected $type metadata" if $$item{ProtectionIndex}; 8445 $warn = "Can't currently extract $type with construction method $$item{ConstructionMethod}" if $$item{ConstructionMethod}; 8446 $et->WarnOnce($warn) if $warn and $name; 8447 $warn = 'Not this file' if $$item{DataReferenceIndex}; # (can only extract from "this file") 8448 unless (($$item{Extents} and @{$$item{Extents}}) or $warn) { 8449 $warn = "No Extents for $type item"; 8450 $et->WarnOnce($warn) if $name; 8451 } 8452 if ($warn) { 8453 $et->VPrint(0, "$$et{INDENT} [not extracted] ($warn)\n") if $verbose > 2; 8454 next; 8455 } 8456 my $base = $$item{BaseOffset} || 0; 8457 if ($verbose > 2) { 8458 # do verbose hex dump 8459 my $len = 0; 8460 undef $buff; 8461 my $val = ''; 8462 my $maxLen = $verbose > 3 ? 2048 : 96; 8463 foreach $extent (@{$$item{Extents}}) { 8464 my $n = $$extent[2]; 8465 my $more = $maxLen - $len; 8466 if ($more > 0 and $n) { 8467 $more = $n if $more > $n; 8468 $val .= $buff if defined $buff; 8469 $raf->Seek($$extent[1] + $base, 0) or last; 8470 $raf->Read($buff, $more) or last; 8471 } 8472 $len += $n; 8473 } 8474 if (defined $buff) { 8475 $buff = $val . $buff if length $val; 8476 $et->VerboseDump(\$buff, DataPos => $$item{Extents}[0][1] + $base); 8477 my $snip = $len - length $buff; 8478 $et->VPrint(0, "$$et{INDENT} [snip $snip bytes]\n") if $snip; 8479 } 8480 } 8481 next unless $name; 8482 # assemble the data for this item 8483 undef $buff; 8484 my $val = ''; 8485 foreach $extent (@{$$item{Extents}}) { 8486 $val .= $buff if defined $buff; 8487 $raf->Seek($$extent[1] + $base, 0) or last; 8488 $raf->Read($buff, $$extent[2]) or last; 8489 } 8490 next unless defined $buff; 8491 $buff = $val . $buff if length $val; 8492 next unless length $buff; # ignore empty directories 8493 my ($start, $subTable, $proc); 8494 my $pos = $$item{Extents}[0][1] + $base; 8495 if ($name eq 'EXIF' and length $buff >= 4) { 8496 if ($buff =~ /^(MM\0\x2a|II\x2a\0)/) { 8497 $et->Warn('Missing Exif header'); 8498 $start = 0; 8499 } elsif ($buff =~ /^Exif\0\0/) { 8500 # (haven't seen this yet, but it is just a matter of time 8501 # until someone screws it up like this) 8502 $et->Warn('Missing Exif header size'); 8503 $start = 6; 8504 } else { 8505 my $n = unpack('N', $buff); 8506 $start = 4 + $n; # skip "Exif\0\0" header if it exists 8507 if ($start > length($buff)) { 8508 $et->Warn('Invalid EXIF header'); 8509 next; 8510 } 8511 if ($$et{HTML_DUMP}) { 8512 $et->HDump($pos, 4, 'Exif header length', "Value: $n"); 8513 $et->HDump($pos+4, $start-4, 'Exif header') if $n; 8514 } 8515 } 8516 $subTable = GetTagTable('Image::ExifTool::Exif::Main'); 8517 $proc = \&Image::ExifTool::ProcessTIFF; 8518 } else { 8519 $start = 0; 8520 $subTable = GetTagTable('Image::ExifTool::XMP::Main'); 8521 } 8522 my %dirInfo = ( 8523 DataPt => \$buff, 8524 DataLen => length $buff, 8525 DirStart => $start, 8526 DirLen => length($buff) - $start, 8527 DataPos => $pos, 8528 Base => $pos + $start, # (needed for HtmlDump and IsOffset tags in binary data) 8529 ); 8530 # handle processing of metadata for sub-documents 8531 if (defined $primary and $$item{RefersTo} and not $$item{RefersTo}{$primary}) { 8532 # set document number if this doesn't refer to the primary document 8533 $$et{DOC_NUM} = ++$$et{DOC_COUNT}; 8534 # associate this document number with the lowest item index 8535 my ($lowest) = sort { $a <=> $b } keys %{$$item{RefersTo}}; 8536 $$items{$lowest}{DocNum} = $$et{DOC_NUM}; 8537 } 8538 $et->ProcessDirectory(\%dirInfo, $subTable, $proc); 8539 delete $$et{DOC_NUM}; 8540 } 8541 $raf->Seek($curPos, 0); # seek back to original position 8542 pop @{$$et{PATH}}; 8543 } 8544 # process the item properties now that we should know their associations and document numbers 8545 if ($$et{ItemPropertyContainer}) { 8546 my ($dirInfo, $subTable, $proc) = @{$$et{ItemPropertyContainer}}; 8547 $$et{IsItemProperty} = 1; # set item property flag 8548 $et->ProcessDirectory($dirInfo, $subTable, $proc); 8549 delete $$et{ItemPropertyContainer}; 8550 delete $$et{IsItemProperty}; 8551 delete $$et{DOC_NUM}; 8552 } 8553 delete $$et{ItemInfo}; 8554} 8555 8556#------------------------------------------------------------------------------ 8557# Warn if ExtractEmbedded option isn't used 8558# Inputs: 0) ExifTool ref 8559sub EEWarn($) 8560{ 8561 my $et = shift; 8562 $et->WarnOnce('The ExtractEmbedded option may find more tags in the media data',3); 8563} 8564 8565#------------------------------------------------------------------------------ 8566# Get quicktime format from flags word 8567# Inputs: 0) quicktime atom flags, 1) data length 8568# Returns: ExifTool format string 8569sub QuickTimeFormat($$) 8570{ 8571 my ($flags, $len) = @_; 8572 my $format; 8573 if ($flags == 0x15 or $flags == 0x16) { 8574 $format = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len}; 8575 $format .= $flags == 0x15 ? 's' : 'u' if $format; 8576 } elsif ($flags == 0x17) { 8577 $format = 'float'; 8578 } elsif ($flags == 0x18) { 8579 $format = 'double'; 8580 } elsif ($flags == 0x00) { 8581 $format = { 1=>'int8u', 2=>'int16u' }->{$len}; 8582 } 8583 return $format; 8584} 8585 8586#------------------------------------------------------------------------------ 8587# Process MPEG-4 MTDT atom (ref 11) 8588# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8589# Returns: 1 on success 8590sub ProcessMetaData($$$) 8591{ 8592 my ($et, $dirInfo, $tagTablePtr) = @_; 8593 my $dataPt = $$dirInfo{DataPt}; 8594 my $dirLen = length $$dataPt; 8595 my $verbose = $et->Options('Verbose'); 8596 return 0 unless $dirLen >= 2; 8597 my $count = Get16u($dataPt, 0); 8598 $verbose and $et->VerboseDir('MetaData', $count); 8599 my $i; 8600 my $pos = 2; 8601 for ($i=0; $i<$count; ++$i) { 8602 last if $pos + 10 > $dirLen; 8603 my $size = Get16u($dataPt, $pos); 8604 last if $size < 10 or $size + $pos > $dirLen; 8605 my $tag = Get32u($dataPt, $pos + 2); 8606 my $lang = Get16u($dataPt, $pos + 6); 8607 my $enc = Get16u($dataPt, $pos + 8); 8608 my $val = substr($$dataPt, $pos + 10, $size); 8609 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 8610 if ($tagInfo) { 8611 # convert language code to ASCII (ignore read-only bit) 8612 $lang = UnpackLang($lang); 8613 # handle alternate languages 8614 if ($lang) { 8615 my $langInfo = GetLangInfoQT($et, $tagInfo, $lang); 8616 $tagInfo = $langInfo if $langInfo; 8617 } 8618 $verbose and $et->VerboseInfo($tag, $tagInfo, 8619 Value => $val, 8620 DataPt => $dataPt, 8621 Start => $pos + 10, 8622 Size => $size - 10, 8623 ); 8624 # convert from UTF-16 BE if necessary 8625 $val = $et->Decode($val, 'UCS2') if $enc == 1; 8626 if ($enc == 0 and $$tagInfo{Unknown}) { 8627 # binary data 8628 $et->FoundTag($tagInfo, \$val); 8629 } else { 8630 $et->FoundTag($tagInfo, $val); 8631 } 8632 } 8633 $pos += $size; 8634 } 8635 return 1; 8636} 8637 8638#------------------------------------------------------------------------------ 8639# Process sample description table 8640# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8641# Returns: 1 on success 8642# (ref https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25691) 8643sub ProcessSampleDesc($$$) 8644{ 8645 my ($et, $dirInfo, $tagTablePtr) = @_; 8646 my $dataPt = $$dirInfo{DataPt}; 8647 my $pos = $$dirInfo{DirStart} || 0; 8648 my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $pos); 8649 return 0 if $pos + 8 > $dirLen; 8650 8651 my $num = Get32u($dataPt, 4); # get number of sample entries in table 8652 $pos += 8; 8653 my $i; 8654 for ($i=0; $i<$num; ++$i) { # loop through sample entries 8655 last if $pos + 8 > $dirLen; 8656 my $size = Get32u($dataPt, $pos); 8657 last if $pos + $size > $dirLen; 8658 $$dirInfo{DirStart} = $pos; 8659 $$dirInfo{DirLen} = $size; 8660 ProcessHybrid($et, $dirInfo, $tagTablePtr); 8661 $pos += $size; 8662 } 8663 return 1; 8664} 8665 8666#------------------------------------------------------------------------------ 8667# Process hybrid binary data + QuickTime container (ref PH) 8668# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8669# Returns: 1 on success 8670sub ProcessHybrid($$$) 8671{ 8672 my ($et, $dirInfo, $tagTablePtr) = @_; 8673 # brute-force search for child atoms after first 8 bytes of binary data 8674 my $dataPt = $$dirInfo{DataPt}; 8675 my $dirStart = $$dirInfo{DirStart} || 0; 8676 my $dirLen = $$dirInfo{DirLen} || length($$dataPt) - $dirStart; 8677 my $end = $dirStart + $dirLen; 8678 my $pos = $dirStart + 8; # skip length/version 8679 my $try = $pos; 8680 my $childPos; 8681 8682 while ($pos <= $end - 8) { 8683 my $tag = substr($$dataPt, $try+4, 4); 8684 # look only for well-behaved tag ID's 8685 $tag =~ /[^\w ]/ and $try = ++$pos, next; 8686 my $size = Get32u($dataPt, $try); 8687 if ($size + $try == $end) { 8688 # the atom ends exactly at the end of the parent -- this must be it 8689 $childPos = $pos; 8690 $$dirInfo{DirLen} = $pos; # the binary data ends at the first child atom 8691 last; 8692 } 8693 if ($size < 8 or $size + $try > $end - 8) { 8694 $try = ++$pos; # fail. try next position 8695 } else { 8696 $try += $size; # could be another atom following this 8697 } 8698 } 8699 # process binary data 8700 $$dirInfo{MixedTags} = 1; # ignore non-integer tag ID's 8701 $et->ProcessBinaryData($dirInfo, $tagTablePtr); 8702 # process child atoms if found 8703 if ($childPos) { 8704 $$dirInfo{DirStart} = $childPos; 8705 $$dirInfo{DirLen} = $end - $childPos; 8706 ProcessMOV($et, $dirInfo, $tagTablePtr); 8707 } 8708 return 1; 8709} 8710 8711#------------------------------------------------------------------------------ 8712# Process iTunes 'righ' atom (ref PH) 8713# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8714# Returns: 1 on success 8715sub ProcessRights($$$) 8716{ 8717 my ($et, $dirInfo, $tagTablePtr) = @_; 8718 my $dataPt = $$dirInfo{DataPt}; 8719 my $dataPos = $$dirInfo{Base}; 8720 my $dirLen = length $$dataPt; 8721 my $unknown = $$et{OPTIONS}{Unknown} || $$et{OPTIONS}{Verbose}; 8722 my $pos; 8723 $et->VerboseDir('righ', $dirLen / 8); 8724 for ($pos = 0; $pos + 8 <= $dirLen; $pos += 8) { 8725 my $tag = substr($$dataPt, $pos, 4); 8726 last if $tag eq "\0\0\0\0"; 8727 my $val = substr($$dataPt, $pos + 4, 4); 8728 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 8729 unless ($tagInfo) { 8730 next unless $unknown; 8731 my $name = PrintableTagID($tag); 8732 $tagInfo = { 8733 Name => "Unknown_$name", 8734 Description => "Unknown $name", 8735 Unknown => 1, 8736 }, 8737 AddTagToTable($tagTablePtr, $tag, $tagInfo); 8738 } 8739 $val = '0x' . unpack('H*', $val) unless $$tagInfo{Format}; 8740 $et->HandleTag($tagTablePtr, $tag, $val, 8741 DataPt => $dataPt, 8742 DataPos => $dataPos, 8743 Start => $pos + 4, 8744 Size => 4, 8745 ); 8746 } 8747 return 1; 8748} 8749 8750#------------------------------------------------------------------------------ 8751# Process iTunes Encoding Params (ref PH) 8752# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8753# Returns: 1 on success 8754sub ProcessEncodingParams($$$) 8755{ 8756 my ($et, $dirInfo, $tagTablePtr) = @_; 8757 my $dataPt = $$dirInfo{DataPt}; 8758 my $dirLen = length $$dataPt; 8759 my $pos; 8760 $et->VerboseDir('Encoding Params', $dirLen / 8); 8761 for ($pos = 0; $pos + 8 <= $dirLen; $pos += 8) { 8762 my ($tag, $val) = unpack("x${pos}a4N", $$dataPt); 8763 $et->HandleTag($tagTablePtr, $tag, $val); 8764 } 8765 return 1; 8766} 8767 8768#------------------------------------------------------------------------------ 8769# Read Meta Keys and add tags to ItemList table ('mdta' handler) (ref PH) 8770# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8771# Returns: 1 on success 8772sub ProcessKeys($$$) 8773{ 8774 local $_; 8775 my ($et, $dirInfo, $tagTablePtr) = @_; 8776 my $dataPt = $$dirInfo{DataPt}; 8777 my $dirLen = length $$dataPt; 8778 my $out; 8779 if ($et->Options('Verbose')) { 8780 $et->VerboseDir('Keys'); 8781 $out = $et->Options('TextOut'); 8782 } 8783 my $pos = 8; 8784 my $index = 1; 8785 ++$$et{KeysCount}; # increment key count for this directory 8786 my $itemList = GetTagTable('Image::ExifTool::QuickTime::ItemList'); 8787 my $userData = GetTagTable('Image::ExifTool::QuickTime::UserData'); 8788 while ($pos < $dirLen - 4) { 8789 my $len = unpack("x${pos}N", $$dataPt); 8790 last if $len < 8 or $pos + $len > $dirLen; 8791 delete $$tagTablePtr{$index}; 8792 my $ns = substr($$dataPt, $pos + 4, 4); 8793 my $tag = substr($$dataPt, $pos + 8, $len - 8); 8794 $tag =~ s/\0.*//s; # truncate at null 8795 $tag =~ s/^com\.(apple\.quicktime\.)?// if $ns eq 'mdta'; # remove apple quicktime domain 8796 $tag = "Tag_$ns" unless $tag; 8797 # (I have some samples where the tag is a reversed ItemList or UserData tag ID) 8798 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 8799 unless ($tagInfo) { 8800 $tagInfo = $et->GetTagInfo($itemList, $tag); 8801 unless ($tagInfo) { 8802 $tagInfo = $et->GetTagInfo($userData, $tag); 8803 if (not $tagInfo and $tag =~ /^\w{3}\xa9$/) { 8804 $tag = pack('N', unpack('V', $tag)); 8805 $tagInfo = $et->GetTagInfo($itemList, $tag); 8806 $tagInfo or $tagInfo = $et->GetTagInfo($userData, $tag); 8807 } 8808 } 8809 } 8810 my ($newInfo, $msg); 8811 if ($tagInfo) { 8812 # copy tag information into new Keys tag 8813 $newInfo = { 8814 Name => $$tagInfo{Name}, 8815 Format => $$tagInfo{Format}, 8816 ValueConv => $$tagInfo{ValueConv}, 8817 ValueConvInv => $$tagInfo{ValueConvInv}, 8818 PrintConv => $$tagInfo{PrintConv}, 8819 PrintConvInv => $$tagInfo{PrintConvInv}, 8820 Writable => defined $$tagInfo{Writable} ? $$tagInfo{Writable} : 1, 8821 SubDirectory => $$tagInfo{SubDirectory}, 8822 }; 8823 my $groups = $$tagInfo{Groups}; 8824 $$newInfo{Groups} = $groups ? { %$groups } : { }; 8825 $$newInfo{Groups}{$_} or $$newInfo{Groups}{$_} = $$tagTablePtr{GROUPS}{$_} foreach 0..2; 8826 $$newInfo{Groups}{1} = 'Keys'; 8827 } elsif ($tag =~ /^[-\w. ]+$/ or $tag =~ /\w{4}/) { 8828 # create info for tags with reasonable id's 8829 my $name = ucfirst $tag; 8830 $name =~ tr/-0-9a-zA-Z_. //dc; 8831 $name =~ s/[. ]+(.?)/\U$1/g; 8832 $name =~ s/_([a-z])/_\U$1/g; 8833 $name =~ s/([a-z])_([A-Z])/$1$2/g; 8834 $name = "Tag_$name" if length $name < 2; 8835 $newInfo = { Name => $name, Groups => { 1 => 'Keys' } }; 8836 $msg = ' (Unknown)'; 8837 } 8838 # substitute this tag in the ItemList table with the given index 8839 my $id = $$et{KeysCount} . '.' . $index; 8840 if (ref $$itemList{$id} eq 'HASH') { 8841 # delete other languages too if they exist 8842 my $oldInfo = $$itemList{$id}; 8843 if ($$oldInfo{OtherLang}) { 8844 delete $$itemList{$_} foreach @{$$oldInfo{OtherLang}}; 8845 } 8846 delete $$itemList{$id}; 8847 } 8848 if ($newInfo) { 8849 AddTagToTable($itemList, $id, $newInfo); 8850 $msg or $msg = ''; 8851 $out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $tag$msg\n"; 8852 } 8853 $pos += $len; 8854 ++$index; 8855 } 8856 return 1; 8857} 8858 8859#------------------------------------------------------------------------------ 8860# Process keys in MetaSampleDesc directory 8861# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 8862# Returns: 1 on success 8863sub ProcessMetaKeys($$$) 8864{ 8865 my ($et, $dirInfo, $tagTablePtr) = @_; 8866 # save this information to decode timed metadata samples when ExtractEmbedded is used 8867 SaveMetaKeys($et, $dirInfo, $tagTablePtr) if $$et{OPTIONS}{ExtractEmbedded}; 8868 return 1; 8869} 8870 8871#------------------------------------------------------------------------------ 8872# Process a QuickTime atom 8873# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) optional tag table ref 8874# Returns: 1 on success 8875sub ProcessMOV($$;$) 8876{ 8877 local $_; 8878 my ($et, $dirInfo, $tagTablePtr) = @_; 8879 my $raf = $$dirInfo{RAF}; 8880 my $dataPt = $$dirInfo{DataPt}; 8881 my $verbose = $et->Options('Verbose'); 8882 my $validate = $$et{OPTIONS}{Validate}; 8883 my $dataPos = $$dirInfo{Base} || 0; 8884 my $dirID = $$dirInfo{DirID} || ''; 8885 my $charsetQuickTime = $et->Options('CharsetQuickTime'); 8886 my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index); 8887 my ($dirEnd, $ee, $unkOpt, %saveOptions, $atomCount); 8888 8889 my $topLevel = not $$et{InQuickTime}; 8890 $$et{InQuickTime} = 1; 8891 $$et{HandlerType} = $$et{MetaFormat} = '' unless defined $$et{HandlerType}; 8892 8893 unless (defined $$et{KeysCount}) { 8894 $$et{KeysCount} = 0; # initialize ItemList key directory count 8895 $doDefaultLang = 1; # flag to generate default language tags 8896 } 8897 # more convenient to package data as a RandomAccess file 8898 unless ($raf) { 8899 $raf = new File::RandomAccess($dataPt); 8900 $dirEnd = $dataPos + $$dirInfo{DirLen} + ($$dirInfo{DirStart} || 0) if $$dirInfo{DirLen}; 8901 } 8902 # skip leading bytes if necessary 8903 if ($$dirInfo{DirStart}) { 8904 $raf->Seek($$dirInfo{DirStart}, 1) or return 0; 8905 $dataPos += $$dirInfo{DirStart}; 8906 } 8907 # read size/tag name atom header 8908 $raf->Read($buff,8) == 8 or return 0; 8909 $dataPos += 8; 8910 if ($tagTablePtr) { 8911 $isUserData = ($tagTablePtr eq \%Image::ExifTool::QuickTime::UserData); 8912 } else { 8913 $tagTablePtr = GetTagTable('Image::ExifTool::QuickTime::Main'); 8914 } 8915 ($size, $tag) = unpack('Na4', $buff); 8916 if ($dataPt) { 8917 $verbose and $et->VerboseDir($$dirInfo{DirName}); 8918 } else { 8919 # check on file type if called with a RAF 8920 $$tagTablePtr{$tag} or return 0; 8921 if ($tag eq 'ftyp' and $size >= 12) { 8922 # read ftyp atom to see what type of file this is 8923 my $fileType; 8924 if ($raf->Read($buff, $size-8) == $size-8) { 8925 $raf->Seek(-($size-8), 1); 8926 my $type = substr($buff, 0, 4); 8927 # see if we know the extension for this file type 8928 if ($ftypLookup{$type} and $ftypLookup{$type} =~ /\(\.(\w+)/) { 8929 $fileType = $1; 8930 # check compatible brands 8931 } elsif ($buff =~ /^.{8}(.{4})+(mp41|mp42|avc1)/s) { 8932 $fileType = 'MP4'; 8933 } elsif ($buff =~ /^.{8}(.{4})+(f4v )/s) { 8934 $fileType = 'F4V'; 8935 } elsif ($buff =~ /^.{8}(.{4})+(qt )/s) { 8936 $fileType = 'MOV'; 8937 } 8938 } 8939 $fileType or $fileType = 'MP4'; # default to MP4 8940 $et->SetFileType($fileType, $mimeLookup{$fileType} || 'video/mp4'); 8941 # temporarily set ExtractEmbedded option for CRX files 8942 $saveOptions{ExtractEmbedded} = $et->Options(ExtractEmbedded => 1) if $fileType eq 'CRX'; 8943 } else { 8944 $et->SetFileType(); # MOV 8945 } 8946 SetByteOrder('MM'); 8947 $$et{PRIORITY_DIR} = 'XMP'; # have XMP take priority 8948 } 8949 $$raf{NoBuffer} = 1 if $et->Options('FastScan'); # disable buffering in FastScan mode 8950 8951 if ($$et{OPTIONS}{ExtractEmbedded}) { 8952 $ee = 1; 8953 $unkOpt = $$et{OPTIONS}{Unknown}; 8954 require 'Image/ExifTool/QuickTimeStream.pl'; 8955 } 8956 if ($$tagTablePtr{VARS}) { 8957 $index = $$tagTablePtr{VARS}{START_INDEX}; 8958 $atomCount = $$tagTablePtr{VARS}{ATOM_COUNT}; 8959 } 8960 for (;;) { 8961 my ($eeTag, $ignore); 8962 last if defined $atomCount and --$atomCount < 0; 8963 if ($size < 8) { 8964 if ($size == 0) { 8965 if ($dataPt) { 8966 # a zero size isn't legal for contained atoms, but Canon uses it to 8967 # terminate the CNTH atom (eg. CanonEOS100D.mov), so tolerate it here 8968 my $pos = $raf->Tell() - 4; 8969 $raf->Seek(0,2); 8970 my $str = $$dirInfo{DirName} . ' with ' . ($raf->Tell() - $pos) . ' bytes'; 8971 $et->VPrint(0,"$$et{INDENT}\[Terminator found in $str remaining]"); 8972 } else { 8973 my $t = PrintableTagID($tag,2); 8974 $et->VPrint(0,"$$et{INDENT}Tag '${t}' extends to end of file"); 8975 } 8976 last; 8977 } 8978 $size == 1 or $et->Warn('Invalid atom size'), last; 8979 # read extended atom size 8980 $raf->Read($buff, 8) == 8 or $et->Warn('Truncated atom header'), last; 8981 $dataPos += 8; 8982 my ($hi, $lo) = unpack('NN', $buff); 8983 if ($hi or $lo > 0x7fffffff) { 8984 if ($hi > 0x7fffffff) { 8985 $et->Warn('Invalid atom size'); 8986 last; 8987 } elsif (not $et->Options('LargeFileSupport')) { 8988 $et->Warn('End of processing at large atom (LargeFileSupport not enabled)'); 8989 last; 8990 } 8991 } 8992 $size = $hi * 4294967296 + $lo - 16; 8993 $size < 0 and $et->Warn('Invalid extended size'), last; 8994 } else { 8995 $size -= 8; 8996 } 8997 if ($validate) { 8998 $$et{ValidatePath} or $$et{ValidatePath} = { }; 8999 my $path = join('-', @{$$et{PATH}}, $tag); 9000 $path =~ s/-Track-/-$$et{SET_GROUP1}-/ if $$et{SET_GROUP1}; 9001 if ($$et{ValidatePath}{$path} and not $dupTagOK{$tag} and not $dupDirOK{$dirID}) { 9002 my $i = Get32u(\$tag,0); 9003 my $str = $i < 255 ? "index $i" : "tag '" . PrintableTagID($tag,2) . "'"; 9004 $et->WarnOnce("Duplicate $str at " . join('-', @{$$et{PATH}})); 9005 $$et{ValidatePath} = { } if $path eq 'MOV-moov'; # avoid warnings for all contained dups 9006 } 9007 $$et{ValidatePath}{$path} = 1; 9008 } 9009 if ($isUserData and $$et{SET_GROUP1}) { 9010 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 9011 # add track name to UserData tags inside tracks 9012 $tag = $$et{SET_GROUP1} . $tag; 9013 if (not $$tagTablePtr{$tag} and $tagInfo) { 9014 my %newInfo = %$tagInfo; 9015 foreach ('Name', 'Description') { 9016 next unless $$tagInfo{$_}; 9017 $newInfo{$_} = $$et{SET_GROUP1} . $$tagInfo{$_}; 9018 $newInfo{$_} =~ s/^(Track\d+)Track/$1/; # remove duplicate "Track" in name 9019 } 9020 AddTagToTable($tagTablePtr, $tag, \%newInfo); 9021 } 9022 } 9023 # set flag to store additional information for ExtractEmbedded option 9024 my $handlerType = $$et{HandlerType}; 9025 if ($eeBox{$handlerType} and $eeBox{$handlerType}{$tag}) { 9026 if ($ee) { 9027 # (there is another 'gps ' box with a track log that doesn't contain offsets) 9028 if ($tag ne 'gps ' or $eeBox{$handlerType}{$tag} eq $dirID) { 9029 $eeTag = 1; 9030 $$et{OPTIONS}{Unknown} = 1; # temporarily enable "Unknown" option 9031 } 9032 } elsif ($handlerType ne 'vide' and not $$et{OPTIONS}{Validate}) { 9033 EEWarn($et); 9034 } 9035 } 9036 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 9037 9038 $$et{OPTIONS}{Unknown} = $unkOpt if $eeTag; # restore Unknown option 9039 9040 # allow numerical tag ID's 9041 unless ($tagInfo) { 9042 my $id = $$et{KeysCount} . '.' . unpack('N', $tag); 9043 if ($$tagTablePtr{$id}) { 9044 $tagInfo = $et->GetTagInfo($tagTablePtr, $id); 9045 $tag = $id; 9046 } 9047 } 9048 # generate tagInfo if Unknown option set 9049 if (not defined $tagInfo and ($$et{OPTIONS}{Unknown} or 9050 $verbose or $tag =~ /^\xa9/)) 9051 { 9052 my $name = PrintableTagID($tag,1); 9053 if ($name =~ /^xa9(.*)/) { 9054 $tagInfo = { 9055 Name => "UserData_$1", 9056 Description => "User Data $1", 9057 }; 9058 } else { 9059 $tagInfo = { 9060 Name => "Unknown_$name", 9061 Description => "Unknown $name", 9062 %unknownInfo, 9063 }; 9064 } 9065 AddTagToTable($tagTablePtr, $tag, $tagInfo); 9066 } 9067 # save required tag sizes 9068 if ($$tagTablePtr{"$tag-size"}) { 9069 $et->HandleTag($tagTablePtr, "$tag-size", $size); 9070 $et->HandleTag($tagTablePtr, "$tag-offset", $raf->Tell()) if $$tagTablePtr{"$tag-offset"}; 9071 } 9072 # load values only if associated with a tag (or verbose) and not too big 9073 if ($size > 0x2000000) { # start to get worried above 32 MB 9074 # check for RIFF trailer (written by Auto-Vox dashcam) 9075 if ($buff =~ /^(gpsa|gps0|gsen|gsea)...\0/s) { # (yet seen only gpsa as first record) 9076 $et->VPrint(0, "Found RIFF trailer"); 9077 if ($et->Options('ExtractEmbedded')) { 9078 $raf->Seek(-8, 1) or last; # seek back to start of trailer 9079 my $tbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); 9080 ProcessRIFFTrailer($et, { RAF => $raf }, $tbl); 9081 } else { 9082 EEWarn($et); 9083 } 9084 last; 9085 } 9086 $ignore = 1; 9087 if ($tagInfo and not $$tagInfo{Unknown} and not $eeTag) { 9088 my $t = PrintableTagID($tag,2); 9089 if ($size > 0x8000000) { 9090 $et->Warn("Skipping '${t}' atom > 128 MB", 1); 9091 } else { 9092 $et->Warn("Skipping '${t}' atom > 32 MB", 2) or $ignore = 0; 9093 } 9094 } 9095 } 9096 if (defined $tagInfo and not $ignore) { 9097 # set document number for this item property if necessary 9098 if ($$et{IsItemProperty}) { 9099 my $items = $$et{ItemInfo}; 9100 my ($id, $prop, $docNum, $lowest); 9101 my $primary = $$et{PrimaryItem} || 0; 9102ItemID: foreach $id (keys %$items) { 9103 next unless $$items{$id}{Association}; 9104 my $item = $$items{$id}; 9105 foreach $prop (@{$$item{Association}}) { 9106 next unless $prop == $index; 9107 if ($id == $primary or (not $dontInherit{$tag} and 9108 (not $$item{RefersTo} or $$item{RefersTo}{$primary}))) 9109 { 9110 # this is associated with the primary item or an item describing 9111 # the primary item, so consider this part of the main document 9112 undef $docNum; 9113 undef $lowest; 9114 last ItemID; 9115 } elsif ($$item{DocNum}) { 9116 # this property is already associated with an item that has 9117 # an ExifTool document number, so use the lowest associated DocNum 9118 $docNum = $$item{DocNum} if not defined $docNum or $docNum > $$item{DocNum}; 9119 } elsif (not defined $lowest or $lowest > $id) { 9120 # keep track of the lowest associated item ID 9121 $lowest = $id; 9122 } 9123 } 9124 } 9125 if (not defined $docNum and defined $lowest) { 9126 # this is the first time we've seen metadata from this item, 9127 # so use a new document number 9128 $docNum = ++$$et{DOC_COUNT}; 9129 $$items{$lowest}{DocNum} = $docNum; 9130 } 9131 $$et{DOC_NUM} = $docNum; 9132 } 9133 my $val; 9134 my $missing = $size - $raf->Read($val, $size); 9135 if ($missing) { 9136 my $t = PrintableTagID($tag,2); 9137 $et->Warn("Truncated '${t}' data (missing $missing bytes)"); 9138 last; 9139 } 9140 # use value to get tag info if necessary 9141 $tagInfo or $tagInfo = $et->GetTagInfo($tagTablePtr, $tag, \$val); 9142 my $hasData = ($$dirInfo{HasData} and $val =~ /\0...data\0/s); 9143 if ($verbose and not $hasData) { 9144 my $tval; 9145 if ($tagInfo and $$tagInfo{Format}) { 9146 $tval = ReadValue(\$val, 0, $$tagInfo{Format}, $$tagInfo{Count}, length($val)); 9147 } 9148 $et->VerboseInfo($tag, $tagInfo, 9149 Value => $tval, 9150 DataPt => \$val, 9151 DataPos => $dataPos, 9152 Size => $size, 9153 Format => $tagInfo ? $$tagInfo{Format} : undef, 9154 Index => $index, 9155 ); 9156 # print iref item ID numbers 9157 if ($dirID eq 'iref') { 9158 my ($id, $count, @to, $i); 9159 if ($$et{ItemRefVersion}) { 9160 ($id, $count, @to) = unpack('NnN*', $val) if length $val >= 10; 9161 } else { 9162 ($id, $count, @to) = unpack('nnn*', $val) if length $val >= 6; 9163 } 9164 defined $id or $id = '<err>', $count = 0; 9165 $id .= " (wrong count: $count)" if $count != @to; 9166 # convert sequential numbers to a range 9167 for ($i=1; $i<@to; ) { 9168 $to[$i-1] =~ /(\d+)$/ and $to[$i] == $1 + 1 or ++$i, next; 9169 $to[$i-1] =~ s/(-.*)?$/-$to[$i]/; 9170 splice @to, $i, 1; 9171 } 9172 $et->VPrint(1, "$$et{INDENT} Item $id refers to: ",join(',',@to),"\n"); 9173 } 9174 } 9175 # extract metadata from stream if ExtractEmbedded option is enabled 9176 if ($eeTag) { 9177 ParseTag($et, $tag, \$val); 9178 # forget this tag if we generated it only for ExtractEmbedded 9179 undef $tagInfo if $tagInfo and $$tagInfo{Unknown} and not $unkOpt; 9180 } 9181 9182 # handle iTunesInfo mean/name/data triplets 9183 if ($tagInfo and $$tagInfo{Triplet}) { 9184 if ($tag eq 'data' and $triplet{mean} and $triplet{name}) { 9185 $tag = $triplet{name}; 9186 # add 'mean' to name unless it is 'com.apple.iTunes' 9187 $tag = $triplet{mean} . '/' . $tag unless $triplet{mean} eq 'com.apple.iTunes'; 9188 $tagInfo = $et->GetTagInfo($tagTablePtr, $tag, \$val); 9189 unless ($tagInfo) { 9190 my $name = $triplet{name}; 9191 my $desc = $name; 9192 $name =~ tr/-_a-zA-Z0-9//dc; 9193 $desc =~ tr/_/ /; 9194 $tagInfo = { 9195 Name => $name, 9196 Description => $desc, 9197 }; 9198 AddTagToTable($tagTablePtr, $tag, $tagInfo); 9199 } 9200 # ignore 8-byte header 9201 $val = substr($val, 8) if length($val) >= 8; 9202 unless ($$tagInfo{Format} or $$tagInfo{SubDirectory}) { 9203 # extract as binary if it contains any non-ASCII or control characters 9204 if ($val =~ /[^\x20-\x7e]/) { 9205 my $buff = $val; 9206 $val = \$buff; 9207 } 9208 } 9209 undef %triplet; 9210 } else { 9211 undef %triplet if $tag eq 'mean'; 9212 $triplet{$tag} = substr($val,4) if length($val) > 4; 9213 undef $tagInfo; # don't store this tag 9214 } 9215 } 9216 if ($tagInfo) { 9217 my $subdir = $$tagInfo{SubDirectory}; 9218 if ($subdir) { 9219 my $start = $$subdir{Start} || 0; 9220 my ($base, $dPos) = ($dataPos, 0); 9221 if ($$subdir{Base}) { 9222 $dPos -= eval $$subdir{Base}; 9223 $base -= $dPos; 9224 } 9225 my %dirInfo = ( 9226 DataPt => \$val, 9227 DataLen => $size, 9228 DirStart => $start, 9229 DirLen => $size - $start, 9230 DirName => $$subdir{DirName} || $$tagInfo{Name}, 9231 DirID => $tag, 9232 HasData => $$subdir{HasData}, 9233 Multi => $$subdir{Multi}, 9234 IgnoreProp => $$subdir{IgnoreProp}, # (XML hack) 9235 DataPos => $dPos, 9236 Base => $base, # (needed for IsOffset tags in binary data) 9237 ); 9238 $dirInfo{BlockInfo} = $tagInfo if $$tagInfo{BlockExtract}; 9239 if ($$subdir{ByteOrder} and $$subdir{ByteOrder} =~ /^Little/) { 9240 SetByteOrder('II'); 9241 } 9242 my $oldGroup1 = $$et{SET_GROUP1}; 9243 if ($$tagInfo{SubDirectory} and $$tagInfo{SubDirectory}{TagTable} and 9244 $$tagInfo{SubDirectory}{TagTable} eq 'Image::ExifTool::QuickTime::Track') 9245 { 9246 $track or $track = 0; 9247 $$et{SET_GROUP1} = 'Track' . (++$track); 9248 } 9249 my $subTable = GetTagTable($$subdir{TagTable}); 9250 my $proc = $$subdir{ProcessProc}; 9251 # make ProcessMOV() the default processing procedure for subdirectories 9252 $proc = \&ProcessMOV unless $proc or $$subTable{PROCESS_PROC}; 9253 if ($size > $start) { 9254 # delay processing of ipco box until after all other boxes 9255 if ($tag eq 'ipco' and not $$et{IsItemProperty}) { 9256 $$et{ItemPropertyContainer} = [ \%dirInfo, $subTable, $proc ]; 9257 $et->VPrint(0,"$$et{INDENT}\[Process ipco box later]"); 9258 } else { 9259 $et->ProcessDirectory(\%dirInfo, $subTable, $proc); 9260 } 9261 } 9262 if ($tag eq 'stbl') { 9263 # process sample data when exiting SampleTable box if extracting embedded 9264 ProcessSamples($et) if $ee; 9265 } elsif ($tag eq 'minf') { 9266 $$et{HandlerType} = ''; # reset handler type at end of media info box 9267 } 9268 $$et{SET_GROUP1} = $oldGroup1; 9269 SetByteOrder('MM'); 9270 } elsif ($hasData) { 9271 # handle atoms containing 'data' tags 9272 # (currently ignore contained atoms: 'itif', 'name', etc.) 9273 my $pos = 0; 9274 for (;;) { 9275 last if $pos + 16 > $size; 9276 my ($len, $type, $flags, $ctry, $lang) = unpack("x${pos}Na4Nnn", $val); 9277 last if $pos + $len > $size; 9278 my ($value, $langInfo, $oldDir); 9279 my $format = $$tagInfo{Format}; 9280 if ($type eq 'data' and $len >= 16) { 9281 $pos += 16; 9282 $len -= 16; 9283 $value = substr($val, $pos, $len); 9284 # format flags (ref 12): 9285 # 0x0=binary, 0x1=UTF-8, 0x2=UTF-16, 0x3=ShiftJIS, 9286 # 0x4=UTF-8 0x5=UTF-16, 0xd=JPEG, 0xe=PNG, 9287 # 0x15=signed int, 0x16=unsigned int, 0x17=float, 9288 # 0x18=double, 0x1b=BMP, 0x1c='meta' atom 9289 if ($stringEncoding{$flags}) { 9290 # handle all string formats 9291 $value = $et->Decode($value, $stringEncoding{$flags}); 9292 # (shouldn't be null terminated, but some software writes it anyway) 9293 $value =~ s/\0$// unless $$tagInfo{Binary}; 9294 } else { 9295 $format = QuickTimeFormat($flags, $len) unless $format; 9296 if ($format) { 9297 $value = ReadValue(\$value, 0, $format, $$tagInfo{Count}, $len); 9298 } elsif (not $$tagInfo{ValueConv}) { 9299 # make binary data a scalar reference unless a ValueConv exists 9300 my $buf = $value; 9301 $value = \$buf; 9302 } 9303 } 9304 } 9305 if ($ctry or $lang) { 9306 my $langCode = GetLangCode($lang, $ctry); 9307 if ($langCode) { 9308 # get tagInfo for other language 9309 $langInfo = GetLangInfoQT($et, $tagInfo, $langCode); 9310 # save other language tag ID's so we can delete later if necessary 9311 if ($langInfo) { 9312 $$tagInfo{OtherLang} or $$tagInfo{OtherLang} = [ ]; 9313 push @{$$tagInfo{OtherLang}}, $$langInfo{TagID}; 9314 } 9315 } 9316 } 9317 $langInfo or $langInfo = $tagInfo; 9318 $et->VerboseInfo($tag, $langInfo, 9319 Value => ref $value ? $$value : $value, 9320 DataPt => \$val, 9321 DataPos => $dataPos, 9322 Start => $pos, 9323 Size => $len, 9324 Format => $format, 9325 Index => $index, 9326 Extra => sprintf(", Type='${type}', Flags=0x%x, Lang=0x%.4x",$flags,$lang), 9327 ) if $verbose; 9328 # use "Keys" in path instead of ItemList if this was defined by a Keys tag 9329 my $isKey = $$tagInfo{Groups} && $$tagInfo{Groups}{1} && $$tagInfo{Groups}{1} eq 'Keys'; 9330 if ($isKey) { 9331 $oldDir = $$et{PATH}[-1]; 9332 $$et{PATH}[-1] = 'Keys'; 9333 } 9334 $et->FoundTag($langInfo, $value) if defined $value; 9335 $$et{PATH}[-1] = $oldDir if $isKey; 9336 $pos += $len; 9337 } 9338 } elsif ($tag =~ /^\xa9/ or $$tagInfo{IText}) { 9339 # parse international text to extract all languages 9340 my $pos = 0; 9341 if ($$tagInfo{Format}) { 9342 $et->FoundTag($tagInfo, ReadValue(\$val, 0, $$tagInfo{Format}, undef, length($val))); 9343 $pos = $size; 9344 } 9345 for (;;) { 9346 my ($len, $lang); 9347 if ($$tagInfo{IText} and $$tagInfo{IText} == 6) { 9348 last if $pos + 6 > $size; 9349 $pos += 4; 9350 $lang = unpack("x${pos}n", $val); 9351 $pos += 2; 9352 $len = $size - $pos; 9353 } else { 9354 last if $pos + 4 > $size; 9355 ($len, $lang) = unpack("x${pos}nn", $val); 9356 $pos += 4; 9357 # according to the QuickTime spec (ref 12), $len should include 9358 # 4 bytes for length and type words, but nobody (including 9359 # Apple, Pentax and Kodak) seems to add these in, so try 9360 # to allow for either 9361 if ($pos + $len > $size) { 9362 $len -= 4; 9363 last if $pos + $len > $size or $len < 0; 9364 } 9365 } 9366 # ignore any empty entries (or null padding) after the first 9367 next if not $len and $pos; 9368 my $str = substr($val, $pos, $len); 9369 my $langInfo; 9370 if (($lang < 0x400 or $lang == 0x7fff) and $str !~ /^\xfe\xff/) { 9371 # this is a Macintosh language code 9372 # a language code of 0 is Macintosh english, so treat as default 9373 if ($lang) { 9374 if ($lang == 0x7fff) { 9375 # technically, ISO 639-2 doesn't have a 2-character 9376 # equivalent for 'und', but use 'un' anyway 9377 $lang = 'un'; 9378 } else { 9379 # use Font.pm to look up language string 9380 require Image::ExifTool::Font; 9381 $lang = $Image::ExifTool::Font::ttLang{Macintosh}{$lang}; 9382 } 9383 } 9384 # the spec says only "Macintosh text encoding", but 9385 # allow this to be configured by the user 9386 $str = $et->Decode($str, $charsetQuickTime); 9387 } else { 9388 # convert language code to ASCII (ignore read-only bit) 9389 $lang = UnpackLang($lang); 9390 # may be either UTF-8 or UTF-16BE 9391 my $enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8'; 9392 $str = $et->Decode($str, $enc); 9393 } 9394 $str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags) 9395 $langInfo = GetLangInfoQT($et, $tagInfo, $lang) if $lang; 9396 $et->FoundTag($langInfo || $tagInfo, $str); 9397 $pos += $len; 9398 } 9399 } else { 9400 my $format = $$tagInfo{Format}; 9401 if ($format) { 9402 $val = ReadValue(\$val, 0, $format, $$tagInfo{Count}, length($val)); 9403 } 9404 my $oldBase; 9405 if ($$tagInfo{SetBase}) { 9406 $oldBase = $$et{BASE}; 9407 $$et{BASE} = $dataPos; 9408 } 9409 my $key = $et->FoundTag($tagInfo, $val); 9410 $$et{BASE} = $oldBase if defined $oldBase; 9411 # decode if necessary (NOTE: must be done after RawConv) 9412 if (defined $key and (not $format or $format =~ /^string/) and 9413 not $$tagInfo{Unknown} and not $$tagInfo{ValueConv} and 9414 not $$tagInfo{Binary} and defined $$et{VALUE}{$key} and not ref $val) 9415 { 9416 my $vp = \$$et{VALUE}{$key}; 9417 if (not ref $$vp and length($$vp) <= 65536 and $$vp =~ /[\x80-\xff]/) { 9418 # the encoding of this is not specified, so use CharsetQuickTime 9419 # unless the string is valid UTF-8 9420 require Image::ExifTool::XMP; 9421 my $enc = Image::ExifTool::XMP::IsUTF8($vp) > 0 ? 'UTF8' : $charsetQuickTime; 9422 $$vp = $et->Decode($$vp, $enc); 9423 } 9424 } 9425 } 9426 } 9427 } else { 9428 $et->VerboseInfo($tag, $tagInfo, 9429 Size => $size, 9430 Extra => sprintf(' at offset 0x%.4x', $raf->Tell()), 9431 ) if $verbose; 9432 if ($size and (not $raf->Seek($size-1, 1) or $raf->Read($buff, 1) != 1)) { 9433 my $t = PrintableTagID($tag,2); 9434 $et->Warn("Truncated '${t}' data"); 9435 last; 9436 } 9437 } 9438 $dataPos += $size + 8; # point to start of next atom data 9439 last if $dirEnd and $dataPos >= $dirEnd; # (note: ignores last value if 0 bytes) 9440 $raf->Read($buff, 8) == 8 or last; 9441 ($size, $tag) = unpack('Na4', $buff); 9442 ++$index if defined $index; 9443 } 9444 # fill in missing defaults for alternate language tags 9445 # (the first language is taken as the default) 9446 if ($doDefaultLang and $$et{QTLang}) { 9447QTLang: foreach $tag (@{$$et{QTLang}}) { 9448 next unless defined $$et{VALUE}{$tag}; 9449 my $langInfo = $$et{TAG_INFO}{$tag} or next; 9450 my $tagInfo = $$langInfo{SrcTagInfo} or next; 9451 my $infoHash = $$et{TAG_INFO}; 9452 my $name = $$tagInfo{Name}; 9453 # loop through all instances of this tag name and generate the default-language 9454 # version only if we don't already have a QuickTime tag with this name 9455 my ($i, $key); 9456 for ($i=0, $key=$name; $$infoHash{$key}; ++$i, $key="$name ($i)") { 9457 next QTLang if $et->GetGroup($key, 0) eq 'QuickTime'; 9458 } 9459 $et->FoundTag($tagInfo, $$et{VALUE}{$tag}); 9460 } 9461 delete $$et{QTLang}; 9462 } 9463 # process item information now that we are done processing its 'meta' container 9464 HandleItemInfo($et) if $topLevel or $dirID eq 'meta'; 9465 9466 ScanMediaData($et) if $ee and $topLevel; # brute force scan for metadata embedded in media data 9467 9468 # restore any changed options 9469 $et->Options($_ => $saveOptions{$_}) foreach keys %saveOptions; 9470 return 1; 9471} 9472 9473#------------------------------------------------------------------------------ 9474# Process a QuickTime Image File 9475# Inputs: 0) ExifTool object reference, 1) directory information reference 9476# Returns: 1 on success 9477sub ProcessQTIF($$) 9478{ 9479 my ($et, $dirInfo) = @_; 9480 my $table = GetTagTable('Image::ExifTool::QuickTime::ImageFile'); 9481 return ProcessMOV($et, $dirInfo, $table); 9482} 9483 94841; # end 9485 9486__END__ 9487 9488=head1 NAME 9489 9490Image::ExifTool::QuickTime - Read QuickTime and MP4 meta information 9491 9492=head1 SYNOPSIS 9493 9494This module is used by Image::ExifTool 9495 9496=head1 DESCRIPTION 9497 9498This module contains routines required by Image::ExifTool to extract 9499information from QuickTime and MP4 video, M4A audio, and HEIC image files. 9500 9501=head1 AUTHOR 9502 9503Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com) 9504 9505This library is free software; you can redistribute it and/or modify it 9506under the same terms as Perl itself. 9507 9508=head1 REFERENCES 9509 9510=over 4 9511 9512=item L<http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html> 9513 9514=item L<http://search.cpan.org/dist/MP4-Info-1.04/> 9515 9516=item L<http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt> 9517 9518=item L<http://wiki.multimedia.cx/index.php?title=Apple_QuickTime> 9519 9520=item L<http://atomicparsley.sourceforge.net/mpeg-4files.html> 9521 9522=item L<http://wiki.multimedia.cx/index.php?title=QuickTime_container> 9523 9524=item L<http://code.google.com/p/mp4v2/wiki/iTunesMetadata> 9525 9526=item L<http://www.canieti.com.mx/assets/files/1011/IEC_100_1384_DC.pdf> 9527 9528=item L<http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v10.pdf> 9529 9530=back 9531 9532=head1 SEE ALSO 9533 9534L<Image::ExifTool::TagNames/QuickTime Tags>, 9535L<Image::ExifTool(3pm)|Image::ExifTool> 9536 9537=cut 9538 9539