File Coverage

blib/lib/Image/ExifTool/QuickTime.pm
Criterion Covered Total %
statement 645 999 64.5
branch 335 712 47.0
condition 174 382 45.5
subroutine 29 39 74.3
pod 0 32 0.0
total 1183 2164 54.6


line stmt bran cond sub pod time code
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              
42             package Image::ExifTool::QuickTime;
43              
44 30     30   6275 use strict;
  30         212  
  30         1219  
45 30     30   184 use vars qw($VERSION $AUTOLOAD %stringEncoding);
  30         74  
  30         1834  
46 30     30   203 use Image::ExifTool qw(:DataAccess :Utils);
  30         69  
  30         6687  
47 30     30   2895 use Image::ExifTool::Exif;
  30         189  
  30         901  
48 30     30   1829 use Image::ExifTool::GPS;
  30         77  
  30         447006  
49              
50             $VERSION = '2.80';
51              
52             sub ProcessMOV($$;$);
53             sub ProcessKeys($$$);
54             sub ProcessMetaKeys($$$);
55             sub ProcessMetaData($$$);
56             sub ProcessEncodingParams($$$);
57             sub ProcessSampleDesc($$$);
58             sub ProcessHybrid($$$);
59             sub ProcessRights($$$);
60             # ++vvvvvvvvvvvv++ (in QuickTimeStream.pl)
61             sub Process_mebx($$$);
62             sub Process_3gf($$$);
63             sub Process_gps0($$$);
64             sub Process_gsen($$$);
65             sub ProcessRIFFTrailer($$$);
66             sub ProcessTTAD($$$);
67             sub ProcessNMEA($$$);
68             sub ProcessGPSLog($$$);
69             sub ProcessGarminGPS($$$);
70             sub SaveMetaKeys($$$);
71             # ++^^^^^^^^^^^^++
72             sub ParseItemLocation($$);
73             sub ParseContentDescribes($$);
74             sub ParseItemInfoEntry($$);
75             sub ParseItemPropAssoc($$);
76             sub FixWrongFormat($);
77             sub GetMatrixStructure($$);
78             sub ConvertISO6709($);
79             sub ConvInvISO6709($);
80             sub ConvertChapterList($);
81             sub PrintChapter($);
82             sub PrintGPSCoordinates($);
83             sub PrintInvGPSCoordinates($);
84             sub UnpackLang($;$);
85             sub WriteKeys($$$);
86             sub WriteQuickTime($$$);
87             sub WriteMOV($$);
88             sub GetLangInfo($$);
89             sub CheckQTValue($$$);
90              
91             # MIME types for all entries in the ftypLookup with file extensions
92             # (defaults to 'video/mp4' if not found in this lookup)
93             my %mimeLookup = (
94             '3G2' => 'video/3gpp2',
95             '3GP' => 'video/3gpp',
96             AAX => 'audio/vnd.audible.aax',
97             DVB => 'video/vnd.dvb.file',
98             F4A => 'audio/mp4',
99             F4B => 'audio/mp4',
100             JP2 => 'image/jp2',
101             JPM => 'image/jpm',
102             JPX => 'image/jpx',
103             M4A => 'audio/mp4',
104             M4B => 'audio/mp4',
105             M4P => 'audio/mp4',
106             M4V => 'video/x-m4v',
107             MOV => 'video/quicktime',
108             MQV => 'video/quicktime',
109             HEIC => 'image/heic',
110             HEVC => 'image/heic-sequence',
111             HEICS=> 'image/heic-sequence',
112             HEIF => 'image/heif',
113             HEIFS=> 'image/heif-sequence',
114             AVIF => 'image/avif', #PH (NC)
115             CRX => 'video/x-canon-crx', # (will get overridden)
116             );
117              
118             # look up file type from ftyp atom type, with MIME type in comment if known
119             # (ref http://www.ftyps.com/)
120             my %ftypLookup = (
121             '3g2a' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-0 V1.0', # video/3gpp2
122             '3g2b' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-A V1.0.0', # video/3gpp2
123             '3g2c' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-B v1.0', # video/3gpp2
124             '3ge6' => '3GPP (.3GP) Release 6 MBMS Extended Presentations', # video/3gpp
125             '3ge7' => '3GPP (.3GP) Release 7 MBMS Extended Presentations', # video/3gpp
126             '3gg6' => '3GPP Release 6 General Profile', # video/3gpp
127             '3gp1' => '3GPP Media (.3GP) Release 1 (probably non-existent)', # video/3gpp
128             '3gp2' => '3GPP Media (.3GP) Release 2 (probably non-existent)', # video/3gpp
129             '3gp3' => '3GPP Media (.3GP) Release 3 (probably non-existent)', # video/3gpp
130             '3gp4' => '3GPP Media (.3GP) Release 4', # video/3gpp
131             '3gp5' => '3GPP Media (.3GP) Release 5', # video/3gpp
132             '3gp6' => '3GPP Media (.3GP) Release 6 Basic Profile', # video/3gpp
133             '3gp6' => '3GPP Media (.3GP) Release 6 Progressive Download', # video/3gpp
134             '3gp6' => '3GPP Media (.3GP) Release 6 Streaming Servers', # video/3gpp
135             '3gs7' => '3GPP Media (.3GP) Release 7 Streaming Servers', # video/3gpp
136             'aax ' => 'Audible Enhanced Audiobook (.AAX)', #PH
137             'avc1' => 'MP4 Base w/ AVC ext [ISO 14496-12:2005]', # video/mp4
138             'CAEP' => 'Canon Digital Camera',
139             'caqv' => 'Casio Digital Camera',
140             'CDes' => 'Convergent Design',
141             'da0a' => 'DMB MAF w/ MPEG Layer II aud, MOT slides, DLS, JPG/PNG/MNG images',
142             'da0b' => 'DMB MAF, extending DA0A, with 3GPP timed text, DID, TVA, REL, IPMP',
143             'da1a' => 'DMB MAF audio with ER-BSAC audio, JPG/PNG/MNG images',
144             'da1b' => 'DMB MAF, extending da1a, with 3GPP timed text, DID, TVA, REL, IPMP',
145             'da2a' => 'DMB MAF aud w/ HE-AAC v2 aud, MOT slides, DLS, JPG/PNG/MNG images',
146             'da2b' => 'DMB MAF, extending da2a, with 3GPP timed text, DID, TVA, REL, IPMP',
147             'da3a' => 'DMB MAF aud with HE-AAC aud, JPG/PNG/MNG images',
148             'da3b' => 'DMB MAF, extending da3a w/ BIFS, 3GPP timed text, DID, TVA, REL, IPMP',
149             'dmb1' => 'DMB MAF supporting all the components defined in the specification',
150             'dmpf' => 'Digital Media Project', # various
151             'drc1' => 'Dirac (wavelet compression), encapsulated in ISO base media (MP4)',
152             'dv1a' => 'DMB MAF vid w/ AVC vid, ER-BSAC aud, BIFS, JPG/PNG/MNG images, TS',
153             'dv1b' => 'DMB MAF, extending dv1a, with 3GPP timed text, DID, TVA, REL, IPMP',
154             'dv2a' => 'DMB MAF vid w/ AVC vid, HE-AAC v2 aud, BIFS, JPG/PNG/MNG images, TS',
155             'dv2b' => 'DMB MAF, extending dv2a, with 3GPP timed text, DID, TVA, REL, IPMP',
156             'dv3a' => 'DMB MAF vid w/ AVC vid, HE-AAC aud, BIFS, JPG/PNG/MNG images, TS',
157             'dv3b' => 'DMB MAF, extending dv3a, with 3GPP timed text, DID, TVA, REL, IPMP',
158             'dvr1' => 'DVB (.DVB) over RTP', # video/vnd.dvb.file
159             'dvt1' => 'DVB (.DVB) over MPEG-2 Transport Stream', # video/vnd.dvb.file
160             'F4A ' => 'Audio for Adobe Flash Player 9+ (.F4A)', # audio/mp4
161             'F4B ' => 'Audio Book for Adobe Flash Player 9+ (.F4B)', # audio/mp4
162             'F4P ' => 'Protected Video for Adobe Flash Player 9+ (.F4P)', # video/mp4
163             'F4V ' => 'Video for Adobe Flash Player 9+ (.F4V)', # video/mp4
164             'isc2' => 'ISMACryp 2.0 Encrypted File', # ?/enc-isoff-generic
165             'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4 (or audio)
166             'iso3' => 'MP4 Base Media v3', # video/mp4 (or audio)
167             'iso4' => 'MP4 Base Media v4', # video/mp4 (or audio)
168             'iso5' => 'MP4 Base Media v5', # video/mp4 (or audio)
169             'iso6' => 'MP4 Base Media v6', # video/mp4 (or audio)
170             'iso7' => 'MP4 Base Media v7', # video/mp4 (or audio)
171             'iso8' => 'MP4 Base Media v8', # video/mp4 (or audio)
172             'iso9' => 'MP4 Base Media v9', # video/mp4 (or audio)
173             'isom' => 'MP4 Base Media v1 [IS0 14496-12:2003]', # video/mp4 (or audio)
174             'JP2 ' => 'JPEG 2000 Image (.JP2) [ISO 15444-1 ?]', # image/jp2
175             'JP20' => 'Unknown, from GPAC samples (prob non-existent)',
176             'jpm ' => 'JPEG 2000 Compound Image (.JPM) [ISO 15444-6]', # image/jpm
177             'jpx ' => 'JPEG 2000 with extensions (.JPX) [ISO 15444-2]', # image/jpx
178             'KDDI' => '3GPP2 EZmovie for KDDI 3G cellphones', # video/3gpp2
179             #LCAG => (found in CompatibleBrands of Leica MOV videos)
180             'M4A ' => 'Apple iTunes AAC-LC (.M4A) Audio', # audio/x-m4a
181             'M4B ' => 'Apple iTunes AAC-LC (.M4B) Audio Book', # audio/mp4
182             'M4P ' => 'Apple iTunes AAC-LC (.M4P) AES Protected Audio', # audio/mp4
183             'M4V ' => 'Apple iTunes Video (.M4V) Video', # video/x-m4v
184             'M4VH' => 'Apple TV (.M4V)', # video/x-m4v
185             'M4VP' => 'Apple iPhone (.M4V)', # video/x-m4v
186             'mj2s' => 'Motion JPEG 2000 [ISO 15444-3] Simple Profile', # video/mj2
187             'mjp2' => 'Motion JPEG 2000 [ISO 15444-3] General Profile', # video/mj2
188             'mmp4' => 'MPEG-4/3GPP Mobile Profile (.MP4/3GP) (for NTT)', # video/mp4
189             'mp21' => 'MPEG-21 [ISO/IEC 21000-9]', # various
190             'mp41' => 'MP4 v1 [ISO 14496-1:ch13]', # video/mp4
191             'mp42' => 'MP4 v2 [ISO 14496-14]', # video/mp4
192             'mp71' => 'MP4 w/ MPEG-7 Metadata [per ISO 14496-12]', # various
193             'MPPI' => 'Photo Player, MAF [ISO/IEC 23000-3]', # various
194             'mqt ' => 'Sony / Mobile QuickTime (.MQV) US Patent 7,477,830 (Sony Corp)', # video/quicktime
195             'MSNV' => 'MPEG-4 (.MP4) for SonyPSP', # audio/mp4
196             'NDAS' => 'MP4 v2 [ISO 14496-14] Nero Digital AAC Audio', # audio/mp4
197             'NDSC' => 'MPEG-4 (.MP4) Nero Cinema Profile', # video/mp4
198             'NDSH' => 'MPEG-4 (.MP4) Nero HDTV Profile', # video/mp4
199             'NDSM' => 'MPEG-4 (.MP4) Nero Mobile Profile', # video/mp4
200             'NDSP' => 'MPEG-4 (.MP4) Nero Portable Profile', # video/mp4
201             'NDSS' => 'MPEG-4 (.MP4) Nero Standard Profile', # video/mp4
202             'NDXC' => 'H.264/MPEG-4 AVC (.MP4) Nero Cinema Profile', # video/mp4
203             'NDXH' => 'H.264/MPEG-4 AVC (.MP4) Nero HDTV Profile', # video/mp4
204             'NDXM' => 'H.264/MPEG-4 AVC (.MP4) Nero Mobile Profile', # video/mp4
205             'NDXP' => 'H.264/MPEG-4 AVC (.MP4) Nero Portable Profile', # video/mp4
206             'NDXS' => 'H.264/MPEG-4 AVC (.MP4) Nero Standard Profile', # video/mp4
207             'odcf' => 'OMA DCF DRM Format 2.0 (OMA-TS-DRM-DCF-V2_0-20060303-A)', # various
208             'opf2' => 'OMA PDCF DRM Format 2.1 (OMA-TS-DRM-DCF-V2_1-20070724-C)',
209             'opx2' => 'OMA PDCF DRM + XBS extensions (OMA-TS-DRM_XBS-V1_0-20070529-C)',
210             'pana' => 'Panasonic Digital Camera',
211             'qt ' => 'Apple QuickTime (.MOV/QT)', # video/quicktime
212             'ROSS' => 'Ross Video',
213             'sdv ' => 'SD Memory Card Video', # various?
214             'ssc1' => 'Samsung stereoscopic, single stream',
215             'ssc2' => 'Samsung stereoscopic, dual stream',
216             'XAVC' => 'Sony XAVC', #PH
217             'heic' => 'High Efficiency Image Format HEVC still image (.HEIC)', # image/heic
218             'hevc' => 'High Efficiency Image Format HEVC sequence (.HEICS)', # image/heic-sequence
219             'mif1' => 'High Efficiency Image Format still image (.HEIF)', # image/heif
220             'msf1' => 'High Efficiency Image Format sequence (.HEIFS)', # image/heif-sequence
221             'heix' => 'High Efficiency Image Format still image (.HEIF)', # image/heif (ref PH, Canon 1DXmkIII)
222             'avif' => 'AV1 Image File Format (.AVIF)', # image/avif
223             'crx ' => 'Canon Raw (.CRX)', #PH (CR3 or CRM; use Canon CompressorVersion to decide)
224             );
225              
226             # information for int32u date/time tags (time zero is Jan 1, 1904)
227             my %timeInfo = (
228             Notes => 'converted from UTC to local time if the QuickTimeUTC option is set',
229             Shift => 'Time',
230             Writable => 1,
231             Permanent => 1,
232             DelValue => 0,
233             # It is not uncommon for brain-dead software to use the wrong time zero, it should be
234             # Jan 1, 1904, so assume a time zero of Jan 1, 1970 if the date is before this
235             # Note: This value will be in UTC if generated by a system that is aware of the time zone
236             # (also note: this code is duplicated for the CreateDate tag)
237             RawConv => q{
238             my $offset = (66 * 365 + 17) * 24 * 3600;
239             return $val - $offset if $val >= $offset or $$self{OPTIONS}{QuickTimeUTC};
240             if ($val and not $$self{IsWriting}) {
241             $self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1);
242             }
243             return $val;
244             },
245             RawConvInv => q{
246             if ($$self{FileType} eq 'CR3' and not $self->Options('QuickTimeUTC')) {
247             # convert to UTC
248             my $offset = (66 * 365 + 17) * 24 * 3600;
249             $val = ConvertUnixTime($val - $offset);
250             $val = GetUnixTime($val, 1) + $offset;
251             }
252             return $val;
253             },
254             # (all CR3 files store UTC times - PH)
255             ValueConv => 'ConvertUnixTime($val, $self->Options("QuickTimeUTC") || $$self{FileType} eq "CR3")',
256             ValueConvInv => q{
257             $val = GetUnixTime($val, $self->Options("QuickTimeUTC"));
258             return undef unless defined $val;
259             return $val + (66 * 365 + 17) * 24 * 3600;
260             },
261             PrintConv => '$self->ConvertDateTime($val)',
262             PrintConvInv => '$self->InverseDateTime($val)',
263             # (can't put Groups here because they aren't constant!)
264             );
265             # information for duration tags
266             my %durationInfo = (
267             ValueConv => '$$self{TimeScale} ? $val / $$self{TimeScale} : $val',
268             PrintConv => '$$self{TimeScale} ? ConvertDuration($val) : $val',
269             );
270             # handle unknown tags
271             my %unknownInfo = (
272             Unknown => 1,
273             ValueConv => '$val =~ /^([\x20-\x7e]*)\0*$/ ? $1 : \$val',
274             );
275              
276             # multi-language text with 6-byte header
277             my %langText = ( IText => 6 );
278              
279             # parsing for most of the 3gp udta language text boxes
280             my %langText3gp = (
281             Notes => 'used in 3gp videos',
282             Avoid => 1,
283             IText => 6,
284             );
285              
286             # 4-character Vendor ID codes (ref PH)
287             my %vendorID = (
288             appl => 'Apple',
289             fe20 => 'Olympus (fe20)', # (FE200)
290             FFMP => 'FFmpeg',
291             'GIC '=> 'General Imaging Co.',
292             kdak => 'Kodak',
293             KMPI => 'Konica-Minolta',
294             leic => 'Leica',
295             mino => 'Minolta',
296             niko => 'Nikon',
297             NIKO => 'Nikon',
298             olym => 'Olympus',
299             pana => 'Panasonic',
300             pent => 'Pentax',
301             pr01 => 'Olympus (pr01)', # (FE100,FE110,FE115)
302             sany => 'Sanyo',
303             'SMI '=> 'Sorenson Media Inc.',
304             ZORA => 'Zoran Corporation',
305             'AR.D'=> 'Parrot AR.Drone',
306             ' KD '=> 'Kodak', # (FZ201)
307             );
308              
309             # QuickTime data atom encodings for string types (ref 12)
310             %stringEncoding = (
311             1 => 'UTF8',
312             2 => 'UTF16',
313             3 => 'ShiftJIS',
314             4 => 'UTF8',
315             5 => 'UTF16',
316             );
317              
318             my %graphicsMode = (
319             # (ref http://homepage.mac.com/vanhoek/MovieGuts%20docs/64.html)
320             0x00 => 'srcCopy',
321             0x01 => 'srcOr',
322             0x02 => 'srcXor',
323             0x03 => 'srcBic',
324             0x04 => 'notSrcCopy',
325             0x05 => 'notSrcOr',
326             0x06 => 'notSrcXor',
327             0x07 => 'notSrcBic',
328             0x08 => 'patCopy',
329             0x09 => 'patOr',
330             0x0a => 'patXor',
331             0x0b => 'patBic',
332             0x0c => 'notPatCopy',
333             0x0d => 'notPatOr',
334             0x0e => 'notPatXor',
335             0x0f => 'notPatBic',
336             0x20 => 'blend',
337             0x21 => 'addPin',
338             0x22 => 'addOver',
339             0x23 => 'subPin',
340             0x24 => 'transparent',
341             0x25 => 'addMax',
342             0x26 => 'subOver',
343             0x27 => 'addMin',
344             0x31 => 'grayishTextOr',
345             0x32 => 'hilite',
346             0x40 => 'ditherCopy',
347             # the following ref ISO/IEC 15444-3
348             0x100 => 'Alpha',
349             0x101 => 'White Alpha',
350             0x102 => 'Pre-multiplied Black Alpha',
351             0x110 => 'Component Alpha',
352             );
353              
354             my %channelLabel = (
355             0xFFFFFFFF => 'Unknown',
356             0 => 'Unused',
357             100 => 'UseCoordinates',
358             1 => 'Left',
359             2 => 'Right',
360             3 => 'Center',
361             4 => 'LFEScreen',
362             5 => 'LeftSurround',
363             6 => 'RightSurround',
364             7 => 'LeftCenter',
365             8 => 'RightCenter',
366             9 => 'CenterSurround',
367             10 => 'LeftSurroundDirect',
368             11 => 'RightSurroundDirect',
369             12 => 'TopCenterSurround',
370             13 => 'VerticalHeightLeft',
371             14 => 'VerticalHeightCenter',
372             15 => 'VerticalHeightRight',
373             16 => 'TopBackLeft',
374             17 => 'TopBackCenter',
375             18 => 'TopBackRight',
376             33 => 'RearSurroundLeft',
377             34 => 'RearSurroundRight',
378             35 => 'LeftWide',
379             36 => 'RightWide',
380             37 => 'LFE2',
381             38 => 'LeftTotal',
382             39 => 'RightTotal',
383             40 => 'HearingImpaired',
384             41 => 'Narration',
385             42 => 'Mono',
386             43 => 'DialogCentricMix',
387             44 => 'CenterSurroundDirect',
388             45 => 'Haptic',
389             200 => 'Ambisonic_W',
390             201 => 'Ambisonic_X',
391             202 => 'Ambisonic_Y',
392             203 => 'Ambisonic_Z',
393             204 => 'MS_Mid',
394             205 => 'MS_Side',
395             206 => 'XY_X',
396             207 => 'XY_Y',
397             301 => 'HeadphonesLeft',
398             302 => 'HeadphonesRight',
399             304 => 'ClickTrack',
400             305 => 'ForeignLanguage',
401             400 => 'Discrete',
402             0x10000 => 'Discrete_0',
403             0x10001 => 'Discrete_1',
404             0x10002 => 'Discrete_2',
405             0x10003 => 'Discrete_3',
406             0x10004 => 'Discrete_4',
407             0x10005 => 'Discrete_5',
408             0x10006 => 'Discrete_6',
409             0x10007 => 'Discrete_7',
410             0x10008 => 'Discrete_8',
411             0x10009 => 'Discrete_9',
412             0x1000a => 'Discrete_10',
413             0x1000b => 'Discrete_11',
414             0x1000c => 'Discrete_12',
415             0x1000d => 'Discrete_13',
416             0x1000e => 'Discrete_14',
417             0x1000f => 'Discrete_15',
418             0x1ffff => 'Discrete_65535',
419             );
420              
421             # properties which don't get inherited from the parent
422             my %dontInherit = (
423             ispe => 1, # size of parent may be different
424             hvcC => 1, # (likely redundant)
425             );
426              
427             # tags that may be duplicated and directories that may contain duplicate tags
428             # (used only to avoid warnings when Validate-ing)
429             my %dupTagOK = ( mdat => 1, trak => 1, free => 1, infe => 1, sgpd => 1, dimg => 1, CCDT => 1,
430             sbgp => 1, csgm => 1, uuid => 1, cdsc => 1, maxr => 1, '----' => 1 );
431             my %dupDirOK = ( ipco => 1, '----' => 1 );
432              
433             # the usual atoms required to decode timed metadata with the ExtractEmbedded option
434             my %eeStd = ( stco => 'stbl', co64 => 'stbl', stsz => 'stbl', stz2 => 'stbl',
435             stsc => 'stbl', stts => 'stbl' );
436              
437             # boxes and their containers for the various handler types that we want to save
438             # when the ExtractEmbedded is enabled (currently only the 'gps ' container name is
439             # used, but others have been checked against all available sample files and may be
440             # useful in the future if the names are used for different boxes on other locations)
441             my %eeBox = (
442             # (note: vide is only processed if specific atoms exist in the VideoSampleDesc)
443             vide => { %eeStd,
444             JPEG => 'stsd',
445             },
446             text => { %eeStd },
447             meta => { %eeStd },
448             sbtl => { %eeStd },
449             data => { %eeStd },
450             camm => { %eeStd }, # (Insta360)
451             ctbx => { %eeStd }, # (GM cars)
452             '' => { 'gps ' => 'moov', 'GPS ' => 'main' }, # (no handler -- in top level 'moov' box, and main)
453             );
454             # boxes to save when ExtractEmbedded is set to 2 or higher
455             my %eeBox2 = (
456             vide => { avcC => 'stsd' }, # (parses H264 video stream)
457             );
458              
459             # QuickTime atoms
460             %Image::ExifTool::QuickTime::Main = (
461             PROCESS_PROC => \&ProcessMOV,
462             WRITE_PROC => \&WriteQuickTime, # (only needs to be defined for directories to process when writing)
463             GROUPS => { 2 => 'Video' },
464             meta => { # 'meta' is found here in my Sony ILCE-7S MP4 sample - PH
465             Name => 'Meta',
466             SubDirectory => {
467             TagTable => 'Image::ExifTool::QuickTime::Meta',
468             Start => 4, # skip 4-byte version number header
469             },
470             },
471             meco => { #ISO14496-12:2015
472             Name => 'OtherMeta',
473             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' },
474             },
475             free => [
476             {
477             Name => 'KodakFree',
478             # (found in Kodak M5370 MP4 videos)
479             Condition => '$$valPt =~ /^\0\0\0.Seri/s',
480             SubDirectory => { TagTable => 'Image::ExifTool::Kodak::Free' },
481             },{
482             Name => 'Pittasoft',
483             # (Pittasoft Blackview dashcam MP4 videos)
484             Condition => '$$valPt =~ /^\0\0..(cprt|sttm|ptnm|ptrh|thum|gps |3gf )/s',
485             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' },
486             },{
487             Name => 'ThumbnailImage',
488             # (DJI Zenmuse XT2 thermal camera)
489             Groups => { 2 => 'Preview' },
490             Condition => '$$valPt =~ /^.{4}mdat\xff\xd8\xff/s',
491             RawConv => q{
492             my $len = unpack('N', $val);
493             return undef if $len <= 8 or $len > length($val);
494             return substr($val, 8, $len-8);
495             },
496             Binary => 1,
497             },{
498             Unknown => 1,
499             Binary => 1,
500             },
501             # (also Samsung WB750 uncompressed thumbnail data starting with "SDIC\0")
502             ],
503             # fre1 - 4 bytes: "june" (Kodak PixPro SP360)
504             frea => {
505             Name => 'Kodak_frea',
506             SubDirectory => { TagTable => 'Image::ExifTool::Kodak::frea' },
507             },
508             skip => [
509             {
510             Name => 'CanonSkip',
511             Condition => '$$valPt =~ /^\0.{3}(CNDB|CNCV|CNMN|CNFV|CNTH|CNDM)/s',
512             SubDirectory => { TagTable => 'Image::ExifTool::Canon::Skip' },
513             },
514             {
515             Name => 'PreviewImage', # (found in DuDuBell M1 dashcam MOV files)
516             Groups => { 2 => 'Preview' },
517             Condition => '$$valPt =~ /^.{12}\xff\xd8\xff/',
518             Binary => 1,
519             RawConv => q{
520             my $len = Get32u(\$val, 8);
521             return undef unless length($val) >= $len + 12;
522             return substr($val, 12, $len);
523             },
524             },
525             {
526             Name => 'SkipInfo', # (found in 70mai Pro Plus+ MP4 videos)
527             # (look for something that looks like a QuickTime atom header)
528             Condition => '$$valPt =~ /^\0[\0-\x04]..[a-zA-Z ]{4}/s',
529             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SkipInfo' },
530             },
531             { Name => 'Skip', Unknown => 1, Binary => 1 },
532             ],
533             wide => { Unknown => 1, Binary => 1 },
534             ftyp => { #MP4
535             Name => 'FileType',
536             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FileType' },
537             },
538             pnot => {
539             Name => 'Preview',
540             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Preview' },
541             },
542             PICT => {
543             Name => 'PreviewPICT',
544             Groups => { 2 => 'Preview' },
545             Binary => 1,
546             },
547             pict => { #8
548             Name => 'PreviewPICT',
549             Groups => { 2 => 'Preview' },
550             Binary => 1,
551             },
552             # (note that moov is present for an HEIF sequence)
553             moov => {
554             Name => 'Movie',
555             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Movie' },
556             },
557             moof => {
558             Name => 'MovieFragment',
559             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieFragment' },
560             },
561             # mfra - movie fragment random access: contains tfra (track fragment random access), and
562             # mfro (movie fragment random access offset) (ref 5)
563             mdat => { Name => 'MediaData', Unknown => 1, Binary => 1 },
564             'mdat-size' => {
565             Name => 'MediaDataSize',
566             RawConv => '$$self{MediaDataSize} = $val',
567             Notes => q{
568             not a real tag ID, this tag represents the size of the 'mdat' data in bytes
569             and is used in the AvgBitrate calculation
570             },
571             },
572             'mdat-offset' => {
573             Name => 'MediaDataOffset',
574             RawConv => '$$self{MediaDataOffset} = $val',
575             },
576             junk => { Unknown => 1, Binary => 1 }, #8
577             uuid => [
578             { #9 (MP4 files)
579             Name => 'XMP',
580             # *** this is where ExifTool writes XMP in MP4 videos (as per XMP spec) ***
581             Condition => '$$valPt=~/^\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac/',
582             WriteGroup => 'XMP', # (write main XMP tags here)
583             PreservePadding => 1,
584             SubDirectory => {
585             TagTable => 'Image::ExifTool::XMP::Main',
586             Start => 16,
587             },
588             },
589             { #11 (MP4 files)
590             Name => 'UUID-PROF',
591             Condition => '$$valPt=~/^PROF!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/',
592             SubDirectory => {
593             TagTable => 'Image::ExifTool::QuickTime::Profile',
594             Start => 24, # uid(16) + version(1) + flags(3) + count(4)
595             },
596             },
597             { #PH (Flip MP4 files)
598             Name => 'UUID-Flip',
599             Condition => '$$valPt=~/^\x4a\xb0\x3b\x0f\x61\x8d\x40\x75\x82\xb2\xd9\xfa\xce\xd3\x5f\xf5/',
600             SubDirectory => {
601             TagTable => 'Image::ExifTool::QuickTime::Flip',
602             Start => 16,
603             },
604             },
605             # "\x98\x7f\xa3\xdf\x2a\x85\x43\xc0\x8f\x8f\xd9\x7c\x47\x1e\x8e\xea" - unknown data in Flip videos
606             { #PH (Canon CR3)
607             Name => 'UUID-Canon2',
608             WriteLast => 1, # MUST come after mdat or DPP will drop mdat when writing!
609             Condition => '$$valPt=~/^\x21\x0f\x16\x87\x91\x49\x11\xe4\x81\x11\x00\x24\x21\x31\xfc\xe4/',
610             SubDirectory => {
611             TagTable => 'Image::ExifTool::Canon::uuid2',
612             Start => 16,
613             },
614             },
615             { # (ref https://github.com/JamesHeinrich/getID3/blob/master/getid3/module.audio-video.quicktime.php)
616             Name => 'SensorData', # sensor data for the 360Fly
617             Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/ and $$self{OPTIONS}{ExtractEmbedded}',
618             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Tags360Fly' },
619             },
620             {
621             Name => 'SensorData',
622             Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/',
623             Notes => 'raw 360Fly sensor data without ExtractEmbedded option',
624             RawConv => q{
625             $self->WarnOnce('Use the ExtractEmbedded option to decode timed SensorData',3);
626             return \$val;
627             },
628             },
629             { #PH (Canon CR3)
630             Name => 'PreviewImage',
631             Condition => '$$valPt=~/^\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16/',
632             Groups => { 2 => 'Preview' },
633             PreservePadding => 1,
634             # 0x00 - undef[16]: UUID
635             # 0x10 - int32u[2]: "0 1" (version and/or item count?)
636             # 0x18 - int32u: PRVW atom size
637             # 0x20 - int32u: 'PRVW'
638             # 0x30 - int32u: 0
639             # 0x34 - int16u: 1
640             # 0x36 - int16u: image width
641             # 0x38 - int16u: image height
642             # 0x3a - int16u: 1
643             # 0x3c - int32u: preview length
644             RawConv => '$val = substr($val, 0x30); $self->ValidateImage(\$val, $tag)',
645             },
646             { #8
647             Name => 'UUID-Unknown',
648             %unknownInfo,
649             },
650             ],
651             _htc => {
652             Name => 'HTCInfo',
653             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HTCInfo' },
654             },
655             udta => {
656             Name => 'UserData',
657             SubDirectory => { TagTable => 'Image::ExifTool::FLIR::UserData' },
658             },
659             thum => { #PH
660             Name => 'ThumbnailImage',
661             Groups => { 2 => 'Preview' },
662             Binary => 1,
663             },
664             'thm ' => { #PH (70mai A800)
665             Name => 'ThumbnailImage',
666             Groups => { 2 => 'Preview' },
667             Binary => 1,
668             },
669             ardt => { #PH
670             Name => 'ARDroneFile',
671             ValueConv => 'length($val) > 4 ? substr($val,4) : $val', # remove length
672             },
673             prrt => { #PH
674             Name => 'ARDroneTelemetry',
675             Notes => q{
676             telemetry information for each video frame: status1, status2, time, pitch,
677             roll, yaw, speed, altitude
678             },
679             ValueConv => q{
680             my $size = length $val;
681             return \$val if $size < 12 or not $$self{OPTIONS}{Binary};
682             my $len = Get16u(\$val, 2);
683             my $str = '';
684             SetByteOrder('II');
685             my $pos = 12;
686             while ($pos + $len <= $size) {
687             my $s1 = Get16u(\$val, $pos);
688             # s2: 7=take-off?, 3=moving, 4=hovering, 9=landing?, 2=landed
689             my $s2 = Get16u(\$val, $pos + 2);
690             $str .= "$s1 $s2";
691             my $num = int(($len-4)/4);
692             my ($i, $v);
693             for ($i=0; $i<$num; ++$i) {
694             my $pt = $pos + 4 + $i * 4;
695             if ($i > 0 && $i < 4) {
696             $v = GetFloat(\$val, $pt); # pitch/roll/yaw
697             } else {
698             $v = Get32u(\$val, $pt);
699             # convert time to sec, and speed(NC)/altitude to metres
700             $v /= 1000 if $i <= 5;
701             }
702             $str .= " $v";
703             }
704             $str .= "\n";
705             $pos += $len;
706             }
707             SetByteOrder('MM');
708             return \$str;
709             },
710             },
711             udat => { #PH (GPS NMEA-format log written by Datakam Player software)
712             Name => 'GPSLog',
713             Binary => 1, # (actually ASCII, but very lengthy)
714             Notes => 'parsed to extract GPS separately when ExtractEmbedded is used',
715             RawConv => q{
716             $val =~ s/\0+$//; # remove trailing nulls
717             if (length $val and $$self{OPTIONS}{ExtractEmbedded}) {
718             my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
719             Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl);
720             }
721             return $val;
722             },
723             },
724             # meta - proprietary XML information written by some Flip cameras - PH
725             # beam - 16 bytes found in an iPhone video
726             IDIT => { #PH (written by DuDuBell M1, VSYS M6L dashcams)
727             Name => 'DateTimeOriginal',
728             Description => 'Date/Time Original',
729             Groups => { 2 => 'Time' },
730             Format => 'string', # (removes trailing "\0")
731             Shift => 'Time',
732             Writable => 1,
733             Permanent => 1,
734             DelValue => '0000-00-00T00:00:00+0000',
735             ValueConv => '$val=~tr/-/:/; $val',
736             ValueConvInv => '$val=~s/(\d+):(\d+):/$1-$2-/; $val',
737             PrintConv => '$self->ConvertDateTime($val)',
738             PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
739             },
740             gps0 => { #PH (DuDuBell M1, VSYS M6L)
741             Name => 'GPSTrack',
742             SubDirectory => {
743             TagTable => 'Image::ExifTool::QuickTime::Stream',
744             ProcessProc => \&Process_gps0,
745             },
746             },
747             gsen => { #PH (DuDuBell M1, VSYS M6L)
748             Name => 'GSensor',
749             SubDirectory => {
750             TagTable => 'Image::ExifTool::QuickTime::Stream',
751             ProcessProc => \&Process_gsen,
752             },
753             },
754             # gpsa - seen hex "01 20 00 00" (DuDuBell M1, VSYS M6L)
755             # gsea - 20 bytes hex "05 00's..." (DuDuBell M1) "05 08 02 01 ..." (VSYS M6L)
756             'GPS ' => { # GPS data written by 70mai dashcam (parsed in QuickTimeStream.pl)
757             Name => 'GPSDataList2',
758             Unknown => 1,
759             Binary => 1,
760             },
761             sefd => {
762             Name => 'SamsungTrailer',
763             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::Trailer' },
764             },
765             # 'samn'? - seen in Vantrue N2S sample video
766             );
767              
768             # stuff seen in 'skip' atom (70mai Pro Plus+ MP4 videos)
769             %Image::ExifTool::QuickTime::SkipInfo = (
770             PROCESS_PROC => \&ProcessMOV,
771             GROUPS => { 2 => 'Video' },
772             'ver ' => 'Version',
773             # tima - int32u: seen 0x3c
774             thma => {
775             Name => 'ThumbnailImage',
776             Groups => { 2 => 'Preview' },
777             Binary => 1,
778             },
779             );
780              
781             # MPEG-4 'ftyp' atom
782             # (ref http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html)
783             %Image::ExifTool::QuickTime::FileType = (
784             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
785             GROUPS => { 2 => 'Video' },
786             FORMAT => 'int32u',
787             0 => {
788             Name => 'MajorBrand',
789             Format => 'undef[4]',
790             PrintConv => \%ftypLookup,
791             },
792             1 => {
793             Name => 'MinorVersion',
794             Format => 'undef[4]',
795             ValueConv => 'sprintf("%x.%x.%x", unpack("nCC", $val))',
796             },
797             2 => {
798             Name => 'CompatibleBrands',
799             Format => 'undef[$size-8]',
800             # ignore any entry with a null, and return others as a list
801             ValueConv => 'my @a=($val=~/.{4}/sg); @a=grep(!/\0/,@a); \@a',
802             },
803             );
804              
805             # proprietary HTC atom (HTC One MP4 video)
806             %Image::ExifTool::QuickTime::HTCInfo = (
807             PROCESS_PROC => \&ProcessMOV,
808             GROUPS => { 2 => 'Video' },
809             NOTES => 'Tags written by some HTC camera phones.',
810             slmt => {
811             Name => 'Unknown_slmt',
812             Unknown => 1,
813             Format => 'int32u', # (observed values: 4)
814             },
815             );
816              
817             # atoms used in QTIF files
818             %Image::ExifTool::QuickTime::ImageFile = (
819             PROCESS_PROC => \&ProcessMOV,
820             GROUPS => { 2 => 'Image' },
821             NOTES => 'Tags used in QTIF QuickTime Image Files.',
822             idsc => {
823             Name => 'ImageDescription',
824             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ImageDesc' },
825             },
826             idat => {
827             Name => 'ImageData',
828             Binary => 1,
829             },
830             iicc => {
831             Name => 'ICC_Profile',
832             SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' },
833             },
834             );
835              
836             # image description data block
837             %Image::ExifTool::QuickTime::ImageDesc = (
838             PROCESS_PROC => \&ProcessHybrid,
839             VARS => { ID_LABEL => 'ID/Index' },
840             GROUPS => { 2 => 'Image' },
841             FORMAT => 'int16u',
842             2 => {
843             Name => 'CompressorID',
844             Format => 'string[4]',
845             # not very useful since this isn't a complete list and name is given below
846             # # ref http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
847             # PrintConv => {
848             # cvid => 'Cinepak',
849             # jpeg => 'JPEG',
850             # 'smc '=> 'Graphics',
851             # 'rle '=> 'Animation',
852             # rpza => 'Apple Video',
853             # kpcd => 'Kodak Photo CD',
854             # 'png '=> 'Portable Network Graphics',
855             # mjpa => 'Motion-JPEG (format A)',
856             # mjpb => 'Motion-JPEG (format B)',
857             # SVQ1 => 'Sorenson video, version 1',
858             # SVQ3 => 'Sorenson video, version 3',
859             # mp4v => 'MPEG-4 video',
860             # 'dvc '=> 'NTSC DV-25 video',
861             # dvcp => 'PAL DV-25 video',
862             # 'gif '=> 'Compuserve Graphics Interchange Format',
863             # h263 => 'H.263 video',
864             # tiff => 'Tagged Image File Format',
865             # 'raw '=> 'Uncompressed RGB',
866             # '2vuY'=> "Uncompressed Y'CbCr, 3x8-bit 4:2:2 (2vuY)",
867             # 'yuv2'=> "Uncompressed Y'CbCr, 3x8-bit 4:2:2 (yuv2)",
868             # v308 => "Uncompressed Y'CbCr, 8-bit 4:4:4",
869             # v408 => "Uncompressed Y'CbCr, 8-bit 4:4:4:4",
870             # v216 => "Uncompressed Y'CbCr, 10, 12, 14, or 16-bit 4:2:2",
871             # v410 => "Uncompressed Y'CbCr, 10-bit 4:4:4",
872             # v210 => "Uncompressed Y'CbCr, 10-bit 4:2:2",
873             # hvc1 => 'HEVC', #PH
874             # },
875             },
876             10 => {
877             Name => 'VendorID',
878             Format => 'string[4]',
879             RawConv => 'length $val ? $val : undef',
880             PrintConv => \%vendorID,
881             SeparateTable => 'VendorID',
882             },
883             # 14 - ("Quality" in QuickTime docs) ??
884             16 => 'SourceImageWidth',
885             17 => 'SourceImageHeight',
886             18 => { Name => 'XResolution', Format => 'fixed32u' },
887             20 => { Name => 'YResolution', Format => 'fixed32u' },
888             # 24 => 'FrameCount', # always 1 (what good is this?)
889             25 => {
890             Name => 'CompressorName',
891             Format => 'string[32]',
892             # (sometimes this is a Pascal string, and sometimes it is a C string)
893             RawConv => q{
894             $val=substr($val,1,ord($1)) if $val=~/^([\0-\x1f])/ and ord($1)
895             length $val ? $val : undef;
896             },
897             },
898             41 => 'BitDepth',
899             #
900             # Observed offsets for child atoms of various CompressorID types:
901             #
902             # CompressorID Offset Child atoms
903             # ----------- ------ ----------------
904             # avc1 86 avcC, btrt, colr, pasp, fiel, clap, svcC
905             # mp4v 86 esds, pasp
906             # s263 86 d263
907             #
908             btrt => {
909             Name => 'BitrateInfo',
910             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Bitrate' },
911             },
912             # Reference for fiel, colr, pasp, clap:
913             # https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
914             fiel => {
915             Name => 'VideoFieldOrder',
916             ValueConv => 'join(" ", unpack("C*",$val))',
917             PrintConv => [{
918             1 => 'Progressive',
919             2 => '2:1 Interlaced',
920             }],
921             },
922             colr => {
923             Name => 'ColorRepresentation',
924             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ColorRep' },
925             },
926             pasp => {
927             Name => 'PixelAspectRatio',
928             ValueConv => 'join(":", unpack("N*",$val))',
929             },
930             clap => {
931             Name => 'CleanAperture',
932             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::CleanAperture' },
933             },
934             avcC => {
935             # (see http://thompsonng.blogspot.ca/2010/11/mp4-file-format-part-2.html)
936             Name => 'AVCConfiguration',
937             Unknown => 1,
938             Binary => 1,
939             },
940             JPEG => { # (found in CR3 images; used as a flag to identify JpgFromRaw 'vide' stream)
941             Name => 'JPEGInfo',
942             # (4 bytes all zero)
943             Unknown => 1,
944             Binary => 1,
945             },
946             # hvcC - HEVC configuration
947             # svcC - 7 bytes: 00 00 00 00 ff e0 00
948             # esds - elementary stream descriptor
949             # d263
950             gama => { Name => 'Gamma', Format => 'fixed32u' },
951             # mjqt - default quantization table for MJPEG
952             # mjht - default Huffman table for MJPEG
953             # csgm ? (seen in hevc video)
954             CMP1 => { # Canon CR3
955             Name => 'CMP1',
956             SubDirectory => { TagTable => 'Image::ExifTool::Canon::CMP1' },
957             },
958             CDI1 => { # Canon CR3
959             Name => 'CDI1',
960             SubDirectory => {
961             TagTable => 'Image::ExifTool::Canon::CDI1',
962             Start => 4,
963             },
964             },
965             # JPEG - 4 bytes all 0 (Canon CR3)
966             # free - (Canon CR3)
967             #
968             # spherical video v2 stuff (untested)
969             #
970             st3d => {
971             Name => 'Stereoscopic3D',
972             Format => 'int8u',
973             ValueConv => '$val =~ s/.* //; $val', # (remove leading version/flags bytes?)
974             PrintConv => {
975             0 => 'Monoscopic',
976             1 => 'Stereoscopic Top-Bottom',
977             2 => 'Stereoscopic Left-Right',
978             3 => 'Stereoscopic Stereo-Custom', # (provisional in spec as of 2017-10-10)
979             },
980             },
981             sv3d => {
982             Name => 'SphericalVideo',
983             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::sv3d' },
984             },
985             );
986              
987             # 'sv3d' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md)
988             %Image::ExifTool::QuickTime::sv3d = (
989             PROCESS_PROC => \&ProcessMOV,
990             GROUPS => { 2 => 'Video' },
991             NOTES => q{
992             Tags defined by the Spherical Video V2 specification. See
993             L
994             for the specification.
995             },
996             svhd => {
997             Name => 'MetadataSource',
998             Format => 'undef',
999             ValueConv => '$val=~tr/\0//d; $val', # (remove version/flags? and terminator?)
1000             },
1001             proj => {
1002             Name => 'Projection',
1003             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::proj' },
1004             },
1005             );
1006              
1007             # 'proj' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md)
1008             %Image::ExifTool::QuickTime::proj = (
1009             PROCESS_PROC => \&ProcessMOV,
1010             GROUPS => { 2 => 'Video' },
1011             prhd => {
1012             Name => 'ProjectionHeader',
1013             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::prhd' },
1014             },
1015             cbmp => {
1016             Name => 'CubemapProj',
1017             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::cbmp' },
1018             },
1019             equi => {
1020             Name => 'EquirectangularProj',
1021             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::equi' },
1022             },
1023             # mshp - MeshProjection (P.I.T.A. to decode, for not much reward, see ref)
1024             );
1025              
1026             # 'prhd' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md)
1027             %Image::ExifTool::QuickTime::prhd = (
1028             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1029             GROUPS => { 2 => 'Video' },
1030             FORMAT => 'fixed32s',
1031             # 0 - version (high 8 bits) / flags (low 24 bits)
1032             1 => 'PoseYawDegrees',
1033             2 => 'PosePitchDegrees',
1034             3 => 'PoseRollDegrees',
1035             );
1036              
1037             # 'cbmp' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md)
1038             %Image::ExifTool::QuickTime::cbmp = (
1039             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1040             GROUPS => { 2 => 'Video' },
1041             FORMAT => 'int32u',
1042             # 0 - version (high 8 bits) / flags (low 24 bits)
1043             1 => 'Layout',
1044             2 => 'Padding',
1045             );
1046              
1047             # 'equi' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md)
1048             %Image::ExifTool::QuickTime::equi = (
1049             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1050             GROUPS => { 2 => 'Video' },
1051             FORMAT => 'int32u', # (actually 0.32 fixed point)
1052             # 0 - version (high 8 bits) / flags (low 24 bits)
1053             1 => { Name => 'ProjectionBoundsTop', ValueConv => '$val / 4294967296' },
1054             2 => { Name => 'ProjectionBoundsBottom',ValueConv => '$val / 4294967296' },
1055             3 => { Name => 'ProjectionBoundsLeft', ValueConv => '$val / 4294967296' },
1056             4 => { Name => 'ProjectionBoundsRight', ValueConv => '$val / 4294967296' },
1057             );
1058              
1059             # 'btrt' atom information (ref http://lists.freedesktop.org/archives/gstreamer-commits/2011-October/054459.html)
1060             %Image::ExifTool::QuickTime::Bitrate = (
1061             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1062             GROUPS => { 2 => 'Video' },
1063             FORMAT => 'int32u',
1064             PRIORITY => 0, # often filled with zeros
1065             0 => 'BufferSize',
1066             1 => 'MaxBitrate',
1067             2 => 'AverageBitrate',
1068             );
1069              
1070             # 'clap' atom information (ref https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9)
1071             %Image::ExifTool::QuickTime::CleanAperture = (
1072             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1073             GROUPS => { 2 => 'Video' },
1074             FORMAT => 'rational64s',
1075             0 => 'CleanApertureWidth',
1076             1 => 'CleanApertureHeight',
1077             2 => 'CleanApertureOffsetX',
1078             3 => 'CleanApertureOffsetY',
1079             );
1080              
1081             # preview data block
1082             %Image::ExifTool::QuickTime::Preview = (
1083             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1084             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
1085             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
1086             GROUPS => { 2 => 'Image' },
1087             FORMAT => 'int16u',
1088             0 => {
1089             Name => 'PreviewDate',
1090             Format => 'int32u',
1091             Groups => { 2 => 'Time' },
1092             %timeInfo,
1093             },
1094             2 => 'PreviewVersion',
1095             3 => {
1096             Name => 'PreviewAtomType',
1097             Format => 'string[4]',
1098             },
1099             5 => 'PreviewAtomIndex',
1100             );
1101              
1102             # movie atoms
1103             %Image::ExifTool::QuickTime::Movie = (
1104             PROCESS_PROC => \&ProcessMOV,
1105             WRITE_PROC => \&WriteQuickTime,
1106             GROUPS => { 2 => 'Video' },
1107             mvhd => {
1108             Name => 'MovieHeader',
1109             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieHeader' },
1110             },
1111             trak => {
1112             Name => 'Track',
1113             CanCreate => 0, # don't create this atom
1114             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' },
1115             },
1116             udta => {
1117             Name => 'UserData',
1118             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::UserData' },
1119             },
1120             meta => { # 'meta' is found here in my EX-F1 MOV sample - PH
1121             Name => 'Meta',
1122             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' },
1123             },
1124             iods => {
1125             Name => 'InitialObjectDescriptor',
1126             Flags => ['Binary','Unknown'],
1127             },
1128             uuid => [
1129             { #11 (MP4 files) (also found in QuickTime::Track)
1130             Name => 'UUID-USMT',
1131             Condition => '$$valPt=~/^USMT!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/',
1132             SubDirectory => {
1133             TagTable => 'Image::ExifTool::QuickTime::UserMedia',
1134             Start => 16,
1135             },
1136             },
1137             { #PH (Canon SX280)
1138             Name => 'UUID-Canon',
1139             Condition => '$$valPt=~/^\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48/',
1140             SubDirectory => {
1141             TagTable => 'Image::ExifTool::Canon::uuid',
1142             Start => 16,
1143             },
1144             },
1145             {
1146             Name => 'GarminGPS',
1147             Condition => '$$valPt=~/^\x9b\x63\x0f\x8d\x63\x74\x40\xec\x82\x04\xbc\x5f\xf5\x09\x17\x28/ and $$self{OPTIONS}{ExtractEmbedded}',
1148             SubDirectory => {
1149             TagTable => 'Image::ExifTool::QuickTime::Stream',
1150             ProcessProc => \&ProcessGarminGPS,
1151             },
1152             },
1153             {
1154             Name => 'GarminGPS',
1155             Condition => '$$valPt=~/^\x9b\x63\x0f\x8d\x63\x74\x40\xec\x82\x04\xbc\x5f\xf5\x09\x17\x28/',
1156             Notes => 'Garmin GPS sensor data',
1157             RawConv => q{
1158             $self->WarnOnce('Use the ExtractEmbedded option to decode timed Garmin GPS',3);
1159             return \$val;
1160             },
1161             },
1162             {
1163             Name => 'UUID-Unknown',
1164             %unknownInfo,
1165             },
1166             ],
1167             cmov => {
1168             Name => 'CompressedMovie',
1169             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::CMovie' },
1170             },
1171             htka => { # (written by HTC One M8 in slow-motion 1280x720 video - PH)
1172             Name => 'HTCTrack',
1173             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' },
1174             },
1175             'gps ' => { # GPS data written by Novatek cameras (parsed in QuickTimeStream.pl)
1176             Name => 'GPSDataList',
1177             Unknown => 1,
1178             Binary => 1,
1179             },
1180             meco => { #ISO14496-12:2015
1181             Name => 'OtherMeta',
1182             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' },
1183             },
1184             # prfl - Profile (ref 12)
1185             # clip - clipping --> contains crgn (clip region) (ref 12)
1186             # mvex - movie extends --> contains mehd (movie extends header), trex (track extends) (ref 14)
1187             # ICAT - 4 bytes: "6350" (Nikon CoolPix S6900), "6500" (Panasonic FT7)
1188             );
1189              
1190             # (ref CFFMediaFormat-2_1.pdf)
1191             %Image::ExifTool::QuickTime::MovieFragment = (
1192             PROCESS_PROC => \&ProcessMOV,
1193             WRITE_PROC => \&WriteQuickTime,
1194             GROUPS => { 2 => 'Video' },
1195             mfhd => {
1196             Name => 'MovieFragmentHeader',
1197             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieFragHdr' },
1198             },
1199             traf => {
1200             Name => 'TrackFragment',
1201             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackFragment' },
1202             },
1203             meta => { #ISO14496-12:2015
1204             Name => 'Meta',
1205             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' },
1206             },
1207             );
1208              
1209             # (ref CFFMediaFormat-2_1.pdf)
1210             %Image::ExifTool::QuickTime::MovieFragHdr = (
1211             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1212             GROUPS => { 2 => 'Video' },
1213             FORMAT => 'int32u',
1214             1 => 'MovieFragmentSequence',
1215             );
1216              
1217             # (ref CFFMediaFormat-2_1.pdf)
1218             %Image::ExifTool::QuickTime::TrackFragment = (
1219             PROCESS_PROC => \&ProcessMOV,
1220             WRITE_PROC => \&WriteQuickTime,
1221             GROUPS => { 2 => 'Video' },
1222             meta => { #ISO14496-12:2015
1223             Name => 'Meta',
1224             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' },
1225             },
1226             # tfhd - track fragment header
1227             # edts - edits --> contains elst (edit list) (ref PH)
1228             # tfdt - track fragment base media decode time
1229             # trik - trick play box
1230             # trun - track fragment run box
1231             # avcn - AVC NAL unit storage box
1232             # secn - sample encryption box
1233             # saio - sample auxiliary information offsets box
1234             # sbgp - sample to group box
1235             # sgpd - sample group description box
1236             # sdtp - independent and disposable samples (ref 5)
1237             # subs - sub-sample information (ref 5)
1238             );
1239              
1240             # movie header data block
1241             %Image::ExifTool::QuickTime::MovieHeader = (
1242             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1243             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
1244             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
1245             GROUPS => { 2 => 'Video' },
1246             FORMAT => 'int32u',
1247             DATAMEMBER => [ 0, 1, 2, 3, 4 ],
1248             0 => {
1249             Name => 'MovieHeaderVersion',
1250             Format => 'int8u',
1251             RawConv => '$$self{MovieHeaderVersion} = $val',
1252             },
1253             1 => {
1254             Name => 'CreateDate',
1255             Groups => { 2 => 'Time' },
1256             %timeInfo,
1257             RawConv => q{
1258             my $offset = (66 * 365 + 17) * 24 * 3600;
1259             if ($val >= $offset or $$self{OPTIONS}{QuickTimeUTC}) {
1260             $val -= $offset;
1261             } elsif ($val and not $$self{IsWriting}) {
1262             $self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1);
1263             }
1264             return $$self{CreateDate} = $val;
1265             },
1266             # this is int64u if MovieHeaderVersion == 1 (ref 13)
1267             Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4',
1268             },
1269             2 => {
1270             Name => 'ModifyDate',
1271             Groups => { 2 => 'Time' },
1272             %timeInfo,
1273             # this is int64u if MovieHeaderVersion == 1 (ref 13)
1274             Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4',
1275             },
1276             3 => {
1277             Name => 'TimeScale',
1278             RawConv => '$$self{TimeScale} = $val',
1279             },
1280             4 => {
1281             Name => 'Duration',
1282             %durationInfo,
1283             # this is int64u if MovieHeaderVersion == 1 (ref 13)
1284             Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4',
1285             },
1286             5 => {
1287             Name => 'PreferredRate',
1288             ValueConv => '$val / 0x10000',
1289             },
1290             6 => {
1291             Name => 'PreferredVolume',
1292             Format => 'int16u',
1293             ValueConv => '$val / 256',
1294             PrintConv => 'sprintf("%.2f%%", $val * 100)',
1295             },
1296             9 => {
1297             Name => 'MatrixStructure',
1298             Format => 'fixed32s[9]',
1299             # (the right column is fixed 2.30 instead of 16.16)
1300             ValueConv => q{
1301             my @a = split ' ',$val;
1302             $_ /= 0x4000 foreach @a[2,5,8];
1303             return "@a";
1304             },
1305             },
1306             18 => { Name => 'PreviewTime', %durationInfo },
1307             19 => { Name => 'PreviewDuration', %durationInfo },
1308             20 => { Name => 'PosterTime', %durationInfo },
1309             21 => { Name => 'SelectionTime', %durationInfo },
1310             22 => { Name => 'SelectionDuration',%durationInfo },
1311             23 => { Name => 'CurrentTime', %durationInfo },
1312             24 => 'NextTrackID',
1313             );
1314              
1315             # track atoms
1316             %Image::ExifTool::QuickTime::Track = (
1317             PROCESS_PROC => \&ProcessMOV,
1318             WRITE_PROC => \&WriteQuickTime,
1319             GROUPS => { 1 => 'Track#', 2 => 'Video' },
1320             tkhd => {
1321             Name => 'TrackHeader',
1322             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackHeader' },
1323             },
1324             udta => {
1325             Name => 'UserData',
1326             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::UserData' },
1327             },
1328             mdia => { #MP4
1329             Name => 'Media',
1330             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Media' },
1331             },
1332             meta => { #PH (MOV)
1333             Name => 'Meta',
1334             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' },
1335             },
1336             tref => {
1337             Name => 'TrackRef',
1338             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackRef' },
1339             },
1340             tapt => {
1341             Name => 'TrackAperture',
1342             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackAperture' },
1343             },
1344             uuid => [
1345             { #11 (MP4 files) (also found in QuickTime::Movie)
1346             Name => 'UUID-USMT',
1347             Condition => '$$valPt=~/^USMT!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/',
1348             SubDirectory => {
1349             TagTable => 'Image::ExifTool::QuickTime::UserMedia',
1350             Start => 16,
1351             },
1352             },
1353             { #https://github.com/google/spatial-media/blob/master/docs/spherical-video-rfc.md
1354             Name => 'SphericalVideoXML',
1355             Condition => '$$valPt=~/^\xff\xcc\x82\x63\xf8\x55\x4a\x93\x88\x14\x58\x7a\x02\x52\x1f\xdd/',
1356             WriteGroup => 'GSpherical', # write only GSpherical XMP tags here
1357             HandlerType => 'vide', # only write in video tracks
1358             SubDirectory => {
1359             TagTable => 'Image::ExifTool::XMP::Main',
1360             Start => 16,
1361             WriteProc => 'Image::ExifTool::XMP::WriteGSpherical',
1362             },
1363             },
1364             {
1365             Name => 'UUID-Unknown',
1366             %unknownInfo,
1367             },
1368             ],
1369             meco => { #ISO14492-12:2015 pg 83
1370             Name => 'OtherMeta',
1371             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' },
1372             },
1373             # edts - edits --> contains elst (edit list)
1374             # clip - clipping --> contains crgn (clip region)
1375             # matt - track matt --> contains kmat (compressed matt)
1376             # load - track loading settings
1377             # imap - track input map --> contains ' in' --> contains ' ty', obid
1378             # prfl - Profile (ref 12)
1379             );
1380              
1381             # track header data block
1382             %Image::ExifTool::QuickTime::TrackHeader = (
1383             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1384             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
1385             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
1386             GROUPS => { 1 => 'Track#', 2 => 'Video' },
1387             FORMAT => 'int32u',
1388             DATAMEMBER => [ 0, 1, 2, 5, 7 ],
1389             0 => {
1390             Name => 'TrackHeaderVersion',
1391             Format => 'int8u',
1392             Priority => 0,
1393             RawConv => '$$self{TrackHeaderVersion} = $val',
1394             },
1395             1 => {
1396             Name => 'TrackCreateDate',
1397             Priority => 0,
1398             Groups => { 2 => 'Time' },
1399             %timeInfo,
1400             # this is int64u if TrackHeaderVersion == 1 (ref 13)
1401             Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4',
1402             },
1403             2 => {
1404             Name => 'TrackModifyDate',
1405             Priority => 0,
1406             Groups => { 2 => 'Time' },
1407             %timeInfo,
1408             # this is int64u if TrackHeaderVersion == 1 (ref 13)
1409             Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4',
1410             },
1411             3 => {
1412             Name => 'TrackID',
1413             Priority => 0,
1414             },
1415             5 => {
1416             Name => 'TrackDuration',
1417             Priority => 0,
1418             %durationInfo,
1419             # this is int64u if TrackHeaderVersion == 1 (ref 13)
1420             Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4',
1421             },
1422             7 => { # (used only for writing MatrixStructure)
1423             Name => 'ImageSizeLookahead',
1424             Hidden => 1,
1425             Format => 'int32u[14]',
1426             RawConv => '$$self{ImageSizeLookahead} = $val; undef',
1427             },
1428             8 => {
1429             Name => 'TrackLayer',
1430             Format => 'int16u',
1431             Priority => 0,
1432             },
1433             9 => {
1434             Name => 'TrackVolume',
1435             Format => 'int16u',
1436             Priority => 0,
1437             ValueConv => '$val / 256',
1438             PrintConv => 'sprintf("%.2f%%", $val * 100)',
1439             },
1440             10 => {
1441             Name => 'MatrixStructure',
1442             Format => 'fixed32s[9]',
1443             Notes => 'writable for the video track via the Composite Rotation tag',
1444             Writable => 1,
1445             Protected => 1,
1446             Permanent => 1,
1447             # only set rotation if image size is non-zero
1448             RawConvInv => \&GetMatrixStructure,
1449             # (the right column is fixed 2.30 instead of 16.16)
1450             ValueConv => q{
1451             my @a = split ' ',$val;
1452             $_ /= 0x4000 foreach @a[2,5,8];
1453             return "@a";
1454             },
1455             ValueConvInv => q{
1456             my @a = split ' ',$val;
1457             $_ *= 0x4000 foreach @a[2,5,8];
1458             return "@a";
1459             },
1460             },
1461             19 => {
1462             Name => 'ImageWidth',
1463             Priority => 0,
1464             RawConv => \&FixWrongFormat,
1465             },
1466             20 => {
1467             Name => 'ImageHeight',
1468             Priority => 0,
1469             RawConv => \&FixWrongFormat,
1470             },
1471             );
1472              
1473             # user data atoms
1474             %Image::ExifTool::QuickTime::UserData = (
1475             PROCESS_PROC => \&ProcessMOV,
1476             WRITE_PROC => \&WriteQuickTime,
1477             CHECK_PROC => \&CheckQTValue,
1478             GROUPS => { 1 => 'UserData', 2 => 'Video' },
1479             WRITABLE => 1,
1480             PREFERRED => 1, # (preferred over Keys tags when writing)
1481             FORMAT => 'string',
1482             WRITE_GROUP => 'UserData',
1483             LANG_INFO => \&GetLangInfo,
1484             NOTES => q{
1485             Tag ID's beginning with the copyright symbol (hex 0xa9) are multi-language
1486             text. Alternate language tags are accessed by adding a dash followed by a
1487             3-character ISO 639-2 language code to the tag name. ExifTool will extract
1488             any multi-language user data tags found, even if they aren't in this table.
1489             Note when creating new tags,
1490             L tags are
1491             preferred over these, so to create the tag when a same-named ItemList tag
1492             exists, either "UserData" must be specified (eg. C<-UserData:Artist=Monet>
1493             on the command line), or the PREFERRED level must be changed via
1494             L.
1495             },
1496             "\xa9cpy" => { Name => 'Copyright', Groups => { 2 => 'Author' } },
1497             "\xa9day" => {
1498             Name => 'ContentCreateDate',
1499             Groups => { 2 => 'Time' },
1500             Shift => 'Time',
1501             # handle values in the form "2010-02-12T13:27:14-0800" (written by Apple iPhone)
1502             ValueConv => q{
1503             require Image::ExifTool::XMP;
1504             $val = Image::ExifTool::XMP::ConvertXMPDate($val);
1505             $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
1506             return $val;
1507             },
1508             ValueConvInv => q{
1509             require Image::ExifTool::XMP;
1510             my $tmp = Image::ExifTool::XMP::FormatXMPDate($val);
1511             ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon
1512             return $val;
1513             },
1514             PrintConv => '$self->ConvertDateTime($val)',
1515             PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
1516             },
1517             "\xa9ART" => 'Artist', #PH (iTunes 8.0.2)
1518             "\xa9alb" => 'Album', #PH (iTunes 8.0.2)
1519             "\xa9arg" => 'Arranger', #12
1520             "\xa9ark" => 'ArrangerKeywords', #12
1521             "\xa9cmt" => 'Comment', #PH (iTunes 8.0.2)
1522             "\xa9cok" => 'ComposerKeywords', #12
1523             "\xa9com" => 'Composer', #12
1524             "\xa9dir" => 'Director', #12
1525             "\xa9ed1" => 'Edit1',
1526             "\xa9ed2" => 'Edit2',
1527             "\xa9ed3" => 'Edit3',
1528             "\xa9ed4" => 'Edit4',
1529             "\xa9ed5" => 'Edit5',
1530             "\xa9ed6" => 'Edit6',
1531             "\xa9ed7" => 'Edit7',
1532             "\xa9ed8" => 'Edit8',
1533             "\xa9ed9" => 'Edit9',
1534             "\xa9fmt" => 'Format',
1535             "\xa9gen" => 'Genre', #PH (iTunes 8.0.2)
1536             "\xa9grp" => 'Grouping', #PH (NC)
1537             "\xa9inf" => 'Information',
1538             "\xa9isr" => 'ISRCCode', #12
1539             "\xa9lab" => 'RecordLabelName', #12
1540             "\xa9lal" => 'RecordLabelURL', #12
1541             "\xa9lyr" => 'Lyrics', #PH (NC)
1542             "\xa9mak" => 'Make', #12
1543             "\xa9mal" => 'MakerURL', #12
1544             "\xa9mod" => 'Model', #PH
1545             "\xa9nam" => 'Title', #12
1546             "\xa9pdk" => 'ProducerKeywords', #12
1547             "\xa9phg" => 'RecordingCopyright', #12
1548             "\xa9prd" => 'Producer',
1549             "\xa9prf" => 'Performers',
1550             "\xa9prk" => 'PerformerKeywords', #12
1551             "\xa9prl" => 'PerformerURL',
1552             "\xa9req" => 'Requirements',
1553             "\xa9snk" => 'SubtitleKeywords', #12
1554             "\xa9snm" => 'Subtitle', #12
1555             "\xa9src" => 'SourceCredits', #12
1556             "\xa9swf" => 'SongWriter', #12
1557             "\xa9swk" => 'SongWriterKeywords', #12
1558             "\xa9swr" => 'SoftwareVersion', #12
1559             "\xa9too" => 'Encoder', #PH (NC)
1560             "\xa9trk" => 'Track', #PH (NC)
1561             "\xa9wrt" => { Name => 'Composer', Avoid => 1 }, # ("\xa9com" is preferred in UserData)
1562             "\xa9xyz" => { #PH (iPhone 3GS)
1563             Name => 'GPSCoordinates',
1564             Groups => { 2 => 'Location' },
1565             ValueConv => \&ConvertISO6709,
1566             ValueConvInv => \&ConvInvISO6709,
1567             PrintConv => \&PrintGPSCoordinates,
1568             PrintConvInv => \&PrintInvGPSCoordinates,
1569             },
1570             # \xa9 tags written by DJI Phantom 3: (ref PH)
1571             "\xa9xsp" => 'SpeedX', #PH (guess)
1572             "\xa9ysp" => 'SpeedY', #PH (guess)
1573             "\xa9zsp" => 'SpeedZ', #PH (guess)
1574             "\xa9fpt" => 'Pitch', #PH
1575             "\xa9fyw" => 'Yaw', #PH
1576             "\xa9frl" => 'Roll', #PH
1577             "\xa9gpt" => 'CameraPitch', #PH
1578             "\xa9gyw" => 'CameraYaw', #PH
1579             "\xa9grl" => 'CameraRoll', #PH
1580             "\xa9enc" => 'EncoderID', #PH (forum9271)
1581             # and the following entries don't have the proper 4-byte header for \xa9 tags:
1582             "\xa9dji" => { Name => 'UserData_dji', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 },
1583             "\xa9res" => { Name => 'UserData_res', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 },
1584             "\xa9uid" => { Name => 'UserData_uid', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 },
1585             "\xa9mdl" => {
1586             Name => 'Model',
1587             Notes => 'non-standard-format DJI tag',
1588             Format => 'string',
1589             Avoid => 1,
1590             },
1591             # end DJI tags
1592             name => 'Name',
1593             WLOC => {
1594             Name => 'WindowLocation',
1595             Format => 'int16u',
1596             },
1597             LOOP => {
1598             Name => 'LoopStyle',
1599             Format => 'int32u',
1600             PrintConv => {
1601             1 => 'Normal',
1602             2 => 'Palindromic',
1603             },
1604             },
1605             SelO => {
1606             Name => 'PlaySelection',
1607             Format => 'int8u',
1608             },
1609             AllF => {
1610             Name => 'PlayAllFrames',
1611             Format => 'int8u',
1612             },
1613             meta => {
1614             Name => 'Meta',
1615             SubDirectory => {
1616             TagTable => 'Image::ExifTool::QuickTime::Meta',
1617             Start => 4, # must skip 4-byte version number header
1618             },
1619             },
1620             'ptv '=> {
1621             Name => 'PrintToVideo',
1622             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Video' },
1623             },
1624             hnti => {
1625             Name => 'HintInfo',
1626             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintInfo' },
1627             },
1628             hinf => {
1629             Name => 'HintTrackInfo',
1630             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintTrackInfo' },
1631             },
1632             hinv => 'HintVersion', #PH (guess)
1633             XMP_ => { #PH (Adobe CS3 Bridge)
1634             Name => 'XMP',
1635             WriteGroup => 'XMP', # (write main tags here)
1636             # *** this is where ExifTool writes XMP in MOV videos (as per XMP spec) ***
1637             SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
1638             },
1639             # the following are 3gp tags, references:
1640             # http://atomicparsley.sourceforge.net
1641             # http://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/TSGS4_25/Docs/
1642             # (note that all %langText3gp tags are Avoid => 1)
1643             cprt => { Name => 'Copyright', %langText3gp, Groups => { 2 => 'Author' } },
1644             auth => { Name => 'Author', %langText3gp, Groups => { 2 => 'Author' } },
1645             titl => { Name => 'Title', %langText3gp },
1646             dscp => { Name => 'Description',%langText3gp },
1647             perf => { Name => 'Performer', %langText3gp },
1648             gnre => { Name => 'Genre', %langText3gp },
1649             albm => { Name => 'Album', %langText3gp },
1650             coll => { Name => 'CollectionName', %langText3gp }, #17
1651             rtng => {
1652             Name => 'Rating',
1653             Writable => 'undef',
1654             Avoid => 1,
1655             # (4-byte flags, 4-char entity, 4-char criteria, 2-byte lang, string)
1656             IText => 14, # (14 bytes before string)
1657             Notes => 'string in the form "Entity=XXXX Criteria=XXXX XXXXX", used in 3gp videos',
1658             ValueConv => '$val=~s/^(.{4})(.{4})/Entity=$1 Criteria=$2 /i; $val',
1659             ValueConvInv => '$val=~s/Entity=(.{4}) Criteria=(.{4}) ?/$1$2/i; $val',
1660             },
1661             clsf => {
1662             Name => 'Classification',
1663             Writable => 'undef',
1664             Avoid => 1,
1665             # (4-byte flags, 4-char entity, 2-byte index, 2-byte lang, string)
1666             IText => 12,
1667             Notes => 'string in the form "Entity=XXXX Index=### XXXXX", used in 3gp videos',
1668             ValueConv => '$val=~s/^(.{4})(.{2})/"Entity=$1 Index=".unpack("n",$2)." "/ie; $val',
1669             ValueConvInv => '$val=~s/Entity=(.{4}) Index=(\d+) ?/$1.pack("n",$2)/ie; $val',
1670             },
1671             kywd => {
1672             Name => 'Keywords',
1673             # (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings, ref 17)
1674             # (but I have also seen a simple string written by iPhone, so don't make writable yet)
1675             Notes => "not writable because Apple doesn't follow the 3gp specification",
1676             RawConv => q{
1677             my $sep = $self->Options('ListSep');
1678             return join($sep, split /\0+/, $val) unless $val =~ /^\0/; # (iPhone)
1679             return '' unless length $val >= 7;
1680             my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4));
1681             $lang = $lang ? "($lang) " : '';
1682             my $num = Get8u(\$val, 6);
1683             my ($i, @vals);
1684             my $pos = 7;
1685             for ($i=0; $i<$num; ++$i) {
1686             last if $pos >= length $val;
1687             my $len = Get8u(\$val, $pos++);
1688             last if $pos + $len > length $val;
1689             my $v = substr($val, $pos, $len);
1690             $v = $self->Decode($v, 'UCS2') if $v =~ /^\xfe\xff/;
1691             push @vals, $v;
1692             $pos += $len;
1693             }
1694             return $lang . join($sep, @vals);
1695             },
1696             },
1697             loci => {
1698             Name => 'LocationInformation',
1699             Groups => { 2 => 'Location' },
1700             Writable => 'undef',
1701             IText => 6,
1702             Avoid => 1,
1703             NoDecode => 1, # (we'll decode the data ourself)
1704             Notes => q{
1705             string in the form "XXXXX Role=XXX Lat=XXX Lon=XXX Alt=XXX Body=XXX
1706             Notes=XXX", used in 3gp videos
1707             },
1708             # (4-byte flags, 2-byte lang, location string, 1-byte role, 4-byte fixed longitude,
1709             # 4-byte fixed latitude, 4-byte fixed altitude, body string, notes string)
1710             RawConv => q{
1711             my $str;
1712             if ($val =~ /^\xfe\xff/) {
1713             $val =~ s/^(\xfe\xff(.{2})*?)\0\0//s or return '';
1714             $str = $self->Decode($1, 'UCS2');
1715             } else {
1716             $val =~ s/^(.*?)\0//s or return '';
1717             $str = $self->Decode($1, 'UTF8');
1718             }
1719             $str = '(none)' unless length $str;
1720             return '' if length $val < 13;
1721             my $role = Get8u(\$val, 0);
1722             my $lon = GetFixed32s(\$val, 1);
1723             my $lat = GetFixed32s(\$val, 5);
1724             my $alt = GetFixed32s(\$val, 9);
1725             my $roleStr = {0=>'shooting',1=>'real',2=>'fictional',3=>'reserved'}->{$role};
1726             $str .= ' Role=' . ($roleStr || "unknown($role)");
1727             $str .= sprintf(' Lat=%.5f Lon=%.5f Alt=%.2f', $lat, $lon, $alt);
1728             $val = substr($val, 13);
1729             if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
1730             $str .= ' Body=' . $self->Decode($1, 'UCS2');
1731             } elsif ($val =~ s/^(.*?)\0//s) {
1732             $str .= ' Body=' . $self->Decode($1, 'UTF8');
1733             }
1734             if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
1735             $str .= ' Notes=' . $self->Decode($1, 'UCS2');
1736             } elsif ($val =~ s/^(.*?)\0//s) {
1737             $str .= ' Notes=' . $self->Decode($1, 'UTF8');
1738             }
1739             return $str;
1740             },
1741             RawConvInv => q{
1742             my ($role, $lat, $lon, $alt, $body, $note);
1743             $lat = $1 if $val =~ s/ Lat=([-+]?[.\d]+)//i;
1744             $lon = $1 if $val =~ s/ Lon=([-+]?[.\d]+)//i;
1745             $alt = $1 if $val =~ s/ Alt=([-+]?[.\d]+)//i;
1746             $note = $val =~ s/ Notes=(.*)//i ? $1 : '';
1747             $body = $val =~ s/ Body=(.*)//i ? $1 : '';
1748             $role = $val =~ s/ Role=(.*)//i ? $1 : '';
1749             $val = '' if $val eq '(none)';
1750             $role = {shooting=>0,real=>1,fictional=>2}->{lc $role} || 0;
1751             return $self->Encode($val, 'UTF8') . "\0" . Set8u($role) .
1752             SetFixed32s(defined $lon ? $lon : 999) .
1753             SetFixed32s(defined $lat ? $lat : 999) .
1754             SetFixed32s(defined $alt ? $alt : 0) .
1755             $self->Encode($body) . "\0" .
1756             $self->Encode($note) . "\0";
1757             },
1758             },
1759             yrrc => {
1760             Name => 'Year',
1761             Writable => 'undef',
1762             Groups => { 2 => 'Time' },
1763             Avoid => 1,
1764             Notes => 'used in 3gp videos',
1765             ValueConv => 'length($val) >= 6 ? unpack("x4n",$val) : ""',
1766             ValueConvInv => 'pack("Nn",0,$val)',
1767             },
1768             urat => { #17
1769             Name => 'UserRating',
1770             Writable => 'undef',
1771             Notes => 'used in 3gp videos',
1772             Avoid => 1,
1773             ValueConv => q{
1774             return '' unless length $val >= 8;
1775             unpack('x7C', $val);
1776             },
1777             ValueConvInv => 'pack("N2",0,$val)',
1778             },
1779             # tsel - TrackSelection (ref 17)
1780             # Apple tags (ref 16[dead] -- see ref 25 instead)
1781             angl => { Name => 'CameraAngle', Format => 'string' }, # (NC)
1782             clfn => { Name => 'ClipFileName', Format => 'string' }, # (NC)
1783             clid => { Name => 'ClipID', Format => 'string' }, # (NC)
1784             cmid => { Name => 'CameraID', Format => 'string' }, # (NC)
1785             cmnm => { # (NC)
1786             Name => 'Model',
1787             Description => 'Camera Model Name',
1788             Avoid => 1,
1789             Format => 'string', # (necessary to remove the trailing NULL)
1790             },
1791             date => {
1792             Name => 'DateTimeOriginal',
1793             Description => 'Date/Time Original',
1794             Groups => { 2 => 'Time' },
1795             Notes => q{
1796             Apple Photos has been reported to show a crazy date/time for some MP4 files
1797             containing this tag, but perhaps only if it is missing a time zone
1798             }, #forum10690/11125
1799             Shift => 'Time',
1800             ValueConv => q{
1801             require Image::ExifTool::XMP;
1802             $val = Image::ExifTool::XMP::ConvertXMPDate($val);
1803             $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
1804             return $val;
1805             },
1806             ValueConvInv => q{
1807             require Image::ExifTool::XMP;
1808             $val = Image::ExifTool::XMP::FormatXMPDate($val);
1809             $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon
1810             return $val;
1811             },
1812             PrintConv => '$self->ConvertDateTime($val)',
1813             PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
1814             },
1815             manu => { # (SX280)
1816             Name => 'Make',
1817             Avoid => 1,
1818             # (with Canon there are 6 unknown bytes before the model: "\0\0\0\0\x15\xc7")
1819             RawConv => '$val=~s/^\0{4}..//s; $val=~s/\0.*//; $val',
1820             },
1821             modl => { # (Samsung GT-S8530, Canon SX280)
1822             Name => 'Model',
1823             Description => 'Camera Model Name',
1824             Avoid => 1,
1825             # (with Canon there are 6 unknown bytes before the model: "\0\0\0\0\x15\xc7")
1826             RawConv => '$val=~s/^\0{4}..//s; $val=~s/\0.*//; $val',
1827             },
1828             reel => { Name => 'ReelName', Format => 'string' }, # (NC)
1829             scen => { Name => 'Scene', Format => 'string' }, # (NC)
1830             shot => { Name => 'ShotName', Format => 'string' }, # (NC)
1831             slno => { Name => 'SerialNumber', Format => 'string' }, # (NC)
1832             apmd => { Name => 'ApertureMode', Format => 'undef' }, #20
1833             kgtt => { #http://lists.ffmpeg.org/pipermail/ffmpeg-devel-irc/2012-June/000707.html
1834             # 'TrackType' will expand to 'Track#Type' when found inside a track
1835             Name => 'TrackType',
1836             # set flag to process this as international text
1837             # even though the tag ID doesn't start with 0xa9
1838             IText => 4, # IText with 4-byte header
1839             },
1840             chpl => { # (Nero chapter list)
1841             Name => 'ChapterList',
1842             ValueConv => \&ConvertChapterList,
1843             PrintConv => \&PrintChapter,
1844             },
1845             # ndrm - 7 bytes (0 0 0 1 0 0 0) Nero Digital Rights Management? (PH)
1846             # other non-Apple tags (ref 16)
1847             # hpix - HipixRichPicture (ref 16, HIPIX)
1848             # strk - sub-track information (ref 16, ISO)
1849             #
1850             # Manufacturer-specific metadata
1851             #
1852             TAGS => [ #PH
1853             # these tags were initially discovered in a Pentax movie,
1854             # but similar information is found in videos from other manufacturers
1855             {
1856             Name => 'FujiFilmTags',
1857             Condition => '$$valPt =~ /^FUJIFILM DIGITAL CAMERA\0/',
1858             SubDirectory => {
1859             TagTable => 'Image::ExifTool::FujiFilm::MOV',
1860             ByteOrder => 'LittleEndian',
1861             },
1862             },
1863             {
1864             Name => 'KodakTags',
1865             Condition => '$$valPt =~ /^EASTMAN KODAK COMPANY/',
1866             SubDirectory => {
1867             TagTable => 'Image::ExifTool::Kodak::MOV',
1868             ByteOrder => 'LittleEndian',
1869             },
1870             },
1871             {
1872             Name => 'KonicaMinoltaTags',
1873             Condition => '$$valPt =~ /^KONICA MINOLTA DIGITAL CAMERA/',
1874             SubDirectory => {
1875             TagTable => 'Image::ExifTool::Minolta::MOV1',
1876             ByteOrder => 'LittleEndian',
1877             },
1878             },
1879             {
1880             Name => 'MinoltaTags',
1881             Condition => '$$valPt =~ /^MINOLTA DIGITAL CAMERA/',
1882             SubDirectory => {
1883             TagTable => 'Image::ExifTool::Minolta::MOV2',
1884             ByteOrder => 'LittleEndian',
1885             },
1886             },
1887             {
1888             Name => 'NikonTags',
1889             Condition => '$$valPt =~ /^NIKON DIGITAL CAMERA\0/',
1890             SubDirectory => {
1891             TagTable => 'Image::ExifTool::Nikon::MOV',
1892             ByteOrder => 'LittleEndian',
1893             },
1894             },
1895             {
1896             Name => 'OlympusTags1',
1897             Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA\0.{9}\x01\0/s',
1898             SubDirectory => {
1899             TagTable => 'Image::ExifTool::Olympus::MOV1',
1900             ByteOrder => 'LittleEndian',
1901             },
1902             },
1903             {
1904             Name => 'OlympusTags2',
1905             Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA(?!\0.{21}\x0a\0{3})/s',
1906             SubDirectory => {
1907             TagTable => 'Image::ExifTool::Olympus::MOV2',
1908             ByteOrder => 'LittleEndian',
1909             },
1910             },
1911             {
1912             Name => 'OlympusTags3',
1913             Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA\0/',
1914             SubDirectory => {
1915             TagTable => 'Image::ExifTool::Olympus::MP4',
1916             ByteOrder => 'LittleEndian',
1917             },
1918             },
1919             {
1920             Name => 'OlympusTags4',
1921             Condition => '$$valPt =~ /^.{16}OLYM\0/s',
1922             SubDirectory => {
1923             TagTable => 'Image::ExifTool::Olympus::MOV3',
1924             Start => 12,
1925             },
1926             },
1927             {
1928             Name => 'PentaxTags',
1929             Condition => '$$valPt =~ /^PENTAX DIGITAL CAMERA\0/',
1930             SubDirectory => {
1931             TagTable => 'Image::ExifTool::Pentax::MOV',
1932             ByteOrder => 'LittleEndian',
1933             },
1934             },
1935             {
1936             Name => 'SamsungTags',
1937             Condition => '$$valPt =~ /^SAMSUNG DIGITAL CAMERA\0/',
1938             SubDirectory => {
1939             TagTable => 'Image::ExifTool::Samsung::MP4',
1940             ByteOrder => 'LittleEndian',
1941             },
1942             },
1943             {
1944             Name => 'SanyoMOV',
1945             Condition => q{
1946             $$valPt =~ /^SANYO DIGITAL CAMERA\0/ and
1947             $self->{VALUE}->{FileType} eq "MOV"
1948             },
1949             SubDirectory => {
1950             TagTable => 'Image::ExifTool::Sanyo::MOV',
1951             ByteOrder => 'LittleEndian',
1952             },
1953             },
1954             {
1955             Name => 'SanyoMP4',
1956             Condition => q{
1957             $$valPt =~ /^SANYO DIGITAL CAMERA\0/ and
1958             $self->{VALUE}->{FileType} eq "MP4"
1959             },
1960             SubDirectory => {
1961             TagTable => 'Image::ExifTool::Sanyo::MP4',
1962             ByteOrder => 'LittleEndian',
1963             },
1964             },
1965             {
1966             Name => 'UnknownTags',
1967             Unknown => 1,
1968             Binary => 1
1969             },
1970             ],
1971             # ---- Canon ----
1972             CNCV => { Name => 'CompressorVersion', Format => 'string' }, #PH (5D Mark II)
1973             CNMN => {
1974             Name => 'Model', #PH (EOS 550D)
1975             Description => 'Camera Model Name',
1976             Avoid => 1,
1977             Format => 'string', # (necessary to remove the trailing NULL)
1978             },
1979             CNFV => { Name => 'FirmwareVersion', Format => 'string' }, #PH (EOS 550D)
1980             CNTH => { #PH (PowerShot S95)
1981             Name => 'CanonCNTH',
1982             SubDirectory => { TagTable => 'Image::ExifTool::Canon::CNTH' },
1983             },
1984             CNOP => { #PH (7DmkII)
1985             Name => 'CanonCNOP',
1986             SubDirectory => { TagTable => 'Image::ExifTool::Canon::CNOP' },
1987             },
1988             # CNDB - 2112 bytes (550D)
1989             # CNDM - 4 bytes - 0xff,0xd8,0xff,0xd9 (S95)
1990             # CNDG - 10232 bytes, mostly zeros (N100)
1991             # ---- Casio ----
1992             QVMI => { #PH
1993             Name => 'CasioQVMI',
1994             # Casio stores standard EXIF-format information in MOV videos (eg. EX-S880)
1995             SubDirectory => {
1996             TagTable => 'Image::ExifTool::Exif::Main',
1997             ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default)
1998             DirName => 'IFD0',
1999             Multi => 0, # (no NextIFD pointer)
2000             Start => 10,
2001             ByteOrder => 'BigEndian',
2002             },
2003             },
2004             # ---- FujiFilm ----
2005             FFMV => { #PH (FinePix HS20EXR)
2006             Name => 'FujiFilmFFMV',
2007             SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::FFMV' },
2008             },
2009             MVTG => { #PH (FinePix HS20EXR)
2010             Name => 'FujiFilmMVTG',
2011             SubDirectory => {
2012             TagTable => 'Image::ExifTool::Exif::Main',
2013             ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default)
2014             DirName => 'IFD0',
2015             Start => 16,
2016             Base => '$start',
2017             ByteOrder => 'LittleEndian',
2018             },
2019             },
2020             # ---- Garmin ---- (ref PH)
2021             uuid => [{
2022             Name => 'GarminSoftware', # (NC)
2023             Condition => '$$valPt =~ /^VIRBactioncamera/',
2024             RawConv => 'substr($val, 16)',
2025             RawConvInv => '"VIRBactioncamera$val"',
2026             },{
2027             # 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)
2028             Name => 'UUID-Unknown',
2029             Writable => 0,
2030             %unknownInfo,
2031             }],
2032             pmcc => {
2033             Name => 'GarminSettings',
2034             ValueConv => 'substr($val, 4)',
2035             ValueConvInv => '"\0\0\0\x01$val"',
2036             },
2037             # hmtp - "\0\0\0\x01" followed by 408 bytes of zero
2038             # vrin - "\0\0\0\x01" followed by 8 bytes of zero
2039             # ---- GoPro ---- (ref PH)
2040             GoPr => 'GoProType', # (Hero3+)
2041             FIRM => { Name => 'FirmwareVersion', Avoid => 1 }, # (Hero4)
2042             LENS => 'LensSerialNumber', # (Hero4)
2043             CAME => { # (Hero4)
2044             Name => 'SerialNumberHash',
2045             Description => 'Camera Serial Number Hash',
2046             ValueConv => 'unpack("H*",$val)',
2047             ValueConvInv => 'pack("H*",$val)',
2048             },
2049             # SETT? 12 bytes (Hero4)
2050             # MUID? 32 bytes (Hero4, starts with serial number hash)
2051             # HMMT? 404 bytes (Hero4, all zero)
2052             # BCID? 26 bytes (Hero5, all zero), 36 bytes GoPro Max
2053             # GUMI? 16 bytes (Hero5)
2054             "FOV\0" => 'FieldOfView', #forum8938 (Hero2) seen: "Wide"
2055             GPMF => {
2056             Name => 'GoProGPMF',
2057             SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' },
2058             },
2059             # free (all zero)
2060             "\xa9TSC" => 'StartTimeScale', # (Hero6)
2061             "\xa9TSZ" => 'StartTimeSampleSize', # (Hero6)
2062             "\xa9TIM" => 'StartTimecode', #PH (NC)
2063             # --- HTC ----
2064             htcb => {
2065             Name => 'HTCBinary',
2066             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HTCBinary' },
2067             },
2068             # ---- Kodak ----
2069             DcMD => {
2070             Name => 'KodakDcMD',
2071             SubDirectory => { TagTable => 'Image::ExifTool::Kodak::DcMD' },
2072             },
2073             SNum => { Name => 'SerialNumber', Avoid => 1, Groups => { 2 => 'Camera' } },
2074             ptch => { Name => 'Pitch', Format => 'rational64s', Avoid => 1 }, # Units??
2075             _yaw => { Name => 'Yaw', Format => 'rational64s', Avoid => 1 }, # Units??
2076             roll => { Name => 'Roll', Format => 'rational64s', Avoid => 1 }, # Units??
2077             _cx_ => { Name => 'CX', Format => 'rational64s', Unknown => 1 },
2078             _cy_ => { Name => 'CY', Format => 'rational64s', Unknown => 1 },
2079             rads => { Name => 'Rads', Format => 'rational64s', Unknown => 1 },
2080             lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess)
2081             Lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess)
2082             pose => { Name => 'pose', SubDirectory => { TagTable => 'Image::ExifTool::Kodak::pose' } },
2083             # AMBA => Ambarella AVC atom (unknown data written by Kodak Playsport video cam)
2084             # tmlp - 1 byte: 0 (PixPro SP360/4KVR360)
2085             # pivi - 72 bytes (PixPro SP360)
2086             # pive - 12 bytes (PixPro SP360)
2087             # loop - 4 bytes: 0 0 0 0 (PixPro 4KVR360)
2088             # m cm - 2 bytes: 0 0 (PixPro 4KVR360)
2089             # m ev - 2 bytes: 0 0 (PixPro SP360/4KVR360) (exposure comp?)
2090             # m vr - 2 bytes: 0 1 (PixPro 4KVR360) (virtual reality?)
2091             # m wb - 4 bytes: 0 0 0 0 (PixPro SP360/4KVR360) (white balance?)
2092             # mclr - 4 bytes: 0 0 0 0 (PixPro SP360/4KVR360)
2093             # mmtr - 4 bytes: 0,6 0 0 0 (PixPro SP360/4KVR360)
2094             # mflr - 4 bytes: 0 0 0 0 (PixPro SP360)
2095             # lvlm - 24 bytes (PixPro SP360)
2096             # Lvlm - 24 bytes (PixPro 4KVR360)
2097             # ufdm - 4 bytes: 0 0 0 1 (PixPro SP360)
2098             # mtdt - 1 byte: 0 (PixPro SP360/4KVR360)
2099             # gdta - 75240 bytes (PixPro SP360)
2100             # EIS1 - 4 bytes: 03 07 00 00 (PixPro 4KVR360)
2101             # EIS2 - 4 bytes: 04 97 00 00 (PixPro 4KVR360)
2102             # ---- LG ----
2103             adzc => { Name => 'Unknown_adzc', Unknown => 1, Hidden => 1, %langText }, # "false\0/","true\0/"
2104             adze => { Name => 'Unknown_adze', Unknown => 1, Hidden => 1, %langText }, # "false\0/"
2105             adzm => { Name => 'Unknown_adzm', Unknown => 1, Hidden => 1, %langText }, # "\x0e\x04/","\x10\x06"
2106             # ---- Microsoft ----
2107             Xtra => { #PH (microsoft)
2108             Name => 'MicrosoftXtra',
2109             WriteGroup => 'Microsoft',
2110             SubDirectory => {
2111             DirName => 'Microsoft',
2112             TagTable => 'Image::ExifTool::Microsoft::Xtra',
2113             },
2114             },
2115             # ---- Minolta ----
2116             MMA0 => { #PH (DiMage 7Hi)
2117             Name => 'MinoltaMMA0',
2118             SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' },
2119             },
2120             MMA1 => { #PH (Dimage A2)
2121             Name => 'MinoltaMMA1',
2122             SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' },
2123             },
2124             # ---- Nikon ----
2125             NCDT => { #PH
2126             Name => 'NikonNCDT',
2127             SubDirectory => { TagTable => 'Image::ExifTool::Nikon::NCDT' },
2128             },
2129             # ---- Olympus ----
2130             scrn => { #PH (TG-810)
2131             Name => 'OlympusPreview',
2132             Condition => '$$valPt =~ /^.{4}\xff\xd8\xff\xdb/s',
2133             SubDirectory => { TagTable => 'Image::ExifTool::Olympus::scrn' },
2134             },
2135             # ---- Panasonic/Leica ----
2136             PANA => { #PH
2137             Name => 'PanasonicPANA',
2138             SubDirectory => { TagTable => 'Image::ExifTool::Panasonic::PANA' },
2139             },
2140             LEIC => { #PH
2141             Name => 'LeicaLEIC',
2142             SubDirectory => { TagTable => 'Image::ExifTool::Panasonic::PANA' },
2143             },
2144             # ---- Pentax ----
2145             thmb => [ # (apparently defined by 3gpp, ref 16)
2146             { #PH (Pentax Q)
2147             Name => 'MakerNotePentax5a',
2148             Condition => '$$valPt =~ /^PENTAX \0II/',
2149             SubDirectory => {
2150             TagTable => 'Image::ExifTool::Pentax::Main',
2151             ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default)
2152             Start => 10,
2153             Base => '$start - 10',
2154             ByteOrder => 'LittleEndian',
2155             },
2156             },{ #PH (TG-810)
2157             Name => 'OlympusThumbnail',
2158             Condition => '$$valPt =~ /^.{4}\xff\xd8\xff\xdb/s',
2159             SubDirectory => { TagTable => 'Image::ExifTool::Olympus::thmb' },
2160             },{ #17 (format is in bytes 3-7)
2161             Name => 'ThumbnailImage',
2162             Condition => '$$valPt =~ /^.{8}\xff\xd8\xff[\xdb\xe0]/s',
2163             Groups => { 2 => 'Preview' },
2164             RawConv => 'substr($val, 8)',
2165             Binary => 1,
2166             },{ #17 (format is in bytes 3-7)
2167             Name => 'ThumbnailPNG',
2168             Condition => '$$valPt =~ /^.{8}\x89PNG\r\n\x1a\n/s',
2169             Groups => { 2 => 'Preview' },
2170             RawConv => 'substr($val, 8)',
2171             Binary => 1,
2172             },{
2173             Name => 'UnknownThumbnail',
2174             Groups => { 2 => 'Preview' },
2175             Binary => 1,
2176             },
2177             ],
2178             PENT => { #PH
2179             Name => 'PentaxPENT',
2180             SubDirectory => {
2181             TagTable => 'Image::ExifTool::Pentax::PENT',
2182             ByteOrder => 'LittleEndian',
2183             },
2184             },
2185             PXTH => { #PH (Pentax K-01)
2186             Name => 'PentaxPreview',
2187             SubDirectory => { TagTable => 'Image::ExifTool::Pentax::PXTH' },
2188             },
2189             PXMN => [{ #PH (Pentax K-01)
2190             Name => 'MakerNotePentax5b',
2191             Condition => '$$valPt =~ /^PENTAX \0MM/',
2192             SubDirectory => {
2193             TagTable => 'Image::ExifTool::Pentax::Main',
2194             ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default)
2195             Start => 10,
2196             Base => '$start - 10',
2197             ByteOrder => 'BigEndian',
2198             },
2199             },{ #PH (Pentax 645Z)
2200             Name => 'MakerNotePentax5c',
2201             Condition => '$$valPt =~ /^PENTAX \0II/',
2202             SubDirectory => {
2203             TagTable => 'Image::ExifTool::Pentax::Main',
2204             ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default)
2205             Start => 10,
2206             Base => '$start - 10',
2207             ByteOrder => 'LittleEndian',
2208             },
2209             },{
2210             Name => 'MakerNotePentaxUnknown',
2211             Binary => 1,
2212             }],
2213             # ---- Ricoh ----
2214             RTHU => { #PH (GR)
2215             Name => 'PreviewImage',
2216             Groups => { 2 => 'Preview' },
2217             RawConv => '$self->ValidateImage(\$val, $tag)',
2218             },
2219             RMKN => { #PH (GR)
2220             Name => 'RicohRMKN',
2221             SubDirectory => {
2222             TagTable => 'Image::ExifTool::Exif::Main',
2223             ProcessProc => \&Image::ExifTool::ProcessTIFF, # (because ProcessMOV is default)
2224             },
2225             },
2226             '@mak' => { Name => 'Make', Avoid => 1 },
2227             '@mod' => { Name => 'Model', Avoid => 1 },
2228             '@swr' => { Name => 'SoftwareVersion', Avoid => 1 },
2229             '@day' => {
2230             Name => 'ContentCreateDate',
2231             Notes => q{
2232             some stupid Ricoh programmer used the '@' symbol instead of the copyright
2233             symbol in these tag ID's for the Ricoh Theta Z1 and maybe other models
2234             },
2235             Groups => { 2 => 'Time' },
2236             Shift => 'Time',
2237             Avoid => 1,
2238             # handle values in the form "2010-02-12T13:27:14-0800"
2239             ValueConv => q{
2240             require Image::ExifTool::XMP;
2241             $val = Image::ExifTool::XMP::ConvertXMPDate($val);
2242             $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
2243             return $val;
2244             },
2245             ValueConvInv => q{
2246             require Image::ExifTool::XMP;
2247             my $tmp = Image::ExifTool::XMP::FormatXMPDate($val);
2248             ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon
2249             return $val;
2250             },
2251             PrintConv => '$self->ConvertDateTime($val)',
2252             PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
2253             },
2254             '@xyz' => { #PH (iPhone 3GS)
2255             Name => 'GPSCoordinates',
2256             Groups => { 2 => 'Location' },
2257             Avoid => 1,
2258             ValueConv => \&ConvertISO6709,
2259             ValueConvInv => \&ConvInvISO6709,
2260             PrintConv => \&PrintGPSCoordinates,
2261             PrintConvInv => \&PrintInvGPSCoordinates,
2262             },
2263             # RDT1 - pairs of int32u_BE, starting at byte 8: "458275 471846"
2264             # RDT2 - pairs of int32u_BE, starting at byte 8: "472276 468526"
2265             # RDT3 - pairs of int32u_BE, starting at byte 8: "876603 482191"
2266             # RDT4 - pairs of int32u_BE, starting at byte 8: "1955 484612"
2267             # RDT6 - empty
2268             # RDT7 - empty
2269             # RDT8 - empty
2270             # RDT9 - only 16-byte header?
2271             # the boxes below all have a similar header (little-endian):
2272             # 0 int32u - number of records
2273             # 4 ? - "1e 00"
2274             # 6 int16u - record length in bytes
2275             # 8 ? - "23 01 00 00 00 00 00 00"
2276             # 16 - start of records (each record ends in an int64u timestamp "ts" in ns)
2277             # RDTA - float[4],ts: "-0.31289672 -0.2245330 11.303817 0 775.780"
2278             # RDTB - float[4],ts: "-0.04841613 -0.2166595 0.0724792 0 775.780"
2279             # RDTC - float[4],ts: "27.60925 -27.10037 -13.27285 0 775.829"
2280             # RDTD - int16s[3],ts: "353 -914 16354 0 775.829"
2281             # RDTG - ts: "775.825"
2282             # RDTI - float[4],ts: "0.00165951 0.005770059 0.06838259 0.1744695 775.862"
2283             # ---- Samsung ----
2284             vndr => 'Vendor', #PH (Samsung PL70)
2285             SDLN => 'PlayMode', #PH (NC, Samsung ST80 "SEQ_PLAY")
2286             INFO => {
2287             Name => 'SamsungINFO',
2288             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::INFO' },
2289             },
2290             '@sec' => { #PH (Samsung WB30F)
2291             Name => 'SamsungSec',
2292             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::sec' },
2293             },
2294             'smta' => { #PH (Samsung SM-C101)
2295             Name => 'SamsungSmta',
2296             SubDirectory => {
2297             TagTable => 'Image::ExifTool::Samsung::smta',
2298             Start => 4,
2299             },
2300             },
2301             cver => 'CodeVersion', #PH (guess, Samsung MV900F)
2302             # ducp - 4 bytes all zero (Samsung ST96,WB750), 52 bytes all zero (Samsung WB30F)
2303             # edli - 52 bytes all zero (Samsung WB30F)
2304             # @etc - 4 bytes all zero (Samsung WB30F)
2305             # saut - 4 bytes all zero (Samsung SM-N900T)
2306             # smrd - string "TRUEBLUE" (Samsung SM-C101)
2307             # ---- TomTom Bandit Action Cam ----
2308             TTMD => {
2309             Name => 'TomTomMetaData',
2310             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TomTom' },
2311             },
2312             # ---- Samsung Gear 360 ----
2313             vrot => {
2314             Name => 'AccelerometerData',
2315             Notes => q{
2316             accelerometer readings for each frame of the video, expressed as sets of
2317             yaw, pitch and roll angles in degrees
2318             },
2319             Format => 'rational64s',
2320             ValueConv => '$val =~ s/^-?\d+ //; \$val', # (ignore leading version/size words)
2321             },
2322             # m360 - 8 bytes "0 0 0 0 0 0 0 1"
2323             # opax - 164 bytes unknown (center and affine arrays? ref 26)
2324             # opai - 32 bytes (maybe contains a serial number starting at byte 16? - PH) (rgb gains, degamma, gamma? ref 26)
2325             # intv - 16 bytes all zero
2326             # ---- Xaiomi ----
2327             mcvr => {
2328             Name => 'PreviewImage',
2329             Groups => { 2 => 'Preview' },
2330             Binary => 1,
2331             },
2332             # ---- Unknown ----
2333             # CDET - 128 bytes (unknown origin)
2334             # mtyp - 4 bytes all zero (some drone video)
2335             # kgrf - 8 bytes all zero ? (in udta inside trak atom)
2336             # kgcg - 128 bytes 0's and 1's
2337             # kgsi - 4 bytes "00 00 00 80"
2338             # FIEL - 18 bytes "FIEL\0\x01\0\0\0..."
2339             #
2340             # other 3rd-party tags
2341             # (ref http://code.google.com/p/mp4parser/source/browse/trunk/isoparser/src/main/resources/isoparser-default.properties?r=814)
2342             #
2343             ccid => 'ContentID',
2344             icnu => 'IconURI',
2345             infu => 'InfoURL',
2346             cdis => 'ContentDistributorID',
2347             albr => { Name => 'AlbumArtist', Groups => { 2 => 'Author' } },
2348             cvru => 'CoverURI',
2349             lrcu => 'LyricsURI',
2350              
2351             tags => { # found in Audible .m4b audio books (ref PH)
2352             Name => 'Audible_tags',
2353             SubDirectory => { TagTable => 'Image::ExifTool::Audible::tags' },
2354             },
2355             );
2356              
2357             # Unknown information stored in HTC One (M8) videos - PH
2358             %Image::ExifTool::QuickTime::HTCBinary = (
2359             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2360             GROUPS => { 0 => 'MakerNotes', 1 => 'HTC', 2 => 'Video' },
2361             TAG_PREFIX => 'HTCBinary',
2362             FORMAT => 'int32u',
2363             FIRST_ENTRY => 0,
2364             # 0 - values: 1
2365             # 1 - values: 0
2366             # 2 - values: 0
2367             # 3 - values: FileSize minus 12 (why?)
2368             # 4 - values: 12
2369             );
2370              
2371             # TomTom Bandit Action Cam metadata (ref PH)
2372             %Image::ExifTool::QuickTime::TomTom = (
2373             PROCESS_PROC => \&ProcessMOV,
2374             GROUPS => { 2 => 'Video' },
2375             NOTES => 'Tags found in TomTom Bandit Action Cam MP4 videos.',
2376             TTAD => {
2377             Name => 'TomTomAD',
2378             SubDirectory => {
2379             TagTable => 'Image::ExifTool::QuickTime::Stream',
2380             ProcessProc => \&Image::ExifTool::QuickTime::ProcessTTAD,
2381             },
2382             },
2383             TTHL => { Name => 'TomTomHL', Binary => 1, Unknown => 1 }, # (mostly zeros)
2384             # (TTID values are different for each video)
2385             TTID => { Name => 'TomTomID', ValueConv => 'unpack("x4H*",$val)' },
2386             TTVI => { Name => 'TomTomVI', Format => 'int32u', Unknown => 1 }, # seen: "0 1 61 508 508"
2387             # TTVD seen: "normal 720p 60fps 60fps 16/9 wide 1x"
2388             TTVD => { Name => 'TomTomVD', ValueConv => 'my @a = ($val =~ /[\x20-\x7f]+/g); "@a"' },
2389             );
2390              
2391             # User-specific media data atoms (ref 11)
2392             %Image::ExifTool::QuickTime::UserMedia = (
2393             PROCESS_PROC => \&ProcessMOV,
2394             GROUPS => { 2 => 'Video' },
2395             MTDT => {
2396             Name => 'MetaData',
2397             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MetaData' },
2398             },
2399             );
2400              
2401             # User-specific media data atoms (ref 11)
2402             %Image::ExifTool::QuickTime::MetaData = (
2403             PROCESS_PROC => \&ProcessMetaData,
2404             GROUPS => { 2 => 'Video' },
2405             TAG_PREFIX => 'MetaData',
2406             0x01 => 'Title',
2407             0x03 => {
2408             Name => 'ProductionDate',
2409             Groups => { 2 => 'Time' },
2410             Shift => 'Time',
2411             Writable => 1,
2412             Permanent => 1,
2413             DelValue => '0000/00/00 00:00:00',
2414             # translate from format "YYYY/mm/dd HH:MM:SS"
2415             ValueConv => '$val=~tr{/}{:}; $val',
2416             ValueConvInv => '$val=~s[^(\d{4}):(\d{2}):][$1/$2/]; $val',
2417             PrintConv => '$self->ConvertDateTime($val)',
2418             PrintConvInv => '$self->InverseDateTime($val)',
2419             },
2420             0x04 => 'Software',
2421             0x05 => 'Product',
2422             0x0a => {
2423             Name => 'TrackProperty',
2424             RawConv => 'my @a=unpack("Nnn",$val); "@a"',
2425             PrintConv => [
2426             { 0 => 'No presentation', BITMASK => { 0 => 'Main track' } },
2427             { 0 => 'No attributes', BITMASK => { 15 => 'Read only' } },
2428             '"Priority $val"',
2429             ],
2430             },
2431             0x0b => {
2432             Name => 'TimeZone',
2433             Groups => { 2 => 'Time' },
2434             Writable => 1,
2435             Permanent => 1,
2436             DelValue => 0,
2437             RawConv => 'Get16s(\$val,0)',
2438             RawConvInv => 'Set16s($val)',
2439             PrintConv => 'TimeZoneString($val)',
2440             PrintConvInv => q{
2441             return undef unless $val =~ /^([-+])(\d{1,2}):?(\d{2})$/'
2442             my $tzmin = $2 * 60 + $3;
2443             $tzmin = -$tzmin if $1 eq '-';
2444             return $tzmin;
2445             }
2446             },
2447             0x0c => {
2448             Name => 'ModifyDate',
2449             Groups => { 2 => 'Time' },
2450             Shift => 'Time',
2451             Writable => 1,
2452             Permanent => 1,
2453             DelValue => '0000/00/00 00:00:00',
2454             # translate from format "YYYY/mm/dd HH:MM:SS"
2455             ValueConv => '$val=~tr{/}{:}; $val',
2456             ValueConvInv => '$val=~s[^(\d{4}):(\d{2}):][$1/$2/]; $val',
2457             PrintConv => '$self->ConvertDateTime($val)',
2458             PrintConvInv => '$self->InverseDateTime($val)',
2459             },
2460             );
2461              
2462             # compressed movie atoms (ref http://wiki.multimedia.cx/index.php?title=QuickTime_container#cmov)
2463             %Image::ExifTool::QuickTime::CMovie = (
2464             PROCESS_PROC => \&ProcessMOV,
2465             GROUPS => { 2 => 'Video' },
2466             dcom => 'Compression',
2467             # cmvd - compressed moov atom data
2468             );
2469              
2470             # Profile atoms (ref 11)
2471             %Image::ExifTool::QuickTime::Profile = (
2472             PROCESS_PROC => \&ProcessMOV,
2473             GROUPS => { 2 => 'Video' },
2474             FPRF => {
2475             Name => 'FileGlobalProfile',
2476             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FileProf' },
2477             },
2478             APRF => {
2479             Name => 'AudioProfile',
2480             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AudioProf' },
2481             },
2482             VPRF => {
2483             Name => 'VideoProfile',
2484             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::VideoProf' },
2485             },
2486             OLYM => { #PH
2487             Name => 'OlympusOLYM',
2488             SubDirectory => {
2489             TagTable => 'Image::ExifTool::Olympus::OLYM',
2490             ByteOrder => 'BigEndian',
2491             },
2492             },
2493             );
2494              
2495             # FPRF atom information (ref 11)
2496             %Image::ExifTool::QuickTime::FileProf = (
2497             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2498             GROUPS => { 2 => 'Video' },
2499             FORMAT => 'int32u',
2500             0 => { Name => 'FileProfileVersion', Unknown => 1 }, # unknown = uninteresting
2501             1 => {
2502             Name => 'FileFunctionFlags',
2503             PrintConv => { BITMASK => {
2504             28 => 'Fragmented',
2505             29 => 'Additional tracks',
2506             30 => 'Edited', # (main AV track is edited)
2507             }},
2508             },
2509             # 2 - reserved
2510             );
2511              
2512             # APRF atom information (ref 11)
2513             %Image::ExifTool::QuickTime::AudioProf = (
2514             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2515             GROUPS => { 2 => 'Audio' },
2516             FORMAT => 'int32u',
2517             0 => { Name => 'AudioProfileVersion', Unknown => 1 },
2518             1 => 'AudioTrackID',
2519             2 => {
2520             Name => 'AudioCodec',
2521             Format => 'undef[4]',
2522             },
2523             3 => {
2524             Name => 'AudioCodecInfo',
2525             Unknown => 1,
2526             PrintConv => 'sprintf("0x%.4x", $val)',
2527             },
2528             4 => {
2529             Name => 'AudioAttributes',
2530             PrintConv => { BITMASK => {
2531             0 => 'Encrypted',
2532             1 => 'Variable bitrate',
2533             2 => 'Dual mono',
2534             }},
2535             },
2536             5 => {
2537             Name => 'AudioAvgBitrate',
2538             ValueConv => '$val * 1000',
2539             PrintConv => 'ConvertBitrate($val)',
2540             },
2541             6 => {
2542             Name => 'AudioMaxBitrate',
2543             ValueConv => '$val * 1000',
2544             PrintConv => 'ConvertBitrate($val)',
2545             },
2546             7 => 'AudioSampleRate',
2547             8 => 'AudioChannels',
2548             );
2549              
2550             # VPRF atom information (ref 11)
2551             %Image::ExifTool::QuickTime::VideoProf = (
2552             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2553             GROUPS => { 2 => 'Video' },
2554             FORMAT => 'int32u',
2555             0 => { Name => 'VideoProfileVersion', Unknown => 1 },
2556             1 => 'VideoTrackID',
2557             2 => {
2558             Name => 'VideoCodec',
2559             Format => 'undef[4]',
2560             },
2561             3 => {
2562             Name => 'VideoCodecInfo',
2563             Unknown => 1,
2564             PrintConv => 'sprintf("0x%.4x", $val)',
2565             },
2566             4 => {
2567             Name => 'VideoAttributes',
2568             PrintConv => { BITMASK => {
2569             0 => 'Encrypted',
2570             1 => 'Variable bitrate',
2571             2 => 'Variable frame rate',
2572             3 => 'Interlaced',
2573             }},
2574             },
2575             5 => {
2576             Name => 'VideoAvgBitrate',
2577             ValueConv => '$val * 1000',
2578             PrintConv => 'ConvertBitrate($val)',
2579             },
2580             6 => {
2581             Name => 'VideoMaxBitrate',
2582             ValueConv => '$val * 1000',
2583             PrintConv => 'ConvertBitrate($val)',
2584             },
2585             7 => {
2586             Name => 'VideoAvgFrameRate',
2587             Format => 'fixed32u',
2588             PrintConv => 'int($val * 1000 + 0.5) / 1000',
2589             },
2590             8 => {
2591             Name => 'VideoMaxFrameRate',
2592             Format => 'fixed32u',
2593             PrintConv => 'int($val * 1000 + 0.5) / 1000',
2594             },
2595             9 => {
2596             Name => 'VideoSize',
2597             Format => 'int16u[2]',
2598             PrintConv => '$val=~tr/ /x/; $val',
2599             },
2600             10 => {
2601             Name => 'PixelAspectRatio',
2602             Format => 'int16u[2]',
2603             PrintConv => '$val=~tr/ /:/; $val',
2604             },
2605             );
2606              
2607             # meta atoms
2608             %Image::ExifTool::QuickTime::Meta = (
2609             PROCESS_PROC => \&ProcessMOV,
2610             WRITE_PROC => \&WriteQuickTime,
2611             GROUPS => { 1 => 'Meta', 2 => 'Video' },
2612             ilst => {
2613             Name => 'ItemList',
2614             SubDirectory => {
2615             TagTable => 'Image::ExifTool::QuickTime::ItemList',
2616             HasData => 1, # process atoms as containers with 'data' elements
2617             },
2618             },
2619             # MP4 tags (ref 5)
2620             hdlr => {
2621             Name => 'Handler',
2622             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' },
2623             },
2624             dinf => {
2625             Name => 'DataInfo', # (don't change this name -- used to recognize directory when writing)
2626             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' },
2627             },
2628             ipmc => {
2629             Name => 'IPMPControl',
2630             Flags => ['Binary','Unknown'],
2631             },
2632             iloc => {
2633             Name => 'ItemLocation',
2634             RawConv => \&ParseItemLocation,
2635             WriteHook => \&ParseItemLocation,
2636             Notes => 'parsed, but not extracted as a tag',
2637             },
2638             ipro => {
2639             Name => 'ItemProtection',
2640             Flags => ['Binary','Unknown'],
2641             },
2642             iinf => [{
2643             Name => 'ItemInformation',
2644             Condition => '$$valPt =~ /^\0/', # (check for version 0)
2645             SubDirectory => {
2646             TagTable => 'Image::ExifTool::QuickTime::ItemInfo',
2647             Start => 6, # (4-byte version/flags + 2-byte count)
2648             },
2649             },{
2650             Name => 'ItemInformation',
2651             SubDirectory => {
2652             TagTable => 'Image::ExifTool::QuickTime::ItemInfo',
2653             Start => 8, # (4-byte version/flags + 4-byte count)
2654             },
2655             }],
2656             'xml ' => {
2657             Name => 'XML',
2658             Flags => [ 'Binary', 'Protected' ],
2659             SubDirectory => {
2660             TagTable => 'Image::ExifTool::XMP::XML',
2661             IgnoreProp => { NonRealTimeMeta => 1 }, # ignore container for Sony 'nrtm'
2662             },
2663             },
2664             'keys' => {
2665             Name => 'Keys',
2666             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Keys' },
2667             },
2668             bxml => {
2669             Name => 'BinaryXML',
2670             Flags => ['Binary','Unknown'],
2671             },
2672             pitm => [{
2673             Name => 'PrimaryItemReference',
2674             Condition => '$$valPt =~ /^\0/', # (version 0?)
2675             RawConv => '$$self{PrimaryItem} = unpack("x4n",$val)',
2676             WriteHook => sub { my ($val,$et) = @_; $$et{PrimaryItem} = unpack("x4n",$val); },
2677             },{
2678             Name => 'PrimaryItemReference',
2679             RawConv => '$$self{PrimaryItem} = unpack("x4N",$val)',
2680             WriteHook => sub { my ($val,$et) = @_; $$et{PrimaryItem} = unpack("x4N",$val); },
2681             }],
2682             free => { #PH
2683             Name => 'Free',
2684             Flags => ['Binary','Unknown'],
2685             },
2686             iprp => {
2687             Name => 'ItemProperties',
2688             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemProp' },
2689             },
2690             iref => {
2691             Name => 'ItemReference',
2692             # the version is needed to parse some of the item references
2693             Condition => '$$self{ItemRefVersion} = ord($$valPt); 1',
2694             SubDirectory => {
2695             TagTable => 'Image::ExifTool::QuickTime::ItemRef',
2696             Start => 4,
2697             },
2698             },
2699             idat => {
2700             Name => 'MetaImageSize', #PH (NC)
2701             Format => 'int16u',
2702             # (don't know what the first two numbers are for)
2703             PrintConv => '$val =~ s/^(\d+) (\d+) (\d+) (\d+)/${3}x$4/; $val',
2704             },
2705             uuid => [
2706             { #PH (Canon R5/R6 HIF)
2707             Name => 'MetaVersion', # (NC)
2708             Condition => '$$valPt=~/^\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48/',
2709             RawConv => 'substr($val, 0x14)',
2710             },
2711             {
2712             Name => 'UUID-Unknown',
2713             %unknownInfo,
2714             },
2715             ],
2716             );
2717              
2718             # additional metadata container (ref ISO14496-12:2015)
2719             %Image::ExifTool::QuickTime::OtherMeta = (
2720             PROCESS_PROC => \&ProcessMOV,
2721             WRITE_PROC => \&WriteQuickTime,
2722             GROUPS => { 2 => 'Video' },
2723             mere => {
2724             Name => 'MetaRelation',
2725             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MetaRelation' },
2726             },
2727             meta => {
2728             Name => 'Meta',
2729             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' },
2730             },
2731             );
2732              
2733             # metabox relation (ref ISO14496-12:2015)
2734             %Image::ExifTool::QuickTime::MetaRelation = (
2735             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2736             GROUPS => { 2 => 'Video' },
2737             FORMAT => 'int32u',
2738             # 0 => 'MetaRelationVersion',
2739             # 1 => 'FirstMetaboxHandlerType',
2740             # 2 => 'FirstMetaboxHandlerType',
2741             # 3 => { Name => 'MetaboxRelation', Format => 'int8u' },
2742             );
2743              
2744             %Image::ExifTool::QuickTime::ItemProp = (
2745             PROCESS_PROC => \&ProcessMOV,
2746             WRITE_PROC => \&WriteQuickTime,
2747             GROUPS => { 2 => 'Image' },
2748             ipco => {
2749             Name => 'ItemPropertyContainer',
2750             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemPropCont' },
2751             },
2752             ipma => {
2753             Name => 'ItemPropertyAssociation',
2754             RawConv => \&ParseItemPropAssoc,
2755             WriteHook => \&ParseItemPropAssoc,
2756             Notes => 'parsed, but not extracted as a tag',
2757             },
2758             );
2759              
2760             %Image::ExifTool::QuickTime::ItemPropCont = (
2761             PROCESS_PROC => \&ProcessMOV,
2762             WRITE_PROC => \&WriteQuickTime,
2763             PERMANENT => 1, # (can't be deleted)
2764             GROUPS => { 2 => 'Image' },
2765             VARS => { START_INDEX => 1 }, # show verbose indices starting at 1
2766             colr => [{
2767             Name => 'ICC_Profile',
2768             Condition => '$$valPt =~ /^(prof|rICC)/',
2769             Permanent => 0, # (in QuickTime, this writes a zero-length box instead of deleting)
2770             SubDirectory => {
2771             TagTable => 'Image::ExifTool::ICC_Profile::Main',
2772             Start => 4,
2773             },
2774             },{
2775             Name => 'ColorRepresentation',
2776             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ColorRep' },
2777             }],
2778             irot => {
2779             Name => 'Rotation',
2780             Format => 'int8u',
2781             Writable => 'int8u',
2782             Protected => 1,
2783             ValueConv => '$val * 90',
2784             ValueConvInv => 'int($val / 90 + 0.5)',
2785             },
2786             ispe => {
2787             Name => 'ImageSpatialExtent',
2788             Condition => '$$valPt =~ /^\0{4}/', # (version/flags == 0/0)
2789             RawConv => q{
2790             my @dim = unpack("x4N*", $val);
2791             return undef if @dim < 2;
2792             unless ($$self{DOC_NUM}) {
2793             $self->FoundTag(ImageWidth => $dim[0]);
2794             $self->FoundTag(ImageHeight => $dim[1]);
2795             }
2796             return join ' ', @dim;
2797             },
2798             PrintConv => '$val =~ tr/ /x/; $val',
2799             },
2800             pixi => {
2801             Name => 'ImagePixelDepth',
2802             Condition => '$$valPt =~ /^\0{4}./s', # (version/flags == 0/0 and count)
2803             RawConv => 'join " ", unpack("x5C*", $val)',
2804             },
2805             auxC => {
2806             Name => 'AuxiliaryImageType',
2807             Format => 'undef',
2808             RawConv => '$val = substr($val, 4); $val =~ s/\0.*//s; $val',
2809             },
2810             pasp => {
2811             Name => 'PixelAspectRatio',
2812             Format => 'int32u',
2813             Writable => 'int32u',
2814             Protected => 1,
2815             },
2816             rloc => {
2817             Name => 'RelativeLocation',
2818             Format => 'int32u',
2819             RawConv => '$val =~ s/^\S+\s+//; $val', # remove version/flags
2820             },
2821             clap => {
2822             Name => 'CleanAperture',
2823             Format => 'rational64s',
2824             Notes => '4 numbers: width, height, left and top',
2825             },
2826             hvcC => {
2827             Name => 'HEVCConfiguration',
2828             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HEVCConfig' },
2829             },
2830             av1C => {
2831             Name => 'AV1Configuration',
2832             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AV1Config' },
2833             },
2834             );
2835              
2836             # ref https://aomediacodec.github.io/av1-spec/av1-spec.pdf
2837             %Image::ExifTool::QuickTime::ColorRep = (
2838             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2839             GROUPS => { 2 => 'Video' },
2840             FIRST_ENTRY => 0,
2841             0 => { Name => 'ColorProfiles', Format => 'undef[4]' },
2842             4 => {
2843             Name => 'ColorPrimaries',
2844             Format => 'int16u',
2845             PrintConv => {
2846             1 => 'BT.709',
2847             2 => 'Unspecified',
2848             4 => 'BT.470 System M (historical)',
2849             5 => 'BT.470 System B, G (historical)',
2850             6 => 'BT.601',
2851             7 => 'SMPTE 240',
2852             8 => 'Generic film (color filters using illuminant C)',
2853             9 => 'BT.2020, BT.2100',
2854             10 => 'SMPTE 428 (CIE 1921 XYZ)',
2855             11 => 'SMPTE RP 431-2',
2856             12 => 'SMPTE EG 432-1',
2857             22 => 'EBU Tech. 3213-E',
2858             },
2859             },
2860             6 => {
2861             Name => 'TransferCharacteristics',
2862             Format => 'int16u',
2863             PrintConv => {
2864             0 => 'For future use (0)',
2865             1 => 'BT.709',
2866             2 => 'Unspecified',
2867             3 => 'For future use (3)',
2868             4 => 'BT.470 System M (historical)',
2869             5 => 'BT.470 System B, G (historical)',
2870             6 => 'BT.601',
2871             7 => 'SMPTE 240 M',
2872             8 => 'Linear',
2873             9 => 'Logarithmic (100 : 1 range)',
2874             10 => 'Logarithmic (100 * Sqrt(10) : 1 range)',
2875             11 => 'IEC 61966-2-4',
2876             12 => 'BT.1361',
2877             13 => 'sRGB or sYCC',
2878             14 => 'BT.2020 10-bit systems',
2879             15 => 'BT.2020 12-bit systems',
2880             16 => 'SMPTE ST 2084, ITU BT.2100 PQ',
2881             17 => 'SMPTE ST 428',
2882             18 => 'BT.2100 HLG, ARIB STD-B67',
2883             },
2884             },
2885             8 => {
2886             Name => 'MatrixCoefficients',
2887             Format => 'int16u',
2888             PrintConv => {
2889             0 => 'Identity matrix',
2890             1 => 'BT.709',
2891             2 => 'Unspecified',
2892             3 => 'For future use (3)',
2893             4 => 'US FCC 73.628',
2894             5 => 'BT.470 System B, G (historical)',
2895             6 => 'BT.601',
2896             7 => 'SMPTE 240 M',
2897             8 => 'YCgCo',
2898             9 => 'BT.2020 non-constant luminance, BT.2100 YCbCr',
2899             10 => 'BT.2020 constant luminance',
2900             11 => 'SMPTE ST 2085 YDzDx',
2901             12 => 'Chromaticity-derived non-constant luminance',
2902             13 => 'Chromaticity-derived constant luminance',
2903             14 => 'BT.2100 ICtCp',
2904             },
2905             },
2906             );
2907              
2908             # HEVC configuration (ref https://github.com/MPEGGroup/isobmff/blob/master/IsoLib/libisomediafile/src/HEVCConfigAtom.c)
2909             %Image::ExifTool::QuickTime::HEVCConfig = (
2910             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2911             GROUPS => { 2 => 'Video' },
2912             FIRST_ENTRY => 0,
2913             0 => 'HEVCConfigurationVersion',
2914             1 => {
2915             Name => 'GeneralProfileSpace',
2916             Mask => 0xc0,
2917             PrintConv => { 0 => 'Conforming' },
2918             },
2919             1.1 => {
2920             Name => 'GeneralTierFlag',
2921             Mask => 0x20,
2922             PrintConv => {
2923             0 => 'Main Tier',
2924             1 => 'High Tier',
2925             },
2926             },
2927             1.2 => {
2928             Name => 'GeneralProfileIDC',
2929             Mask => 0x1f,
2930             PrintConv => {
2931             0 => 'No Profile',
2932             1 => 'Main',
2933             2 => 'Main 10',
2934             3 => 'Main Still Picture',
2935             4 => 'Format Range Extensions',
2936             5 => 'High Throughput',
2937             6 => 'Multiview Main',
2938             7 => 'Scalable Main',
2939             8 => '3D Main',
2940             9 => 'Screen Content Coding Extensions',
2941             10 => 'Scalable Format Range Extensions',
2942             11 => 'High Throughput Screen Content Coding Extensions',
2943             },
2944             },
2945             2 => {
2946             Name => 'GenProfileCompatibilityFlags',
2947             Format => 'int32u',
2948             PrintConv => { BITMASK => {
2949             31 => 'No Profile', # (bit 0 in stream)
2950             30 => 'Main', # (bit 1 in stream)
2951             29 => 'Main 10', # (bit 2 in stream)
2952             28 => 'Main Still Picture', # (bit 3 in stream)
2953             27 => 'Format Range Extensions',# (...)
2954             26 => 'High Throughput',
2955             25 => 'Multiview Main',
2956             24 => 'Scalable Main',
2957             23 => '3D Main',
2958             22 => 'Screen Content Coding Extensions',
2959             21 => 'Scalable Format Range Extensions',
2960             20 => 'High Throughput Screen Content Coding Extensions',
2961             }},
2962             },
2963             6 => {
2964             Name => 'ConstraintIndicatorFlags',
2965             Format => 'int8u[6]',
2966             },
2967             12 => {
2968             Name => 'GeneralLevelIDC',
2969             PrintConv => 'sprintf("%d (level %.1f)", $val, $val/30)',
2970             },
2971             13 => {
2972             Name => 'MinSpatialSegmentationIDC',
2973             Format => 'int16u',
2974             Mask => 0x0fff,
2975             },
2976             15 => {
2977             Name => 'ParallelismType',
2978             Mask => 0x03,
2979             },
2980             16 => {
2981             Name => 'ChromaFormat',
2982             Mask => 0x03,
2983             PrintConv => {
2984             0 => 'Monochrome',
2985             1 => '4:2:0',
2986             2 => '4:2:2',
2987             3 => '4:4:4',
2988             },
2989             },
2990             17 => {
2991             Name => 'BitDepthLuma',
2992             Mask => 0x07,
2993             ValueConv => '$val + 8',
2994             },
2995             18 => {
2996             Name => 'BitDepthChroma',
2997             Mask => 0x07,
2998             ValueConv => '$val + 8',
2999             },
3000             19 => {
3001             Name => 'AverageFrameRate',
3002             Format => 'int16u',
3003             ValueConv => '$val / 256',
3004             },
3005             21 => {
3006             Name => 'ConstantFrameRate',
3007             Mask => 0xc0,
3008             PrintConv => {
3009             0 => 'Unknown',
3010             1 => 'Constant Frame Rate',
3011             2 => 'Each Temporal Layer is Constant Frame Rate',
3012             },
3013             },
3014             21.1 => {
3015             Name => 'NumTemporalLayers',
3016             Mask => 0x38,
3017             },
3018             21.2 => {
3019             Name => 'TemporalIDNested',
3020             Mask => 0x04,
3021             PrintConv => { 0 => 'No', 1 => 'Yes' },
3022             },
3023             #21.3 => {
3024             # Name => 'NALUnitLengthSize',
3025             # Mask => 0x03,
3026             # ValueConv => '$val + 1',
3027             # PrintConv => { 1 => '8-bit', 2 => '16-bit', 4 => '32-bit' },
3028             #},
3029             #22 => 'NumberOfNALUnitArrays',
3030             # (don't decode the NAL unit arrays)
3031             );
3032              
3033             # HEVC configuration (ref https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox)
3034             %Image::ExifTool::QuickTime::AV1Config = (
3035             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
3036             GROUPS => { 2 => 'Video' },
3037             FIRST_ENTRY => 0,
3038             0 => {
3039             Name => 'AV1ConfigurationVersion',
3040             Mask => 0x7f,
3041             },
3042             1.0 => {
3043             Name => 'SeqProfile',
3044             Mask => 0xe0,
3045             Unknown => 1,
3046             },
3047             1.1 => {
3048             Name => 'SeqLevelIdx0',
3049             Mask => 0x1f,
3050             Unknown => 1,
3051             },
3052             2.0 => {
3053             Name => 'SeqTier0',
3054             Mask => 0x80,
3055             Unknown => 1,
3056             },
3057             2.1 => {
3058             Name => 'HighBitDepth',
3059             Mask => 0x40,
3060             Unknown => 1,
3061             },
3062             2.2 => {
3063             Name => 'TwelveBit',
3064             Mask => 0x20,
3065             Unknown => 1,
3066             },
3067             2.3 => {
3068             Name => 'ChromaFormat', # (Monochrome+SubSamplingX+SubSamplingY)
3069             Notes => 'bits: 0x04 = Monochrome, 0x02 = SubSamplingX, 0x01 = SubSamplingY',
3070             Mask => 0x1c,
3071             PrintConv => {
3072             0x00 => 'YUV 4:4:4',
3073             0x02 => 'YUV 4:2:2',
3074             0x03 => 'YUV 4:2:0',
3075             0x07 => 'Monochrome 4:0:0',
3076             },
3077             },
3078             2.4 => {
3079             Name => 'ChromaSamplePosition',
3080             Mask => 0x03,
3081             PrintConv => {
3082             0 => 'Unknown',
3083             1 => 'Vertical',
3084             2 => 'Colocated',
3085             3 => '(reserved)',
3086             },
3087             },
3088             3 => {
3089             Name => 'InitialDelaySamples',
3090             RawConv => '$val & 0x10 ? undef : ($val & 0x0f) + 1',
3091             Unknown => 1,
3092             },
3093             );
3094              
3095             %Image::ExifTool::QuickTime::ItemRef = (
3096             PROCESS_PROC => \&ProcessMOV,
3097             WRITE_PROC => \&WriteQuickTime,
3098             GROUPS => { 2 => 'Image' },
3099             # (Note: ExifTool's ItemRefVersion may be used to test the iref version number)
3100             NOTES => q{
3101             The Item reference entries listed in the table below contain information about
3102             the associations between items in the file. This information is used by
3103             ExifTool, but these entries are not extracted as tags.
3104             },
3105             dimg => { Name => 'DerivedImageRef', RawConv => 'undef' },
3106             thmb => { Name => 'ThumbnailRef', RawConv => 'undef' },
3107             auxl => { Name => 'AuxiliaryImageRef', RawConv => 'undef' },
3108             cdsc => {
3109             Name => 'ContentDescribes',
3110             RawConv => \&ParseContentDescribes,
3111             WriteHook => \&ParseContentDescribes,
3112             },
3113             );
3114              
3115             %Image::ExifTool::QuickTime::ItemInfo = (
3116             PROCESS_PROC => \&ProcessMOV,
3117             WRITE_PROC => \&WriteQuickTime,
3118             GROUPS => { 2 => 'Image' },
3119             # avc1 - AVC image
3120             # hvc1 - HEVC image
3121             # lhv1 - L-HEVC image
3122             # infe - ItemInformationEntry
3123             # infe types: avc1,hvc1,lhv1,Exif,xml1,iovl(overlay image),grid,mime,hvt1(tile image)
3124             infe => {
3125             Name => 'ItemInfoEntry',
3126             RawConv => \&ParseItemInfoEntry,
3127             WriteHook => \&ParseItemInfoEntry,
3128             Notes => 'parsed, but not extracted as a tag',
3129             },
3130             );
3131              
3132             # track reference atoms
3133             %Image::ExifTool::QuickTime::TrackRef = (
3134             PROCESS_PROC => \&ProcessMOV,
3135             GROUPS => { 1 => 'Track#', 2 => 'Video' },
3136             chap => { Name => 'ChapterListTrackID', Format => 'int32u' },
3137             tmcd => { Name => 'TimeCode', Format => 'int32u' },
3138             mpod => { #PH (FLIR MP4)
3139             Name => 'ElementaryStreamTrack',
3140             Format => 'int32u',
3141             ValueConv => '$val =~ s/^1 //; $val', # (why 2 numbers? -- ignore the first if "1")
3142             },
3143             # also: sync, scpt, ssrc, iTunesInfo
3144             cdsc => {
3145             Name => 'ContentDescribes',
3146             Format => 'int32u',
3147             PrintConv => '"Track $val"',
3148             },
3149             # cdep (Structural Dependency QT tag?)
3150             );
3151              
3152             # track aperture mode dimensions atoms
3153             # (ref https://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap2/qtff2.html)
3154             %Image::ExifTool::QuickTime::TrackAperture = (
3155             PROCESS_PROC => \&ProcessMOV,
3156             GROUPS => { 1 => 'Track#', 2 => 'Video' },
3157             clef => {
3158             Name => 'CleanApertureDimensions',
3159             Format => 'fixed32u',
3160             Count => 3,
3161             ValueConv => '$val =~ s/^.*? //; $val', # remove flags word
3162             PrintConv => '$val =~ tr/ /x/; $val',
3163             },
3164             prof => {
3165             Name => 'ProductionApertureDimensions',
3166             Format => 'fixed32u',
3167             Count => 3,
3168             ValueConv => '$val =~ s/^.*? //; $val',
3169             PrintConv => '$val =~ tr/ /x/; $val',
3170             },
3171             enof => {
3172             Name => 'EncodedPixelsDimensions',
3173             Format => 'fixed32u',
3174             Count => 3,
3175             ValueConv => '$val =~ s/^.*? //; $val',
3176             PrintConv => '$val =~ tr/ /x/; $val',
3177             },
3178             );
3179              
3180             # item list atoms
3181             # -> these atoms are unique, and contain one or more 'data' atoms
3182             %Image::ExifTool::QuickTime::ItemList = (
3183             PROCESS_PROC => \&ProcessMOV,
3184             WRITE_PROC => \&WriteQuickTime,
3185             CHECK_PROC => \&CheckQTValue,
3186             WRITABLE => 1,
3187             PREFERRED => 2, # (preferred over UserData and Keys tags when writing)
3188             FORMAT => 'string',
3189             GROUPS => { 1 => 'ItemList', 2 => 'Audio' },
3190             WRITE_GROUP => 'ItemList',
3191             LANG_INFO => \&GetLangInfo,
3192             NOTES => q{
3193             This is the preferred location for creating new QuickTime tags. Tags in
3194             this table support alternate languages which are accessed by adding a
3195             3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2
3196             country code to the tag name (eg. "ItemList:Title-fra" or
3197             "ItemList::Title-fra-FR"). When creating a new Meta box to contain the
3198             ItemList directory, by default ExifTool adds an 'mdir' (Metadata) Handler
3199             box because Apple software may ignore ItemList tags otherwise, but the API
3200             L option may be set to 0 to avoid this.
3201             },
3202             # in this table, binary 1 and 2-byte "data"-type tags are interpreted as
3203             # int8u and int16u. Multi-byte binary "data" tags are extracted as binary data.
3204             # (Note that the Preferred property is set to 0 for some tags to prevent them
3205             # from being created when a same-named tag already exists in the table)
3206             "\xa9ART" => 'Artist',
3207             "\xa9alb" => 'Album',
3208             "\xa9aut" => { Name => 'Author', Avoid => 1, Groups => { 2 => 'Author' } }, #forum10091 ('auth' is preferred)
3209             "\xa9cmt" => 'Comment',
3210             "\xa9com" => { Name => 'Composer', Avoid => 1, }, # ("\xa9wrt" is preferred in ItemList)
3211             "\xa9day" => {
3212             Name => 'ContentCreateDate',
3213             Groups => { 2 => 'Time' },
3214             Shift => 'Time',
3215             # handle values in the form "2010-02-12T13:27:14-0800"
3216             ValueConv => q{
3217             require Image::ExifTool::XMP;
3218             $val = Image::ExifTool::XMP::ConvertXMPDate($val);
3219             $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
3220             return $val;
3221             },
3222             ValueConvInv => q{
3223             require Image::ExifTool::XMP;
3224             $val = Image::ExifTool::XMP::FormatXMPDate($val);
3225             $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon
3226             return $val;
3227             },
3228             PrintConv => '$self->ConvertDateTime($val)',
3229             PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
3230             },
3231             "\xa9des" => 'Description', #4
3232             "\xa9enc" => 'EncodedBy', #10
3233             "\xa9gen" => 'Genre',
3234             "\xa9grp" => 'Grouping',
3235             "\xa9lyr" => 'Lyrics',
3236             "\xa9nam" => 'Title',
3237             "\xa9too" => 'Encoder',
3238             "\xa9trk" => 'Track',
3239             "\xa9wrt" => 'Composer',
3240             #
3241             # the following tags written by AtomicParsley 0.9.6
3242             # (ref https://exiftool.org/forum/index.php?topic=11455.0)
3243             #
3244             "\xa9st3" => 'Subtitle',
3245             "\xa9con" => 'Conductor',
3246             "\xa9sol" => 'Soloist',
3247             "\xa9arg" => 'Arranger',
3248             "\xa9ope" => 'OriginalArtist',
3249             "\xa9dir" => 'Director',
3250             "\xa9ard" => 'ArtDirector',
3251             "\xa9sne" => 'SoundEngineer',
3252             "\xa9prd" => 'Producer',
3253             "\xa9xpd" => 'ExecutiveProducer',
3254             sdes => 'StoreDescription',
3255             #
3256             '----' => {
3257             Name => 'iTunesInfo',
3258             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::iTunesInfo' },
3259             },
3260             aART => { Name => 'AlbumArtist', Groups => { 2 => 'Author' } },
3261             covr => { Name => 'CoverArt', Groups => { 2 => 'Preview' } },
3262             cpil => { #10
3263             Name => 'Compilation',
3264             Format => 'int8u', #27 (ref 23 contradicts what AtomicParsley actually writes, which is int8s)
3265             Writable => 'int8s',
3266             PrintConv => { 0 => 'No', 1 => 'Yes' },
3267             },
3268             disk => {
3269             Name => 'DiskNumber',
3270             Format => 'undef', # (necessary to prevent decoding as string!)
3271             ValueConv => q{
3272             return \$val unless length($val) >= 6;
3273             my @a = unpack 'x2nn', $val;
3274             return $a[1] ? join(' of ', @a) : $a[0];
3275             },
3276             ValueConvInv => q{
3277             my @a = $val =~ /\d+/g;
3278             return undef if @a == 0 or @a > 2;
3279             push @a, 0 if @a == 1;
3280             return pack('n3', 0, @a);
3281             },
3282             },
3283             pgap => { #10
3284             Name => 'PlayGap',
3285             Format => 'int8u', #23
3286             Writable => 'int8s', #27
3287             PrintConv => {
3288             0 => 'Insert Gap',
3289             1 => 'No Gap',
3290             },
3291             },
3292             tmpo => {
3293             Name => 'BeatsPerMinute',
3294             # marked as boolean but really int16u in my sample
3295             # (but written as int16s by iTunes and AtomicParsley, ref forum11506)
3296             Format => 'int16u',
3297             Writable => 'int16s',
3298             },
3299             trkn => {
3300             Name => 'TrackNumber',
3301             Format => 'undef', # (necessary to prevent decoding as string!)
3302             ValueConv => q{
3303             return \$val unless length($val) >= 6;
3304             my @a = unpack 'x2nn', $val;
3305             return $a[1] ? join(' of ', @a) : $a[0];
3306             },
3307             # (see forum11501 for discussion about the format used)
3308             ValueConvInv => q{
3309             my @a = $val =~ /\d+/g;
3310             return undef if @a == 0 or @a > 2;
3311             push @a, 0 if @a == 1;
3312             return pack('n4', 0, @a, 0);
3313             },
3314             },
3315             #
3316             # Note: it is possible that the tags below are not being decoded properly
3317             # because I don't have samples to verify many of these - PH
3318             #
3319             akID => { #10
3320             Name => 'AppleStoreAccountType',
3321             Format => 'int8u', #24
3322             Writable => 'int8s', #27
3323             PrintConv => {
3324             0 => 'iTunes',
3325             1 => 'AOL',
3326             },
3327             },
3328             albm => { Name => 'Album', Avoid => 1 }, #(ffmpeg source)
3329             apID => 'AppleStoreAccount',
3330             atID => { #10 (or TV series)
3331             Name => 'AlbumTitleID',
3332             Format => 'int32u',
3333             Writable => 'int32s', #27
3334             },
3335             auth => { Name => 'Author', Groups => { 2 => 'Author' } },
3336             catg => 'Category', #7
3337             cnID => { #10
3338             Name => 'AppleStoreCatalogID',
3339             Format => 'int32u',
3340             Writable => 'int32s', #27
3341             },
3342             cprt => { Name => 'Copyright', Groups => { 2 => 'Author' } },
3343             dscp => { Name => 'Description', Avoid => 1 },
3344             desc => { Name => 'Description', Avoid => 1 }, #7
3345             gnre => { #10
3346             Name => 'Genre',
3347             Avoid => 1,
3348             # (Note: see https://exiftool.org/forum/index.php?topic=11537.0)
3349             Format => 'undef',
3350             ValueConv => 'unpack("n",$val)',
3351             ValueConvInv => '$val =~ /^\d+$/ ? pack("n",$val) : undef',
3352             PrintConv => q{
3353             return $val unless $val =~ /^\d+$/;
3354             require Image::ExifTool::ID3;
3355             Image::ExifTool::ID3::PrintGenre($val - 1); # note the "- 1"
3356             },
3357             PrintConvInv => q{
3358             return $val if $val =~ /^[0-9]+$/;
3359             require Image::ExifTool::ID3;
3360             my $id = Image::ExifTool::ID3::GetGenreID($val);
3361             return unless defined $id and $id =~ /^\d+$/;
3362             return $id + 1;
3363             },
3364             },
3365             egid => 'EpisodeGlobalUniqueID', #7
3366             geID => { #10
3367             Name => 'GenreID',
3368             Format => 'int32u',
3369             Writable => 'int32s', #27
3370             SeparateTable => 1,
3371             # the following lookup is based on http://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/genres
3372             # (see scripts/parse_genre to parse genre JSON file from above)
3373             PrintConv => { #21/PH
3374             2 => 'Music|Blues',
3375             3 => 'Music|Comedy',
3376             4 => "Music|Children's Music",
3377             5 => 'Music|Classical',
3378             6 => 'Music|Country',
3379             7 => 'Music|Electronic',
3380             8 => 'Music|Holiday',
3381             9 => 'Music|Classical|Opera',
3382             10 => 'Music|Singer/Songwriter',
3383             11 => 'Music|Jazz',
3384             12 => 'Music|Latino',
3385             13 => 'Music|New Age',
3386             14 => 'Music|Pop',
3387             15 => 'Music|R&B/Soul',
3388             16 => 'Music|Soundtrack',
3389             17 => 'Music|Dance',
3390             18 => 'Music|Hip-Hop/Rap',
3391             19 => 'Music|World',
3392             20 => 'Music|Alternative',
3393             21 => 'Music|Rock',
3394             22 => 'Music|Christian & Gospel',
3395             23 => 'Music|Vocal',
3396             24 => 'Music|Reggae',
3397             25 => 'Music|Easy Listening',
3398             26 => 'Podcasts',
3399             27 => 'Music|J-Pop',
3400             28 => 'Music|Enka',
3401             29 => 'Music|Anime',
3402             30 => 'Music|Kayokyoku',
3403             31 => 'Music Videos',
3404             32 => 'TV Shows',
3405             33 => 'Movies',
3406             34 => 'Music',
3407             35 => 'iPod Games',
3408             36 => 'App Store',
3409             37 => 'Tones',
3410             38 => 'Books',
3411             39 => 'Mac App Store',
3412             40 => 'Textbooks',
3413             50 => 'Music|Fitness & Workout',
3414             51 => 'Music|Pop|K-Pop',
3415             52 => 'Music|Karaoke',
3416             53 => 'Music|Instrumental',
3417             74 => 'Audiobooks|News',
3418             75 => 'Audiobooks|Programs & Performances',
3419             500 => 'Fitness Music',
3420             501 => 'Fitness Music|Pop',
3421             502 => 'Fitness Music|Dance',
3422             503 => 'Fitness Music|Hip-Hop',
3423             504 => 'Fitness Music|Rock',
3424             505 => 'Fitness Music|Alt/Indie',
3425             506 => 'Fitness Music|Latino',
3426             507 => 'Fitness Music|Country',
3427             508 => 'Fitness Music|World',
3428             509 => 'Fitness Music|New Age',
3429             510 => 'Fitness Music|Classical',
3430             1001 => 'Music|Alternative|College Rock',
3431             1002 => 'Music|Alternative|Goth Rock',
3432             1003 => 'Music|Alternative|Grunge',
3433             1004 => 'Music|Alternative|Indie Rock',
3434             1005 => 'Music|Alternative|New Wave',
3435             1006 => 'Music|Alternative|Punk',
3436             1007 => 'Music|Blues|Chicago Blues',
3437             1009 => 'Music|Blues|Classic Blues',
3438             1010 => 'Music|Blues|Contemporary Blues',
3439             1011 => 'Music|Blues|Country Blues',
3440             1012 => 'Music|Blues|Delta Blues',
3441             1013 => 'Music|Blues|Electric Blues',
3442             1014 => "Music|Children's Music|Lullabies",
3443             1015 => "Music|Children's Music|Sing-Along",
3444             1016 => "Music|Children's Music|Stories",
3445             1017 => 'Music|Classical|Avant-Garde',
3446             1018 => 'Music|Classical|Baroque Era',
3447             1019 => 'Music|Classical|Chamber Music',
3448             1020 => 'Music|Classical|Chant',
3449             1021 => 'Music|Classical|Choral',
3450             1022 => 'Music|Classical|Classical Crossover',
3451             1023 => 'Music|Classical|Early Music',
3452             1024 => 'Music|Classical|Impressionist',
3453             1025 => 'Music|Classical|Medieval Era',
3454             1026 => 'Music|Classical|Minimalism',
3455             1027 => 'Music|Classical|Modern Era',
3456             1028 => 'Music|Classical|Opera',
3457             1029 => 'Music|Classical|Orchestral',
3458             1030 => 'Music|Classical|Renaissance',
3459             1031 => 'Music|Classical|Romantic Era',
3460             1032 => 'Music|Classical|Wedding Music',
3461             1033 => 'Music|Country|Alternative Country',
3462             1034 => 'Music|Country|Americana',
3463             1035 => 'Music|Country|Bluegrass',
3464             1036 => 'Music|Country|Contemporary Bluegrass',
3465             1037 => 'Music|Country|Contemporary Country',
3466             1038 => 'Music|Country|Country Gospel',
3467             1039 => 'Music|Country|Honky Tonk',
3468             1040 => 'Music|Country|Outlaw Country',
3469             1041 => 'Music|Country|Traditional Bluegrass',
3470             1042 => 'Music|Country|Traditional Country',
3471             1043 => 'Music|Country|Urban Cowboy',
3472             1044 => 'Music|Dance|Breakbeat',
3473             1045 => 'Music|Dance|Exercise',
3474             1046 => 'Music|Dance|Garage',
3475             1047 => 'Music|Dance|Hardcore',
3476             1048 => 'Music|Dance|House',
3477             1049 => "Music|Dance|Jungle/Drum'n'bass",
3478             1050 => 'Music|Dance|Techno',
3479             1051 => 'Music|Dance|Trance',
3480             1052 => 'Music|Jazz|Big Band',
3481             1053 => 'Music|Jazz|Bop',
3482             1054 => 'Music|Easy Listening|Lounge',
3483             1055 => 'Music|Easy Listening|Swing',
3484             1056 => 'Music|Electronic|Ambient',
3485             1057 => 'Music|Electronic|Downtempo',
3486             1058 => 'Music|Electronic|Electronica',
3487             1060 => 'Music|Electronic|IDM/Experimental',
3488             1061 => 'Music|Electronic|Industrial',
3489             1062 => 'Music|Singer/Songwriter|Alternative Folk',
3490             1063 => 'Music|Singer/Songwriter|Contemporary Folk',
3491             1064 => 'Music|Singer/Songwriter|Contemporary Singer/Songwriter',
3492             1065 => 'Music|Singer/Songwriter|Folk-Rock',
3493             1066 => 'Music|Singer/Songwriter|New Acoustic',
3494             1067 => 'Music|Singer/Songwriter|Traditional Folk',
3495             1068 => 'Music|Hip-Hop/Rap|Alternative Rap',
3496             1069 => 'Music|Hip-Hop/Rap|Dirty South',
3497             1070 => 'Music|Hip-Hop/Rap|East Coast Rap',
3498             1071 => 'Music|Hip-Hop/Rap|Gangsta Rap',
3499             1072 => 'Music|Hip-Hop/Rap|Hardcore Rap',
3500             1073 => 'Music|Hip-Hop/Rap|Hip-Hop',
3501             1074 => 'Music|Hip-Hop/Rap|Latin Rap',
3502             1075 => 'Music|Hip-Hop/Rap|Old School Rap',
3503             1076 => 'Music|Hip-Hop/Rap|Rap',
3504             1077 => 'Music|Hip-Hop/Rap|Underground Rap',
3505             1078 => 'Music|Hip-Hop/Rap|West Coast Rap',
3506             1079 => 'Music|Holiday|Chanukah',
3507             1080 => 'Music|Holiday|Christmas',
3508             1081 => "Music|Holiday|Christmas: Children's",
3509             1082 => 'Music|Holiday|Christmas: Classic',
3510             1083 => 'Music|Holiday|Christmas: Classical',
3511             1084 => 'Music|Holiday|Christmas: Jazz',
3512             1085 => 'Music|Holiday|Christmas: Modern',
3513             1086 => 'Music|Holiday|Christmas: Pop',
3514             1087 => 'Music|Holiday|Christmas: R&B',
3515             1088 => 'Music|Holiday|Christmas: Religious',
3516             1089 => 'Music|Holiday|Christmas: Rock',
3517             1090 => 'Music|Holiday|Easter',
3518             1091 => 'Music|Holiday|Halloween',
3519             1092 => 'Music|Holiday|Holiday: Other',
3520             1093 => 'Music|Holiday|Thanksgiving',
3521             1094 => 'Music|Christian & Gospel|CCM',
3522             1095 => 'Music|Christian & Gospel|Christian Metal',
3523             1096 => 'Music|Christian & Gospel|Christian Pop',
3524             1097 => 'Music|Christian & Gospel|Christian Rap',
3525             1098 => 'Music|Christian & Gospel|Christian Rock',
3526             1099 => 'Music|Christian & Gospel|Classic Christian',
3527             1100 => 'Music|Christian & Gospel|Contemporary Gospel',
3528             1101 => 'Music|Christian & Gospel|Gospel',
3529             1103 => 'Music|Christian & Gospel|Praise & Worship',
3530             1104 => 'Music|Christian & Gospel|Southern Gospel',
3531             1105 => 'Music|Christian & Gospel|Traditional Gospel',
3532             1106 => 'Music|Jazz|Avant-Garde Jazz',
3533             1107 => 'Music|Jazz|Contemporary Jazz',
3534             1108 => 'Music|Jazz|Crossover Jazz',
3535             1109 => 'Music|Jazz|Dixieland',
3536             1110 => 'Music|Jazz|Fusion',
3537             1111 => 'Music|Jazz|Latin Jazz',
3538             1112 => 'Music|Jazz|Mainstream Jazz',
3539             1113 => 'Music|Jazz|Ragtime',
3540             1114 => 'Music|Jazz|Smooth Jazz',
3541             1115 => 'Music|Latino|Latin Jazz',
3542             1116 => 'Music|Latino|Contemporary Latin',
3543             1117 => 'Music|Latino|Pop Latino',
3544             1118 => 'Music|Latino|Raices', # (Raíces)
3545             1119 => 'Music|Latino|Urbano latino',
3546             1120 => 'Music|Latino|Baladas y Boleros',
3547             1121 => 'Music|Latino|Rock y Alternativo',
3548             1122 => 'Music|Brazilian',
3549             1123 => 'Music|Latino|Musica Mexicana', # (Música Mexicana)
3550             1124 => 'Music|Latino|Musica tropical', # (Música tropical)
3551             1125 => 'Music|New Age|Environmental',
3552             1126 => 'Music|New Age|Healing',
3553             1127 => 'Music|New Age|Meditation',
3554             1128 => 'Music|New Age|Nature',
3555             1129 => 'Music|New Age|Relaxation',
3556             1130 => 'Music|New Age|Travel',
3557             1131 => 'Music|Pop|Adult Contemporary',
3558             1132 => 'Music|Pop|Britpop',
3559             1133 => 'Music|Pop|Pop/Rock',
3560             1134 => 'Music|Pop|Soft Rock',
3561             1135 => 'Music|Pop|Teen Pop',
3562             1136 => 'Music|R&B/Soul|Contemporary R&B',
3563             1137 => 'Music|R&B/Soul|Disco',
3564             1138 => 'Music|R&B/Soul|Doo Wop',
3565             1139 => 'Music|R&B/Soul|Funk',
3566             1140 => 'Music|R&B/Soul|Motown',
3567             1141 => 'Music|R&B/Soul|Neo-Soul',
3568             1142 => 'Music|R&B/Soul|Quiet Storm',
3569             1143 => 'Music|R&B/Soul|Soul',
3570             1144 => 'Music|Rock|Adult Alternative',
3571             1145 => 'Music|Rock|American Trad Rock',
3572             1146 => 'Music|Rock|Arena Rock',
3573             1147 => 'Music|Rock|Blues-Rock',
3574             1148 => 'Music|Rock|British Invasion',
3575             1149 => 'Music|Rock|Death Metal/Black Metal',
3576             1150 => 'Music|Rock|Glam Rock',
3577             1151 => 'Music|Rock|Hair Metal',
3578             1152 => 'Music|Rock|Hard Rock',
3579             1153 => 'Music|Rock|Metal',
3580             1154 => 'Music|Rock|Jam Bands',
3581             1155 => 'Music|Rock|Prog-Rock/Art Rock',
3582             1156 => 'Music|Rock|Psychedelic',
3583             1157 => 'Music|Rock|Rock & Roll',
3584             1158 => 'Music|Rock|Rockabilly',
3585             1159 => 'Music|Rock|Roots Rock',
3586             1160 => 'Music|Rock|Singer/Songwriter',
3587             1161 => 'Music|Rock|Southern Rock',
3588             1162 => 'Music|Rock|Surf',
3589             1163 => 'Music|Rock|Tex-Mex',
3590             1165 => 'Music|Soundtrack|Foreign Cinema',
3591             1166 => 'Music|Soundtrack|Musicals',
3592             1167 => 'Music|Comedy|Novelty',
3593             1168 => 'Music|Soundtrack|Original Score',
3594             1169 => 'Music|Soundtrack|Soundtrack',
3595             1171 => 'Music|Comedy|Standup Comedy',
3596             1172 => 'Music|Soundtrack|TV Soundtrack',
3597             1173 => 'Music|Vocal|Standards',
3598             1174 => 'Music|Vocal|Traditional Pop',
3599             1175 => 'Music|Jazz|Vocal Jazz',
3600             1176 => 'Music|Vocal|Vocal Pop',
3601             1177 => 'Music|African|Afro-Beat',
3602             1178 => 'Music|African|Afro-Pop',
3603             1179 => 'Music|World|Cajun',
3604             1180 => 'Music|World|Celtic',
3605             1181 => 'Music|World|Celtic Folk',
3606             1182 => 'Music|World|Contemporary Celtic',
3607             1183 => 'Music|Reggae|Modern Dancehall',
3608             1184 => 'Music|World|Drinking Songs',
3609             1185 => 'Music|Indian|Indian Pop',
3610             1186 => 'Music|World|Japanese Pop',
3611             1187 => 'Music|World|Klezmer',
3612             1188 => 'Music|World|Polka',
3613             1189 => 'Music|World|Traditional Celtic',
3614             1190 => 'Music|World|Worldbeat',
3615             1191 => 'Music|World|Zydeco',
3616             1192 => 'Music|Reggae|Roots Reggae',
3617             1193 => 'Music|Reggae|Dub',
3618             1194 => 'Music|Reggae|Ska',
3619             1195 => 'Music|World|Caribbean',
3620             1196 => 'Music|World|South America',
3621             1197 => 'Music|Arabic',
3622             1198 => 'Music|World|North America',
3623             1199 => 'Music|World|Hawaii',
3624             1200 => 'Music|World|Australia',
3625             1201 => 'Music|World|Japan',
3626             1202 => 'Music|World|France',
3627             1203 => 'Music|African',
3628             1204 => 'Music|World|Asia',
3629             1205 => 'Music|World|Europe',
3630             1206 => 'Music|World|South Africa',
3631             1207 => 'Music|Jazz|Hard Bop',
3632             1208 => 'Music|Jazz|Trad Jazz',
3633             1209 => 'Music|Jazz|Cool Jazz',
3634             1210 => 'Music|Blues|Acoustic Blues',
3635             1211 => 'Music|Classical|High Classical',
3636             1220 => 'Music|Brazilian|Axe', # (Axé)
3637             1221 => 'Music|Brazilian|Bossa Nova',
3638             1222 => 'Music|Brazilian|Choro',
3639             1223 => 'Music|Brazilian|Forro', # (Forró)
3640             1224 => 'Music|Brazilian|Frevo',
3641             1225 => 'Music|Brazilian|MPB',
3642             1226 => 'Music|Brazilian|Pagode',
3643             1227 => 'Music|Brazilian|Samba',
3644             1228 => 'Music|Brazilian|Sertanejo',
3645             1229 => 'Music|Brazilian|Baile Funk',
3646             1230 => 'Music|Alternative|Chinese Alt',
3647             1231 => 'Music|Alternative|Korean Indie',
3648             1232 => 'Music|Chinese',
3649             1233 => 'Music|Chinese|Chinese Classical',
3650             1234 => 'Music|Chinese|Chinese Flute',
3651             1235 => 'Music|Chinese|Chinese Opera',
3652             1236 => 'Music|Chinese|Chinese Orchestral',
3653             1237 => 'Music|Chinese|Chinese Regional Folk',
3654             1238 => 'Music|Chinese|Chinese Strings',
3655             1239 => 'Music|Chinese|Taiwanese Folk',
3656             1240 => 'Music|Chinese|Tibetan Native Music',
3657             1241 => 'Music|Hip-Hop/Rap|Chinese Hip-Hop',
3658             1242 => 'Music|Hip-Hop/Rap|Korean Hip-Hop',
3659             1243 => 'Music|Korean',
3660             1244 => 'Music|Korean|Korean Classical',
3661             1245 => 'Music|Korean|Korean Trad Song',
3662             1246 => 'Music|Korean|Korean Trad Instrumental',
3663             1247 => 'Music|Korean|Korean Trad Theater',
3664             1248 => 'Music|Rock|Chinese Rock',
3665             1249 => 'Music|Rock|Korean Rock',
3666             1250 => 'Music|Pop|C-Pop',
3667             1251 => 'Music|Pop|Cantopop/HK-Pop',
3668             1252 => 'Music|Pop|Korean Folk-Pop',
3669             1253 => 'Music|Pop|Mandopop',
3670             1254 => 'Music|Pop|Tai-Pop',
3671             1255 => 'Music|Pop|Malaysian Pop',
3672             1256 => 'Music|Pop|Pinoy Pop',
3673             1257 => 'Music|Pop|Original Pilipino Music',
3674             1258 => 'Music|Pop|Manilla Sound',
3675             1259 => 'Music|Pop|Indo Pop',
3676             1260 => 'Music|Pop|Thai Pop',
3677             1261 => 'Music|Vocal|Trot',
3678             1262 => 'Music|Indian',
3679             1263 => 'Music|Indian|Bollywood',
3680             1264 => 'Music|Indian|Regional Indian|Tamil',
3681             1265 => 'Music|Indian|Regional Indian|Telugu',
3682             1266 => 'Music|Indian|Regional Indian',
3683             1267 => 'Music|Indian|Devotional & Spiritual',
3684             1268 => 'Music|Indian|Sufi',
3685             1269 => 'Music|Indian|Indian Classical',
3686             1270 => 'Music|Russian|Russian Chanson',
3687             1271 => 'Music|World|Dini',
3688             1272 => 'Music|Turkish|Halk',
3689             1273 => 'Music|Turkish|Sanat',
3690             1274 => 'Music|World|Dangdut',
3691             1275 => 'Music|World|Indonesian Religious',
3692             1276 => 'Music|World|Calypso',
3693             1277 => 'Music|World|Soca',
3694             1278 => 'Music|Indian|Ghazals',
3695             1279 => 'Music|Indian|Indian Folk',
3696             1280 => 'Music|Turkish|Arabesque',
3697             1281 => 'Music|African|Afrikaans',
3698             1282 => 'Music|World|Farsi',
3699             1283 => 'Music|World|Israeli',
3700             1284 => 'Music|Arabic|Khaleeji',
3701             1285 => 'Music|Arabic|North African',
3702             1286 => 'Music|Arabic|Arabic Pop',
3703             1287 => 'Music|Arabic|Islamic',
3704             1288 => 'Music|Soundtrack|Sound Effects',
3705             1289 => 'Music|Folk',
3706             1290 => 'Music|Orchestral',
3707             1291 => 'Music|Marching',
3708             1293 => 'Music|Pop|Oldies',
3709             1294 => 'Music|Country|Thai Country',
3710             1295 => 'Music|World|Flamenco',
3711             1296 => 'Music|World|Tango',
3712             1297 => 'Music|World|Fado',
3713             1298 => 'Music|World|Iberia',
3714             1299 => 'Music|Russian',
3715             1300 => 'Music|Turkish',
3716             1301 => 'Podcasts|Arts',
3717             1302 => 'Podcasts|Society & Culture|Personal Journals',
3718             1303 => 'Podcasts|Comedy',
3719             1304 => 'Podcasts|Education',
3720             1305 => 'Podcasts|Kids & Family',
3721             1306 => 'Podcasts|Arts|Food',
3722             1307 => 'Podcasts|Health',
3723             1309 => 'Podcasts|TV & Film',
3724             1310 => 'Podcasts|Music',
3725             1311 => 'Podcasts|News & Politics',
3726             1314 => 'Podcasts|Religion & Spirituality',
3727             1315 => 'Podcasts|Science & Medicine',
3728             1316 => 'Podcasts|Sports & Recreation',
3729             1318 => 'Podcasts|Technology',
3730             1320 => 'Podcasts|Society & Culture|Places & Travel',
3731             1321 => 'Podcasts|Business',
3732             1323 => 'Podcasts|Games & Hobbies',
3733             1324 => 'Podcasts|Society & Culture',
3734             1325 => 'Podcasts|Government & Organizations',
3735             1337 => 'Music Videos|Classical|Piano',
3736             1401 => 'Podcasts|Arts|Literature',
3737             1402 => 'Podcasts|Arts|Design',
3738             1404 => 'Podcasts|Games & Hobbies|Video Games',
3739             1405 => 'Podcasts|Arts|Performing Arts',
3740             1406 => 'Podcasts|Arts|Visual Arts',
3741             1410 => 'Podcasts|Business|Careers',
3742             1412 => 'Podcasts|Business|Investing',
3743             1413 => 'Podcasts|Business|Management & Marketing',
3744             1415 => 'Podcasts|Education|K-12',
3745             1416 => 'Podcasts|Education|Higher Education',
3746             1417 => 'Podcasts|Health|Fitness & Nutrition',
3747             1420 => 'Podcasts|Health|Self-Help',
3748             1421 => 'Podcasts|Health|Sexuality',
3749             1438 => 'Podcasts|Religion & Spirituality|Buddhism',
3750             1439 => 'Podcasts|Religion & Spirituality|Christianity',
3751             1440 => 'Podcasts|Religion & Spirituality|Islam',
3752             1441 => 'Podcasts|Religion & Spirituality|Judaism',
3753             1443 => 'Podcasts|Society & Culture|Philosophy',
3754             1444 => 'Podcasts|Religion & Spirituality|Spirituality',
3755             1446 => 'Podcasts|Technology|Gadgets',
3756             1448 => 'Podcasts|Technology|Tech News',
3757             1450 => 'Podcasts|Technology|Podcasting',
3758             1454 => 'Podcasts|Games & Hobbies|Automotive',
3759             1455 => 'Podcasts|Games & Hobbies|Aviation',
3760             1456 => 'Podcasts|Sports & Recreation|Outdoor',
3761             1459 => 'Podcasts|Arts|Fashion & Beauty',
3762             1460 => 'Podcasts|Games & Hobbies|Hobbies',
3763             1461 => 'Podcasts|Games & Hobbies|Other Games',
3764             1462 => 'Podcasts|Society & Culture|History',
3765             1463 => 'Podcasts|Religion & Spirituality|Hinduism',
3766             1464 => 'Podcasts|Religion & Spirituality|Other',
3767             1465 => 'Podcasts|Sports & Recreation|Professional',
3768             1466 => 'Podcasts|Sports & Recreation|College & High School',
3769             1467 => 'Podcasts|Sports & Recreation|Amateur',
3770             1468 => 'Podcasts|Education|Educational Technology',
3771             1469 => 'Podcasts|Education|Language Courses',
3772             1470 => 'Podcasts|Education|Training',
3773             1471 => 'Podcasts|Business|Business News',
3774             1472 => 'Podcasts|Business|Shopping',
3775             1473 => 'Podcasts|Government & Organizations|National',
3776             1474 => 'Podcasts|Government & Organizations|Regional',
3777             1475 => 'Podcasts|Government & Organizations|Local',
3778             1476 => 'Podcasts|Government & Organizations|Non-Profit',
3779             1477 => 'Podcasts|Science & Medicine|Natural Sciences',
3780             1478 => 'Podcasts|Science & Medicine|Medicine',
3781             1479 => 'Podcasts|Science & Medicine|Social Sciences',
3782             1480 => 'Podcasts|Technology|Software How-To',
3783             1481 => 'Podcasts|Health|Alternative Health',
3784             1482 => 'Podcasts|Arts|Books',
3785             1483 => 'Podcasts|Fiction',
3786             1484 => 'Podcasts|Fiction|Drama',
3787             1485 => 'Podcasts|Fiction|Science Fiction',
3788             1486 => 'Podcasts|Fiction|Comedy Fiction',
3789             1487 => 'Podcasts|History',
3790             1488 => 'Podcasts|True Crime',
3791             1489 => 'Podcasts|News',
3792             1490 => 'Podcasts|News|Business News',
3793             1491 => 'Podcasts|Business|Management',
3794             1492 => 'Podcasts|Business|Marketing',
3795             1493 => 'Podcasts|Business|Entrepreneurship',
3796             1494 => 'Podcasts|Business|Non-Profit',
3797             1495 => 'Podcasts|Comedy|Improv',
3798             1496 => 'Podcasts|Comedy|Comedy Interviews',
3799             1497 => 'Podcasts|Comedy|Stand-Up',
3800             1498 => 'Podcasts|Education|Language Learning',
3801             1499 => 'Podcasts|Education|How To',
3802             1500 => 'Podcasts|Education|Self-Improvement',
3803             1501 => 'Podcasts|Education|Courses',
3804             1502 => 'Podcasts|Leisure',
3805             1503 => 'Podcasts|Leisure|Automotive',
3806             1504 => 'Podcasts|Leisure|Aviation',
3807             1505 => 'Podcasts|Leisure|Hobbies',
3808             1506 => 'Podcasts|Leisure|Crafts',
3809             1507 => 'Podcasts|Leisure|Games',
3810             1508 => 'Podcasts|Leisure|Home & Garden',
3811             1509 => 'Podcasts|Leisure|Video Games',
3812             1510 => 'Podcasts|Leisure|Animation & Manga',
3813             1511 => 'Podcasts|Government',
3814             1512 => 'Podcasts|Health & Fitness',
3815             1513 => 'Podcasts|Health & Fitness|Alternative Health',
3816             1514 => 'Podcasts|Health & Fitness|Fitness',
3817             1515 => 'Podcasts|Health & Fitness|Nutrition',
3818             1516 => 'Podcasts|Health & Fitness|Sexuality',
3819             1517 => 'Podcasts|Health & Fitness|Mental Health',
3820             1518 => 'Podcasts|Health & Fitness|Medicine',
3821             1519 => 'Podcasts|Kids & Family|Education for Kids',
3822             1520 => 'Podcasts|Kids & Family|Stories for Kids',
3823             1521 => 'Podcasts|Kids & Family|Parenting',
3824             1522 => 'Podcasts|Kids & Family|Pets & Animals',
3825             1523 => 'Podcasts|Music|Music Commentary',
3826             1524 => 'Podcasts|Music|Music History',
3827             1525 => 'Podcasts|Music|Music Interviews',
3828             1526 => 'Podcasts|News|Daily News',
3829             1527 => 'Podcasts|News|Politics',
3830             1528 => 'Podcasts|News|Tech News',
3831             1529 => 'Podcasts|News|Sports News',
3832             1530 => 'Podcasts|News|News Commentary',
3833             1531 => 'Podcasts|News|Entertainment News',
3834             1532 => 'Podcasts|Religion & Spirituality|Religion',
3835             1533 => 'Podcasts|Science',
3836             1534 => 'Podcasts|Science|Natural Sciences',
3837             1535 => 'Podcasts|Science|Social Sciences',
3838             1536 => 'Podcasts|Science|Mathematics',
3839             1537 => 'Podcasts|Science|Nature',
3840             1538 => 'Podcasts|Science|Astronomy',
3841             1539 => 'Podcasts|Science|Chemistry',
3842             1540 => 'Podcasts|Science|Earth Sciences',
3843             1541 => 'Podcasts|Science|Life Sciences',
3844             1542 => 'Podcasts|Science|Physics',
3845             1543 => 'Podcasts|Society & Culture|Documentary',
3846             1544 => 'Podcasts|Society & Culture|Relationships',
3847             1545 => 'Podcasts|Sports',
3848             1546 => 'Podcasts|Sports|Soccer',
3849             1547 => 'Podcasts|Sports|Football',
3850             1548 => 'Podcasts|Sports|Basketball',
3851             1549 => 'Podcasts|Sports|Baseball',
3852             1550 => 'Podcasts|Sports|Hockey',
3853             1551 => 'Podcasts|Sports|Running',
3854             1552 => 'Podcasts|Sports|Rugby',
3855             1553 => 'Podcasts|Sports|Golf',
3856             1554 => 'Podcasts|Sports|Cricket',
3857             1555 => 'Podcasts|Sports|Wrestling',
3858             1556 => 'Podcasts|Sports|Tennis',
3859             1557 => 'Podcasts|Sports|Volleyball',
3860             1558 => 'Podcasts|Sports|Swimming',
3861             1559 => 'Podcasts|Sports|Wilderness',
3862             1560 => 'Podcasts|Sports|Fantasy Sports',
3863             1561 => 'Podcasts|TV & Film|TV Reviews',
3864             1562 => 'Podcasts|TV & Film|After Shows',
3865             1563 => 'Podcasts|TV & Film|Film Reviews',
3866             1564 => 'Podcasts|TV & Film|Film History',
3867             1565 => 'Podcasts|TV & Film|Film Interviews',
3868             1602 => 'Music Videos|Blues',
3869             1603 => 'Music Videos|Comedy',
3870             1604 => "Music Videos|Children's Music",
3871             1605 => 'Music Videos|Classical',
3872             1606 => 'Music Videos|Country',
3873             1607 => 'Music Videos|Electronic',
3874             1608 => 'Music Videos|Holiday',
3875             1609 => 'Music Videos|Classical|Opera',
3876             1610 => 'Music Videos|Singer/Songwriter',
3877             1611 => 'Music Videos|Jazz',
3878             1612 => 'Music Videos|Latin',
3879             1613 => 'Music Videos|New Age',
3880             1614 => 'Music Videos|Pop',
3881             1615 => 'Music Videos|R&B/Soul',
3882             1616 => 'Music Videos|Soundtrack',
3883             1617 => 'Music Videos|Dance',
3884             1618 => 'Music Videos|Hip-Hop/Rap',
3885             1619 => 'Music Videos|World',
3886             1620 => 'Music Videos|Alternative',
3887             1621 => 'Music Videos|Rock',
3888             1622 => 'Music Videos|Christian & Gospel',
3889             1623 => 'Music Videos|Vocal',
3890             1624 => 'Music Videos|Reggae',
3891             1625 => 'Music Videos|Easy Listening',
3892             1626 => 'Music Videos|Podcasts',
3893             1627 => 'Music Videos|J-Pop',
3894             1628 => 'Music Videos|Enka',
3895             1629 => 'Music Videos|Anime',
3896             1630 => 'Music Videos|Kayokyoku',
3897             1631 => 'Music Videos|Disney',
3898             1632 => 'Music Videos|French Pop',
3899             1633 => 'Music Videos|German Pop',
3900             1634 => 'Music Videos|German Folk',
3901             1635 => 'Music Videos|Alternative|Chinese Alt',
3902             1636 => 'Music Videos|Alternative|Korean Indie',
3903             1637 => 'Music Videos|Chinese',
3904             1638 => 'Music Videos|Chinese|Chinese Classical',
3905             1639 => 'Music Videos|Chinese|Chinese Flute',
3906             1640 => 'Music Videos|Chinese|Chinese Opera',
3907             1641 => 'Music Videos|Chinese|Chinese Orchestral',
3908             1642 => 'Music Videos|Chinese|Chinese Regional Folk',
3909             1643 => 'Music Videos|Chinese|Chinese Strings',
3910             1644 => 'Music Videos|Chinese|Taiwanese Folk',
3911             1645 => 'Music Videos|Chinese|Tibetan Native Music',
3912             1646 => 'Music Videos|Hip-Hop/Rap|Chinese Hip-Hop',
3913             1647 => 'Music Videos|Hip-Hop/Rap|Korean Hip-Hop',
3914             1648 => 'Music Videos|Korean',
3915             1649 => 'Music Videos|Korean|Korean Classical',
3916             1650 => 'Music Videos|Korean|Korean Trad Song',
3917             1651 => 'Music Videos|Korean|Korean Trad Instrumental',
3918             1652 => 'Music Videos|Korean|Korean Trad Theater',
3919             1653 => 'Music Videos|Rock|Chinese Rock',
3920             1654 => 'Music Videos|Rock|Korean Rock',
3921             1655 => 'Music Videos|Pop|C-Pop',
3922             1656 => 'Music Videos|Pop|Cantopop/HK-Pop',
3923             1657 => 'Music Videos|Pop|Korean Folk-Pop',
3924             1658 => 'Music Videos|Pop|Mandopop',
3925             1659 => 'Music Videos|Pop|Tai-Pop',
3926             1660 => 'Music Videos|Pop|Malaysian Pop',
3927             1661 => 'Music Videos|Pop|Pinoy Pop',
3928             1662 => 'Music Videos|Pop|Original Pilipino Music',
3929             1663 => 'Music Videos|Pop|Manilla Sound',
3930             1664 => 'Music Videos|Pop|Indo Pop',
3931             1665 => 'Music Videos|Pop|Thai Pop',
3932             1666 => 'Music Videos|Vocal|Trot',
3933             1671 => 'Music Videos|Brazilian',
3934             1672 => 'Music Videos|Brazilian|Axe', # (Axé)
3935             1673 => 'Music Videos|Brazilian|Baile Funk',
3936             1674 => 'Music Videos|Brazilian|Bossa Nova',
3937             1675 => 'Music Videos|Brazilian|Choro',
3938             1676 => 'Music Videos|Brazilian|Forro',
3939             1677 => 'Music Videos|Brazilian|Frevo',
3940             1678 => 'Music Videos|Brazilian|MPB',
3941             1679 => 'Music Videos|Brazilian|Pagode',
3942             1680 => 'Music Videos|Brazilian|Samba',
3943             1681 => 'Music Videos|Brazilian|Sertanejo',
3944             1682 => 'Music Videos|Classical|High Classical',
3945             1683 => 'Music Videos|Fitness & Workout',
3946             1684 => 'Music Videos|Instrumental',
3947             1685 => 'Music Videos|Jazz|Big Band',
3948             1686 => 'Music Videos|Pop|K-Pop',
3949             1687 => 'Music Videos|Karaoke',
3950             1688 => 'Music Videos|Rock|Heavy Metal',
3951             1689 => 'Music Videos|Spoken Word',
3952             1690 => 'Music Videos|Indian',
3953             1691 => 'Music Videos|Indian|Bollywood',
3954             1692 => 'Music Videos|Indian|Regional Indian|Tamil',
3955             1693 => 'Music Videos|Indian|Regional Indian|Telugu',
3956             1694 => 'Music Videos|Indian|Regional Indian',
3957             1695 => 'Music Videos|Indian|Devotional & Spiritual',
3958             1696 => 'Music Videos|Indian|Sufi',
3959             1697 => 'Music Videos|Indian|Indian Classical',
3960             1698 => 'Music Videos|Russian|Russian Chanson',
3961             1699 => 'Music Videos|World|Dini',
3962             1700 => 'Music Videos|Turkish|Halk',
3963             1701 => 'Music Videos|Turkish|Sanat',
3964             1702 => 'Music Videos|World|Dangdut',
3965             1703 => 'Music Videos|World|Indonesian Religious',
3966             1704 => 'Music Videos|Indian|Indian Pop',
3967             1705 => 'Music Videos|World|Calypso',
3968             1706 => 'Music Videos|World|Soca',
3969             1707 => 'Music Videos|Indian|Ghazals',
3970             1708 => 'Music Videos|Indian|Indian Folk',
3971             1709 => 'Music Videos|Turkish|Arabesque',
3972             1710 => 'Music Videos|African|Afrikaans',
3973             1711 => 'Music Videos|World|Farsi',
3974             1712 => 'Music Videos|World|Israeli',
3975             1713 => 'Music Videos|Arabic',
3976             1714 => 'Music Videos|Arabic|Khaleeji',
3977             1715 => 'Music Videos|Arabic|North African',
3978             1716 => 'Music Videos|Arabic|Arabic Pop',
3979             1717 => 'Music Videos|Arabic|Islamic',
3980             1718 => 'Music Videos|Soundtrack|Sound Effects',
3981             1719 => 'Music Videos|Folk',
3982             1720 => 'Music Videos|Orchestral',
3983             1721 => 'Music Videos|Marching',
3984             1723 => 'Music Videos|Pop|Oldies',
3985             1724 => 'Music Videos|Country|Thai Country',
3986             1725 => 'Music Videos|World|Flamenco',
3987             1726 => 'Music Videos|World|Tango',
3988             1727 => 'Music Videos|World|Fado',
3989             1728 => 'Music Videos|World|Iberia',
3990             1729 => 'Music Videos|Russian',
3991             1730 => 'Music Videos|Turkish',
3992             1731 => 'Music Videos|Alternative|College Rock',
3993             1732 => 'Music Videos|Alternative|Goth Rock',
3994             1733 => 'Music Videos|Alternative|Grunge',
3995             1734 => 'Music Videos|Alternative|Indie Rock',
3996             1735 => 'Music Videos|Alternative|New Wave',
3997             1736 => 'Music Videos|Alternative|Punk',
3998             1737 => 'Music Videos|Blues|Acoustic Blues',
3999             1738 => 'Music Videos|Blues|Chicago Blues',
4000             1739 => 'Music Videos|Blues|Classic Blues',
4001             1740 => 'Music Videos|Blues|Contemporary Blues',
4002             1741 => 'Music Videos|Blues|Country Blues',
4003             1742 => 'Music Videos|Blues|Delta Blues',
4004             1743 => 'Music Videos|Blues|Electric Blues',
4005             1744 => "Music Videos|Children's Music|Lullabies",
4006             1745 => "Music Videos|Children's Music|Sing-Along",
4007             1746 => "Music Videos|Children's Music|Stories",
4008             1747 => 'Music Videos|Christian & Gospel|CCM',
4009             1748 => 'Music Videos|Christian & Gospel|Christian Metal',
4010             1749 => 'Music Videos|Christian & Gospel|Christian Pop',
4011             1750 => 'Music Videos|Christian & Gospel|Christian Rap',
4012             1751 => 'Music Videos|Christian & Gospel|Christian Rock',
4013             1752 => 'Music Videos|Christian & Gospel|Classic Christian',
4014             1753 => 'Music Videos|Christian & Gospel|Contemporary Gospel',
4015             1754 => 'Music Videos|Christian & Gospel|Gospel',
4016             1755 => 'Music Videos|Christian & Gospel|Praise & Worship',
4017             1756 => 'Music Videos|Christian & Gospel|Southern Gospel',
4018             1757 => 'Music Videos|Christian & Gospel|Traditional Gospel',
4019             1758 => 'Music Videos|Classical|Avant-Garde',
4020             1759 => 'Music Videos|Classical|Baroque Era',
4021             1760 => 'Music Videos|Classical|Chamber Music',
4022             1761 => 'Music Videos|Classical|Chant',
4023             1762 => 'Music Videos|Classical|Choral',
4024             1763 => 'Music Videos|Classical|Classical Crossover',
4025             1764 => 'Music Videos|Classical|Early Music',
4026             1765 => 'Music Videos|Classical|Impressionist',
4027             1766 => 'Music Videos|Classical|Medieval Era',
4028             1767 => 'Music Videos|Classical|Minimalism',
4029             1768 => 'Music Videos|Classical|Modern Era',
4030             1769 => 'Music Videos|Classical|Orchestral',
4031             1770 => 'Music Videos|Classical|Renaissance',
4032             1771 => 'Music Videos|Classical|Romantic Era',
4033             1772 => 'Music Videos|Classical|Wedding Music',
4034             1773 => 'Music Videos|Comedy|Novelty',
4035             1774 => 'Music Videos|Comedy|Standup Comedy',
4036             1775 => 'Music Videos|Country|Alternative Country',
4037             1776 => 'Music Videos|Country|Americana',
4038             1777 => 'Music Videos|Country|Bluegrass',
4039             1778 => 'Music Videos|Country|Contemporary Bluegrass',
4040             1779 => 'Music Videos|Country|Contemporary Country',
4041             1780 => 'Music Videos|Country|Country Gospel',
4042             1781 => 'Music Videos|Country|Honky Tonk',
4043             1782 => 'Music Videos|Country|Outlaw Country',
4044             1783 => 'Music Videos|Country|Traditional Bluegrass',
4045             1784 => 'Music Videos|Country|Traditional Country',
4046             1785 => 'Music Videos|Country|Urban Cowboy',
4047             1786 => 'Music Videos|Dance|Breakbeat',
4048             1787 => 'Music Videos|Dance|Exercise',
4049             1788 => 'Music Videos|Dance|Garage',
4050             1789 => 'Music Videos|Dance|Hardcore',
4051             1790 => 'Music Videos|Dance|House',
4052             1791 => "Music Videos|Dance|Jungle/Drum'n'bass",
4053             1792 => 'Music Videos|Dance|Techno',
4054             1793 => 'Music Videos|Dance|Trance',
4055             1794 => 'Music Videos|Easy Listening|Lounge',
4056             1795 => 'Music Videos|Easy Listening|Swing',
4057             1796 => 'Music Videos|Electronic|Ambient',
4058             1797 => 'Music Videos|Electronic|Downtempo',
4059             1798 => 'Music Videos|Electronic|Electronica',
4060             1799 => 'Music Videos|Electronic|IDM/Experimental',
4061             1800 => 'Music Videos|Electronic|Industrial',
4062             1801 => 'Music Videos|Hip-Hop/Rap|Alternative Rap',
4063             1802 => 'Music Videos|Hip-Hop/Rap|Dirty South',
4064             1803 => 'Music Videos|Hip-Hop/Rap|East Coast Rap',
4065             1804 => 'Music Videos|Hip-Hop/Rap|Gangsta Rap',
4066             1805 => 'Music Videos|Hip-Hop/Rap|Hardcore Rap',
4067             1806 => 'Music Videos|Hip-Hop/Rap|Hip-Hop',
4068             1807 => 'Music Videos|Hip-Hop/Rap|Latin Rap',
4069             1808 => 'Music Videos|Hip-Hop/Rap|Old School Rap',
4070             1809 => 'Music Videos|Hip-Hop/Rap|Rap',
4071             1810 => 'Music Videos|Hip-Hop/Rap|Underground Rap',
4072             1811 => 'Music Videos|Hip-Hop/Rap|West Coast Rap',
4073             1812 => 'Music Videos|Holiday|Chanukah',
4074             1813 => 'Music Videos|Holiday|Christmas',
4075             1814 => "Music Videos|Holiday|Christmas: Children's",
4076             1815 => 'Music Videos|Holiday|Christmas: Classic',
4077             1816 => 'Music Videos|Holiday|Christmas: Classical',
4078             1817 => 'Music Videos|Holiday|Christmas: Jazz',
4079             1818 => 'Music Videos|Holiday|Christmas: Modern',
4080             1819 => 'Music Videos|Holiday|Christmas: Pop',
4081             1820 => 'Music Videos|Holiday|Christmas: R&B',
4082             1821 => 'Music Videos|Holiday|Christmas: Religious',
4083             1822 => 'Music Videos|Holiday|Christmas: Rock',
4084             1823 => 'Music Videos|Holiday|Easter',
4085             1824 => 'Music Videos|Holiday|Halloween',
4086             1825 => 'Music Videos|Holiday|Thanksgiving',
4087             1826 => 'Music Videos|Jazz|Avant-Garde Jazz',
4088             1828 => 'Music Videos|Jazz|Bop',
4089             1829 => 'Music Videos|Jazz|Contemporary Jazz',
4090             1830 => 'Music Videos|Jazz|Cool Jazz',
4091             1831 => 'Music Videos|Jazz|Crossover Jazz',
4092             1832 => 'Music Videos|Jazz|Dixieland',
4093             1833 => 'Music Videos|Jazz|Fusion',
4094             1834 => 'Music Videos|Jazz|Hard Bop',
4095             1835 => 'Music Videos|Jazz|Latin Jazz',
4096             1836 => 'Music Videos|Jazz|Mainstream Jazz',
4097             1837 => 'Music Videos|Jazz|Ragtime',
4098             1838 => 'Music Videos|Jazz|Smooth Jazz',
4099             1839 => 'Music Videos|Jazz|Trad Jazz',
4100             1840 => 'Music Videos|Latin|Alternative & Rock in Spanish',
4101             1841 => 'Music Videos|Latin|Baladas y Boleros',
4102             1842 => 'Music Videos|Latin|Contemporary Latin',
4103             1843 => 'Music Videos|Latin|Latin Jazz',
4104             1844 => 'Music Videos|Latin|Latin Urban',
4105             1845 => 'Music Videos|Latin|Pop in Spanish',
4106             1846 => 'Music Videos|Latin|Raices',
4107             1847 => 'Music Videos|Latin|Musica Mexicana', # (Música Mexicana)
4108             1848 => 'Music Videos|Latin|Salsa y Tropical',
4109             1849 => 'Music Videos|New Age|Healing',
4110             1850 => 'Music Videos|New Age|Meditation',
4111             1851 => 'Music Videos|New Age|Nature',
4112             1852 => 'Music Videos|New Age|Relaxation',
4113             1853 => 'Music Videos|New Age|Travel',
4114             1854 => 'Music Videos|Pop|Adult Contemporary',
4115             1855 => 'Music Videos|Pop|Britpop',
4116             1856 => 'Music Videos|Pop|Pop/Rock',
4117             1857 => 'Music Videos|Pop|Soft Rock',
4118             1858 => 'Music Videos|Pop|Teen Pop',
4119             1859 => 'Music Videos|R&B/Soul|Contemporary R&B',
4120             1860 => 'Music Videos|R&B/Soul|Disco',
4121             1861 => 'Music Videos|R&B/Soul|Doo Wop',
4122             1862 => 'Music Videos|R&B/Soul|Funk',
4123             1863 => 'Music Videos|R&B/Soul|Motown',
4124             1864 => 'Music Videos|R&B/Soul|Neo-Soul',
4125             1865 => 'Music Videos|R&B/Soul|Soul',
4126             1866 => 'Music Videos|Reggae|Modern Dancehall',
4127             1867 => 'Music Videos|Reggae|Dub',
4128             1868 => 'Music Videos|Reggae|Roots Reggae',
4129             1869 => 'Music Videos|Reggae|Ska',
4130             1870 => 'Music Videos|Rock|Adult Alternative',
4131             1871 => 'Music Videos|Rock|American Trad Rock',
4132             1872 => 'Music Videos|Rock|Arena Rock',
4133             1873 => 'Music Videos|Rock|Blues-Rock',
4134             1874 => 'Music Videos|Rock|British Invasion',
4135             1875 => 'Music Videos|Rock|Death Metal/Black Metal',
4136             1876 => 'Music Videos|Rock|Glam Rock',
4137             1877 => 'Music Videos|Rock|Hair Metal',
4138             1878 => 'Music Videos|Rock|Hard Rock',
4139             1879 => 'Music Videos|Rock|Jam Bands',
4140             1880 => 'Music Videos|Rock|Prog-Rock/Art Rock',
4141             1881 => 'Music Videos|Rock|Psychedelic',
4142             1882 => 'Music Videos|Rock|Rock & Roll',
4143             1883 => 'Music Videos|Rock|Rockabilly',
4144             1884 => 'Music Videos|Rock|Roots Rock',
4145             1885 => 'Music Videos|Rock|Singer/Songwriter',
4146             1886 => 'Music Videos|Rock|Southern Rock',
4147             1887 => 'Music Videos|Rock|Surf',
4148             1888 => 'Music Videos|Rock|Tex-Mex',
4149             1889 => 'Music Videos|Singer/Songwriter|Alternative Folk',
4150             1890 => 'Music Videos|Singer/Songwriter|Contemporary Folk',
4151             1891 => 'Music Videos|Singer/Songwriter|Contemporary Singer/Songwriter',
4152             1892 => 'Music Videos|Singer/Songwriter|Folk-Rock',
4153             1893 => 'Music Videos|Singer/Songwriter|New Acoustic',
4154             1894 => 'Music Videos|Singer/Songwriter|Traditional Folk',
4155             1895 => 'Music Videos|Soundtrack|Foreign Cinema',
4156             1896 => 'Music Videos|Soundtrack|Musicals',
4157             1897 => 'Music Videos|Soundtrack|Original Score',
4158             1898 => 'Music Videos|Soundtrack|Soundtrack',
4159             1899 => 'Music Videos|Soundtrack|TV Soundtrack',
4160             1900 => 'Music Videos|Vocal|Standards',
4161             1901 => 'Music Videos|Vocal|Traditional Pop',
4162             1902 => 'Music Videos|Jazz|Vocal Jazz',
4163             1903 => 'Music Videos|Vocal|Vocal Pop',
4164             1904 => 'Music Videos|African',
4165             1905 => 'Music Videos|African|Afro-Beat',
4166             1906 => 'Music Videos|African|Afro-Pop',
4167             1907 => 'Music Videos|World|Asia',
4168             1908 => 'Music Videos|World|Australia',
4169             1909 => 'Music Videos|World|Cajun',
4170             1910 => 'Music Videos|World|Caribbean',
4171             1911 => 'Music Videos|World|Celtic',
4172             1912 => 'Music Videos|World|Celtic Folk',
4173             1913 => 'Music Videos|World|Contemporary Celtic',
4174             1914 => 'Music Videos|World|Europe',
4175             1915 => 'Music Videos|World|France',
4176             1916 => 'Music Videos|World|Hawaii',
4177             1917 => 'Music Videos|World|Japan',
4178             1918 => 'Music Videos|World|Klezmer',
4179             1919 => 'Music Videos|World|North America',
4180             1920 => 'Music Videos|World|Polka',
4181             1921 => 'Music Videos|World|South Africa',
4182             1922 => 'Music Videos|World|South America',
4183             1923 => 'Music Videos|World|Traditional Celtic',
4184             1924 => 'Music Videos|World|Worldbeat',
4185             1925 => 'Music Videos|World|Zydeco',
4186             1926 => 'Music Videos|Christian & Gospel',
4187             1928 => 'Music Videos|Classical|Art Song',
4188             1929 => 'Music Videos|Classical|Brass & Woodwinds',
4189             1930 => 'Music Videos|Classical|Solo Instrumental',
4190             1931 => 'Music Videos|Classical|Contemporary Era',
4191             1932 => 'Music Videos|Classical|Oratorio',
4192             1933 => 'Music Videos|Classical|Cantata',
4193             1934 => 'Music Videos|Classical|Electronic',
4194             1935 => 'Music Videos|Classical|Sacred',
4195             1936 => 'Music Videos|Classical|Guitar',
4196             1938 => 'Music Videos|Classical|Violin',
4197             1939 => 'Music Videos|Classical|Cello',
4198             1940 => 'Music Videos|Classical|Percussion',
4199             1941 => 'Music Videos|Electronic|Dubstep',
4200             1942 => 'Music Videos|Electronic|Bass',
4201             1943 => 'Music Videos|Hip-Hop/Rap|UK Hip-Hop',
4202             1944 => 'Music Videos|Reggae|Lovers Rock',
4203             1945 => 'Music Videos|Alternative|EMO',
4204             1946 => 'Music Videos|Alternative|Pop Punk',
4205             1947 => 'Music Videos|Alternative|Indie Pop',
4206             1948 => 'Music Videos|New Age|Yoga',
4207             1949 => 'Music Videos|Pop|Tribute',
4208             1950 => 'Music Videos|Pop|Shows',
4209             1951 => 'Music Videos|Cuban',
4210             1952 => 'Music Videos|Cuban|Mambo',
4211             1953 => 'Music Videos|Cuban|Chachacha',
4212             1954 => 'Music Videos|Cuban|Guajira',
4213             1955 => 'Music Videos|Cuban|Son',
4214             1956 => 'Music Videos|Cuban|Bolero',
4215             1957 => 'Music Videos|Cuban|Guaracha',
4216             1958 => 'Music Videos|Cuban|Timba',
4217             1959 => 'Music Videos|Soundtrack|Video Game',
4218             1960 => 'Music Videos|Indian|Regional Indian|Punjabi|Punjabi Pop',
4219             1961 => 'Music Videos|Indian|Regional Indian|Bengali|Rabindra Sangeet',
4220             1962 => 'Music Videos|Indian|Regional Indian|Malayalam',
4221             1963 => 'Music Videos|Indian|Regional Indian|Kannada',
4222             1964 => 'Music Videos|Indian|Regional Indian|Marathi',
4223             1965 => 'Music Videos|Indian|Regional Indian|Gujarati',
4224             1966 => 'Music Videos|Indian|Regional Indian|Assamese',
4225             1967 => 'Music Videos|Indian|Regional Indian|Bhojpuri',
4226             1968 => 'Music Videos|Indian|Regional Indian|Haryanvi',
4227             1969 => 'Music Videos|Indian|Regional Indian|Odia',
4228             1970 => 'Music Videos|Indian|Regional Indian|Rajasthani',
4229             1971 => 'Music Videos|Indian|Regional Indian|Urdu',
4230             1972 => 'Music Videos|Indian|Regional Indian|Punjabi',
4231             1973 => 'Music Videos|Indian|Regional Indian|Bengali',
4232             1974 => 'Music Videos|Indian|Indian Classical|Carnatic Classical',
4233             1975 => 'Music Videos|Indian|Indian Classical|Hindustani Classical',
4234             1976 => 'Music Videos|African|Afro House',
4235             1977 => 'Music Videos|African|Afro Soul',
4236             1978 => 'Music Videos|African|Afrobeats',
4237             1979 => 'Music Videos|African|Benga',
4238             1980 => 'Music Videos|African|Bongo-Flava',
4239             1981 => 'Music Videos|African|Coupe-Decale',
4240             1982 => 'Music Videos|African|Gqom',
4241             1983 => 'Music Videos|African|Highlife',
4242             1984 => 'Music Videos|African|Kuduro',
4243             1985 => 'Music Videos|African|Kizomba',
4244             1986 => 'Music Videos|African|Kwaito',
4245             1987 => 'Music Videos|African|Mbalax',
4246             1988 => 'Music Videos|African|Ndombolo',
4247             1989 => 'Music Videos|African|Shangaan Electro',
4248             1990 => 'Music Videos|African|Soukous',
4249             1991 => 'Music Videos|African|Taarab',
4250             1992 => 'Music Videos|African|Zouglou',
4251             1993 => 'Music Videos|Turkish|Ozgun',
4252             1994 => 'Music Videos|Turkish|Fantezi',
4253             1995 => 'Music Videos|Turkish|Religious',
4254             1996 => 'Music Videos|Pop|Turkish Pop',
4255             1997 => 'Music Videos|Rock|Turkish Rock',
4256             1998 => 'Music Videos|Alternative|Turkish Alternative',
4257             1999 => 'Music Videos|Hip-Hop/Rap|Turkish Hip-Hop/Rap',
4258             2000 => 'Music Videos|African|Maskandi',
4259             2001 => 'Music Videos|Russian|Russian Romance',
4260             2002 => 'Music Videos|Russian|Russian Bard',
4261             2003 => 'Music Videos|Russian|Russian Pop',
4262             2004 => 'Music Videos|Russian|Russian Rock',
4263             2005 => 'Music Videos|Russian|Russian Hip-Hop',
4264             2006 => 'Music Videos|Arabic|Levant',
4265             2007 => 'Music Videos|Arabic|Levant|Dabke',
4266             2008 => 'Music Videos|Arabic|Maghreb Rai',
4267             2009 => 'Music Videos|Arabic|Khaleeji|Khaleeji Jalsat',
4268             2010 => 'Music Videos|Arabic|Khaleeji|Khaleeji Shailat',
4269             2011 => 'Music Videos|Tarab',
4270             2012 => 'Music Videos|Tarab|Iraqi Tarab',
4271             2013 => 'Music Videos|Tarab|Egyptian Tarab',
4272             2014 => 'Music Videos|Tarab|Khaleeji Tarab',
4273             2015 => 'Music Videos|Pop|Levant Pop',
4274             2016 => 'Music Videos|Pop|Iraqi Pop',
4275             2017 => 'Music Videos|Pop|Egyptian Pop',
4276             2018 => 'Music Videos|Pop|Maghreb Pop',
4277             2019 => 'Music Videos|Pop|Khaleeji Pop',
4278             2020 => 'Music Videos|Hip-Hop/Rap|Levant Hip-Hop',
4279             2021 => 'Music Videos|Hip-Hop/Rap|Egyptian Hip-Hop',
4280             2022 => 'Music Videos|Hip-Hop/Rap|Maghreb Hip-Hop',
4281             2023 => 'Music Videos|Hip-Hop/Rap|Khaleeji Hip-Hop',
4282             2024 => 'Music Videos|Alternative|Indie Levant',
4283             2025 => 'Music Videos|Alternative|Indie Egyptian',
4284             2026 => 'Music Videos|Alternative|Indie Maghreb',
4285             2027 => 'Music Videos|Electronic|Levant Electronic',
4286             2028 => "Music Videos|Electronic|Electro-Cha'abi",
4287             2029 => 'Music Videos|Electronic|Maghreb Electronic',
4288             2030 => 'Music Videos|Folk|Iraqi Folk',
4289             2031 => 'Music Videos|Folk|Khaleeji Folk',
4290             2032 => 'Music Videos|Dance|Maghreb Dance',
4291             4000 => 'TV Shows|Comedy',
4292             4001 => 'TV Shows|Drama',
4293             4002 => 'TV Shows|Animation',
4294             4003 => 'TV Shows|Action & Adventure',
4295             4004 => 'TV Shows|Classics',
4296             4005 => 'TV Shows|Kids & Family',
4297             4006 => 'TV Shows|Nonfiction',
4298             4007 => 'TV Shows|Reality TV',
4299             4008 => 'TV Shows|Sci-Fi & Fantasy',
4300             4009 => 'TV Shows|Sports',
4301             4010 => 'TV Shows|Teens',
4302             4011 => 'TV Shows|Latino TV',
4303             4401 => 'Movies|Action & Adventure',
4304             4402 => 'Movies|Anime',
4305             4403 => 'Movies|Classics',
4306             4404 => 'Movies|Comedy',
4307             4405 => 'Movies|Documentary',
4308             4406 => 'Movies|Drama',
4309             4407 => 'Movies|Foreign',
4310             4408 => 'Movies|Horror',
4311             4409 => 'Movies|Independent',
4312             4410 => 'Movies|Kids & Family',
4313             4411 => 'Movies|Musicals',
4314             4412 => 'Movies|Romance',
4315             4413 => 'Movies|Sci-Fi & Fantasy',
4316             4414 => 'Movies|Short Films',
4317             4415 => 'Movies|Special Interest',
4318             4416 => 'Movies|Thriller',
4319             4417 => 'Movies|Sports',
4320             4418 => 'Movies|Western',
4321             4419 => 'Movies|Urban',
4322             4420 => 'Movies|Holiday',
4323             4421 => 'Movies|Made for TV',
4324             4422 => 'Movies|Concert Films',
4325             4423 => 'Movies|Music Documentaries',
4326             4424 => 'Movies|Music Feature Films',
4327             4425 => 'Movies|Japanese Cinema',
4328             4426 => 'Movies|Jidaigeki',
4329             4427 => 'Movies|Tokusatsu',
4330             4428 => 'Movies|Korean Cinema',
4331             4429 => 'Movies|Russian',
4332             4430 => 'Movies|Turkish',
4333             4431 => 'Movies|Bollywood',
4334             4432 => 'Movies|Regional Indian',
4335             4433 => 'Movies|Middle Eastern',
4336             4434 => 'Movies|African',
4337             6000 => 'App Store|Business',
4338             6001 => 'App Store|Weather',
4339             6002 => 'App Store|Utilities',
4340             6003 => 'App Store|Travel',
4341             6004 => 'App Store|Sports',
4342             6005 => 'App Store|Social Networking',
4343             6006 => 'App Store|Reference',
4344             6007 => 'App Store|Productivity',
4345             6008 => 'App Store|Photo & Video',
4346             6009 => 'App Store|News',
4347             6010 => 'App Store|Navigation',
4348             6011 => 'App Store|Music',
4349             6012 => 'App Store|Lifestyle',
4350             6013 => 'App Store|Health & Fitness',
4351             6014 => 'App Store|Games',
4352             6015 => 'App Store|Finance',
4353             6016 => 'App Store|Entertainment',
4354             6017 => 'App Store|Education',
4355             6018 => 'App Store|Books',
4356             6020 => 'App Store|Medical',
4357             6021 => 'App Store|Magazines & Newspapers',
4358             6022 => 'App Store|Catalogs',
4359             6023 => 'App Store|Food & Drink',
4360             6024 => 'App Store|Shopping',
4361             6025 => 'App Store|Stickers',
4362             6026 => 'App Store|Developer Tools',
4363             6027 => 'App Store|Graphics & Design',
4364             7001 => 'App Store|Games|Action',
4365             7002 => 'App Store|Games|Adventure',
4366             7003 => 'App Store|Games|Casual',
4367             7004 => 'App Store|Games|Board',
4368             7005 => 'App Store|Games|Card',
4369             7006 => 'App Store|Games|Casino',
4370             7007 => 'App Store|Games|Dice',
4371             7008 => 'App Store|Games|Educational',
4372             7009 => 'App Store|Games|Family',
4373             7011 => 'App Store|Games|Music',
4374             7012 => 'App Store|Games|Puzzle',
4375             7013 => 'App Store|Games|Racing',
4376             7014 => 'App Store|Games|Role Playing',
4377             7015 => 'App Store|Games|Simulation',
4378             7016 => 'App Store|Games|Sports',
4379             7017 => 'App Store|Games|Strategy',
4380             7018 => 'App Store|Games|Trivia',
4381             7019 => 'App Store|Games|Word',
4382             8001 => 'Tones|Ringtones|Alternative',
4383             8002 => 'Tones|Ringtones|Blues',
4384             8003 => "Tones|Ringtones|Children's Music",
4385             8004 => 'Tones|Ringtones|Classical',
4386             8005 => 'Tones|Ringtones|Comedy',
4387             8006 => 'Tones|Ringtones|Country',
4388             8007 => 'Tones|Ringtones|Dance',
4389             8008 => 'Tones|Ringtones|Electronic',
4390             8009 => 'Tones|Ringtones|Enka',
4391             8010 => 'Tones|Ringtones|French Pop',
4392             8011 => 'Tones|Ringtones|German Folk',
4393             8012 => 'Tones|Ringtones|German Pop',
4394             8013 => 'Tones|Ringtones|Hip-Hop/Rap',
4395             8014 => 'Tones|Ringtones|Holiday',
4396             8015 => 'Tones|Ringtones|Inspirational',
4397             8016 => 'Tones|Ringtones|J-Pop',
4398             8017 => 'Tones|Ringtones|Jazz',
4399             8018 => 'Tones|Ringtones|Kayokyoku',
4400             8019 => 'Tones|Ringtones|Latin',
4401             8020 => 'Tones|Ringtones|New Age',
4402             8021 => 'Tones|Ringtones|Classical|Opera',
4403             8022 => 'Tones|Ringtones|Pop',
4404             8023 => 'Tones|Ringtones|R&B/Soul',
4405             8024 => 'Tones|Ringtones|Reggae',
4406             8025 => 'Tones|Ringtones|Rock',
4407             8026 => 'Tones|Ringtones|Singer/Songwriter',
4408             8027 => 'Tones|Ringtones|Soundtrack',
4409             8028 => 'Tones|Ringtones|Spoken Word',
4410             8029 => 'Tones|Ringtones|Vocal',
4411             8030 => 'Tones|Ringtones|World',
4412             8050 => 'Tones|Alert Tones|Sound Effects',
4413             8051 => 'Tones|Alert Tones|Dialogue',
4414             8052 => 'Tones|Alert Tones|Music',
4415             8053 => 'Tones|Ringtones',
4416             8054 => 'Tones|Alert Tones',
4417             8055 => 'Tones|Ringtones|Alternative|Chinese Alt',
4418             8056 => 'Tones|Ringtones|Alternative|College Rock',
4419             8057 => 'Tones|Ringtones|Alternative|Goth Rock',
4420             8058 => 'Tones|Ringtones|Alternative|Grunge',
4421             8059 => 'Tones|Ringtones|Alternative|Indie Rock',
4422             8060 => 'Tones|Ringtones|Alternative|Korean Indie',
4423             8061 => 'Tones|Ringtones|Alternative|New Wave',
4424             8062 => 'Tones|Ringtones|Alternative|Punk',
4425             8063 => 'Tones|Ringtones|Anime',
4426             8064 => 'Tones|Ringtones|Arabic',
4427             8065 => 'Tones|Ringtones|Arabic|Arabic Pop',
4428             8066 => 'Tones|Ringtones|Arabic|Islamic',
4429             8067 => 'Tones|Ringtones|Arabic|Khaleeji',
4430             8068 => 'Tones|Ringtones|Arabic|North African',
4431             8069 => 'Tones|Ringtones|Blues|Acoustic Blues',
4432             8070 => 'Tones|Ringtones|Blues|Chicago Blues',
4433             8071 => 'Tones|Ringtones|Blues|Classic Blues',
4434             8072 => 'Tones|Ringtones|Blues|Contemporary Blues',
4435             8073 => 'Tones|Ringtones|Blues|Country Blues',
4436             8074 => 'Tones|Ringtones|Blues|Delta Blues',
4437             8075 => 'Tones|Ringtones|Blues|Electric Blues',
4438             8076 => 'Tones|Ringtones|Brazilian',
4439             8077 => 'Tones|Ringtones|Brazilian|Axe', # (Axé)
4440             8078 => 'Tones|Ringtones|Brazilian|Baile Funk',
4441             8079 => 'Tones|Ringtones|Brazilian|Bossa Nova',
4442             8080 => 'Tones|Ringtones|Brazilian|Choro',
4443             8081 => 'Tones|Ringtones|Brazilian|Forro', # (Forró)
4444             8082 => 'Tones|Ringtones|Brazilian|Frevo',
4445             8083 => 'Tones|Ringtones|Brazilian|MPB',
4446             8084 => 'Tones|Ringtones|Brazilian|Pagode',
4447             8085 => 'Tones|Ringtones|Brazilian|Samba',
4448             8086 => 'Tones|Ringtones|Brazilian|Sertanejo',
4449             8087 => "Tones|Ringtones|Children's Music|Lullabies",
4450             8088 => "Tones|Ringtones|Children's Music|Sing-Along",
4451             8089 => "Tones|Ringtones|Children's Music|Stories",
4452             8090 => 'Tones|Ringtones|Chinese',
4453             8091 => 'Tones|Ringtones|Chinese|Chinese Classical',
4454             8092 => 'Tones|Ringtones|Chinese|Chinese Flute',
4455             8093 => 'Tones|Ringtones|Chinese|Chinese Opera',
4456             8094 => 'Tones|Ringtones|Chinese|Chinese Orchestral',
4457             8095 => 'Tones|Ringtones|Chinese|Chinese Regional Folk',
4458             8096 => 'Tones|Ringtones|Chinese|Chinese Strings',
4459             8097 => 'Tones|Ringtones|Chinese|Taiwanese Folk',
4460             8098 => 'Tones|Ringtones|Chinese|Tibetan Native Music',
4461             8099 => 'Tones|Ringtones|Christian & Gospel',
4462             8100 => 'Tones|Ringtones|Christian & Gospel|CCM',
4463             8101 => 'Tones|Ringtones|Christian & Gospel|Christian Metal',
4464             8102 => 'Tones|Ringtones|Christian & Gospel|Christian Pop',
4465             8103 => 'Tones|Ringtones|Christian & Gospel|Christian Rap',
4466             8104 => 'Tones|Ringtones|Christian & Gospel|Christian Rock',
4467             8105 => 'Tones|Ringtones|Christian & Gospel|Classic Christian',
4468             8106 => 'Tones|Ringtones|Christian & Gospel|Contemporary Gospel',
4469             8107 => 'Tones|Ringtones|Christian & Gospel|Gospel',
4470             8108 => 'Tones|Ringtones|Christian & Gospel|Praise & Worship',
4471             8109 => 'Tones|Ringtones|Christian & Gospel|Southern Gospel',
4472             8110 => 'Tones|Ringtones|Christian & Gospel|Traditional Gospel',
4473             8111 => 'Tones|Ringtones|Classical|Avant-Garde',
4474             8112 => 'Tones|Ringtones|Classical|Baroque Era',
4475             8113 => 'Tones|Ringtones|Classical|Chamber Music',
4476             8114 => 'Tones|Ringtones|Classical|Chant',
4477             8115 => 'Tones|Ringtones|Classical|Choral',
4478             8116 => 'Tones|Ringtones|Classical|Classical Crossover',
4479             8117 => 'Tones|Ringtones|Classical|Early Music',
4480             8118 => 'Tones|Ringtones|Classical|High Classical',
4481             8119 => 'Tones|Ringtones|Classical|Impressionist',
4482             8120 => 'Tones|Ringtones|Classical|Medieval Era',
4483             8121 => 'Tones|Ringtones|Classical|Minimalism',
4484             8122 => 'Tones|Ringtones|Classical|Modern Era',
4485             8123 => 'Tones|Ringtones|Classical|Orchestral',
4486             8124 => 'Tones|Ringtones|Classical|Renaissance',
4487             8125 => 'Tones|Ringtones|Classical|Romantic Era',
4488             8126 => 'Tones|Ringtones|Classical|Wedding Music',
4489             8127 => 'Tones|Ringtones|Comedy|Novelty',
4490             8128 => 'Tones|Ringtones|Comedy|Standup Comedy',
4491             8129 => 'Tones|Ringtones|Country|Alternative Country',
4492             8130 => 'Tones|Ringtones|Country|Americana',
4493             8131 => 'Tones|Ringtones|Country|Bluegrass',
4494             8132 => 'Tones|Ringtones|Country|Contemporary Bluegrass',
4495             8133 => 'Tones|Ringtones|Country|Contemporary Country',
4496             8134 => 'Tones|Ringtones|Country|Country Gospel',
4497             8135 => 'Tones|Ringtones|Country|Honky Tonk',
4498             8136 => 'Tones|Ringtones|Country|Outlaw Country',
4499             8137 => 'Tones|Ringtones|Country|Thai Country',
4500             8138 => 'Tones|Ringtones|Country|Traditional Bluegrass',
4501             8139 => 'Tones|Ringtones|Country|Traditional Country',
4502             8140 => 'Tones|Ringtones|Country|Urban Cowboy',
4503             8141 => 'Tones|Ringtones|Dance|Breakbeat',
4504             8142 => 'Tones|Ringtones|Dance|Exercise',
4505             8143 => 'Tones|Ringtones|Dance|Garage',
4506             8144 => 'Tones|Ringtones|Dance|Hardcore',
4507             8145 => 'Tones|Ringtones|Dance|House',
4508             8146 => "Tones|Ringtones|Dance|Jungle/Drum'n'bass",
4509             8147 => 'Tones|Ringtones|Dance|Techno',
4510             8148 => 'Tones|Ringtones|Dance|Trance',
4511             8149 => 'Tones|Ringtones|Disney',
4512             8150 => 'Tones|Ringtones|Easy Listening',
4513             8151 => 'Tones|Ringtones|Easy Listening|Lounge',
4514             8152 => 'Tones|Ringtones|Easy Listening|Swing',
4515             8153 => 'Tones|Ringtones|Electronic|Ambient',
4516             8154 => 'Tones|Ringtones|Electronic|Downtempo',
4517             8155 => 'Tones|Ringtones|Electronic|Electronica',
4518             8156 => 'Tones|Ringtones|Electronic|IDM/Experimental',
4519             8157 => 'Tones|Ringtones|Electronic|Industrial',
4520             8158 => 'Tones|Ringtones|Fitness & Workout',
4521             8159 => 'Tones|Ringtones|Folk',
4522             8160 => 'Tones|Ringtones|Hip-Hop/Rap|Alternative Rap',
4523             8161 => 'Tones|Ringtones|Hip-Hop/Rap|Chinese Hip-Hop',
4524             8162 => 'Tones|Ringtones|Hip-Hop/Rap|Dirty South',
4525             8163 => 'Tones|Ringtones|Hip-Hop/Rap|East Coast Rap',
4526             8164 => 'Tones|Ringtones|Hip-Hop/Rap|Gangsta Rap',
4527             8165 => 'Tones|Ringtones|Hip-Hop/Rap|Hardcore Rap',
4528             8166 => 'Tones|Ringtones|Hip-Hop/Rap|Hip-Hop',
4529             8167 => 'Tones|Ringtones|Hip-Hop/Rap|Korean Hip-Hop',
4530             8168 => 'Tones|Ringtones|Hip-Hop/Rap|Latin Rap',
4531             8169 => 'Tones|Ringtones|Hip-Hop/Rap|Old School Rap',
4532             8170 => 'Tones|Ringtones|Hip-Hop/Rap|Rap',
4533             8171 => 'Tones|Ringtones|Hip-Hop/Rap|Underground Rap',
4534             8172 => 'Tones|Ringtones|Hip-Hop/Rap|West Coast Rap',
4535             8173 => 'Tones|Ringtones|Holiday|Chanukah',
4536             8174 => 'Tones|Ringtones|Holiday|Christmas',
4537             8175 => "Tones|Ringtones|Holiday|Christmas: Children's",
4538             8176 => 'Tones|Ringtones|Holiday|Christmas: Classic',
4539             8177 => 'Tones|Ringtones|Holiday|Christmas: Classical',
4540             8178 => 'Tones|Ringtones|Holiday|Christmas: Jazz',
4541             8179 => 'Tones|Ringtones|Holiday|Christmas: Modern',
4542             8180 => 'Tones|Ringtones|Holiday|Christmas: Pop',
4543             8181 => 'Tones|Ringtones|Holiday|Christmas: R&B',
4544             8182 => 'Tones|Ringtones|Holiday|Christmas: Religious',
4545             8183 => 'Tones|Ringtones|Holiday|Christmas: Rock',
4546             8184 => 'Tones|Ringtones|Holiday|Easter',
4547             8185 => 'Tones|Ringtones|Holiday|Halloween',
4548             8186 => 'Tones|Ringtones|Holiday|Thanksgiving',
4549             8187 => 'Tones|Ringtones|Indian',
4550             8188 => 'Tones|Ringtones|Indian|Bollywood',
4551             8189 => 'Tones|Ringtones|Indian|Devotional & Spiritual',
4552             8190 => 'Tones|Ringtones|Indian|Ghazals',
4553             8191 => 'Tones|Ringtones|Indian|Indian Classical',
4554             8192 => 'Tones|Ringtones|Indian|Indian Folk',
4555             8193 => 'Tones|Ringtones|Indian|Indian Pop',
4556             8194 => 'Tones|Ringtones|Indian|Regional Indian',
4557             8195 => 'Tones|Ringtones|Indian|Sufi',
4558             8196 => 'Tones|Ringtones|Indian|Regional Indian|Tamil',
4559             8197 => 'Tones|Ringtones|Indian|Regional Indian|Telugu',
4560             8198 => 'Tones|Ringtones|Instrumental',
4561             8199 => 'Tones|Ringtones|Jazz|Avant-Garde Jazz',
4562             8201 => 'Tones|Ringtones|Jazz|Big Band',
4563             8202 => 'Tones|Ringtones|Jazz|Bop',
4564             8203 => 'Tones|Ringtones|Jazz|Contemporary Jazz',
4565             8204 => 'Tones|Ringtones|Jazz|Cool Jazz',
4566             8205 => 'Tones|Ringtones|Jazz|Crossover Jazz',
4567             8206 => 'Tones|Ringtones|Jazz|Dixieland',
4568             8207 => 'Tones|Ringtones|Jazz|Fusion',
4569             8208 => 'Tones|Ringtones|Jazz|Hard Bop',
4570             8209 => 'Tones|Ringtones|Jazz|Latin Jazz',
4571             8210 => 'Tones|Ringtones|Jazz|Mainstream Jazz',
4572             8211 => 'Tones|Ringtones|Jazz|Ragtime',
4573             8212 => 'Tones|Ringtones|Jazz|Smooth Jazz',
4574             8213 => 'Tones|Ringtones|Jazz|Trad Jazz',
4575             8214 => 'Tones|Ringtones|Pop|K-Pop',
4576             8215 => 'Tones|Ringtones|Karaoke',
4577             8216 => 'Tones|Ringtones|Korean',
4578             8217 => 'Tones|Ringtones|Korean|Korean Classical',
4579             8218 => 'Tones|Ringtones|Korean|Korean Trad Instrumental',
4580             8219 => 'Tones|Ringtones|Korean|Korean Trad Song',
4581             8220 => 'Tones|Ringtones|Korean|Korean Trad Theater',
4582             8221 => 'Tones|Ringtones|Latin|Alternative & Rock in Spanish',
4583             8222 => 'Tones|Ringtones|Latin|Baladas y Boleros',
4584             8223 => 'Tones|Ringtones|Latin|Contemporary Latin',
4585             8224 => 'Tones|Ringtones|Latin|Latin Jazz',
4586             8225 => 'Tones|Ringtones|Latin|Latin Urban',
4587             8226 => 'Tones|Ringtones|Latin|Pop in Spanish',
4588             8227 => 'Tones|Ringtones|Latin|Raices',
4589             8228 => 'Tones|Ringtones|Latin|Musica Mexicana', # (Música Mexicana)
4590             8229 => 'Tones|Ringtones|Latin|Salsa y Tropical',
4591             8230 => 'Tones|Ringtones|Marching Bands',
4592             8231 => 'Tones|Ringtones|New Age|Healing',
4593             8232 => 'Tones|Ringtones|New Age|Meditation',
4594             8233 => 'Tones|Ringtones|New Age|Nature',
4595             8234 => 'Tones|Ringtones|New Age|Relaxation',
4596             8235 => 'Tones|Ringtones|New Age|Travel',
4597             8236 => 'Tones|Ringtones|Orchestral',
4598             8237 => 'Tones|Ringtones|Pop|Adult Contemporary',
4599             8238 => 'Tones|Ringtones|Pop|Britpop',
4600             8239 => 'Tones|Ringtones|Pop|C-Pop',
4601             8240 => 'Tones|Ringtones|Pop|Cantopop/HK-Pop',
4602             8241 => 'Tones|Ringtones|Pop|Indo Pop',
4603             8242 => 'Tones|Ringtones|Pop|Korean Folk-Pop',
4604             8243 => 'Tones|Ringtones|Pop|Malaysian Pop',
4605             8244 => 'Tones|Ringtones|Pop|Mandopop',
4606             8245 => 'Tones|Ringtones|Pop|Manilla Sound',
4607             8246 => 'Tones|Ringtones|Pop|Oldies',
4608             8247 => 'Tones|Ringtones|Pop|Original Pilipino Music',
4609             8248 => 'Tones|Ringtones|Pop|Pinoy Pop',
4610             8249 => 'Tones|Ringtones|Pop|Pop/Rock',
4611             8250 => 'Tones|Ringtones|Pop|Soft Rock',
4612             8251 => 'Tones|Ringtones|Pop|Tai-Pop',
4613             8252 => 'Tones|Ringtones|Pop|Teen Pop',
4614             8253 => 'Tones|Ringtones|Pop|Thai Pop',
4615             8254 => 'Tones|Ringtones|R&B/Soul|Contemporary R&B',
4616             8255 => 'Tones|Ringtones|R&B/Soul|Disco',
4617             8256 => 'Tones|Ringtones|R&B/Soul|Doo Wop',
4618             8257 => 'Tones|Ringtones|R&B/Soul|Funk',
4619             8258 => 'Tones|Ringtones|R&B/Soul|Motown',
4620             8259 => 'Tones|Ringtones|R&B/Soul|Neo-Soul',
4621             8260 => 'Tones|Ringtones|R&B/Soul|Soul',
4622             8261 => 'Tones|Ringtones|Reggae|Modern Dancehall',
4623             8262 => 'Tones|Ringtones|Reggae|Dub',
4624             8263 => 'Tones|Ringtones|Reggae|Roots Reggae',
4625             8264 => 'Tones|Ringtones|Reggae|Ska',
4626             8265 => 'Tones|Ringtones|Rock|Adult Alternative',
4627             8266 => 'Tones|Ringtones|Rock|American Trad Rock',
4628             8267 => 'Tones|Ringtones|Rock|Arena Rock',
4629             8268 => 'Tones|Ringtones|Rock|Blues-Rock',
4630             8269 => 'Tones|Ringtones|Rock|British Invasion',
4631             8270 => 'Tones|Ringtones|Rock|Chinese Rock',
4632             8271 => 'Tones|Ringtones|Rock|Death Metal/Black Metal',
4633             8272 => 'Tones|Ringtones|Rock|Glam Rock',
4634             8273 => 'Tones|Ringtones|Rock|Hair Metal',
4635             8274 => 'Tones|Ringtones|Rock|Hard Rock',
4636             8275 => 'Tones|Ringtones|Rock|Metal',
4637             8276 => 'Tones|Ringtones|Rock|Jam Bands',
4638             8277 => 'Tones|Ringtones|Rock|Korean Rock',
4639             8278 => 'Tones|Ringtones|Rock|Prog-Rock/Art Rock',
4640             8279 => 'Tones|Ringtones|Rock|Psychedelic',
4641             8280 => 'Tones|Ringtones|Rock|Rock & Roll',
4642             8281 => 'Tones|Ringtones|Rock|Rockabilly',
4643             8282 => 'Tones|Ringtones|Rock|Roots Rock',
4644             8283 => 'Tones|Ringtones|Rock|Singer/Songwriter',
4645             8284 => 'Tones|Ringtones|Rock|Southern Rock',
4646             8285 => 'Tones|Ringtones|Rock|Surf',
4647             8286 => 'Tones|Ringtones|Rock|Tex-Mex',
4648             8287 => 'Tones|Ringtones|Singer/Songwriter|Alternative Folk',
4649             8288 => 'Tones|Ringtones|Singer/Songwriter|Contemporary Folk',
4650             8289 => 'Tones|Ringtones|Singer/Songwriter|Contemporary Singer/Songwriter',
4651             8290 => 'Tones|Ringtones|Singer/Songwriter|Folk-Rock',
4652             8291 => 'Tones|Ringtones|Singer/Songwriter|New Acoustic',
4653             8292 => 'Tones|Ringtones|Singer/Songwriter|Traditional Folk',
4654             8293 => 'Tones|Ringtones|Soundtrack|Foreign Cinema',
4655             8294 => 'Tones|Ringtones|Soundtrack|Musicals',
4656             8295 => 'Tones|Ringtones|Soundtrack|Original Score',
4657             8296 => 'Tones|Ringtones|Soundtrack|Sound Effects',
4658             8297 => 'Tones|Ringtones|Soundtrack|Soundtrack',
4659             8298 => 'Tones|Ringtones|Soundtrack|TV Soundtrack',
4660             8299 => 'Tones|Ringtones|Vocal|Standards',
4661             8300 => 'Tones|Ringtones|Vocal|Traditional Pop',
4662             8301 => 'Tones|Ringtones|Vocal|Trot',
4663             8302 => 'Tones|Ringtones|Jazz|Vocal Jazz',
4664             8303 => 'Tones|Ringtones|Vocal|Vocal Pop',
4665             8304 => 'Tones|Ringtones|African',
4666             8305 => 'Tones|Ringtones|African|Afrikaans',
4667             8306 => 'Tones|Ringtones|African|Afro-Beat',
4668             8307 => 'Tones|Ringtones|African|Afro-Pop',
4669             8308 => 'Tones|Ringtones|Turkish|Arabesque',
4670             8309 => 'Tones|Ringtones|World|Asia',
4671             8310 => 'Tones|Ringtones|World|Australia',
4672             8311 => 'Tones|Ringtones|World|Cajun',
4673             8312 => 'Tones|Ringtones|World|Calypso',
4674             8313 => 'Tones|Ringtones|World|Caribbean',
4675             8314 => 'Tones|Ringtones|World|Celtic',
4676             8315 => 'Tones|Ringtones|World|Celtic Folk',
4677             8316 => 'Tones|Ringtones|World|Contemporary Celtic',
4678             8317 => 'Tones|Ringtones|World|Dangdut',
4679             8318 => 'Tones|Ringtones|World|Dini',
4680             8319 => 'Tones|Ringtones|World|Europe',
4681             8320 => 'Tones|Ringtones|World|Fado',
4682             8321 => 'Tones|Ringtones|World|Farsi',
4683             8322 => 'Tones|Ringtones|World|Flamenco',
4684             8323 => 'Tones|Ringtones|World|France',
4685             8324 => 'Tones|Ringtones|Turkish|Halk',
4686             8325 => 'Tones|Ringtones|World|Hawaii',
4687             8326 => 'Tones|Ringtones|World|Iberia',
4688             8327 => 'Tones|Ringtones|World|Indonesian Religious',
4689             8328 => 'Tones|Ringtones|World|Israeli',
4690             8329 => 'Tones|Ringtones|World|Japan',
4691             8330 => 'Tones|Ringtones|World|Klezmer',
4692             8331 => 'Tones|Ringtones|World|North America',
4693             8332 => 'Tones|Ringtones|World|Polka',
4694             8333 => 'Tones|Ringtones|Russian',
4695             8334 => 'Tones|Ringtones|Russian|Russian Chanson',
4696             8335 => 'Tones|Ringtones|Turkish|Sanat',
4697             8336 => 'Tones|Ringtones|World|Soca',
4698             8337 => 'Tones|Ringtones|World|South Africa',
4699             8338 => 'Tones|Ringtones|World|South America',
4700             8339 => 'Tones|Ringtones|World|Tango',
4701             8340 => 'Tones|Ringtones|World|Traditional Celtic',
4702             8341 => 'Tones|Ringtones|Turkish',
4703             8342 => 'Tones|Ringtones|World|Worldbeat',
4704             8343 => 'Tones|Ringtones|World|Zydeco',
4705             8345 => 'Tones|Ringtones|Classical|Art Song',
4706             8346 => 'Tones|Ringtones|Classical|Brass & Woodwinds',
4707             8347 => 'Tones|Ringtones|Classical|Solo Instrumental',
4708             8348 => 'Tones|Ringtones|Classical|Contemporary Era',
4709             8349 => 'Tones|Ringtones|Classical|Oratorio',
4710             8350 => 'Tones|Ringtones|Classical|Cantata',
4711             8351 => 'Tones|Ringtones|Classical|Electronic',
4712             8352 => 'Tones|Ringtones|Classical|Sacred',
4713             8353 => 'Tones|Ringtones|Classical|Guitar',
4714             8354 => 'Tones|Ringtones|Classical|Piano',
4715             8355 => 'Tones|Ringtones|Classical|Violin',
4716             8356 => 'Tones|Ringtones|Classical|Cello',
4717             8357 => 'Tones|Ringtones|Classical|Percussion',
4718             8358 => 'Tones|Ringtones|Electronic|Dubstep',
4719             8359 => 'Tones|Ringtones|Electronic|Bass',
4720             8360 => 'Tones|Ringtones|Hip-Hop/Rap|UK Hip Hop',
4721             8361 => 'Tones|Ringtones|Reggae|Lovers Rock',
4722             8362 => 'Tones|Ringtones|Alternative|EMO',
4723             8363 => 'Tones|Ringtones|Alternative|Pop Punk',
4724             8364 => 'Tones|Ringtones|Alternative|Indie Pop',
4725             8365 => 'Tones|Ringtones|New Age|Yoga',
4726             8366 => 'Tones|Ringtones|Pop|Tribute',
4727             8367 => 'Tones|Ringtones|Pop|Shows',
4728             8368 => 'Tones|Ringtones|Cuban',
4729             8369 => 'Tones|Ringtones|Cuban|Mambo',
4730             8370 => 'Tones|Ringtones|Cuban|Chachacha',
4731             8371 => 'Tones|Ringtones|Cuban|Guajira',
4732             8372 => 'Tones|Ringtones|Cuban|Son',
4733             8373 => 'Tones|Ringtones|Cuban|Bolero',
4734             8374 => 'Tones|Ringtones|Cuban|Guaracha',
4735             8375 => 'Tones|Ringtones|Cuban|Timba',
4736             8376 => 'Tones|Ringtones|Soundtrack|Video Game',
4737             8377 => 'Tones|Ringtones|Indian|Regional Indian|Punjabi|Punjabi Pop',
4738             8378 => 'Tones|Ringtones|Indian|Regional Indian|Bengali|Rabindra Sangeet',
4739             8379 => 'Tones|Ringtones|Indian|Regional Indian|Malayalam',
4740             8380 => 'Tones|Ringtones|Indian|Regional Indian|Kannada',
4741             8381 => 'Tones|Ringtones|Indian|Regional Indian|Marathi',
4742             8382 => 'Tones|Ringtones|Indian|Regional Indian|Gujarati',
4743             8383 => 'Tones|Ringtones|Indian|Regional Indian|Assamese',
4744             8384 => 'Tones|Ringtones|Indian|Regional Indian|Bhojpuri',
4745             8385 => 'Tones|Ringtones|Indian|Regional Indian|Haryanvi',
4746             8386 => 'Tones|Ringtones|Indian|Regional Indian|Odia',
4747             8387 => 'Tones|Ringtones|Indian|Regional Indian|Rajasthani',
4748             8388 => 'Tones|Ringtones|Indian|Regional Indian|Urdu',
4749             8389 => 'Tones|Ringtones|Indian|Regional Indian|Punjabi',
4750             8390 => 'Tones|Ringtones|Indian|Regional Indian|Bengali',
4751             8391 => 'Tones|Ringtones|Indian|Indian Classical|Carnatic Classical',
4752             8392 => 'Tones|Ringtones|Indian|Indian Classical|Hindustani Classical',
4753             8393 => 'Tones|Ringtones|African|Afro House',
4754             8394 => 'Tones|Ringtones|African|Afro Soul',
4755             8395 => 'Tones|Ringtones|African|Afrobeats',
4756             8396 => 'Tones|Ringtones|African|Benga',
4757             8397 => 'Tones|Ringtones|African|Bongo-Flava',
4758             8398 => 'Tones|Ringtones|African|Coupe-Decale',
4759             8399 => 'Tones|Ringtones|African|Gqom',
4760             8400 => 'Tones|Ringtones|African|Highlife',
4761             8401 => 'Tones|Ringtones|African|Kuduro',
4762             8402 => 'Tones|Ringtones|African|Kizomba',
4763             8403 => 'Tones|Ringtones|African|Kwaito',
4764             8404 => 'Tones|Ringtones|African|Mbalax',
4765             8405 => 'Tones|Ringtones|African|Ndombolo',
4766             8406 => 'Tones|Ringtones|African|Shangaan Electro',
4767             8407 => 'Tones|Ringtones|African|Soukous',
4768             8408 => 'Tones|Ringtones|African|Taarab',
4769             8409 => 'Tones|Ringtones|African|Zouglou',
4770             8410 => 'Tones|Ringtones|Turkish|Ozgun',
4771             8411 => 'Tones|Ringtones|Turkish|Fantezi',
4772             8412 => 'Tones|Ringtones|Turkish|Religious',
4773             8413 => 'Tones|Ringtones|Pop|Turkish Pop',
4774             8414 => 'Tones|Ringtones|Rock|Turkish Rock',
4775             8415 => 'Tones|Ringtones|Alternative|Turkish Alternative',
4776             8416 => 'Tones|Ringtones|Hip-Hop/Rap|Turkish Hip-Hop/Rap',
4777             8417 => 'Tones|Ringtones|African|Maskandi',
4778             8418 => 'Tones|Ringtones|Russian|Russian Romance',
4779             8419 => 'Tones|Ringtones|Russian|Russian Bard',
4780             8420 => 'Tones|Ringtones|Russian|Russian Pop',
4781             8421 => 'Tones|Ringtones|Russian|Russian Rock',
4782             8422 => 'Tones|Ringtones|Russian|Russian Hip-Hop',
4783             8423 => 'Tones|Ringtones|Arabic|Levant',
4784             8424 => 'Tones|Ringtones|Arabic|Levant|Dabke',
4785             8425 => 'Tones|Ringtones|Arabic|Maghreb Rai',
4786             8426 => 'Tones|Ringtones|Arabic|Khaleeji|Khaleeji Jalsat',
4787             8427 => 'Tones|Ringtones|Arabic|Khaleeji|Khaleeji Shailat',
4788             8428 => 'Tones|Ringtones|Tarab',
4789             8429 => 'Tones|Ringtones|Tarab|Iraqi Tarab',
4790             8430 => 'Tones|Ringtones|Tarab|Egyptian Tarab',
4791             8431 => 'Tones|Ringtones|Tarab|Khaleeji Tarab',
4792             8432 => 'Tones|Ringtones|Pop|Levant Pop',
4793             8433 => 'Tones|Ringtones|Pop|Iraqi Pop',
4794             8434 => 'Tones|Ringtones|Pop|Egyptian Pop',
4795             8435 => 'Tones|Ringtones|Pop|Maghreb Pop',
4796             8436 => 'Tones|Ringtones|Pop|Khaleeji Pop',
4797             8437 => 'Tones|Ringtones|Hip-Hop/Rap|Levant Hip-Hop',
4798             8438 => 'Tones|Ringtones|Hip-Hop/Rap|Egyptian Hip-Hop',
4799             8439 => 'Tones|Ringtones|Hip-Hop/Rap|Maghreb Hip-Hop',
4800             8440 => 'Tones|Ringtones|Hip-Hop/Rap|Khaleeji Hip-Hop',
4801             8441 => 'Tones|Ringtones|Alternative|Indie Levant',
4802             8442 => 'Tones|Ringtones|Alternative|Indie Egyptian',
4803             8443 => 'Tones|Ringtones|Alternative|Indie Maghreb',
4804             8444 => 'Tones|Ringtones|Electronic|Levant Electronic',
4805             8445 => "Tones|Ringtones|Electronic|Electro-Cha'abi",
4806             8446 => 'Tones|Ringtones|Electronic|Maghreb Electronic',
4807             8447 => 'Tones|Ringtones|Folk|Iraqi Folk',
4808             8448 => 'Tones|Ringtones|Folk|Khaleeji Folk',
4809             8449 => 'Tones|Ringtones|Dance|Maghreb Dance',
4810             9002 => 'Books|Nonfiction',
4811             9003 => 'Books|Romance',
4812             9004 => 'Books|Travel & Adventure',
4813             9007 => 'Books|Arts & Entertainment',
4814             9008 => 'Books|Biographies & Memoirs',
4815             9009 => 'Books|Business & Personal Finance',
4816             9010 => 'Books|Children & Teens',
4817             9012 => 'Books|Humor',
4818             9015 => 'Books|History',
4819             9018 => 'Books|Religion & Spirituality',
4820             9019 => 'Books|Science & Nature',
4821             9020 => 'Books|Sci-Fi & Fantasy',
4822             9024 => 'Books|Lifestyle & Home',
4823             9025 => 'Books|Self-Development',
4824             9026 => 'Books|Comics & Graphic Novels',
4825             9027 => 'Books|Computers & Internet',
4826             9028 => 'Books|Cookbooks, Food & Wine',
4827             9029 => 'Books|Professional & Technical',
4828             9030 => 'Books|Parenting',
4829             9031 => 'Books|Fiction & Literature',
4830             9032 => 'Books|Mysteries & Thrillers',
4831             9033 => 'Books|Reference',
4832             9034 => 'Books|Politics & Current Events',
4833             9035 => 'Books|Sports & Outdoors',
4834             10001 => 'Books|Lifestyle & Home|Antiques & Collectibles',
4835             10002 => 'Books|Arts & Entertainment|Art & Architecture',
4836             10003 => 'Books|Religion & Spirituality|Bibles',
4837             10004 => 'Books|Self-Development|Spirituality',
4838             10005 => 'Books|Business & Personal Finance|Industries & Professions',
4839             10006 => 'Books|Business & Personal Finance|Marketing & Sales',
4840             10007 => 'Books|Business & Personal Finance|Small Business & Entrepreneurship',
4841             10008 => 'Books|Business & Personal Finance|Personal Finance',
4842             10009 => 'Books|Business & Personal Finance|Reference',
4843             10010 => 'Books|Business & Personal Finance|Careers',
4844             10011 => 'Books|Business & Personal Finance|Economics',
4845             10012 => 'Books|Business & Personal Finance|Investing',
4846             10013 => 'Books|Business & Personal Finance|Finance',
4847             10014 => 'Books|Business & Personal Finance|Management & Leadership',
4848             10015 => 'Books|Comics & Graphic Novels|Graphic Novels',
4849             10016 => 'Books|Comics & Graphic Novels|Manga',
4850             10017 => 'Books|Computers & Internet|Computers',
4851             10018 => 'Books|Computers & Internet|Databases',
4852             10019 => 'Books|Computers & Internet|Digital Media',
4853             10020 => 'Books|Computers & Internet|Internet',
4854             10021 => 'Books|Computers & Internet|Network',
4855             10022 => 'Books|Computers & Internet|Operating Systems',
4856             10023 => 'Books|Computers & Internet|Programming',
4857             10024 => 'Books|Computers & Internet|Software',
4858             10025 => 'Books|Computers & Internet|System Administration',
4859             10026 => 'Books|Cookbooks, Food & Wine|Beverages',
4860             10027 => 'Books|Cookbooks, Food & Wine|Courses & Dishes',
4861             10028 => 'Books|Cookbooks, Food & Wine|Special Diet',
4862             10029 => 'Books|Cookbooks, Food & Wine|Special Occasions',
4863             10030 => 'Books|Cookbooks, Food & Wine|Methods',
4864             10031 => 'Books|Cookbooks, Food & Wine|Reference',
4865             10032 => 'Books|Cookbooks, Food & Wine|Regional & Ethnic',
4866             10033 => 'Books|Cookbooks, Food & Wine|Specific Ingredients',
4867             10034 => 'Books|Lifestyle & Home|Crafts & Hobbies',
4868             10035 => 'Books|Professional & Technical|Design',
4869             10036 => 'Books|Arts & Entertainment|Theater',
4870             10037 => 'Books|Professional & Technical|Education',
4871             10038 => 'Books|Nonfiction|Family & Relationships',
4872             10039 => 'Books|Fiction & Literature|Action & Adventure',
4873             10040 => 'Books|Fiction & Literature|African American',
4874             10041 => 'Books|Fiction & Literature|Religious',
4875             10042 => 'Books|Fiction & Literature|Classics',
4876             10043 => 'Books|Fiction & Literature|Erotica',
4877             10044 => 'Books|Sci-Fi & Fantasy|Fantasy',
4878             10045 => 'Books|Fiction & Literature|Gay',
4879             10046 => 'Books|Fiction & Literature|Ghost',
4880             10047 => 'Books|Fiction & Literature|Historical',
4881             10048 => 'Books|Fiction & Literature|Horror',
4882             10049 => 'Books|Fiction & Literature|Literary',
4883             10050 => 'Books|Mysteries & Thrillers|Hard-Boiled',
4884             10051 => 'Books|Mysteries & Thrillers|Historical',
4885             10052 => 'Books|Mysteries & Thrillers|Police Procedural',
4886             10053 => 'Books|Mysteries & Thrillers|Short Stories',
4887             10054 => 'Books|Mysteries & Thrillers|British Detectives',
4888             10055 => 'Books|Mysteries & Thrillers|Women Sleuths',
4889             10056 => 'Books|Romance|Erotic Romance',
4890             10057 => 'Books|Romance|Contemporary',
4891             10058 => 'Books|Romance|Paranormal',
4892             10059 => 'Books|Romance|Historical',
4893             10060 => 'Books|Romance|Short Stories',
4894             10061 => 'Books|Romance|Suspense',
4895             10062 => 'Books|Romance|Western',
4896             10063 => 'Books|Sci-Fi & Fantasy|Science Fiction',
4897             10064 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature',
4898             10065 => 'Books|Fiction & Literature|Short Stories',
4899             10066 => 'Books|Reference|Foreign Languages',
4900             10067 => 'Books|Arts & Entertainment|Games',
4901             10068 => 'Books|Lifestyle & Home|Gardening',
4902             10069 => 'Books|Self-Development|Health & Fitness',
4903             10070 => 'Books|History|Africa',
4904             10071 => 'Books|History|Americas',
4905             10072 => 'Books|History|Ancient',
4906             10073 => 'Books|History|Asia',
4907             10074 => 'Books|History|Australia & Oceania',
4908             10075 => 'Books|History|Europe',
4909             10076 => 'Books|History|Latin America',
4910             10077 => 'Books|History|Middle East',
4911             10078 => 'Books|History|Military',
4912             10079 => 'Books|History|United States',
4913             10080 => 'Books|History|World',
4914             10081 => "Books|Children & Teens|Children's Fiction",
4915             10082 => "Books|Children & Teens|Children's Nonfiction",
4916             10083 => 'Books|Professional & Technical|Law',
4917             10084 => 'Books|Fiction & Literature|Literary Criticism',
4918             10085 => 'Books|Science & Nature|Mathematics',
4919             10086 => 'Books|Professional & Technical|Medical',
4920             10087 => 'Books|Arts & Entertainment|Music',
4921             10088 => 'Books|Science & Nature|Nature',
4922             10089 => 'Books|Arts & Entertainment|Performing Arts',
4923             10090 => 'Books|Lifestyle & Home|Pets',
4924             10091 => 'Books|Nonfiction|Philosophy',
4925             10092 => 'Books|Arts & Entertainment|Photography',
4926             10093 => 'Books|Fiction & Literature|Poetry',
4927             10094 => 'Books|Self-Development|Psychology',
4928             10095 => 'Books|Reference|Almanacs & Yearbooks',
4929             10096 => 'Books|Reference|Atlases & Maps',
4930             10097 => 'Books|Reference|Catalogs & Directories',
4931             10098 => 'Books|Reference|Consumer Guides',
4932             10099 => 'Books|Reference|Dictionaries & Thesauruses',
4933             10100 => 'Books|Reference|Encyclopedias',
4934             10101 => 'Books|Reference|Etiquette',
4935             10102 => 'Books|Reference|Quotations',
4936             10103 => 'Books|Reference|Words & Language',
4937             10104 => 'Books|Reference|Writing',
4938             10105 => 'Books|Religion & Spirituality|Bible Studies',
4939             10106 => 'Books|Religion & Spirituality|Buddhism',
4940             10107 => 'Books|Religion & Spirituality|Christianity',
4941             10108 => 'Books|Religion & Spirituality|Hinduism',
4942             10109 => 'Books|Religion & Spirituality|Islam',
4943             10110 => 'Books|Religion & Spirituality|Judaism',
4944             10111 => 'Books|Science & Nature|Astronomy',
4945             10112 => 'Books|Science & Nature|Chemistry',
4946             10113 => 'Books|Science & Nature|Earth Sciences',
4947             10114 => 'Books|Science & Nature|Essays',
4948             10115 => 'Books|Science & Nature|History',
4949             10116 => 'Books|Science & Nature|Life Sciences',
4950             10117 => 'Books|Science & Nature|Physics',
4951             10118 => 'Books|Science & Nature|Reference',
4952             10119 => 'Books|Self-Development|Self-Improvement',
4953             10120 => 'Books|Nonfiction|Social Science',
4954             10121 => 'Books|Sports & Outdoors|Baseball',
4955             10122 => 'Books|Sports & Outdoors|Basketball',
4956             10123 => 'Books|Sports & Outdoors|Coaching',
4957             10124 => 'Books|Sports & Outdoors|Extreme Sports',
4958             10125 => 'Books|Sports & Outdoors|Football',
4959             10126 => 'Books|Sports & Outdoors|Golf',
4960             10127 => 'Books|Sports & Outdoors|Hockey',
4961             10128 => 'Books|Sports & Outdoors|Mountaineering',
4962             10129 => 'Books|Sports & Outdoors|Outdoors',
4963             10130 => 'Books|Sports & Outdoors|Racket Sports',
4964             10131 => 'Books|Sports & Outdoors|Reference',
4965             10132 => 'Books|Sports & Outdoors|Soccer',
4966             10133 => 'Books|Sports & Outdoors|Training',
4967             10134 => 'Books|Sports & Outdoors|Water Sports',
4968             10135 => 'Books|Sports & Outdoors|Winter Sports',
4969             10136 => 'Books|Reference|Study Aids',
4970             10137 => 'Books|Professional & Technical|Engineering',
4971             10138 => 'Books|Nonfiction|Transportation',
4972             10139 => 'Books|Travel & Adventure|Africa',
4973             10140 => 'Books|Travel & Adventure|Asia',
4974             10141 => 'Books|Travel & Adventure|Specialty Travel',
4975             10142 => 'Books|Travel & Adventure|Canada',
4976             10143 => 'Books|Travel & Adventure|Caribbean',
4977             10144 => 'Books|Travel & Adventure|Latin America',
4978             10145 => 'Books|Travel & Adventure|Essays & Memoirs',
4979             10146 => 'Books|Travel & Adventure|Europe',
4980             10147 => 'Books|Travel & Adventure|Middle East',
4981             10148 => 'Books|Travel & Adventure|United States',
4982             10149 => 'Books|Nonfiction|True Crime',
4983             11001 => 'Books|Sci-Fi & Fantasy|Fantasy|Contemporary',
4984             11002 => 'Books|Sci-Fi & Fantasy|Fantasy|Epic',
4985             11003 => 'Books|Sci-Fi & Fantasy|Fantasy|Historical',
4986             11004 => 'Books|Sci-Fi & Fantasy|Fantasy|Paranormal',
4987             11005 => 'Books|Sci-Fi & Fantasy|Fantasy|Short Stories',
4988             11006 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|Adventure',
4989             11007 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|High Tech',
4990             11008 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|Short Stories',
4991             11009 => 'Books|Professional & Technical|Education|Language Arts & Disciplines',
4992             11010 => 'Books|Communications & Media',
4993             11011 => 'Books|Communications & Media|Broadcasting',
4994             11012 => 'Books|Communications & Media|Digital Media',
4995             11013 => 'Books|Communications & Media|Journalism',
4996             11014 => 'Books|Communications & Media|Photojournalism',
4997             11015 => 'Books|Communications & Media|Print',
4998             11016 => 'Books|Communications & Media|Speech',
4999             11017 => 'Books|Communications & Media|Writing',
5000             11018 => 'Books|Arts & Entertainment|Art & Architecture|Urban Planning',
5001             11019 => 'Books|Arts & Entertainment|Dance',
5002             11020 => 'Books|Arts & Entertainment|Fashion',
5003             11021 => 'Books|Arts & Entertainment|Film',
5004             11022 => 'Books|Arts & Entertainment|Interior Design',
5005             11023 => 'Books|Arts & Entertainment|Media Arts',
5006             11024 => 'Books|Arts & Entertainment|Radio',
5007             11025 => 'Books|Arts & Entertainment|TV',
5008             11026 => 'Books|Arts & Entertainment|Visual Arts',
5009             11027 => 'Books|Biographies & Memoirs|Arts & Entertainment',
5010             11028 => 'Books|Biographies & Memoirs|Business',
5011             11029 => 'Books|Biographies & Memoirs|Culinary',
5012             11030 => 'Books|Biographies & Memoirs|Gay & Lesbian',
5013             11031 => 'Books|Biographies & Memoirs|Historical',
5014             11032 => 'Books|Biographies & Memoirs|Literary',
5015             11033 => 'Books|Biographies & Memoirs|Media & Journalism',
5016             11034 => 'Books|Biographies & Memoirs|Military',
5017             11035 => 'Books|Biographies & Memoirs|Politics',
5018             11036 => 'Books|Biographies & Memoirs|Religious',
5019             11037 => 'Books|Biographies & Memoirs|Science & Technology',
5020             11038 => 'Books|Biographies & Memoirs|Sports',
5021             11039 => 'Books|Biographies & Memoirs|Women',
5022             11040 => 'Books|Romance|New Adult',
5023             11042 => 'Books|Romance|Romantic Comedy',
5024             11043 => 'Books|Romance|Gay & Lesbian',
5025             11044 => 'Books|Fiction & Literature|Essays',
5026             11045 => 'Books|Fiction & Literature|Anthologies',
5027             11046 => 'Books|Fiction & Literature|Comparative Literature',
5028             11047 => 'Books|Fiction & Literature|Drama',
5029             11049 => 'Books|Fiction & Literature|Fairy Tales, Myths & Fables',
5030             11050 => 'Books|Fiction & Literature|Family',
5031             11051 => 'Books|Comics & Graphic Novels|Manga|School Drama',
5032             11052 => 'Books|Comics & Graphic Novels|Manga|Human Drama',
5033             11053 => 'Books|Comics & Graphic Novels|Manga|Family Drama',
5034             11054 => 'Books|Sports & Outdoors|Boxing',
5035             11055 => 'Books|Sports & Outdoors|Cricket',
5036             11056 => 'Books|Sports & Outdoors|Cycling',
5037             11057 => 'Books|Sports & Outdoors|Equestrian',
5038             11058 => 'Books|Sports & Outdoors|Martial Arts & Self Defense',
5039             11059 => 'Books|Sports & Outdoors|Motor Sports',
5040             11060 => 'Books|Sports & Outdoors|Rugby',
5041             11061 => 'Books|Sports & Outdoors|Running',
5042             11062 => 'Books|Self-Development|Diet & Nutrition',
5043             11063 => 'Books|Science & Nature|Agriculture',
5044             11064 => 'Books|Science & Nature|Atmosphere',
5045             11065 => 'Books|Science & Nature|Biology',
5046             11066 => 'Books|Science & Nature|Ecology',
5047             11067 => 'Books|Science & Nature|Environment',
5048             11068 => 'Books|Science & Nature|Geography',
5049             11069 => 'Books|Science & Nature|Geology',
5050             11070 => 'Books|Nonfiction|Social Science|Anthropology',
5051             11071 => 'Books|Nonfiction|Social Science|Archaeology',
5052             11072 => 'Books|Nonfiction|Social Science|Civics',
5053             11073 => 'Books|Nonfiction|Social Science|Government',
5054             11074 => 'Books|Nonfiction|Social Science|Social Studies',
5055             11075 => 'Books|Nonfiction|Social Science|Social Welfare',
5056             11076 => 'Books|Nonfiction|Social Science|Society',
5057             11077 => 'Books|Nonfiction|Philosophy|Aesthetics',
5058             11078 => 'Books|Nonfiction|Philosophy|Epistemology',
5059             11079 => 'Books|Nonfiction|Philosophy|Ethics',
5060             11080 => 'Books|Nonfiction|Philosophy|Language',
5061             11081 => 'Books|Nonfiction|Philosophy|Logic',
5062             11082 => 'Books|Nonfiction|Philosophy|Metaphysics',
5063             11083 => 'Books|Nonfiction|Philosophy|Political',
5064             11084 => 'Books|Nonfiction|Philosophy|Religion',
5065             11085 => 'Books|Reference|Manuals',
5066             11086 => 'Books|Kids',
5067             11087 => 'Books|Kids|Animals',
5068             11088 => 'Books|Kids|Basic Concepts',
5069             11089 => 'Books|Kids|Basic Concepts|Alphabet',
5070             11090 => 'Books|Kids|Basic Concepts|Body',
5071             11091 => 'Books|Kids|Basic Concepts|Colors',
5072             11092 => 'Books|Kids|Basic Concepts|Counting & Numbers',
5073             11093 => 'Books|Kids|Basic Concepts|Date & Time',
5074             11094 => 'Books|Kids|Basic Concepts|General',
5075             11095 => 'Books|Kids|Basic Concepts|Money',
5076             11096 => 'Books|Kids|Basic Concepts|Opposites',
5077             11097 => 'Books|Kids|Basic Concepts|Seasons',
5078             11098 => 'Books|Kids|Basic Concepts|Senses & Sensation',
5079             11099 => 'Books|Kids|Basic Concepts|Size & Shape',
5080             11100 => 'Books|Kids|Basic Concepts|Sounds',
5081             11101 => 'Books|Kids|Basic Concepts|Words',
5082             11102 => 'Books|Kids|Biography',
5083             11103 => 'Books|Kids|Careers & Occupations',
5084             11104 => 'Books|Kids|Computers & Technology',
5085             11105 => 'Books|Kids|Cooking & Food',
5086             11106 => 'Books|Kids|Arts & Entertainment',
5087             11107 => 'Books|Kids|Arts & Entertainment|Art',
5088             11108 => 'Books|Kids|Arts & Entertainment|Crafts',
5089             11109 => 'Books|Kids|Arts & Entertainment|Music',
5090             11110 => 'Books|Kids|Arts & Entertainment|Performing Arts',
5091             11111 => 'Books|Kids|Family',
5092             11112 => 'Books|Kids|Fiction',
5093             11113 => 'Books|Kids|Fiction|Action & Adventure',
5094             11114 => 'Books|Kids|Fiction|Animals',
5095             11115 => 'Books|Kids|Fiction|Classics',
5096             11116 => 'Books|Kids|Fiction|Comics & Graphic Novels',
5097             11117 => 'Books|Kids|Fiction|Culture, Places & People',
5098             11118 => 'Books|Kids|Fiction|Family & Relationships',
5099             11119 => 'Books|Kids|Fiction|Fantasy',
5100             11120 => 'Books|Kids|Fiction|Fairy Tales, Myths & Fables',
5101             11121 => 'Books|Kids|Fiction|Favorite Characters',
5102             11122 => 'Books|Kids|Fiction|Historical',
5103             11123 => 'Books|Kids|Fiction|Holidays & Celebrations',
5104             11124 => 'Books|Kids|Fiction|Monsters & Ghosts',
5105             11125 => 'Books|Kids|Fiction|Mysteries',
5106             11126 => 'Books|Kids|Fiction|Nature',
5107             11127 => 'Books|Kids|Fiction|Religion',
5108             11128 => 'Books|Kids|Fiction|Sci-Fi',
5109             11129 => 'Books|Kids|Fiction|Social Issues',
5110             11130 => 'Books|Kids|Fiction|Sports & Recreation',
5111             11131 => 'Books|Kids|Fiction|Transportation',
5112             11132 => 'Books|Kids|Games & Activities',
5113             11133 => 'Books|Kids|General Nonfiction',
5114             11134 => 'Books|Kids|Health',
5115             11135 => 'Books|Kids|History',
5116             11136 => 'Books|Kids|Holidays & Celebrations',
5117             11137 => 'Books|Kids|Holidays & Celebrations|Birthdays',
5118             11138 => 'Books|Kids|Holidays & Celebrations|Christmas & Advent',
5119             11139 => 'Books|Kids|Holidays & Celebrations|Easter & Lent',
5120             11140 => 'Books|Kids|Holidays & Celebrations|General',
5121             11141 => 'Books|Kids|Holidays & Celebrations|Halloween',
5122             11142 => 'Books|Kids|Holidays & Celebrations|Hanukkah',
5123             11143 => 'Books|Kids|Holidays & Celebrations|Other',
5124             11144 => 'Books|Kids|Holidays & Celebrations|Passover',
5125             11145 => 'Books|Kids|Holidays & Celebrations|Patriotic Holidays',
5126             11146 => 'Books|Kids|Holidays & Celebrations|Ramadan',
5127             11147 => 'Books|Kids|Holidays & Celebrations|Thanksgiving',
5128             11148 => "Books|Kids|Holidays & Celebrations|Valentine's Day",
5129             11149 => 'Books|Kids|Humor',
5130             11150 => 'Books|Kids|Humor|Jokes & Riddles',
5131             11151 => 'Books|Kids|Poetry',
5132             11152 => 'Books|Kids|Learning to Read',
5133             11153 => 'Books|Kids|Learning to Read|Chapter Books',
5134             11154 => 'Books|Kids|Learning to Read|Early Readers',
5135             11155 => 'Books|Kids|Learning to Read|Intermediate Readers',
5136             11156 => 'Books|Kids|Nursery Rhymes',
5137             11157 => 'Books|Kids|Government',
5138             11158 => 'Books|Kids|Reference',
5139             11159 => 'Books|Kids|Religion',
5140             11160 => 'Books|Kids|Science & Nature',
5141             11161 => 'Books|Kids|Social Issues',
5142             11162 => 'Books|Kids|Social Studies',
5143             11163 => 'Books|Kids|Sports & Recreation',
5144             11164 => 'Books|Kids|Transportation',
5145             11165 => 'Books|Young Adult',
5146             11166 => 'Books|Young Adult|Animals',
5147             11167 => 'Books|Young Adult|Biography',
5148             11168 => 'Books|Young Adult|Careers & Occupations',
5149             11169 => 'Books|Young Adult|Computers & Technology',
5150             11170 => 'Books|Young Adult|Cooking & Food',
5151             11171 => 'Books|Young Adult|Arts & Entertainment',
5152             11172 => 'Books|Young Adult|Arts & Entertainment|Art',
5153             11173 => 'Books|Young Adult|Arts & Entertainment|Crafts',
5154             11174 => 'Books|Young Adult|Arts & Entertainment|Music',
5155             11175 => 'Books|Young Adult|Arts & Entertainment|Performing Arts',
5156             11176 => 'Books|Young Adult|Family',
5157             11177 => 'Books|Young Adult|Fiction',
5158             11178 => 'Books|Young Adult|Fiction|Action & Adventure',
5159             11179 => 'Books|Young Adult|Fiction|Animals',
5160             11180 => 'Books|Young Adult|Fiction|Classics',
5161             11181 => 'Books|Young Adult|Fiction|Comics & Graphic Novels',
5162             11182 => 'Books|Young Adult|Fiction|Culture, Places & People',
5163             11183 => 'Books|Young Adult|Fiction|Dystopian',
5164             11184 => 'Books|Young Adult|Fiction|Family & Relationships',
5165             11185 => 'Books|Young Adult|Fiction|Fantasy',
5166             11186 => 'Books|Young Adult|Fiction|Fairy Tales, Myths & Fables',
5167             11187 => 'Books|Young Adult|Fiction|Favorite Characters',
5168             11188 => 'Books|Young Adult|Fiction|Historical',
5169             11189 => 'Books|Young Adult|Fiction|Holidays & Celebrations',
5170             11190 => 'Books|Young Adult|Fiction|Horror, Monsters & Ghosts',
5171             11191 => 'Books|Young Adult|Fiction|Crime & Mystery',
5172             11192 => 'Books|Young Adult|Fiction|Nature',
5173             11193 => 'Books|Young Adult|Fiction|Religion',
5174             11194 => 'Books|Young Adult|Fiction|Romance',
5175             11195 => 'Books|Young Adult|Fiction|Sci-Fi',
5176             11196 => 'Books|Young Adult|Fiction|Coming of Age',
5177             11197 => 'Books|Young Adult|Fiction|Sports & Recreation',
5178             11198 => 'Books|Young Adult|Fiction|Transportation',
5179             11199 => 'Books|Young Adult|Games & Activities',
5180             11200 => 'Books|Young Adult|General Nonfiction',
5181             11201 => 'Books|Young Adult|Health',
5182             11202 => 'Books|Young Adult|History',
5183             11203 => 'Books|Young Adult|Holidays & Celebrations',
5184             11204 => 'Books|Young Adult|Holidays & Celebrations|Birthdays',
5185             11205 => 'Books|Young Adult|Holidays & Celebrations|Christmas & Advent',
5186             11206 => 'Books|Young Adult|Holidays & Celebrations|Easter & Lent',
5187             11207 => 'Books|Young Adult|Holidays & Celebrations|General',
5188             11208 => 'Books|Young Adult|Holidays & Celebrations|Halloween',
5189             11209 => 'Books|Young Adult|Holidays & Celebrations|Hanukkah',
5190             11210 => 'Books|Young Adult|Holidays & Celebrations|Other',
5191             11211 => 'Books|Young Adult|Holidays & Celebrations|Passover',
5192             11212 => 'Books|Young Adult|Holidays & Celebrations|Patriotic Holidays',
5193             11213 => 'Books|Young Adult|Holidays & Celebrations|Ramadan',
5194             11214 => 'Books|Young Adult|Holidays & Celebrations|Thanksgiving',
5195             11215 => "Books|Young Adult|Holidays & Celebrations|Valentine's Day",
5196             11216 => 'Books|Young Adult|Humor',
5197             11217 => 'Books|Young Adult|Humor|Jokes & Riddles',
5198             11218 => 'Books|Young Adult|Poetry',
5199             11219 => 'Books|Young Adult|Politics & Government',
5200             11220 => 'Books|Young Adult|Reference',
5201             11221 => 'Books|Young Adult|Religion',
5202             11222 => 'Books|Young Adult|Science & Nature',
5203             11223 => 'Books|Young Adult|Coming of Age',
5204             11224 => 'Books|Young Adult|Social Studies',
5205             11225 => 'Books|Young Adult|Sports & Recreation',
5206             11226 => 'Books|Young Adult|Transportation',
5207             11227 => 'Books|Communications & Media',
5208             11228 => 'Books|Military & Warfare',
5209             11229 => 'Books|Romance|Inspirational',
5210             11231 => 'Books|Romance|Holiday',
5211             11232 => 'Books|Romance|Wholesome',
5212             11233 => 'Books|Romance|Military',
5213             11234 => 'Books|Arts & Entertainment|Art History',
5214             11236 => 'Books|Arts & Entertainment|Design',
5215             11243 => 'Books|Business & Personal Finance|Accounting',
5216             11244 => 'Books|Business & Personal Finance|Hospitality',
5217             11245 => 'Books|Business & Personal Finance|Real Estate',
5218             11246 => 'Books|Humor|Jokes & Riddles',
5219             11247 => 'Books|Religion & Spirituality|Comparative Religion',
5220             11255 => 'Books|Cookbooks, Food & Wine|Culinary Arts',
5221             11259 => 'Books|Mysteries & Thrillers|Cozy',
5222             11260 => 'Books|Politics & Current Events|Current Events',
5223             11261 => 'Books|Politics & Current Events|Foreign Policy & International Relations',
5224             11262 => 'Books|Politics & Current Events|Local Government',
5225             11263 => 'Books|Politics & Current Events|National Government',
5226             11264 => 'Books|Politics & Current Events|Political Science',
5227             11265 => 'Books|Politics & Current Events|Public Administration',
5228             11266 => 'Books|Politics & Current Events|World Affairs',
5229             11273 => 'Books|Nonfiction|Family & Relationships|Family & Childcare',
5230             11274 => 'Books|Nonfiction|Family & Relationships|Love & Romance',
5231             11275 => 'Books|Sci-Fi & Fantasy|Fantasy|Urban',
5232             11276 => 'Books|Reference|Foreign Languages|Arabic',
5233             11277 => 'Books|Reference|Foreign Languages|Bilingual Editions',
5234             11278 => 'Books|Reference|Foreign Languages|African Languages',
5235             11279 => 'Books|Reference|Foreign Languages|Ancient Languages',
5236             11280 => 'Books|Reference|Foreign Languages|Chinese',
5237             11281 => 'Books|Reference|Foreign Languages|English',
5238             11282 => 'Books|Reference|Foreign Languages|French',
5239             11283 => 'Books|Reference|Foreign Languages|German',
5240             11284 => 'Books|Reference|Foreign Languages|Hebrew',
5241             11285 => 'Books|Reference|Foreign Languages|Hindi',
5242             11286 => 'Books|Reference|Foreign Languages|Italian',
5243             11287 => 'Books|Reference|Foreign Languages|Japanese',
5244             11288 => 'Books|Reference|Foreign Languages|Korean',
5245             11289 => 'Books|Reference|Foreign Languages|Linguistics',
5246             11290 => 'Books|Reference|Foreign Languages|Other Languages',
5247             11291 => 'Books|Reference|Foreign Languages|Portuguese',
5248             11292 => 'Books|Reference|Foreign Languages|Russian',
5249             11293 => 'Books|Reference|Foreign Languages|Spanish',
5250             11294 => 'Books|Reference|Foreign Languages|Speech Pathology',
5251             11295 => 'Books|Science & Nature|Mathematics|Advanced Mathematics',
5252             11296 => 'Books|Science & Nature|Mathematics|Algebra',
5253             11297 => 'Books|Science & Nature|Mathematics|Arithmetic',
5254             11298 => 'Books|Science & Nature|Mathematics|Calculus',
5255             11299 => 'Books|Science & Nature|Mathematics|Geometry',
5256             11300 => 'Books|Science & Nature|Mathematics|Statistics',
5257             11301 => 'Books|Professional & Technical|Medical|Veterinary',
5258             11302 => 'Books|Professional & Technical|Medical|Neuroscience',
5259             11303 => 'Books|Professional & Technical|Medical|Immunology',
5260             11304 => 'Books|Professional & Technical|Medical|Nursing',
5261             11305 => 'Books|Professional & Technical|Medical|Pharmacology & Toxicology',
5262             11306 => 'Books|Professional & Technical|Medical|Anatomy & Physiology',
5263             11307 => 'Books|Professional & Technical|Medical|Dentistry',
5264             11308 => 'Books|Professional & Technical|Medical|Emergency Medicine',
5265             11309 => 'Books|Professional & Technical|Medical|Genetics',
5266             11310 => 'Books|Professional & Technical|Medical|Psychiatry',
5267             11311 => 'Books|Professional & Technical|Medical|Radiology',
5268             11312 => 'Books|Professional & Technical|Medical|Alternative Medicine',
5269             11317 => 'Books|Nonfiction|Philosophy|Political Philosophy',
5270             11319 => 'Books|Nonfiction|Philosophy|Philosophy of Language',
5271             11320 => 'Books|Nonfiction|Philosophy|Philosophy of Religion',
5272             11327 => 'Books|Nonfiction|Social Science|Sociology',
5273             11329 => 'Books|Professional & Technical|Engineering|Aeronautics',
5274             11330 => 'Books|Professional & Technical|Engineering|Chemical & Petroleum Engineering',
5275             11331 => 'Books|Professional & Technical|Engineering|Civil Engineering',
5276             11332 => 'Books|Professional & Technical|Engineering|Computer Science',
5277             11333 => 'Books|Professional & Technical|Engineering|Electrical Engineering',
5278             11334 => 'Books|Professional & Technical|Engineering|Environmental Engineering',
5279             11335 => 'Books|Professional & Technical|Engineering|Mechanical Engineering',
5280             11336 => 'Books|Professional & Technical|Engineering|Power Resources',
5281             11337 => 'Books|Comics & Graphic Novels|Manga|Boys',
5282             11338 => 'Books|Comics & Graphic Novels|Manga|Men',
5283             11339 => 'Books|Comics & Graphic Novels|Manga|Girls',
5284             11340 => 'Books|Comics & Graphic Novels|Manga|Women',
5285             11341 => 'Books|Comics & Graphic Novels|Manga|Other',
5286             11342 => 'Books|Comics & Graphic Novels|Manga|Yaoi',
5287             11343 => 'Books|Comics & Graphic Novels|Manga|Comic Essays',
5288             12001 => 'Mac App Store|Business',
5289             12002 => 'Mac App Store|Developer Tools',
5290             12003 => 'Mac App Store|Education',
5291             12004 => 'Mac App Store|Entertainment',
5292             12005 => 'Mac App Store|Finance',
5293             12006 => 'Mac App Store|Games',
5294             12007 => 'Mac App Store|Health & Fitness',
5295             12008 => 'Mac App Store|Lifestyle',
5296             12010 => 'Mac App Store|Medical',
5297             12011 => 'Mac App Store|Music',
5298             12012 => 'Mac App Store|News',
5299             12013 => 'Mac App Store|Photography',
5300             12014 => 'Mac App Store|Productivity',
5301             12015 => 'Mac App Store|Reference',
5302             12016 => 'Mac App Store|Social Networking',
5303             12017 => 'Mac App Store|Sports',
5304             12018 => 'Mac App Store|Travel',
5305             12019 => 'Mac App Store|Utilities',
5306             12020 => 'Mac App Store|Video',
5307             12021 => 'Mac App Store|Weather',
5308             12022 => 'Mac App Store|Graphics & Design',
5309             12201 => 'Mac App Store|Games|Action',
5310             12202 => 'Mac App Store|Games|Adventure',
5311             12203 => 'Mac App Store|Games|Casual',
5312             12204 => 'Mac App Store|Games|Board',
5313             12205 => 'Mac App Store|Games|Card',
5314             12206 => 'Mac App Store|Games|Casino',
5315             12207 => 'Mac App Store|Games|Dice',
5316             12208 => 'Mac App Store|Games|Educational',
5317             12209 => 'Mac App Store|Games|Family',
5318             12210 => 'Mac App Store|Games|Kids',
5319             12211 => 'Mac App Store|Games|Music',
5320             12212 => 'Mac App Store|Games|Puzzle',
5321             12213 => 'Mac App Store|Games|Racing',
5322             12214 => 'Mac App Store|Games|Role Playing',
5323             12215 => 'Mac App Store|Games|Simulation',
5324             12216 => 'Mac App Store|Games|Sports',
5325             12217 => 'Mac App Store|Games|Strategy',
5326             12218 => 'Mac App Store|Games|Trivia',
5327             12219 => 'Mac App Store|Games|Word',
5328             13001 => 'App Store|Magazines & Newspapers|News & Politics',
5329             13002 => 'App Store|Magazines & Newspapers|Fashion & Style',
5330             13003 => 'App Store|Magazines & Newspapers|Home & Garden',
5331             13004 => 'App Store|Magazines & Newspapers|Outdoors & Nature',
5332             13005 => 'App Store|Magazines & Newspapers|Sports & Leisure',
5333             13006 => 'App Store|Magazines & Newspapers|Automotive',
5334             13007 => 'App Store|Magazines & Newspapers|Arts & Photography',
5335             13008 => 'App Store|Magazines & Newspapers|Brides & Weddings',
5336             13009 => 'App Store|Magazines & Newspapers|Business & Investing',
5337             13010 => "App Store|Magazines & Newspapers|Children's Magazines",
5338             13011 => 'App Store|Magazines & Newspapers|Computers & Internet',
5339             13012 => 'App Store|Magazines & Newspapers|Cooking, Food & Drink',
5340             13013 => 'App Store|Magazines & Newspapers|Crafts & Hobbies',
5341             13014 => 'App Store|Magazines & Newspapers|Electronics & Audio',
5342             13015 => 'App Store|Magazines & Newspapers|Entertainment',
5343             13017 => 'App Store|Magazines & Newspapers|Health, Mind & Body',
5344             13018 => 'App Store|Magazines & Newspapers|History',
5345             13019 => 'App Store|Magazines & Newspapers|Literary Magazines & Journals',
5346             13020 => "App Store|Magazines & Newspapers|Men's Interest",
5347             13021 => 'App Store|Magazines & Newspapers|Movies & Music',
5348             13023 => 'App Store|Magazines & Newspapers|Parenting & Family',
5349             13024 => 'App Store|Magazines & Newspapers|Pets',
5350             13025 => 'App Store|Magazines & Newspapers|Professional & Trade',
5351             13026 => 'App Store|Magazines & Newspapers|Regional News',
5352             13027 => 'App Store|Magazines & Newspapers|Science',
5353             13028 => 'App Store|Magazines & Newspapers|Teens',
5354             13029 => 'App Store|Magazines & Newspapers|Travel & Regional',
5355             13030 => "App Store|Magazines & Newspapers|Women's Interest",
5356             15000 => 'Textbooks|Arts & Entertainment',
5357             15001 => 'Textbooks|Arts & Entertainment|Art & Architecture',
5358             15002 => 'Textbooks|Arts & Entertainment|Art & Architecture|Urban Planning',
5359             15003 => 'Textbooks|Arts & Entertainment|Art History',
5360             15004 => 'Textbooks|Arts & Entertainment|Dance',
5361             15005 => 'Textbooks|Arts & Entertainment|Design',
5362             15006 => 'Textbooks|Arts & Entertainment|Fashion',
5363             15007 => 'Textbooks|Arts & Entertainment|Film',
5364             15008 => 'Textbooks|Arts & Entertainment|Games',
5365             15009 => 'Textbooks|Arts & Entertainment|Interior Design',
5366             15010 => 'Textbooks|Arts & Entertainment|Media Arts',
5367             15011 => 'Textbooks|Arts & Entertainment|Music',
5368             15012 => 'Textbooks|Arts & Entertainment|Performing Arts',
5369             15013 => 'Textbooks|Arts & Entertainment|Photography',
5370             15014 => 'Textbooks|Arts & Entertainment|Theater',
5371             15015 => 'Textbooks|Arts & Entertainment|TV',
5372             15016 => 'Textbooks|Arts & Entertainment|Visual Arts',
5373             15017 => 'Textbooks|Biographies & Memoirs',
5374             15018 => 'Textbooks|Business & Personal Finance',
5375             15019 => 'Textbooks|Business & Personal Finance|Accounting',
5376             15020 => 'Textbooks|Business & Personal Finance|Careers',
5377             15021 => 'Textbooks|Business & Personal Finance|Economics',
5378             15022 => 'Textbooks|Business & Personal Finance|Finance',
5379             15023 => 'Textbooks|Business & Personal Finance|Hospitality',
5380             15024 => 'Textbooks|Business & Personal Finance|Industries & Professions',
5381             15025 => 'Textbooks|Business & Personal Finance|Investing',
5382             15026 => 'Textbooks|Business & Personal Finance|Management & Leadership',
5383             15027 => 'Textbooks|Business & Personal Finance|Marketing & Sales',
5384             15028 => 'Textbooks|Business & Personal Finance|Personal Finance',
5385             15029 => 'Textbooks|Business & Personal Finance|Real Estate',
5386             15030 => 'Textbooks|Business & Personal Finance|Reference',
5387             15031 => 'Textbooks|Business & Personal Finance|Small Business & Entrepreneurship',
5388             15032 => 'Textbooks|Children & Teens',
5389             15033 => 'Textbooks|Children & Teens|Fiction',
5390             15034 => 'Textbooks|Children & Teens|Nonfiction',
5391             15035 => 'Textbooks|Comics & Graphic Novels',
5392             15036 => 'Textbooks|Comics & Graphic Novels|Graphic Novels',
5393             15037 => 'Textbooks|Comics & Graphic Novels|Manga',
5394             15038 => 'Textbooks|Communications & Media',
5395             15039 => 'Textbooks|Communications & Media|Broadcasting',
5396             15040 => 'Textbooks|Communications & Media|Digital Media',
5397             15041 => 'Textbooks|Communications & Media|Journalism',
5398             15042 => 'Textbooks|Communications & Media|Photojournalism',
5399             15043 => 'Textbooks|Communications & Media|Print',
5400             15044 => 'Textbooks|Communications & Media|Speech',
5401             15045 => 'Textbooks|Communications & Media|Writing',
5402             15046 => 'Textbooks|Computers & Internet',
5403             15047 => 'Textbooks|Computers & Internet|Computers',
5404             15048 => 'Textbooks|Computers & Internet|Databases',
5405             15049 => 'Textbooks|Computers & Internet|Digital Media',
5406             15050 => 'Textbooks|Computers & Internet|Internet',
5407             15051 => 'Textbooks|Computers & Internet|Network',
5408             15052 => 'Textbooks|Computers & Internet|Operating Systems',
5409             15053 => 'Textbooks|Computers & Internet|Programming',
5410             15054 => 'Textbooks|Computers & Internet|Software',
5411             15055 => 'Textbooks|Computers & Internet|System Administration',
5412             15056 => 'Textbooks|Cookbooks, Food & Wine',
5413             15057 => 'Textbooks|Cookbooks, Food & Wine|Beverages',
5414             15058 => 'Textbooks|Cookbooks, Food & Wine|Courses & Dishes',
5415             15059 => 'Textbooks|Cookbooks, Food & Wine|Culinary Arts',
5416             15060 => 'Textbooks|Cookbooks, Food & Wine|Methods',
5417             15061 => 'Textbooks|Cookbooks, Food & Wine|Reference',
5418             15062 => 'Textbooks|Cookbooks, Food & Wine|Regional & Ethnic',
5419             15063 => 'Textbooks|Cookbooks, Food & Wine|Special Diet',
5420             15064 => 'Textbooks|Cookbooks, Food & Wine|Special Occasions',
5421             15065 => 'Textbooks|Cookbooks, Food & Wine|Specific Ingredients',
5422             15066 => 'Textbooks|Engineering',
5423             15067 => 'Textbooks|Engineering|Aeronautics',
5424             15068 => 'Textbooks|Engineering|Chemical & Petroleum Engineering',
5425             15069 => 'Textbooks|Engineering|Civil Engineering',
5426             15070 => 'Textbooks|Engineering|Computer Science',
5427             15071 => 'Textbooks|Engineering|Electrical Engineering',
5428             15072 => 'Textbooks|Engineering|Environmental Engineering',
5429             15073 => 'Textbooks|Engineering|Mechanical Engineering',
5430             15074 => 'Textbooks|Engineering|Power Resources',
5431             15075 => 'Textbooks|Fiction & Literature',
5432             15076 => 'Textbooks|Fiction & Literature|Latino',
5433             15077 => 'Textbooks|Fiction & Literature|Action & Adventure',
5434             15078 => 'Textbooks|Fiction & Literature|African American',
5435             15079 => 'Textbooks|Fiction & Literature|Anthologies',
5436             15080 => 'Textbooks|Fiction & Literature|Classics',
5437             15081 => 'Textbooks|Fiction & Literature|Comparative Literature',
5438             15082 => 'Textbooks|Fiction & Literature|Erotica',
5439             15083 => 'Textbooks|Fiction & Literature|Gay',
5440             15084 => 'Textbooks|Fiction & Literature|Ghost',
5441             15085 => 'Textbooks|Fiction & Literature|Historical',
5442             15086 => 'Textbooks|Fiction & Literature|Horror',
5443             15087 => 'Textbooks|Fiction & Literature|Literary',
5444             15088 => 'Textbooks|Fiction & Literature|Literary Criticism',
5445             15089 => 'Textbooks|Fiction & Literature|Poetry',
5446             15090 => 'Textbooks|Fiction & Literature|Religious',
5447             15091 => 'Textbooks|Fiction & Literature|Short Stories',
5448             15092 => 'Textbooks|Health, Mind & Body',
5449             15093 => 'Textbooks|Health, Mind & Body|Fitness',
5450             15094 => 'Textbooks|Health, Mind & Body|Self-Improvement',
5451             15095 => 'Textbooks|History',
5452             15096 => 'Textbooks|History|Africa',
5453             15097 => 'Textbooks|History|Americas',
5454             15098 => 'Textbooks|History|Americas|Canada',
5455             15099 => 'Textbooks|History|Americas|Latin America',
5456             15100 => 'Textbooks|History|Americas|United States',
5457             15101 => 'Textbooks|History|Ancient',
5458             15102 => 'Textbooks|History|Asia',
5459             15103 => 'Textbooks|History|Australia & Oceania',
5460             15104 => 'Textbooks|History|Europe',
5461             15105 => 'Textbooks|History|Middle East',
5462             15106 => 'Textbooks|History|Military',
5463             15107 => 'Textbooks|History|World',
5464             15108 => 'Textbooks|Humor',
5465             15109 => 'Textbooks|Language Studies',
5466             15110 => 'Textbooks|Language Studies|African Languages',
5467             15111 => 'Textbooks|Language Studies|Ancient Languages',
5468             15112 => 'Textbooks|Language Studies|Arabic',
5469             15113 => 'Textbooks|Language Studies|Bilingual Editions',
5470             15114 => 'Textbooks|Language Studies|Chinese',
5471             15115 => 'Textbooks|Language Studies|English',
5472             15116 => 'Textbooks|Language Studies|French',
5473             15117 => 'Textbooks|Language Studies|German',
5474             15118 => 'Textbooks|Language Studies|Hebrew',
5475             15119 => 'Textbooks|Language Studies|Hindi',
5476             15120 => 'Textbooks|Language Studies|Indigenous Languages',
5477             15121 => 'Textbooks|Language Studies|Italian',
5478             15122 => 'Textbooks|Language Studies|Japanese',
5479             15123 => 'Textbooks|Language Studies|Korean',
5480             15124 => 'Textbooks|Language Studies|Linguistics',
5481             15125 => 'Textbooks|Language Studies|Other Language',
5482             15126 => 'Textbooks|Language Studies|Portuguese',
5483             15127 => 'Textbooks|Language Studies|Russian',
5484             15128 => 'Textbooks|Language Studies|Spanish',
5485             15129 => 'Textbooks|Language Studies|Speech Pathology',
5486             15130 => 'Textbooks|Lifestyle & Home',
5487             15131 => 'Textbooks|Lifestyle & Home|Antiques & Collectibles',
5488             15132 => 'Textbooks|Lifestyle & Home|Crafts & Hobbies',
5489             15133 => 'Textbooks|Lifestyle & Home|Gardening',
5490             15134 => 'Textbooks|Lifestyle & Home|Pets',
5491             15135 => 'Textbooks|Mathematics',
5492             15136 => 'Textbooks|Mathematics|Advanced Mathematics',
5493             15137 => 'Textbooks|Mathematics|Algebra',
5494             15138 => 'Textbooks|Mathematics|Arithmetic',
5495             15139 => 'Textbooks|Mathematics|Calculus',
5496             15140 => 'Textbooks|Mathematics|Geometry',
5497             15141 => 'Textbooks|Mathematics|Statistics',
5498             15142 => 'Textbooks|Medicine',
5499             15143 => 'Textbooks|Medicine|Anatomy & Physiology',
5500             15144 => 'Textbooks|Medicine|Dentistry',
5501             15145 => 'Textbooks|Medicine|Emergency Medicine',
5502             15146 => 'Textbooks|Medicine|Genetics',
5503             15147 => 'Textbooks|Medicine|Immunology',
5504             15148 => 'Textbooks|Medicine|Neuroscience',
5505             15149 => 'Textbooks|Medicine|Nursing',
5506             15150 => 'Textbooks|Medicine|Pharmacology & Toxicology',
5507             15151 => 'Textbooks|Medicine|Psychiatry',
5508             15152 => 'Textbooks|Medicine|Psychology',
5509             15153 => 'Textbooks|Medicine|Radiology',
5510             15154 => 'Textbooks|Medicine|Veterinary',
5511             15155 => 'Textbooks|Mysteries & Thrillers',
5512             15156 => 'Textbooks|Mysteries & Thrillers|British Detectives',
5513             15157 => 'Textbooks|Mysteries & Thrillers|Hard-Boiled',
5514             15158 => 'Textbooks|Mysteries & Thrillers|Historical',
5515             15159 => 'Textbooks|Mysteries & Thrillers|Police Procedural',
5516             15160 => 'Textbooks|Mysteries & Thrillers|Short Stories',
5517             15161 => 'Textbooks|Mysteries & Thrillers|Women Sleuths',
5518             15162 => 'Textbooks|Nonfiction',
5519             15163 => 'Textbooks|Nonfiction|Family & Relationships',
5520             15164 => 'Textbooks|Nonfiction|Transportation',
5521             15165 => 'Textbooks|Nonfiction|True Crime',
5522             15166 => 'Textbooks|Parenting',
5523             15167 => 'Textbooks|Philosophy',
5524             15168 => 'Textbooks|Philosophy|Aesthetics',
5525             15169 => 'Textbooks|Philosophy|Epistemology',
5526             15170 => 'Textbooks|Philosophy|Ethics',
5527             15171 => 'Textbooks|Philosophy|Philosophy of Language',
5528             15172 => 'Textbooks|Philosophy|Logic',
5529             15173 => 'Textbooks|Philosophy|Metaphysics',
5530             15174 => 'Textbooks|Philosophy|Political Philosophy',
5531             15175 => 'Textbooks|Philosophy|Philosophy of Religion',
5532             15176 => 'Textbooks|Politics & Current Events',
5533             15177 => 'Textbooks|Politics & Current Events|Current Events',
5534             15178 => 'Textbooks|Politics & Current Events|Foreign Policy & International Relations',
5535             15179 => 'Textbooks|Politics & Current Events|Local Governments',
5536             15180 => 'Textbooks|Politics & Current Events|National Governments',
5537             15181 => 'Textbooks|Politics & Current Events|Political Science',
5538             15182 => 'Textbooks|Politics & Current Events|Public Administration',
5539             15183 => 'Textbooks|Politics & Current Events|World Affairs',
5540             15184 => 'Textbooks|Professional & Technical',
5541             15185 => 'Textbooks|Professional & Technical|Design',
5542             15186 => 'Textbooks|Professional & Technical|Language Arts & Disciplines',
5543             15187 => 'Textbooks|Professional & Technical|Engineering',
5544             15188 => 'Textbooks|Professional & Technical|Law',
5545             15189 => 'Textbooks|Professional & Technical|Medical',
5546             15190 => 'Textbooks|Reference',
5547             15191 => 'Textbooks|Reference|Almanacs & Yearbooks',
5548             15192 => 'Textbooks|Reference|Atlases & Maps',
5549             15193 => 'Textbooks|Reference|Catalogs & Directories',
5550             15194 => 'Textbooks|Reference|Consumer Guides',
5551             15195 => 'Textbooks|Reference|Dictionaries & Thesauruses',
5552             15196 => 'Textbooks|Reference|Encyclopedias',
5553             15197 => 'Textbooks|Reference|Etiquette',
5554             15198 => 'Textbooks|Reference|Quotations',
5555             15199 => 'Textbooks|Reference|Study Aids',
5556             15200 => 'Textbooks|Reference|Words & Language',
5557             15201 => 'Textbooks|Reference|Writing',
5558             15202 => 'Textbooks|Religion & Spirituality',
5559             15203 => 'Textbooks|Religion & Spirituality|Bible Studies',
5560             15204 => 'Textbooks|Religion & Spirituality|Bibles',
5561             15205 => 'Textbooks|Religion & Spirituality|Buddhism',
5562             15206 => 'Textbooks|Religion & Spirituality|Christianity',
5563             15207 => 'Textbooks|Religion & Spirituality|Comparative Religion',
5564             15208 => 'Textbooks|Religion & Spirituality|Hinduism',
5565             15209 => 'Textbooks|Religion & Spirituality|Islam',
5566             15210 => 'Textbooks|Religion & Spirituality|Judaism',
5567             15211 => 'Textbooks|Religion & Spirituality|Spirituality',
5568             15212 => 'Textbooks|Romance',
5569             15213 => 'Textbooks|Romance|Contemporary',
5570             15214 => 'Textbooks|Romance|Erotic Romance',
5571             15215 => 'Textbooks|Romance|Paranormal',
5572             15216 => 'Textbooks|Romance|Historical',
5573             15217 => 'Textbooks|Romance|Short Stories',
5574             15218 => 'Textbooks|Romance|Suspense',
5575             15219 => 'Textbooks|Romance|Western',
5576             15220 => 'Textbooks|Sci-Fi & Fantasy',
5577             15221 => 'Textbooks|Sci-Fi & Fantasy|Fantasy',
5578             15222 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Contemporary',
5579             15223 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Epic',
5580             15224 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Historical',
5581             15225 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Paranormal',
5582             15226 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Short Stories',
5583             15227 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction',
5584             15228 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature',
5585             15229 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|Adventure',
5586             15230 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|High Tech',
5587             15231 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|Short Stories',
5588             15232 => 'Textbooks|Science & Nature',
5589             15233 => 'Textbooks|Science & Nature|Agriculture',
5590             15234 => 'Textbooks|Science & Nature|Astronomy',
5591             15235 => 'Textbooks|Science & Nature|Atmosphere',
5592             15236 => 'Textbooks|Science & Nature|Biology',
5593             15237 => 'Textbooks|Science & Nature|Chemistry',
5594             15238 => 'Textbooks|Science & Nature|Earth Sciences',
5595             15239 => 'Textbooks|Science & Nature|Ecology',
5596             15240 => 'Textbooks|Science & Nature|Environment',
5597             15241 => 'Textbooks|Science & Nature|Essays',
5598             15242 => 'Textbooks|Science & Nature|Geography',
5599             15243 => 'Textbooks|Science & Nature|Geology',
5600             15244 => 'Textbooks|Science & Nature|History',
5601             15245 => 'Textbooks|Science & Nature|Life Sciences',
5602             15246 => 'Textbooks|Science & Nature|Nature',
5603             15247 => 'Textbooks|Science & Nature|Physics',
5604             15248 => 'Textbooks|Science & Nature|Reference',
5605             15249 => 'Textbooks|Social Science',
5606             15250 => 'Textbooks|Social Science|Anthropology',
5607             15251 => 'Textbooks|Social Science|Archaeology',
5608             15252 => 'Textbooks|Social Science|Civics',
5609             15253 => 'Textbooks|Social Science|Government',
5610             15254 => 'Textbooks|Social Science|Social Studies',
5611             15255 => 'Textbooks|Social Science|Social Welfare',
5612             15256 => 'Textbooks|Social Science|Society',
5613             15257 => 'Textbooks|Social Science|Society|African Studies',
5614             15258 => 'Textbooks|Social Science|Society|American Studies',
5615             15259 => 'Textbooks|Social Science|Society|Asia Pacific Studies',
5616             15260 => 'Textbooks|Social Science|Society|Cross-Cultural Studies',
5617             15261 => 'Textbooks|Social Science|Society|European Studies',
5618             15262 => 'Textbooks|Social Science|Society|Immigration & Emigration',
5619             15263 => 'Textbooks|Social Science|Society|Indigenous Studies',
5620             15264 => 'Textbooks|Social Science|Society|Latin & Caribbean Studies',
5621             15265 => 'Textbooks|Social Science|Society|Middle Eastern Studies',
5622             15266 => 'Textbooks|Social Science|Society|Race & Ethnicity Studies',
5623             15267 => 'Textbooks|Social Science|Society|Sexuality Studies',
5624             15268 => "Textbooks|Social Science|Society|Women's Studies",
5625             15269 => 'Textbooks|Social Science|Sociology',
5626             15270 => 'Textbooks|Sports & Outdoors',
5627             15271 => 'Textbooks|Sports & Outdoors|Baseball',
5628             15272 => 'Textbooks|Sports & Outdoors|Basketball',
5629             15273 => 'Textbooks|Sports & Outdoors|Coaching',
5630             15274 => 'Textbooks|Sports & Outdoors|Equestrian',
5631             15275 => 'Textbooks|Sports & Outdoors|Extreme Sports',
5632             15276 => 'Textbooks|Sports & Outdoors|Football',
5633             15277 => 'Textbooks|Sports & Outdoors|Golf',
5634             15278 => 'Textbooks|Sports & Outdoors|Hockey',
5635             15279 => 'Textbooks|Sports & Outdoors|Motor Sports',
5636             15280 => 'Textbooks|Sports & Outdoors|Mountaineering',
5637             15281 => 'Textbooks|Sports & Outdoors|Outdoors',
5638             15282 => 'Textbooks|Sports & Outdoors|Racket Sports',
5639             15283 => 'Textbooks|Sports & Outdoors|Reference',
5640             15284 => 'Textbooks|Sports & Outdoors|Soccer',
5641             15285 => 'Textbooks|Sports & Outdoors|Training',
5642             15286 => 'Textbooks|Sports & Outdoors|Water Sports',
5643             15287 => 'Textbooks|Sports & Outdoors|Winter Sports',
5644             15288 => 'Textbooks|Teaching & Learning',
5645             15289 => 'Textbooks|Teaching & Learning|Adult Education',
5646             15290 => 'Textbooks|Teaching & Learning|Curriculum & Teaching',
5647             15291 => 'Textbooks|Teaching & Learning|Educational Leadership',
5648             15292 => 'Textbooks|Teaching & Learning|Educational Technology',
5649             15293 => 'Textbooks|Teaching & Learning|Family & Childcare',
5650             15294 => 'Textbooks|Teaching & Learning|Information & Library Science',
5651             15295 => 'Textbooks|Teaching & Learning|Learning Resources',
5652             15296 => 'Textbooks|Teaching & Learning|Psychology & Research',
5653             15297 => 'Textbooks|Teaching & Learning|Special Education',
5654             15298 => 'Textbooks|Travel & Adventure',
5655             15299 => 'Textbooks|Travel & Adventure|Africa',
5656             15300 => 'Textbooks|Travel & Adventure|Americas',
5657             15301 => 'Textbooks|Travel & Adventure|Americas|Canada',
5658             15302 => 'Textbooks|Travel & Adventure|Americas|Latin America',
5659             15303 => 'Textbooks|Travel & Adventure|Americas|United States',
5660             15304 => 'Textbooks|Travel & Adventure|Asia',
5661             15305 => 'Textbooks|Travel & Adventure|Caribbean',
5662             15306 => 'Textbooks|Travel & Adventure|Essays & Memoirs',
5663             15307 => 'Textbooks|Travel & Adventure|Europe',
5664             15308 => 'Textbooks|Travel & Adventure|Middle East',
5665             15309 => 'Textbooks|Travel & Adventure|Oceania',
5666             15310 => 'Textbooks|Travel & Adventure|Specialty Travel',
5667             15311 => 'Textbooks|Comics & Graphic Novels|Comics',
5668             15312 => 'Textbooks|Reference|Manuals',
5669             16001 => 'App Store|Stickers|Emoji & Expressions',
5670             16003 => 'App Store|Stickers|Animals & Nature',
5671             16005 => 'App Store|Stickers|Art',
5672             16006 => 'App Store|Stickers|Celebrations',
5673             16007 => 'App Store|Stickers|Celebrities',
5674             16008 => 'App Store|Stickers|Comics & Cartoons',
5675             16009 => 'App Store|Stickers|Eating & Drinking',
5676             16010 => 'App Store|Stickers|Gaming',
5677             16014 => 'App Store|Stickers|Movies & TV',
5678             16015 => 'App Store|Stickers|Music',
5679             16017 => 'App Store|Stickers|People',
5680             16019 => 'App Store|Stickers|Places & Objects',
5681             16021 => 'App Store|Stickers|Sports & Activities',
5682             16025 => 'App Store|Stickers|Kids & Family',
5683             16026 => 'App Store|Stickers|Fashion',
5684             100000 => 'Music|Christian & Gospel',
5685             100001 => 'Music|Classical|Art Song',
5686             100002 => 'Music|Classical|Brass & Woodwinds',
5687             100003 => 'Music|Classical|Solo Instrumental',
5688             100004 => 'Music|Classical|Contemporary Era',
5689             100005 => 'Music|Classical|Oratorio',
5690             100006 => 'Music|Classical|Cantata',
5691             100007 => 'Music|Classical|Electronic',
5692             100008 => 'Music|Classical|Sacred',
5693             100009 => 'Music|Classical|Guitar',
5694             100010 => 'Music|Classical|Piano',
5695             100011 => 'Music|Classical|Violin',
5696             100012 => 'Music|Classical|Cello',
5697             100013 => 'Music|Classical|Percussion',
5698             100014 => 'Music|Electronic|Dubstep',
5699             100015 => 'Music|Electronic|Bass',
5700             100016 => 'Music|Hip-Hop/Rap|UK Hip-Hop',
5701             100017 => 'Music|Reggae|Lovers Rock',
5702             100018 => 'Music|Alternative|EMO',
5703             100019 => 'Music|Alternative|Pop Punk',
5704             100020 => 'Music|Alternative|Indie Pop',
5705             100021 => 'Music|New Age|Yoga',
5706             100022 => 'Music|Pop|Tribute',
5707             100023 => 'Music|Pop|Shows',
5708             100024 => 'Music|Cuban',
5709             100025 => 'Music|Cuban|Mambo',
5710             100026 => 'Music|Cuban|Chachacha',
5711             100027 => 'Music|Cuban|Guajira',
5712             100028 => 'Music|Cuban|Son',
5713             100029 => 'Music|Cuban|Bolero',
5714             100030 => 'Music|Cuban|Guaracha',
5715             100031 => 'Music|Cuban|Timba',
5716             100032 => 'Music|Soundtrack|Video Game',
5717             100033 => 'Music|Indian|Regional Indian|Punjabi|Punjabi Pop',
5718             100034 => 'Music|Indian|Regional Indian|Bengali|Rabindra Sangeet',
5719             100035 => 'Music|Indian|Regional Indian|Malayalam',
5720             100036 => 'Music|Indian|Regional Indian|Kannada',
5721             100037 => 'Music|Indian|Regional Indian|Marathi',
5722             100038 => 'Music|Indian|Regional Indian|Gujarati',
5723             100039 => 'Music|Indian|Regional Indian|Assamese',
5724             100040 => 'Music|Indian|Regional Indian|Bhojpuri',
5725             100041 => 'Music|Indian|Regional Indian|Haryanvi',
5726             100042 => 'Music|Indian|Regional Indian|Odia',
5727             100043 => 'Music|Indian|Regional Indian|Rajasthani',
5728             100044 => 'Music|Indian|Regional Indian|Urdu',
5729             100045 => 'Music|Indian|Regional Indian|Punjabi',
5730             100046 => 'Music|Indian|Regional Indian|Bengali',
5731             100047 => 'Music|Indian|Indian Classical|Carnatic Classical',
5732             100048 => 'Music|Indian|Indian Classical|Hindustani Classical',
5733             100049 => 'Music|African|Afro House',
5734             100050 => 'Music|African|Afro Soul',
5735             100051 => 'Music|African|Afrobeats',
5736             100052 => 'Music|African|Benga',
5737             100053 => 'Music|African|Bongo-Flava',
5738             100054 => 'Music|African|Coupe-Decale',
5739             100055 => 'Music|African|Gqom',
5740             100056 => 'Music|African|Highlife',
5741             100057 => 'Music|African|Kuduro',
5742             100058 => 'Music|African|Kizomba',
5743             100059 => 'Music|African|Kwaito',
5744             100060 => 'Music|African|Mbalax',
5745             100061 => 'Music|African|Ndombolo',
5746             100062 => 'Music|African|Shangaan Electro',
5747             100063 => 'Music|African|Soukous',
5748             100064 => 'Music|African|Taarab',
5749             100065 => 'Music|African|Zouglou',
5750             100066 => 'Music|Turkish|Ozgun',
5751             100067 => 'Music|Turkish|Fantezi',
5752             100068 => 'Music|Turkish|Religious',
5753             100069 => 'Music|Pop|Turkish Pop',
5754             100070 => 'Music|Rock|Turkish Rock',
5755             100071 => 'Music|Alternative|Turkish Alternative',
5756             100072 => 'Music|Hip-Hop/Rap|Turkish Hip-Hop/Rap',
5757             100073 => 'Music|African|Maskandi',
5758             100074 => 'Music|Russian|Russian Romance',
5759             100075 => 'Music|Russian|Russian Bard',
5760             100076 => 'Music|Russian|Russian Pop',
5761             100077 => 'Music|Russian|Russian Rock',
5762             100078 => 'Music|Russian|Russian Hip-Hop',
5763             100079 => 'Music|Arabic|Levant',
5764             100080 => 'Music|Arabic|Levant|Dabke',
5765             100081 => 'Music|Arabic|Maghreb Rai',
5766             100082 => 'Music|Arabic|Khaleeji|Khaleeji Jalsat',
5767             100083 => 'Music|Arabic|Khaleeji|Khaleeji Shailat',
5768             100084 => 'Music|Tarab',
5769             100085 => 'Music|Tarab|Iraqi Tarab',
5770             100086 => 'Music|Tarab|Egyptian Tarab',
5771             100087 => 'Music|Tarab|Khaleeji Tarab',
5772             100088 => 'Music|Pop|Levant Pop',
5773             100089 => 'Music|Pop|Iraqi Pop',
5774             100090 => 'Music|Pop|Egyptian Pop',
5775             100091 => 'Music|Pop|Maghreb Pop',
5776             100092 => 'Music|Pop|Khaleeji Pop',
5777             100093 => 'Music|Hip-Hop/Rap|Levant Hip-Hop',
5778             100094 => 'Music|Hip-Hop/Rap|Egyptian Hip-Hop',
5779             100095 => 'Music|Hip-Hop/Rap|Maghreb Hip-Hop',
5780             100096 => 'Music|Hip-Hop/Rap|Khaleeji Hip-Hop',
5781             100097 => 'Music|Alternative|Indie Levant',
5782             100098 => 'Music|Alternative|Indie Egyptian',
5783             100099 => 'Music|Alternative|Indie Maghreb',
5784             100100 => 'Music|Electronic|Levant Electronic',
5785             100101 => "Music|Electronic|Electro-Cha'abi",
5786             100102 => 'Music|Electronic|Maghreb Electronic',
5787             100103 => 'Music|Folk|Iraqi Folk',
5788             100104 => 'Music|Folk|Khaleeji Folk',
5789             100105 => 'Music|Dance|Maghreb Dance',
5790             40000000 => 'iTunes U',
5791             40000001 => 'iTunes U|Business & Economics',
5792             40000002 => 'iTunes U|Business & Economics|Economics',
5793             40000003 => 'iTunes U|Business & Economics|Finance',
5794             40000004 => 'iTunes U|Business & Economics|Hospitality',
5795             40000005 => 'iTunes U|Business & Economics|Management',
5796             40000006 => 'iTunes U|Business & Economics|Marketing',
5797             40000007 => 'iTunes U|Business & Economics|Personal Finance',
5798             40000008 => 'iTunes U|Business & Economics|Real Estate',
5799             40000009 => 'iTunes U|Engineering',
5800             40000010 => 'iTunes U|Engineering|Chemical & Petroleum Engineering',
5801             40000011 => 'iTunes U|Engineering|Civil Engineering',
5802             40000012 => 'iTunes U|Engineering|Computer Science',
5803             40000013 => 'iTunes U|Engineering|Electrical Engineering',
5804             40000014 => 'iTunes U|Engineering|Environmental Engineering',
5805             40000015 => 'iTunes U|Engineering|Mechanical Engineering',
5806             40000016 => 'iTunes U|Music, Art, & Design',
5807             40000017 => 'iTunes U|Music, Art, & Design|Architecture',
5808             40000019 => 'iTunes U|Music, Art, & Design|Art History',
5809             40000020 => 'iTunes U|Music, Art, & Design|Dance',
5810             40000021 => 'iTunes U|Music, Art, & Design|Film',
5811             40000022 => 'iTunes U|Music, Art, & Design|Design',
5812             40000023 => 'iTunes U|Music, Art, & Design|Interior Design',
5813             40000024 => 'iTunes U|Music, Art, & Design|Music',
5814             40000025 => 'iTunes U|Music, Art, & Design|Theater',
5815             40000026 => 'iTunes U|Health & Medicine',
5816             40000027 => 'iTunes U|Health & Medicine|Anatomy & Physiology',
5817             40000028 => 'iTunes U|Health & Medicine|Behavioral Science',
5818             40000029 => 'iTunes U|Health & Medicine|Dentistry',
5819             40000030 => 'iTunes U|Health & Medicine|Diet & Nutrition',
5820             40000031 => 'iTunes U|Health & Medicine|Emergency Medicine',
5821             40000032 => 'iTunes U|Health & Medicine|Genetics',
5822             40000033 => 'iTunes U|Health & Medicine|Gerontology',
5823             40000034 => 'iTunes U|Health & Medicine|Health & Exercise Science',
5824             40000035 => 'iTunes U|Health & Medicine|Immunology',
5825             40000036 => 'iTunes U|Health & Medicine|Neuroscience',
5826             40000037 => 'iTunes U|Health & Medicine|Pharmacology & Toxicology',
5827             40000038 => 'iTunes U|Health & Medicine|Psychiatry',
5828             40000039 => 'iTunes U|Health & Medicine|Global Health',
5829             40000040 => 'iTunes U|Health & Medicine|Radiology',
5830             40000041 => 'iTunes U|History',
5831             40000042 => 'iTunes U|History|Ancient History',
5832             40000043 => 'iTunes U|History|Medieval History',
5833             40000044 => 'iTunes U|History|Military History',
5834             40000045 => 'iTunes U|History|Modern History',
5835             40000046 => 'iTunes U|History|African History',
5836             40000047 => 'iTunes U|History|Asia-Pacific History',
5837             40000048 => 'iTunes U|History|European History',
5838             40000049 => 'iTunes U|History|Middle Eastern History',
5839             40000050 => 'iTunes U|History|North American History',
5840             40000051 => 'iTunes U|History|South American History',
5841             40000053 => 'iTunes U|Communications & Journalism',
5842             40000054 => 'iTunes U|Philosophy',
5843             40000055 => 'iTunes U|Religion & Spirituality',
5844             40000056 => 'iTunes U|Languages',
5845             40000057 => 'iTunes U|Languages|African Languages',
5846             40000058 => 'iTunes U|Languages|Ancient Languages',
5847             40000061 => 'iTunes U|Languages|English',
5848             40000063 => 'iTunes U|Languages|French',
5849             40000064 => 'iTunes U|Languages|German',
5850             40000065 => 'iTunes U|Languages|Italian',
5851             40000066 => 'iTunes U|Languages|Linguistics',
5852             40000068 => 'iTunes U|Languages|Spanish',
5853             40000069 => 'iTunes U|Languages|Speech Pathology',
5854             40000070 => 'iTunes U|Writing & Literature',
5855             40000071 => 'iTunes U|Writing & Literature|Anthologies',
5856             40000072 => 'iTunes U|Writing & Literature|Biography',
5857             40000073 => 'iTunes U|Writing & Literature|Classics',
5858             40000074 => 'iTunes U|Writing & Literature|Literary Criticism',
5859             40000075 => 'iTunes U|Writing & Literature|Fiction',
5860             40000076 => 'iTunes U|Writing & Literature|Poetry',
5861             40000077 => 'iTunes U|Mathematics',
5862             40000078 => 'iTunes U|Mathematics|Advanced Mathematics',
5863             40000079 => 'iTunes U|Mathematics|Algebra',
5864             40000080 => 'iTunes U|Mathematics|Arithmetic',
5865             40000081 => 'iTunes U|Mathematics|Calculus',
5866             40000082 => 'iTunes U|Mathematics|Geometry',
5867             40000083 => 'iTunes U|Mathematics|Statistics',
5868             40000084 => 'iTunes U|Science',
5869             40000085 => 'iTunes U|Science|Agricultural',
5870             40000086 => 'iTunes U|Science|Astronomy',
5871             40000087 => 'iTunes U|Science|Atmosphere',
5872             40000088 => 'iTunes U|Science|Biology',
5873             40000089 => 'iTunes U|Science|Chemistry',
5874             40000090 => 'iTunes U|Science|Ecology',
5875             40000091 => 'iTunes U|Science|Geography',
5876             40000092 => 'iTunes U|Science|Geology',
5877             40000093 => 'iTunes U|Science|Physics',
5878             40000094 => 'iTunes U|Social Science',
5879             40000095 => 'iTunes U|Law & Politics|Law',
5880             40000096 => 'iTunes U|Law & Politics|Political Science',
5881             40000097 => 'iTunes U|Law & Politics|Public Administration',
5882             40000098 => 'iTunes U|Social Science|Psychology',
5883             40000099 => 'iTunes U|Social Science|Social Welfare',
5884             40000100 => 'iTunes U|Social Science|Sociology',
5885             40000101 => 'iTunes U|Society',
5886             40000103 => 'iTunes U|Society|Asia Pacific Studies',
5887             40000104 => 'iTunes U|Society|European Studies',
5888             40000105 => 'iTunes U|Society|Indigenous Studies',
5889             40000106 => 'iTunes U|Society|Latin & Caribbean Studies',
5890             40000107 => 'iTunes U|Society|Middle Eastern Studies',
5891             40000108 => "iTunes U|Society|Women's Studies",
5892             40000109 => 'iTunes U|Teaching & Learning',
5893             40000110 => 'iTunes U|Teaching & Learning|Curriculum & Teaching',
5894             40000111 => 'iTunes U|Teaching & Learning|Educational Leadership',
5895             40000112 => 'iTunes U|Teaching & Learning|Family & Childcare',
5896             40000113 => 'iTunes U|Teaching & Learning|Learning Resources',
5897             40000114 => 'iTunes U|Teaching & Learning|Psychology & Research',
5898             40000115 => 'iTunes U|Teaching & Learning|Special Education',
5899             40000116 => 'iTunes U|Music, Art, & Design|Culinary Arts',
5900             40000117 => 'iTunes U|Music, Art, & Design|Fashion',
5901             40000118 => 'iTunes U|Music, Art, & Design|Media Arts',
5902             40000119 => 'iTunes U|Music, Art, & Design|Photography',
5903             40000120 => 'iTunes U|Music, Art, & Design|Visual Art',
5904             40000121 => 'iTunes U|Business & Economics|Entrepreneurship',
5905             40000122 => 'iTunes U|Communications & Journalism|Broadcasting',
5906             40000123 => 'iTunes U|Communications & Journalism|Digital Media',
5907             40000124 => 'iTunes U|Communications & Journalism|Journalism',
5908             40000125 => 'iTunes U|Communications & Journalism|Photojournalism',
5909             40000126 => 'iTunes U|Communications & Journalism|Print',
5910             40000127 => 'iTunes U|Communications & Journalism|Speech',
5911             40000128 => 'iTunes U|Communications & Journalism|Writing',
5912             40000129 => 'iTunes U|Health & Medicine|Nursing',
5913             40000130 => 'iTunes U|Languages|Arabic',
5914             40000131 => 'iTunes U|Languages|Chinese',
5915             40000132 => 'iTunes U|Languages|Hebrew',
5916             40000133 => 'iTunes U|Languages|Hindi',
5917             40000134 => 'iTunes U|Languages|Indigenous Languages',
5918             40000135 => 'iTunes U|Languages|Japanese',
5919             40000136 => 'iTunes U|Languages|Korean',
5920             40000137 => 'iTunes U|Languages|Other Languages',
5921             40000138 => 'iTunes U|Languages|Portuguese',
5922             40000139 => 'iTunes U|Languages|Russian',
5923             40000140 => 'iTunes U|Law & Politics',
5924             40000141 => 'iTunes U|Law & Politics|Foreign Policy & International Relations',
5925             40000142 => 'iTunes U|Law & Politics|Local Governments',
5926             40000143 => 'iTunes U|Law & Politics|National Governments',
5927             40000144 => 'iTunes U|Law & Politics|World Affairs',
5928             40000145 => 'iTunes U|Writing & Literature|Comparative Literature',
5929             40000146 => 'iTunes U|Philosophy|Aesthetics',
5930             40000147 => 'iTunes U|Philosophy|Epistemology',
5931             40000148 => 'iTunes U|Philosophy|Ethics',
5932             40000149 => 'iTunes U|Philosophy|Metaphysics',
5933             40000150 => 'iTunes U|Philosophy|Political Philosophy',
5934             40000151 => 'iTunes U|Philosophy|Logic',
5935             40000152 => 'iTunes U|Philosophy|Philosophy of Language',
5936             40000153 => 'iTunes U|Philosophy|Philosophy of Religion',
5937             40000154 => 'iTunes U|Social Science|Archaeology',
5938             40000155 => 'iTunes U|Social Science|Anthropology',
5939             40000156 => 'iTunes U|Religion & Spirituality|Buddhism',
5940             40000157 => 'iTunes U|Religion & Spirituality|Christianity',
5941             40000158 => 'iTunes U|Religion & Spirituality|Comparative Religion',
5942             40000159 => 'iTunes U|Religion & Spirituality|Hinduism',
5943             40000160 => 'iTunes U|Religion & Spirituality|Islam',
5944             40000161 => 'iTunes U|Religion & Spirituality|Judaism',
5945             40000162 => 'iTunes U|Religion & Spirituality|Other Religions',
5946             40000163 => 'iTunes U|Religion & Spirituality|Spirituality',
5947             40000164 => 'iTunes U|Science|Environment',
5948             40000165 => 'iTunes U|Society|African Studies',
5949             40000166 => 'iTunes U|Society|American Studies',
5950             40000167 => 'iTunes U|Society|Cross-cultural Studies',
5951             40000168 => 'iTunes U|Society|Immigration & Emigration',
5952             40000169 => 'iTunes U|Society|Race & Ethnicity Studies',
5953             40000170 => 'iTunes U|Society|Sexuality Studies',
5954             40000171 => 'iTunes U|Teaching & Learning|Educational Technology',
5955             40000172 => 'iTunes U|Teaching & Learning|Information/Library Science',
5956             40000173 => 'iTunes U|Languages|Dutch',
5957             40000174 => 'iTunes U|Languages|Luxembourgish',
5958             40000175 => 'iTunes U|Languages|Swedish',
5959             40000176 => 'iTunes U|Languages|Norwegian',
5960             40000177 => 'iTunes U|Languages|Finnish',
5961             40000178 => 'iTunes U|Languages|Danish',
5962             40000179 => 'iTunes U|Languages|Polish',
5963             40000180 => 'iTunes U|Languages|Turkish',
5964             40000181 => 'iTunes U|Languages|Flemish',
5965             50000024 => 'Audiobooks',
5966             50000040 => 'Audiobooks|Fiction',
5967             50000041 => 'Audiobooks|Arts & Entertainment',
5968             50000042 => 'Audiobooks|Biographies & Memoirs',
5969             50000043 => 'Audiobooks|Business & Personal Finance',
5970             50000044 => 'Audiobooks|Kids & Young Adults',
5971             50000045 => 'Audiobooks|Classics',
5972             50000046 => 'Audiobooks|Comedy',
5973             50000047 => 'Audiobooks|Drama & Poetry',
5974             50000048 => 'Audiobooks|Speakers & Storytellers',
5975             50000049 => 'Audiobooks|History',
5976             50000050 => 'Audiobooks|Languages',
5977             50000051 => 'Audiobooks|Mysteries & Thrillers',
5978             50000052 => 'Audiobooks|Nonfiction',
5979             50000053 => 'Audiobooks|Religion & Spirituality',
5980             50000054 => 'Audiobooks|Science & Nature',
5981             50000055 => 'Audiobooks|Sci Fi & Fantasy',
5982             50000056 => 'Audiobooks|Self-Development',
5983             50000057 => 'Audiobooks|Sports & Outdoors',
5984             50000058 => 'Audiobooks|Technology',
5985             50000059 => 'Audiobooks|Travel & Adventure',
5986             50000061 => 'Music|Spoken Word',
5987             50000063 => 'Music|Disney',
5988             50000064 => 'Music|French Pop',
5989             50000066 => 'Music|German Pop',
5990             50000068 => 'Music|German Folk',
5991             50000069 => 'Audiobooks|Romance',
5992             50000070 => 'Audiobooks|Audiobooks Latino',
5993             50000071 => 'Books|Comics & Graphic Novels|Manga|Action',
5994             50000072 => 'Books|Comics & Graphic Novels|Manga|Comedy',
5995             50000073 => 'Books|Comics & Graphic Novels|Manga|Erotica',
5996             50000074 => 'Books|Comics & Graphic Novels|Manga|Fantasy',
5997             50000075 => 'Books|Comics & Graphic Novels|Manga|Four Cell Manga',
5998             50000076 => 'Books|Comics & Graphic Novels|Manga|Gay & Lesbian',
5999             50000077 => 'Books|Comics & Graphic Novels|Manga|Hard-Boiled',
6000             50000078 => 'Books|Comics & Graphic Novels|Manga|Heroes',
6001             50000079 => 'Books|Comics & Graphic Novels|Manga|Historical Fiction',
6002             50000080 => 'Books|Comics & Graphic Novels|Manga|Mecha',
6003             50000081 => 'Books|Comics & Graphic Novels|Manga|Mystery',
6004             50000082 => 'Books|Comics & Graphic Novels|Manga|Nonfiction',
6005             50000083 => 'Books|Comics & Graphic Novels|Manga|Religious',
6006             50000084 => 'Books|Comics & Graphic Novels|Manga|Romance',
6007             50000085 => 'Books|Comics & Graphic Novels|Manga|Romantic Comedy',
6008             50000086 => 'Books|Comics & Graphic Novels|Manga|Science Fiction',
6009             50000087 => 'Books|Comics & Graphic Novels|Manga|Sports',
6010             50000088 => 'Books|Fiction & Literature|Light Novels',
6011             50000089 => 'Books|Comics & Graphic Novels|Manga|Horror',
6012             50000090 => 'Books|Comics & Graphic Novels|Comics',
6013             50000091 => 'Books|Romance|Multicultural',
6014             50000092 => 'Audiobooks|Erotica',
6015             50000093 => 'Audiobooks|Light Novels',
6016             },
6017             },
6018             grup => { Name => 'Grouping', Avoid => 1 }, #10
6019             hdvd => { #10
6020             Name => 'HDVideo',
6021             Format => 'int8u', #24
6022             Writable => 'int8s', #27
6023             PrintConv => { 0 => 'No', 1 => 'Yes' },
6024             },
6025             keyw => 'Keyword', #7
6026             ldes => 'LongDescription', #10
6027             pcst => { #7
6028             Name => 'Podcast',
6029             Format => 'int8u', #23
6030             Writable => 'int8s', #27
6031             PrintConv => { 0 => 'No', 1 => 'Yes' },
6032             },
6033             perf => 'Performer',
6034             plID => { #10 (or TV season)
6035             Name => 'PlayListID',
6036             Format => 'int8u', # actually int64u, but split it up
6037             Writable => 'int32s', #27
6038             },
6039             purd => 'PurchaseDate', #7
6040             purl => 'PodcastURL', #7
6041             rtng => { #10
6042             Name => 'Rating',
6043             Format => 'int8u', #23
6044             Writable => 'int8s', #27
6045             PrintConv => {
6046             0 => 'none',
6047             1 => 'Explicit',
6048             2 => 'Clean',
6049             4 => 'Explicit (old)',
6050             },
6051             },
6052             sfID => { #10
6053             Name => 'AppleStoreCountry',
6054             Format => 'int32u',
6055             Writable => 'int32s', #27
6056             SeparateTable => 1,
6057             PrintConv => { #21
6058             143441 => 'United States', # US
6059             143442 => 'France', # FR
6060             143443 => 'Germany', # DE
6061             143444 => 'United Kingdom', # GB
6062             143445 => 'Austria', # AT
6063             143446 => 'Belgium', # BE
6064             143447 => 'Finland', # FI
6065             143448 => 'Greece', # GR
6066             143449 => 'Ireland', # IE
6067             143450 => 'Italy', # IT
6068             143451 => 'Luxembourg', # LU
6069             143452 => 'Netherlands', # NL
6070             143453 => 'Portugal', # PT
6071             143454 => 'Spain', # ES
6072             143455 => 'Canada', # CA
6073             143456 => 'Sweden', # SE
6074             143457 => 'Norway', # NO
6075             143458 => 'Denmark', # DK
6076             143459 => 'Switzerland', # CH
6077             143460 => 'Australia', # AU
6078             143461 => 'New Zealand', # NZ
6079             143462 => 'Japan', # JP
6080             143463 => 'Hong Kong', # HK
6081             143464 => 'Singapore', # SG
6082             143465 => 'China', # CN
6083             143466 => 'Republic of Korea', # KR
6084             143467 => 'India', # IN
6085             143468 => 'Mexico', # MX
6086             143469 => 'Russia', # RU
6087             143470 => 'Taiwan', # TW
6088             143471 => 'Vietnam', # VN
6089             143472 => 'South Africa', # ZA
6090             143473 => 'Malaysia', # MY
6091             143474 => 'Philippines', # PH
6092             143475 => 'Thailand', # TH
6093             143476 => 'Indonesia', # ID
6094             143477 => 'Pakistan', # PK
6095             143478 => 'Poland', # PL
6096             143479 => 'Saudi Arabia', # SA
6097             143480 => 'Turkey', # TR
6098             143481 => 'United Arab Emirates', # AE
6099             143482 => 'Hungary', # HU
6100             143483 => 'Chile', # CL
6101             143484 => 'Nepal', # NP
6102             143485 => 'Panama', # PA
6103             143486 => 'Sri Lanka', # LK
6104             143487 => 'Romania', # RO
6105             143489 => 'Czech Republic', # CZ
6106             143491 => 'Israel', # IL
6107             143492 => 'Ukraine', # UA
6108             143493 => 'Kuwait', # KW
6109             143494 => 'Croatia', # HR
6110             143495 => 'Costa Rica', # CR
6111             143496 => 'Slovakia', # SK
6112             143497 => 'Lebanon', # LB
6113             143498 => 'Qatar', # QA
6114             143499 => 'Slovenia', # SI
6115             143501 => 'Colombia', # CO
6116             143502 => 'Venezuela', # VE
6117             143503 => 'Brazil', # BR
6118             143504 => 'Guatemala', # GT
6119             143505 => 'Argentina', # AR
6120             143506 => 'El Salvador', # SV
6121             143507 => 'Peru', # PE
6122             143508 => 'Dominican Republic', # DO
6123             143509 => 'Ecuador', # EC
6124             143510 => 'Honduras', # HN
6125             143511 => 'Jamaica', # JM
6126             143512 => 'Nicaragua', # NI
6127             143513 => 'Paraguay', # PY
6128             143514 => 'Uruguay', # UY
6129             143515 => 'Macau', # MO
6130             143516 => 'Egypt', # EG
6131             143517 => 'Kazakhstan', # KZ
6132             143518 => 'Estonia', # EE
6133             143519 => 'Latvia', # LV
6134             143520 => 'Lithuania', # LT
6135             143521 => 'Malta', # MT
6136             143523 => 'Moldova', # MD
6137             143524 => 'Armenia', # AM
6138             143525 => 'Botswana', # BW
6139             143526 => 'Bulgaria', # BG
6140             143528 => 'Jordan', # JO
6141             143529 => 'Kenya', # KE
6142             143530 => 'Macedonia', # MK
6143             143531 => 'Madagascar', # MG
6144             143532 => 'Mali', # ML
6145             143533 => 'Mauritius', # MU
6146             143534 => 'Niger', # NE
6147             143535 => 'Senegal', # SN
6148             143536 => 'Tunisia', # TN
6149             143537 => 'Uganda', # UG
6150             143538 => 'Anguilla', # AI
6151             143539 => 'Bahamas', # BS
6152             143540 => 'Antigua and Barbuda', # AG
6153             143541 => 'Barbados', # BB
6154             143542 => 'Bermuda', # BM
6155             143543 => 'British Virgin Islands', # VG
6156             143544 => 'Cayman Islands', # KY
6157             143545 => 'Dominica', # DM
6158             143546 => 'Grenada', # GD
6159             143547 => 'Montserrat', # MS
6160             143548 => 'St. Kitts and Nevis', # KN
6161             143549 => 'St. Lucia', # LC
6162             143550 => 'St. Vincent and The Grenadines', # VC
6163             143551 => 'Trinidad and Tobago', # TT
6164             143552 => 'Turks and Caicos', # TC
6165             143553 => 'Guyana', # GY
6166             143554 => 'Suriname', # SR
6167             143555 => 'Belize', # BZ
6168             143556 => 'Bolivia', # BO
6169             143557 => 'Cyprus', # CY
6170             143558 => 'Iceland', # IS
6171             143559 => 'Bahrain', # BH
6172             143560 => 'Brunei Darussalam', # BN
6173             143561 => 'Nigeria', # NG
6174             143562 => 'Oman', # OM
6175             143563 => 'Algeria', # DZ
6176             143564 => 'Angola', # AO
6177             143565 => 'Belarus', # BY
6178             143566 => 'Uzbekistan', # UZ
6179             143568 => 'Azerbaijan', # AZ
6180             143571 => 'Yemen', # YE
6181             143572 => 'Tanzania', # TZ
6182             143573 => 'Ghana', # GH
6183             143575 => 'Albania', # AL
6184             143576 => 'Benin', # BJ
6185             143577 => 'Bhutan', # BT
6186             143578 => 'Burkina Faso', # BF
6187             143579 => 'Cambodia', # KH
6188             143580 => 'Cape Verde', # CV
6189             143581 => 'Chad', # TD
6190             143582 => 'Republic of the Congo', # CG
6191             143583 => 'Fiji', # FJ
6192             143584 => 'Gambia', # GM
6193             143585 => 'Guinea-Bissau', # GW
6194             143586 => 'Kyrgyzstan', # KG
6195             143587 => "Lao People's Democratic Republic", # LA
6196             143588 => 'Liberia', # LR
6197             143589 => 'Malawi', # MW
6198             143590 => 'Mauritania', # MR
6199             143591 => 'Federated States of Micronesia', # FM
6200             143592 => 'Mongolia', # MN
6201             143593 => 'Mozambique', # MZ
6202             143594 => 'Namibia', # NA
6203             143595 => 'Palau', # PW
6204             143597 => 'Papua New Guinea', # PG
6205             143598 => 'Sao Tome and Principe', # ST (São Tomé and Príncipe)
6206             143599 => 'Seychelles', # SC
6207             143600 => 'Sierra Leone', # SL
6208             143601 => 'Solomon Islands', # SB
6209             143602 => 'Swaziland', # SZ
6210             143603 => 'Tajikistan', # TJ
6211             143604 => 'Turkmenistan', # TM
6212             143605 => 'Zimbabwe', # ZW
6213             },
6214             },
6215             soaa => 'SortAlbumArtist', #10
6216             soal => 'SortAlbum', #10
6217             soar => 'SortArtist', #10
6218             soco => 'SortComposer', #10
6219             sonm => 'SortName', #10
6220             sosn => 'SortShow', #10
6221             stik => { #10
6222             Name => 'MediaType',
6223             Format => 'int8u', #23
6224             Writable => 'int8s', #27
6225             PrintConvColumns => 2,
6226             PrintConv => { #(http://weblog.xanga.com/gryphondwb/615474010/iphone-ringtones---what-did-itunes-741-really-do.html)
6227             0 => 'Movie (old)', #forum9059 (was Movie)
6228             1 => 'Normal (Music)',
6229             2 => 'Audiobook',
6230             5 => 'Whacked Bookmark',
6231             6 => 'Music Video',
6232             9 => 'Movie', #forum9059 (was Short Film)
6233             10 => 'TV Show',
6234             11 => 'Booklet',
6235             14 => 'Ringtone',
6236             21 => 'Podcast', #15
6237             23 => 'iTunes U', #forum9059
6238             },
6239             },
6240             rate => 'RatingPercent', #PH
6241             titl => { Name => 'Title', Avoid => 1 },
6242             tven => 'TVEpisodeID', #7
6243             tves => { #7/10
6244             Name => 'TVEpisode',
6245             Format => 'int32u',
6246             Writable => 'int32s', #27
6247             },
6248             tvnn => 'TVNetworkName', #7
6249             tvsh => 'TVShow', #10
6250             tvsn => { #7/10
6251             Name => 'TVSeason',
6252             Format => 'int32u',
6253             },
6254             yrrc => 'Year', #(ffmpeg source)
6255             itnu => { #PH (iTunes 10.5)
6256             Name => 'iTunesU',
6257             Format => 'int8u', #27
6258             Writable => 'int8s', #27
6259             Description => 'iTunes U',
6260             PrintConv => { 0 => 'No', 1 => 'Yes' },
6261             },
6262             #https://github.com/communitymedia/mediautilities/blob/master/src/net/sourceforge/jaad/mp4/boxes/BoxTypes.java
6263             gshh => { Name => 'GoogleHostHeader', Format => 'string' },
6264             gspm => { Name => 'GooglePingMessage', Format => 'string' },
6265             gspu => { Name => 'GooglePingURL', Format => 'string' },
6266             gssd => { Name => 'GoogleSourceData', Format => 'string' },
6267             gsst => { Name => 'GoogleStartTime', Format => 'string' },
6268             gstd => {
6269             Name => 'GoogleTrackDuration',
6270             Format => 'string',
6271             ValueConv => '$val / 1000',
6272             ValueConvInv => '$val * 1000',
6273             PrintConv => 'ConvertDuration($val)',
6274             PrintConvInv => q{
6275             $val =~ s/ s$//;
6276             my @a = split /(:| days )/, $val;
6277             my $sign = ($val =~ s/^-//) ? -1 : 1;
6278             $a[0] += shift(@a) * 24 if @a == 4;
6279             $a[0] += shift(@a) * 60 while @a > 1;
6280             return $a[0] * $sign;
6281             },
6282             },
6283              
6284             # atoms observed in AAX audiobooks (ref PH)
6285             "\xa9cpy" => { Name => 'Copyright', Avoid => 1, Groups => { 2 => 'Author' } },
6286             "\xa9pub" => 'Publisher',
6287             "\xa9nrt" => 'Narrator',
6288             '@pti' => 'ParentTitle', # (guess -- same as "\xa9nam")
6289             '@PST' => 'ParentShortTitle', # (guess -- same as "\xa9nam")
6290             '@ppi' => 'ParentProductID', # (guess -- same as 'prID')
6291             '@sti' => 'ShortTitle', # (guess -- same as "\xa9nam")
6292             prID => 'ProductID',
6293             rldt => { Name => 'ReleaseDate', Groups => { 2 => 'Time' }},
6294             CDEK => { Name => 'Unknown_CDEK', Unknown => 1 }, # eg: "B004ZMTFEG" - used in URL's ("asin=")
6295             CDET => { Name => 'Unknown_CDET', Unknown => 1 }, # eg: "ADBL"
6296             VERS => 'ProductVersion',
6297             GUID => 'GUID',
6298             AACR => { Name => 'Unknown_AACR', Unknown => 1 }, # eg: "CR!1T1H1QH6WX7T714G2BMFX3E9MC4S"
6299             # ausr - 30 bytes (User Alias?)
6300             "\xa9xyz" => { #PH (written by Google Photos)
6301             Name => 'GPSCoordinates',
6302             Groups => { 2 => 'Location' },
6303             ValueConv => \&ConvertISO6709,
6304             ValueConvInv => \&ConvInvISO6709,
6305             PrintConv => \&PrintGPSCoordinates,
6306             PrintConvInv => \&PrintInvGPSCoordinates,
6307             },
6308             # the following tags written by iTunes 12.5.1.21
6309             # (ref https://www.ventismedia.com/mantis/view.php?id=14963
6310             # https://community.mp3tag.de/t/x-mp4-new-tag-problems/19488)
6311             "\xa9wrk" => 'Work', #PH
6312             "\xa9mvn" => 'MovementName', #PH
6313             "\xa9mvi" => { #PH
6314             Name => 'MovementNumber',
6315             Format => 'int16u', #27
6316             Writable => 'int16s', #27
6317             },
6318             "\xa9mvc" => { #PH
6319             Name => 'MovementCount',
6320             Format => 'int16u', #27
6321             Writable => 'int16s', #27
6322             },
6323             shwm => { #PH
6324             Name => 'ShowMovement',
6325             Format => 'int8u', #27
6326             Writable => 'int8s', #27
6327             PrintConv => { 0 => 'No', 1 => 'Yes' },
6328             },
6329             );
6330              
6331             # tag decoded from timed face records
6332             %Image::ExifTool::QuickTime::FaceInfo = (
6333             PROCESS_PROC => \&ProcessMOV,
6334             GROUPS => { 2 => 'Video' },
6335             crec => {
6336             Name => 'FaceRec',
6337             SubDirectory => {
6338             TagTable => 'Image::ExifTool::QuickTime::FaceRec',
6339             },
6340             },
6341             );
6342              
6343             # tag decoded from timed face records
6344             %Image::ExifTool::QuickTime::FaceRec = (
6345             PROCESS_PROC => \&ProcessMOV,
6346             GROUPS => { 2 => 'Video' },
6347             cits => {
6348             Name => 'FaceItem',
6349             SubDirectory => {
6350             TagTable => 'Image::ExifTool::QuickTime::Keys',
6351             ProcessProc => \&Process_mebx,
6352             },
6353             },
6354             );
6355              
6356             # item list keys (ref PH)
6357             %Image::ExifTool::QuickTime::Keys = (
6358             PROCESS_PROC => \&ProcessKeys,
6359             WRITE_PROC => \&WriteKeys,
6360             CHECK_PROC => \&CheckQTValue,
6361             VARS => { LONG_TAGS => 7 },
6362             WRITABLE => 1,
6363             # (not PREFERRED when writing)
6364             GROUPS => { 1 => 'Keys' },
6365             WRITE_GROUP => 'Keys',
6366             LANG_INFO => \&GetLangInfo,
6367             NOTES => q{
6368             This directory contains a list of key names which are used to decode tags
6369             written by the "mdta" handler. Also in this table are a few tags found in
6370             timed metadata that are not yet writable by ExifTool. The prefix of
6371             "com.apple.quicktime." has been removed from the TagID's below. These tags
6372             support alternate languages in the same way as the
6373             L tags. Note
6374             that by default,
6375             L and
6376             L tags are
6377             preferred when writing, so to create a tag when a same-named tag exists in
6378             either of these tables, either the "Keys" location must be specified (eg.
6379             C<-Keys:Author=Phil> on the command line), or the PREFERRED level must be
6380             changed via L.
6381             },
6382             version => 'Version',
6383             album => 'Album',
6384             artist => { },
6385             artwork => { },
6386             author => { Name => 'Author', Groups => { 2 => 'Author' } },
6387             comment => { },
6388             copyright => { Name => 'Copyright', Groups => { 2 => 'Author' } },
6389             creationdate=> {
6390             Name => 'CreationDate',
6391             Groups => { 2 => 'Time' },
6392             Shift => 'Time',
6393             ValueConv => q{
6394             require Image::ExifTool::XMP;
6395             $val = Image::ExifTool::XMP::ConvertXMPDate($val,1);
6396             $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
6397             return $val;
6398             },
6399             ValueConvInv => q{
6400             require Image::ExifTool::XMP;
6401             $val = Image::ExifTool::XMP::FormatXMPDate($val);
6402             $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon
6403             return $val;
6404             },
6405             PrintConv => '$self->ConvertDateTime($val)',
6406             PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
6407             },
6408             description => { },
6409             director => { },
6410             displayname => { Name => 'DisplayName' },
6411             title => { }, #22
6412             genre => { },
6413             information => { },
6414             keywords => { },
6415             producer => { }, #22
6416             make => { Name => 'Make', Groups => { 2 => 'Camera' } },
6417             model => { Name => 'Model', Groups => { 2 => 'Camera' } },
6418             publisher => { },
6419             software => { },
6420             year => { Groups => { 2 => 'Time' } },
6421             'camera.identifier' => 'CameraIdentifier', # (iPhone 4)
6422             'camera.framereadouttimeinmicroseconds' => { # (iPhone 4)
6423             Name => 'FrameReadoutTime',
6424             ValueConv => '$val * 1e-6',
6425             ValueConvInv => 'int($val * 1e6 + 0.5)',
6426             PrintConv => '$val * 1e6 . " microseconds"',
6427             PrintConvInv => '$val =~ s/ .*//; $val * 1e-6',
6428             },
6429             'location.ISO6709' => {
6430             Name => 'GPSCoordinates',
6431             Groups => { 2 => 'Location' },
6432             Notes => q{
6433             Google Photos may ignore this if the coorinates have more than 5 digits
6434             after the decimal
6435             },
6436             ValueConv => \&ConvertISO6709,
6437             ValueConvInv => \&ConvInvISO6709,
6438             PrintConv => \&PrintGPSCoordinates,
6439             PrintConvInv => \&PrintInvGPSCoordinates,
6440             },
6441             'location.name' => { Name => 'LocationName', Groups => { 2 => 'Location' } },
6442             'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } },
6443             'location.note' => { Name => 'LocationNote', Groups => { 2 => 'Location' } },
6444             'location.role' => {
6445             Name => 'LocationRole',
6446             Groups => { 2 => 'Location' },
6447             PrintConv => {
6448             0 => 'Shooting Location',
6449             1 => 'Real Location',
6450             2 => 'Fictional Location',
6451             },
6452             },
6453             'location.date' => {
6454             Name => 'LocationDate',
6455             Groups => { 2 => 'Time' },
6456             Shift => 'Time',
6457             ValueConv => q{
6458             require Image::ExifTool::XMP;
6459             $val = Image::ExifTool::XMP::ConvertXMPDate($val);
6460             $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
6461             return $val;
6462             },
6463             ValueConvInv => q{
6464             require Image::ExifTool::XMP;
6465             $val = Image::ExifTool::XMP::FormatXMPDate($val);
6466             $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon
6467             return $val;
6468             },
6469             PrintConv => '$self->ConvertDateTime($val)',
6470             PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
6471             },
6472             'location.accuracy.horizontal' => { Name => 'LocationAccuracyHorizontal' },
6473             'live-photo.auto' => { Name => 'LivePhotoAuto', Writable => 'int8u' },
6474             'live-photo.vitality-score' => { Name => 'LivePhotoVitalityScore', Writable => 'float' },
6475             'live-photo.vitality-scoring-version' => { Name => 'LivePhotoVitalityScoringVersion', Writable => 'int64s' },
6476             'apple.photos.variation-identifier' => { Name => 'ApplePhotosVariationIdentifier', Writable => 'int64s' },
6477             'direction.facing' => { Name => 'CameraDirection', Groups => { 2 => 'Location' } },
6478             'direction.motion' => { Name => 'CameraMotion', Groups => { 2 => 'Location' } },
6479             'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } },
6480             'player.version' => 'PlayerVersion',
6481             'player.movie.visual.brightness'=> 'Brightness',
6482             'player.movie.visual.color' => 'Color',
6483             'player.movie.visual.tint' => 'Tint',
6484             'player.movie.visual.contrast' => 'Contrast',
6485             'player.movie.audio.gain' => 'AudioGain',
6486             'player.movie.audio.treble' => 'Treble',
6487             'player.movie.audio.bass' => 'Bass',
6488             'player.movie.audio.balance' => 'Balance',
6489             'player.movie.audio.pitchshift' => 'PitchShift',
6490             'player.movie.audio.mute' => {
6491             Name => 'Mute',
6492             Format => 'int8u',
6493             PrintConv => { 0 => 'Off', 1 => 'On' },
6494             },
6495             'rating.user' => 'UserRating', # (Canon ELPH 510 HS)
6496             'collection.user' => 'UserCollection', #22
6497             'Encoded_With' => 'EncodedWith',
6498             #
6499             # the following tags aren't in the com.apple.quicktime namespace:
6500             #
6501             'com.apple.photos.captureMode' => 'CaptureMode',
6502             'com.android.version' => 'AndroidVersion',
6503             #
6504             # also seen
6505             #
6506             # com.divergentmedia.clipwrap.model ('NEX-FS700EK')
6507             # com.divergentmedia.clipwrap.model1 ('49')
6508             # com.divergentmedia.clipwrap.model2 ('0')
6509             # com.divergentmedia.clipwrap.manufacturer ('Sony')
6510             # com.divergentmedia.clipwrap.originalDateTime ('2013/2/6 10:30:40+0200')
6511             #
6512             # seen in timed metadata (mebx), and added dynamically to the table via SaveMetaKeys()
6513             # NOTE: these tags are not writable! (timed metadata cannot yet be written)
6514             #
6515             # (mdta)com.apple.quicktime.video-orientation (dtyp=66, int16s)
6516             'video-orientation' => {
6517             Name => 'VideoOrientation',
6518             Writable => 0,
6519             PrintConv => \%Image::ExifTool::Exif::orientation, #PH (NC)
6520             },
6521             # (mdta)com.apple.quicktime.live-photo-info (dtyp=com.apple.quicktime.com.apple.quicktime.live-photo-info)
6522             'live-photo-info' => {
6523             Name => 'LivePhotoInfo',
6524             Writable => 0,
6525             # not sure what these values mean, but unpack them anyway - PH
6526             # (ignore the fact that the "f" and "l" unpacks won't work on a big-endian machine)
6527             ValueConv => 'join " ",unpack "VfVVf6c4lCCcclf4Vvv", $val',
6528             },
6529             # (mdta)com.apple.quicktime.still-image-time (dtyp=65, int8s)
6530             'still-image-time' => { # (found in live photo)
6531             Name => 'StillImageTime',
6532             Writable => 0,
6533             Notes => q{
6534             this tag always has a value of -1; the time of the still image is obtained
6535             from the associated SampleTime
6536             },
6537             },
6538             # (mdta)com.apple.quicktime.detected-face (dtyp='com.apple.quicktime.detected-face')
6539             'detected-face' => {
6540             Name => 'FaceInfo',
6541             Writable => 0,
6542             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FaceInfo' },
6543             },
6544             # ---- detected-face fields ( ----
6545             # --> back here after a round trip through FaceInfo -> FaceRec -> FaceItem
6546             # (fiel)com.apple.quicktime.detected-face.bounds (dtyp=80, float[8])
6547             'detected-face.bounds' => {
6548             Name => 'DetectedFaceBounds',
6549             Writable => 0,
6550             # round to a reasonable number of decimal places
6551             PrintConv => 'my @a=split " ",$val;$_=int($_*1e6+.5)/1e6 foreach @a;join " ",@a',
6552             PrintConvInv => '$val',
6553             },
6554             # (fiel)com.apple.quicktime.detected-face.face-id (dtyp=77, int32u)
6555             'detected-face.face-id' => { Name => 'DetectedFaceID', Writable => 0 },
6556             # (fiel)com.apple.quicktime.detected-face.roll-angle (dtyp=23, float)
6557             'detected-face.roll-angle' => { Name => 'DetectedFaceRollAngle', Writable => 0 },
6558             # (fiel)com.apple.quicktime.detected-face.yaw-angle (dtyp=23, float)
6559             'detected-face.yaw-angle' => { Name => 'DetectedFaceYawAngle', Writable => 0 },
6560             #
6561             # seen in Apple ProRes RAW file
6562             #
6563             # (mdta)com.apple.proapps.manufacturer (eg. "Sony")
6564             # (mdta)com.apple.proapps.exif.{Exif}.FNumber (float, eg. 1.0)
6565             # (mdta)org.smpte.rdd18.lens.irisfnumber (eg. "F1.0")
6566             # (mdta)com.apple.proapps.exif.{Exif}.ShutterSpeedValue (float, eg. 1.006)
6567             # (mdta)org.smpte.rdd18.camera.shutterspeed_angle (eg. "179.2deg")
6568             # (mdta)org.smpte.rdd18.camera.neutraldensityfilterwheelsetting (eg. "ND1")
6569             # (mdta)org.smpte.rdd18.camera.whitebalance (eg. "4300K")
6570             # (mdta)com.apple.proapps.exif.{Exif}.ExposureIndex (float, eg. 4000)
6571             # (mdta)org.smpte.rdd18.camera.isosensitivity (eg. "4000")
6572             # (mdta)com.apple.proapps.image.{TIFF}.Make (eg. "Atmos")
6573             # (mdta)com.apple.proapps.image.{TIFF}.Model (eg. "ShogunInferno")
6574             # (mdta)com.apple.proapps.image.{TIFF}.Software (eg. "9.0")
6575             );
6576              
6577             # iTunes info ('----') atoms
6578             %Image::ExifTool::QuickTime::iTunesInfo = (
6579             PROCESS_PROC => \&ProcessMOV,
6580             GROUPS => { 1 => 'iTunes', 2 => 'Audio' },
6581             VARS => { LONG_TAGS => 0 }, # (hack for discrepancy in the way long tags are counted in BuildTagLookup)
6582             NOTES => q{
6583             ExifTool will extract any iTunesInfo tags that exist, even if they are not
6584             defined in this table. These tags belong to the family 1 "iTunes" group,
6585             and are not currently writable.
6586             },
6587             # 'mean'/'name'/'data' atoms form a triplet, but unfortunately
6588             # I haven't been able to find any documentation on this.
6589             # 'mean' is normally 'com.apple.iTunes'
6590             mean => {
6591             Name => 'Mean',
6592             # the 'Triplet' flag tells ProcessMOV() to generate
6593             # a single tag from the mean/name/data triplet
6594             Triplet => 1,
6595             Hidden => 1,
6596             },
6597             name => {
6598             Name => 'Name',
6599             Triplet => 1,
6600             Hidden => 1,
6601             },
6602             data => {
6603             Name => 'Data',
6604             Triplet => 1,
6605             Hidden => 1,
6606             },
6607             # the tag ID's below are composed from "mean/name",
6608             # but "mean/" is omitted if it is "com.apple.iTunes/":
6609             'iTunMOVI' => {
6610             Name => 'iTunMOVI',
6611             SubDirectory => { TagTable => 'Image::ExifTool::PLIST::Main' },
6612             },
6613             'tool' => {
6614             Name => 'iTunTool',
6615             Description => 'iTunTool',
6616             Format => 'int32u',
6617             PrintConv => 'sprintf("0x%.8x",$val)',
6618             },
6619             'iTunEXTC' => {
6620             Name => 'ContentRating',
6621             Notes => 'standard | rating | score | reasons',
6622             # eg. 'us-tv|TV-14|500|V', 'mpaa|PG-13|300|For violence and sexuality'
6623             # (see http://shadowofged.blogspot.ca/2008/06/itunes-content-ratings.html)
6624             },
6625             'iTunNORM' => {
6626             Name => 'VolumeNormalization',
6627             PrintConv => '$val=~s/ 0+(\w)/ $1/g; $val=~s/^\s+//; $val',
6628             },
6629             'iTunSMPB' => {
6630             Name => 'iTunSMPB',
6631             Description => 'iTunSMPB',
6632             # hex format, similar to iTunNORM, but 12 words instead of 10,
6633             # and 4th word is 16 hex digits (all others are 8)
6634             # (gives AAC encoder delay, ref http://code.google.com/p/l-smash/issues/detail?id=1)
6635             PrintConv => '$val=~s/ 0+(\w)/ $1/g; $val=~s/^\s+//; $val',
6636             },
6637             # (CDDB = Compact Disc DataBase)
6638             # iTunes_CDDB_1 = +<# tracks>+...
6639             'iTunes_CDDB_1' => 'CDDB1Info',
6640             'iTunes_CDDB_TrackNumber' => 'CDDBTrackNumber',
6641             'Encoding Params' => {
6642             Name => 'EncodingParams',
6643             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::EncodingParams' },
6644             },
6645             # also heard about 'iTunPGAP', but I haven't seen a sample
6646             # all tags below were added based on samples I have seen - PH
6647             DISCNUMBER => 'DiscNumber',
6648             TRACKNUMBER => 'TrackNumber',
6649             ARTISTS => 'Artists',
6650             CATALOGNUMBER => 'CatalogNumber',
6651             RATING => 'Rating',
6652             MEDIA => 'Media',
6653             SCRIPT => 'Script', # character set? (seen 'Latn')
6654             BARCODE => 'Barcode',
6655             LABEL => 'Label',
6656             MOOD => 'Mood',
6657             popularimeter => 'Popularimeter',
6658             'Dynamic Range (DR)'=> 'DynamicRange',
6659             initialkey => 'InitialKey',
6660             originalyear => 'OriginalYear',
6661             originaldate => 'OriginalDate',
6662             '~length' => 'Length', # play length? (ie. duration?)
6663             replaygain_track_gain=>'ReplayTrackGain',
6664             replaygain_track_peak=>'ReplayTrackPeak',
6665             'Volume Level (ReplayGain)'=> 'ReplayVolumeLevel',
6666             'Dynamic Range (R128)'=> 'DynamicRangeR128',
6667             'Volume Level (R128)' => 'VolumeLevelR128',
6668             'Peak Level (Sample)' => 'PeakLevelSample',
6669             'Peak Level (R128)' => 'PeakLevelR128',
6670             # also seen (many from forum12777):
6671             # 'MusicBrainz Album Release Country'
6672             # 'MusicBrainz Album Type'
6673             # 'MusicBrainz Album Status'
6674             # 'MusicBrainz Track Id'
6675             # 'MusicBrainz Release Track Id'
6676             # 'MusicBrainz Album Id'
6677             # 'MusicBrainz Album Artist Id'
6678             # 'MusicBrainz Artist Id'
6679             # 'Acoustid Id' (sic)
6680             # 'Tool Version'
6681             # 'Tool Name'
6682             # 'ISRC'
6683             # 'HDCD'
6684             # 'Waveform'
6685             );
6686              
6687             # iTunes audio encoding parameters
6688             # ref https://developer.apple.com/library/mac/#documentation/MusicAudio/Reference/AudioCodecServicesRef/Reference/reference.html
6689             %Image::ExifTool::QuickTime::EncodingParams = (
6690             PROCESS_PROC => \&ProcessEncodingParams,
6691             GROUPS => { 2 => 'Audio' },
6692             # (I have commented out the ones that don't have integer values because they
6693             # probably don't appear, and definitely wouldn't work with current decoding - PH)
6694              
6695             # global codec properties
6696             #'lnam' => 'AudioCodecName',
6697             #'lmak' => 'AudioCodecManufacturer',
6698             #'lfor' => 'AudioCodecFormat',
6699             'vpk?' => 'AudioHasVariablePacketByteSizes',
6700             #'ifm#' => 'AudioSupportedInputFormats',
6701             #'ofm#' => 'AudioSupportedOutputFormats',
6702             #'aisr' => 'AudioAvailableInputSampleRates',
6703             #'aosr' => 'AudioAvailableOutputSampleRates',
6704             'abrt' => 'AudioAvailableBitRateRange',
6705             'mnip' => 'AudioMinimumNumberInputPackets',
6706             'mnop' => 'AudioMinimumNumberOutputPackets',
6707             'cmnc' => 'AudioAvailableNumberChannels',
6708             'lmrc' => 'AudioDoesSampleRateConversion',
6709             #'aicl' => 'AudioAvailableInputChannelLayoutTags',
6710             #'aocl' => 'AudioAvailableOutputChannelLayoutTags',
6711             #'if4o' => 'AudioInputFormatsForOutputFormat',
6712             #'of4i' => 'AudioOutputFormatsForInputFormat',
6713             #'acfi' => 'AudioFormatInfo',
6714              
6715             # instance codec properties
6716             'tbuf' => 'AudioInputBufferSize',
6717             'pakf' => 'AudioPacketFrameSize',
6718             'pakb' => 'AudioMaximumPacketByteSize',
6719             #'ifmt' => 'AudioCurrentInputFormat',
6720             #'ofmt' => 'AudioCurrentOutputFormat',
6721             #'kuki' => 'AudioMagicCookie',
6722             'ubuf' => 'AudioUsedInputBufferSize',
6723             'init' => 'AudioIsInitialized',
6724             'brat' => 'AudioCurrentTargetBitRate',
6725             #'cisr' => 'AudioCurrentInputSampleRate',
6726             #'cosr' => 'AudioCurrentOutputSampleRate',
6727             'srcq' => 'AudioQualitySetting',
6728             #'brta' => 'AudioApplicableBitRateRange',
6729             #'isra' => 'AudioApplicableInputSampleRates',
6730             #'osra' => 'AudioApplicableOutputSampleRates',
6731             'pad0' => 'AudioZeroFramesPadded',
6732             'prmm' => 'AudioCodecPrimeMethod',
6733             #'prim' => 'AudioCodecPrimeInfo',
6734             #'icl ' => 'AudioInputChannelLayout',
6735             #'ocl ' => 'AudioOutputChannelLayout',
6736             #'acs ' => 'AudioCodecSettings',
6737             #'acfl' => 'AudioCodecFormatList',
6738             'acbf' => 'AudioBitRateControlMode',
6739             'vbrq' => 'AudioVBRQuality',
6740             'mdel' => 'AudioMinimumDelayMode',
6741              
6742             # deprecated
6743             'pakd' => 'AudioRequiresPacketDescription',
6744             #'brt#' => 'AudioAvailableBitRates',
6745             'acef' => 'AudioExtendFrequencies',
6746             'ursr' => 'AudioUseRecommendedSampleRate',
6747             'oppr' => 'AudioOutputPrecedence',
6748             #'loud' => 'AudioCurrentLoudnessStatistics',
6749              
6750             # others
6751             'vers' => 'AudioEncodingParamsVersion', #PH
6752             'cdcv' => { #PH
6753             Name => 'AudioComponentVersion',
6754             ValueConv => 'join ".", unpack("ncc", pack("N",$val))',
6755             },
6756             );
6757              
6758             # print to video data block
6759             %Image::ExifTool::QuickTime::Video = (
6760             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
6761             GROUPS => { 2 => 'Video' },
6762             0 => {
6763             Name => 'DisplaySize',
6764             PrintConv => {
6765             0 => 'Normal',
6766             1 => 'Double Size',
6767             2 => 'Half Size',
6768             3 => 'Full Screen',
6769             4 => 'Current Size',
6770             },
6771             },
6772             6 => {
6773             Name => 'SlideShow',
6774             PrintConv => {
6775             0 => 'No',
6776             1 => 'Yes',
6777             },
6778             },
6779             );
6780              
6781             # 'hnti' atoms
6782             %Image::ExifTool::QuickTime::HintInfo = (
6783             PROCESS_PROC => \&ProcessMOV,
6784             GROUPS => { 2 => 'Video' },
6785             'rtp ' => {
6786             Name => 'RealtimeStreamingProtocol',
6787             PrintConv => '$val=~s/^sdp /(SDP) /; $val',
6788             },
6789             'sdp ' => 'StreamingDataProtocol',
6790             );
6791              
6792             # 'hinf' atoms
6793             %Image::ExifTool::QuickTime::HintTrackInfo = (
6794             PROCESS_PROC => \&ProcessMOV,
6795             GROUPS => { 2 => 'Video' },
6796             trpY => { Name => 'TotalBytes', Format => 'int64u' }, #(documented)
6797             trpy => { Name => 'TotalBytes', Format => 'int64u' }, #(observed)
6798             totl => { Name => 'TotalBytes', Format => 'int32u' },
6799             nump => { Name => 'NumPackets', Format => 'int64u' },
6800             npck => { Name => 'NumPackets', Format => 'int32u' },
6801             tpyl => { Name => 'TotalBytesNoRTPHeaders', Format => 'int64u' },
6802             tpaY => { Name => 'TotalBytesNoRTPHeaders', Format => 'int32u' }, #(documented)
6803             tpay => { Name => 'TotalBytesNoRTPHeaders', Format => 'int32u' }, #(observed)
6804             maxr => {
6805             Name => 'MaxDataRate',
6806             Format => 'int32u',
6807             Count => 2,
6808             PrintConv => 'my @a=split(" ",$val);sprintf("%d bytes in %.3f s",$a[1],$a[0]/1000)',
6809             },
6810             dmed => { Name => 'MediaTrackBytes', Format => 'int64u' },
6811             dimm => { Name => 'ImmediateDataBytes', Format => 'int64u' },
6812             drep => { Name => 'RepeatedDataBytes', Format => 'int64u' },
6813             tmin => {
6814             Name => 'MinTransmissionTime',
6815             Format => 'int32u',
6816             PrintConv => 'sprintf("%.3f s",$val/1000)',
6817             },
6818             tmax => {
6819             Name => 'MaxTransmissionTime',
6820             Format => 'int32u',
6821             PrintConv => 'sprintf("%.3f s",$val/1000)',
6822             },
6823             pmax => { Name => 'LargestPacketSize', Format => 'int32u' },
6824             dmax => {
6825             Name => 'LargestPacketDuration',
6826             Format => 'int32u',
6827             PrintConv => 'sprintf("%.3f s",$val/1000)',
6828             },
6829             payt => {
6830             Name => 'PayloadType',
6831             Format => 'undef', # (necessary to prevent decoding as string!)
6832             ValueConv => 'unpack("N",$val) . " " . substr($val, 5)',
6833             PrintConv => '$val=~s/ /, /;$val',
6834             },
6835             );
6836              
6837             # MP4 media box (ref 5)
6838             %Image::ExifTool::QuickTime::Media = (
6839             PROCESS_PROC => \&ProcessMOV,
6840             WRITE_PROC => \&WriteQuickTime,
6841             GROUPS => { 1 => 'Track#', 2 => 'Video' },
6842             NOTES => 'MP4 media box.',
6843             mdhd => {
6844             Name => 'MediaHeader',
6845             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MediaHeader' },
6846             },
6847             hdlr => {
6848             Name => 'Handler',
6849             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' },
6850             },
6851             minf => {
6852             Name => 'MediaInfo',
6853             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MediaInfo' },
6854             },
6855             );
6856              
6857             # MP4 media header box (ref 5)
6858             %Image::ExifTool::QuickTime::MediaHeader = (
6859             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
6860             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
6861             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
6862             GROUPS => { 1 => 'Track#', 2 => 'Video' },
6863             FORMAT => 'int32u',
6864             DATAMEMBER => [ 0, 1, 2, 3, 4 ],
6865             0 => {
6866             Name => 'MediaHeaderVersion',
6867             RawConv => '$$self{MediaHeaderVersion} = $val',
6868             },
6869             1 => {
6870             Name => 'MediaCreateDate',
6871             Groups => { 2 => 'Time' },
6872             %timeInfo,
6873             # this is int64u if MediaHeaderVersion == 1 (ref 5/13)
6874             Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4',
6875             },
6876             2 => {
6877             Name => 'MediaModifyDate',
6878             Groups => { 2 => 'Time' },
6879             %timeInfo,
6880             # this is int64u if MediaHeaderVersion == 1 (ref 5/13)
6881             Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4',
6882             },
6883             3 => {
6884             Name => 'MediaTimeScale',
6885             RawConv => '$$self{MediaTS} = $val',
6886             },
6887             4 => {
6888             Name => 'MediaDuration',
6889             RawConv => '$$self{MediaTS} ? $val / $$self{MediaTS} : $val',
6890             PrintConv => '$$self{MediaTS} ? ConvertDuration($val) : $val',
6891             # this is int64u if MediaHeaderVersion == 1 (ref 5/13)
6892             Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4',
6893             },
6894             5 => {
6895             Name => 'MediaLanguageCode',
6896             Format => 'int16u',
6897             RawConv => '$val ? $val : undef',
6898             # allow both Macintosh (for MOV files) and ISO (for MP4 files) language codes
6899             ValueConv => '($val < 0x400 or $val == 0x7fff) ? $val : pack "C*", map { (($val>>$_)&0x1f)+0x60 } 10, 5, 0',
6900             PrintConv => q{
6901             return $val unless $val =~ /^\d+$/;
6902             require Image::ExifTool::Font;
6903             return $Image::ExifTool::Font::ttLang{Macintosh}{$val} || "Unknown ($val)";
6904             },
6905             },
6906             );
6907              
6908             # MP4 media information box (ref 5)
6909             %Image::ExifTool::QuickTime::MediaInfo = (
6910             PROCESS_PROC => \&ProcessMOV,
6911             WRITE_PROC => \&WriteQuickTime,
6912             GROUPS => { 1 => 'Track#', 2 => 'Video' },
6913             NOTES => 'MP4 media info box.',
6914             vmhd => {
6915             Name => 'VideoHeader',
6916             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::VideoHeader' },
6917             },
6918             smhd => {
6919             Name => 'AudioHeader',
6920             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AudioHeader' },
6921             },
6922             hmhd => {
6923             Name => 'HintHeader',
6924             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintHeader' },
6925             },
6926             nmhd => {
6927             Name => 'NullMediaHeader',
6928             Flags => ['Binary','Unknown'],
6929             },
6930             dinf => {
6931             Name => 'DataInfo', # (don't change this name -- used to recognize directory when writing)
6932             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' },
6933             },
6934             gmhd => {
6935             Name => 'GenMediaHeader',
6936             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::GenMediaHeader' },
6937             },
6938             hdlr => { #PH
6939             Name => 'Handler',
6940             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' },
6941             },
6942             stbl => {
6943             Name => 'SampleTable',
6944             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SampleTable' },
6945             },
6946             );
6947              
6948             # MP4 video media header (ref 5)
6949             %Image::ExifTool::QuickTime::VideoHeader = (
6950             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
6951             GROUPS => { 2 => 'Video' },
6952             NOTES => 'MP4 video media header.',
6953             FORMAT => 'int16u',
6954             2 => {
6955             Name => 'GraphicsMode',
6956             PrintHex => 1,
6957             SeparateTable => 'GraphicsMode',
6958             PrintConv => \%graphicsMode,
6959             },
6960             3 => { Name => 'OpColor', Format => 'int16u[3]' },
6961             );
6962              
6963             # MP4 audio media header (ref 5)
6964             %Image::ExifTool::QuickTime::AudioHeader = (
6965             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
6966             GROUPS => { 2 => 'Audio' },
6967             NOTES => 'MP4 audio media header.',
6968             FORMAT => 'int16u',
6969             2 => { Name => 'Balance', Format => 'fixed16s' },
6970             );
6971              
6972             # MP4 hint media header (ref 5)
6973             %Image::ExifTool::QuickTime::HintHeader = (
6974             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
6975             NOTES => 'MP4 hint media header.',
6976             FORMAT => 'int16u',
6977             2 => 'MaxPDUSize',
6978             3 => 'AvgPDUSize',
6979             4 => { Name => 'MaxBitrate', Format => 'int32u', PrintConv => 'ConvertBitrate($val)' },
6980             6 => { Name => 'AvgBitrate', Format => 'int32u', PrintConv => 'ConvertBitrate($val)' },
6981             );
6982              
6983             # MP4 sample table box (ref 5)
6984             %Image::ExifTool::QuickTime::SampleTable = (
6985             PROCESS_PROC => \&ProcessMOV,
6986             WRITE_PROC => \&WriteQuickTime,
6987             GROUPS => { 2 => 'Video' },
6988             NOTES => 'MP4 sample table box.',
6989             stsd => [
6990             {
6991             Name => 'AudioSampleDesc',
6992             Condition => '$$self{HandlerType} and $$self{HandlerType} eq "soun"',
6993             SubDirectory => {
6994             TagTable => 'Image::ExifTool::QuickTime::AudioSampleDesc',
6995             ProcessProc => \&ProcessSampleDesc,
6996             },
6997             },{
6998             Name => 'VideoSampleDesc',
6999             Condition => '$$self{HandlerType} and $$self{HandlerType} eq "vide"',
7000             SubDirectory => {
7001             TagTable => 'Image::ExifTool::QuickTime::ImageDesc',
7002             ProcessProc => \&ProcessSampleDesc,
7003             },
7004             },{
7005             Name => 'HintSampleDesc',
7006             Condition => '$$self{HandlerType} and $$self{HandlerType} eq "hint"',
7007             SubDirectory => {
7008             TagTable => 'Image::ExifTool::QuickTime::HintSampleDesc',
7009             ProcessProc => \&ProcessSampleDesc,
7010             },
7011             },{
7012             Name => 'MetaSampleDesc',
7013             Condition => '$$self{HandlerType} and $$self{HandlerType} eq "meta"',
7014             SubDirectory => {
7015             TagTable => 'Image::ExifTool::QuickTime::MetaSampleDesc',
7016             ProcessProc => \&ProcessSampleDesc,
7017             },
7018             },{
7019             Name => 'OtherSampleDesc',
7020             SubDirectory => {
7021             TagTable => 'Image::ExifTool::QuickTime::OtherSampleDesc',
7022             ProcessProc => \&ProcessSampleDesc,
7023             },
7024             },
7025             # (Note: "alis" HandlerType handled by the parent audio or video handler)
7026             ],
7027             stts => [ # decoding time-to-sample table
7028             {
7029             Name => 'VideoFrameRate',
7030             Notes => 'average rate calculated from time-to-sample table for video media',
7031             Condition => '$$self{HandlerType} and $$self{HandlerType} eq "vide"',
7032             Format => 'undef', # (necessary to prevent decoding as string!)
7033             # (must be RawConv so appropriate MediaTS is used in calculation)
7034             RawConv => 'Image::ExifTool::QuickTime::CalcSampleRate($self, \$val)',
7035             PrintConv => 'int($val * 1000 + 0.5) / 1000',
7036             },
7037             {
7038             Name => 'TimeToSampleTable',
7039             Flags => ['Binary','Unknown'],
7040             },
7041             ],
7042             ctts => {
7043             Name => 'CompositionTimeToSample',
7044             Flags => ['Binary','Unknown'],
7045             },
7046             stsc => {
7047             Name => 'SampleToChunk',
7048             Flags => ['Binary','Unknown'],
7049             },
7050             stsz => {
7051             Name => 'SampleSizes',
7052             Flags => ['Binary','Unknown'],
7053             },
7054             stz2 => {
7055             Name => 'CompactSampleSizes',
7056             Flags => ['Binary','Unknown'],
7057             },
7058             stco => {
7059             Name => 'ChunkOffset',
7060             Flags => ['Binary','Unknown'],
7061             },
7062             co64 => {
7063             Name => 'ChunkOffset64',
7064             Flags => ['Binary','Unknown'],
7065             },
7066             stss => {
7067             Name => 'SyncSampleTable',
7068             Flags => ['Binary','Unknown'],
7069             },
7070             stsh => {
7071             Name => 'ShadowSyncSampleTable',
7072             Flags => ['Binary','Unknown'],
7073             },
7074             padb => {
7075             Name => 'SamplePaddingBits',
7076             Flags => ['Binary','Unknown'],
7077             },
7078             stdp => {
7079             Name => 'SampleDegradationPriority',
7080             Flags => ['Binary','Unknown'],
7081             },
7082             sdtp => {
7083             Name => 'IdependentAndDisposableSamples',
7084             Flags => ['Binary','Unknown'],
7085             },
7086             sbgp => {
7087             Name => 'SampleToGroup',
7088             Flags => ['Binary','Unknown'],
7089             },
7090             sgpd => {
7091             Name => 'SampleGroupDescription',
7092             Flags => ['Binary','Unknown'],
7093             # bytes 4-7 give grouping type (ref ISO/IEC 14496-15:2014)
7094             # tsas - temporal sublayer sample
7095             # stsa - step-wise temporal layer access
7096             # avss - AVC sample
7097             # tscl - temporal layer scalability
7098             # sync - sync sample
7099             },
7100             subs => {
7101             Name => 'Sub-sampleInformation',
7102             Flags => ['Binary','Unknown'],
7103             },
7104             cslg => {
7105             Name => 'CompositionToDecodeTimelineMapping',
7106             Flags => ['Binary','Unknown'],
7107             },
7108             stps => {
7109             Name => 'PartialSyncSamples',
7110             ValueConv => 'join " ",unpack("x8N*",$val)',
7111             },
7112             # mark - 8 bytes all zero (GoPro)
7113             );
7114              
7115             # MP4 audio sample description box (ref 5/AtomicParsley 0.9.4 parsley.cpp)
7116             %Image::ExifTool::QuickTime::AudioSampleDesc = (
7117             PROCESS_PROC => \&ProcessHybrid,
7118             VARS => { ID_LABEL => 'ID/Index' },
7119             GROUPS => { 2 => 'Audio' },
7120             NOTES => q{
7121             MP4 audio sample description. This hybrid atom contains both data and child
7122             atoms.
7123             },
7124             4 => {
7125             Name => 'AudioFormat',
7126             Format => 'undef[4]',
7127             RawConv => q{
7128             $$self{AudioFormat} = $val;
7129             return undef unless $val =~ /^[\w ]{4}$/i;
7130             # check for protected audio format
7131             $self->OverrideFileType('M4P') if $val eq 'drms' and $$self{VALUE}{FileType} eq 'M4A';
7132             return $val;
7133             },
7134             # see this link for print conversions (not complete):
7135             # https://github.com/yannickcr/brooser/blob/master/php/librairies/getid3/module.audio-video.quicktime.php
7136             },
7137             20 => { #PH
7138             Name => 'AudioVendorID',
7139             Condition => '$$self{AudioFormat} ne "mp4s"',
7140             Format => 'undef[4]',
7141             RawConv => '$val eq "\0\0\0\0" ? undef : $val',
7142             PrintConv => \%vendorID,
7143             SeparateTable => 'VendorID',
7144             },
7145             24 => { Name => 'AudioChannels', Format => 'int16u' },
7146             26 => { Name => 'AudioBitsPerSample', Format => 'int16u' },
7147             32 => { Name => 'AudioSampleRate', Format => 'fixed32u' },
7148             #
7149             # Observed offsets for child atoms of various AudioFormat types:
7150             #
7151             # AudioFormat Offset Child atoms
7152             # ----------- ------ ----------------
7153             # mp4a 52 * wave, chan, esds, SA3D(Insta360 spherical video params?,also GoPro Max)
7154             # in24 52 wave, chan
7155             # "ms\0\x11" 52 wave
7156             # sowt 52 chan
7157             # mp4a 36 * esds, pinf
7158             # drms 36 esds, sinf
7159             # samr 36 damr
7160             # alac 36 alac
7161             # ac-3 36 dac3
7162             #
7163             # (* child atoms found at different offsets in mp4a)
7164             #
7165             pinf => {
7166             Name => 'PurchaseInfo',
7167             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ProtectionInfo' },
7168             },
7169             sinf => { # "protection scheme information"
7170             Name => 'ProtectionInfo', #3
7171             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ProtectionInfo' },
7172             },
7173             # f - 16/36 bytes
7174             # esds - 31/40/42/43 bytes - ES descriptor (ref 3)
7175             damr => { #3
7176             Name => 'DecodeConfig',
7177             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DecodeConfig' },
7178             },
7179             wave => {
7180             Name => 'Wave',
7181             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Wave' },
7182             },
7183             chan => {
7184             Name => 'AudioChannelLayout',
7185             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ChannelLayout' },
7186             }
7187             # alac - 28 bytes
7188             # adrm - AAX DRM atom? 148 bytes
7189             # aabd - AAX unknown 17kB (contains 'aavd' strings)
7190             # SA3D - written by Garmin VIRB360
7191             );
7192              
7193             # AMR decode config box (ref 3)
7194             %Image::ExifTool::QuickTime::DecodeConfig = (
7195             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
7196             GROUPS => { 2 => 'Audio' },
7197             0 => {
7198             Name => 'EncoderVendor',
7199             Format => 'undef[4]',
7200             },
7201             4 => 'EncoderVersion',
7202             # 5 - int16u - packet modes
7203             # 7 - int8u - number of packet mode changes
7204             # 8 - int8u - bytes per packet
7205             );
7206              
7207             %Image::ExifTool::QuickTime::ProtectionInfo = (
7208             PROCESS_PROC => \&ProcessMOV,
7209             GROUPS => { 2 => 'Audio' },
7210             NOTES => 'Child atoms found in "sinf" and/or "pinf" atoms.',
7211             frma => 'OriginalFormat',
7212             # imif - IPMP information
7213             schm => {
7214             Name => 'SchemeType',
7215             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeType' },
7216             },
7217             schi => {
7218             Name => 'SchemeInfo',
7219             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeInfo' },
7220             },
7221             enda => {
7222             Name => 'Endianness',
7223             Format => 'int16u',
7224             PrintConv => {
7225             0 => 'Big-endian (Motorola, MM)',
7226             1 => 'Little-endian (Intel, II)',
7227             },
7228             },
7229             # skcr
7230             );
7231              
7232             %Image::ExifTool::QuickTime::Wave = (
7233             PROCESS_PROC => \&ProcessMOV,
7234             frma => 'PurchaseFileFormat',
7235             enda => {
7236             Name => 'Endianness',
7237             Format => 'int16u',
7238             PrintConv => {
7239             0 => 'Big-endian (Motorola, MM)',
7240             1 => 'Little-endian (Intel, II)',
7241             },
7242             },
7243             # "ms\0\x11" - 20 bytes
7244             );
7245              
7246             # audio channel layout (ref CoreAudioTypes.h)
7247             %Image::ExifTool::QuickTime::ChannelLayout = (
7248             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
7249             GROUPS => { 2 => 'Audio' },
7250             DATAMEMBER => [ 0, 8 ],
7251             NOTES => 'Audio channel layout.',
7252             # 0 - version and flags
7253             4 => {
7254             Name => 'LayoutFlags',
7255             Format => 'int16u',
7256             RawConv => '$$self{LayoutFlags} = $val',
7257             PrintConvColumns => 2,
7258             PrintConv => {
7259             0 => 'UseDescriptions',
7260             1 => 'UseBitmap',
7261             100 => 'Mono',
7262             101 => 'Stereo',
7263             102 => 'StereoHeadphones',
7264             100 => 'Mono',
7265             101 => 'Stereo',
7266             102 => 'StereoHeadphones',
7267             103 => 'MatrixStereo',
7268             104 => 'MidSide',
7269             105 => 'XY',
7270             106 => 'Binaural',
7271             107 => 'Ambisonic_B_Format',
7272             108 => 'Quadraphonic',
7273             109 => 'Pentagonal',
7274             110 => 'Hexagonal',
7275             111 => 'Octagonal',
7276             112 => 'Cube',
7277             113 => 'MPEG_3_0_A',
7278             114 => 'MPEG_3_0_B',
7279             115 => 'MPEG_4_0_A',
7280             116 => 'MPEG_4_0_B',
7281             117 => 'MPEG_5_0_A',
7282             118 => 'MPEG_5_0_B',
7283             119 => 'MPEG_5_0_C',
7284             120 => 'MPEG_5_0_D',
7285             121 => 'MPEG_5_1_A',
7286             122 => 'MPEG_5_1_B',
7287             123 => 'MPEG_5_1_C',
7288             124 => 'MPEG_5_1_D',
7289             125 => 'MPEG_6_1_A',
7290             126 => 'MPEG_7_1_A',
7291             127 => 'MPEG_7_1_B',
7292             128 => 'MPEG_7_1_C',
7293             129 => 'Emagic_Default_7_1',
7294             130 => 'SMPTE_DTV',
7295             131 => 'ITU_2_1',
7296             132 => 'ITU_2_2',
7297             133 => 'DVD_4',
7298             134 => 'DVD_5',
7299             135 => 'DVD_6',
7300             136 => 'DVD_10',
7301             137 => 'DVD_11',
7302             138 => 'DVD_18',
7303             139 => 'AudioUnit_6_0',
7304             140 => 'AudioUnit_7_0',
7305             141 => 'AAC_6_0',
7306             142 => 'AAC_6_1',
7307             143 => 'AAC_7_0',
7308             144 => 'AAC_Octagonal',
7309             145 => 'TMH_10_2_std',
7310             146 => 'TMH_10_2_full',
7311             147 => 'DiscreteInOrder',
7312             148 => 'AudioUnit_7_0_Front',
7313             149 => 'AC3_1_0_1',
7314             150 => 'AC3_3_0',
7315             151 => 'AC3_3_1',
7316             152 => 'AC3_3_0_1',
7317             153 => 'AC3_2_1_1',
7318             154 => 'AC3_3_1_1',
7319             155 => 'EAC_6_0_A',
7320             156 => 'EAC_7_0_A',
7321             157 => 'EAC3_6_1_A',
7322             158 => 'EAC3_6_1_B',
7323             159 => 'EAC3_6_1_C',
7324             160 => 'EAC3_7_1_A',
7325             161 => 'EAC3_7_1_B',
7326             162 => 'EAC3_7_1_C',
7327             163 => 'EAC3_7_1_D',
7328             164 => 'EAC3_7_1_E',
7329             165 => 'EAC3_7_1_F',
7330             166 => 'EAC3_7_1_G',
7331             167 => 'EAC3_7_1_H',
7332             168 => 'DTS_3_1',
7333             169 => 'DTS_4_1',
7334             170 => 'DTS_6_0_A',
7335             171 => 'DTS_6_0_B',
7336             172 => 'DTS_6_0_C',
7337             173 => 'DTS_6_1_A',
7338             174 => 'DTS_6_1_B',
7339             175 => 'DTS_6_1_C',
7340             176 => 'DTS_7_0',
7341             177 => 'DTS_7_1',
7342             178 => 'DTS_8_0_A',
7343             179 => 'DTS_8_0_B',
7344             180 => 'DTS_8_1_A',
7345             181 => 'DTS_8_1_B',
7346             182 => 'DTS_6_1_D',
7347             183 => 'AAC_7_1_B',
7348             0xffff => 'Unknown',
7349             },
7350             },
7351             6 => {
7352             Name => 'AudioChannels',
7353             Condition => '$$self{LayoutFlags} != 0 and $$self{LayoutFlags} != 1',
7354             Format => 'int16u',
7355             },
7356             8 => {
7357             Name => 'AudioChannelTypes',
7358             Condition => '$$self{LayoutFlags} == 1',
7359             Format => 'int32u',
7360             PrintConv => { BITMASK => {
7361             0 => 'Left',
7362             1 => 'Right',
7363             2 => 'Center',
7364             3 => 'LFEScreen',
7365             4 => 'LeftSurround',
7366             5 => 'RightSurround',
7367             6 => 'LeftCenter',
7368             7 => 'RightCenter',
7369             8 => 'CenterSurround',
7370             9 => 'LeftSurroundDirect',
7371             10 => 'RightSurroundDirect',
7372             11 => 'TopCenterSurround',
7373             12 => 'VerticalHeightLeft',
7374             13 => 'VerticalHeightCenter',
7375             14 => 'VerticalHeightRight',
7376             15 => 'TopBackLeft',
7377             16 => 'TopBackCenter',
7378             17 => 'TopBackRight',
7379             }},
7380             },
7381             12 => {
7382             Name => 'NumChannelDescriptions',
7383             Condition => '$$self{LayoutFlags} == 1',
7384             Format => 'int32u',
7385             RawConv => '$$self{NumChannelDescriptions} = $val',
7386             },
7387             16 => {
7388             Name => 'Channel1Label',
7389             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0',
7390             Format => 'int32u',
7391             SeparateTable => 'ChannelLabel',
7392             PrintConv => \%channelLabel,
7393             },
7394             20 => {
7395             Name => 'Channel1Flags',
7396             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0',
7397             Format => 'int32u',
7398             PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7399             },
7400             24 => {
7401             Name => 'Channel1Coordinates',
7402             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0',
7403             Notes => q{
7404             3 numbers: for rectangular coordinates left/right, back/front, down/up; for
7405             spherical coordinates left/right degrees, down/up degrees, distance
7406             },
7407             Format => 'float[3]',
7408             },
7409             36 => {
7410             Name => 'Channel2Label',
7411             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1',
7412             Format => 'int32u',
7413             SeparateTable => 'ChannelLabel',
7414             PrintConv => \%channelLabel,
7415             },
7416             40 => {
7417             Name => 'Channel2Flags',
7418             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1',
7419             Format => 'int32u',
7420             PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7421             },
7422             44 => {
7423             Name => 'Channel2Coordinates',
7424             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1',
7425             Format => 'float[3]',
7426             },
7427             56 => {
7428             Name => 'Channel3Label',
7429             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2',
7430             Format => 'int32u',
7431             SeparateTable => 'ChannelLabel',
7432             PrintConv => \%channelLabel,
7433             },
7434             60 => {
7435             Name => 'Channel3Flags',
7436             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2',
7437             Format => 'int32u',
7438             PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7439             },
7440             64 => {
7441             Name => 'Channel3Coordinates',
7442             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2',
7443             Format => 'float[3]',
7444             },
7445             76 => {
7446             Name => 'Channel4Label',
7447             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3',
7448             Format => 'int32u',
7449             SeparateTable => 'ChannelLabel',
7450             PrintConv => \%channelLabel,
7451             },
7452             80 => {
7453             Name => 'Channel4Flags',
7454             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3',
7455             Format => 'int32u',
7456             PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7457             },
7458             84 => {
7459             Name => 'Channel4Coordinates',
7460             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3',
7461             Format => 'float[3]',
7462             },
7463             96 => {
7464             Name => 'Channel5Label',
7465             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4',
7466             Format => 'int32u',
7467             SeparateTable => 'ChannelLabel',
7468             PrintConv => \%channelLabel,
7469             },
7470             100 => {
7471             Name => 'Channel5Flags',
7472             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4',
7473             Format => 'int32u',
7474             PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7475             },
7476             104 => {
7477             Name => 'Channel5Coordinates',
7478             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4',
7479             Format => 'float[3]',
7480             },
7481             116 => {
7482             Name => 'Channel6Label',
7483             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5',
7484             Format => 'int32u',
7485             SeparateTable => 'ChannelLabel',
7486             PrintConv => \%channelLabel,
7487             },
7488             120 => {
7489             Name => 'Channel6Flags',
7490             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5',
7491             Format => 'int32u',
7492             PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7493             },
7494             124 => {
7495             Name => 'Channel6Coordinates',
7496             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5',
7497             Format => 'float[3]',
7498             },
7499             136 => {
7500             Name => 'Channel7Label',
7501             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6',
7502             Format => 'int32u',
7503             SeparateTable => 'ChannelLabel',
7504             PrintConv => \%channelLabel,
7505             },
7506             140 => {
7507             Name => 'Channel7Flags',
7508             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6',
7509             Format => 'int32u',
7510             PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7511             },
7512             144 => {
7513             Name => 'Channel7Coordinates',
7514             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6',
7515             Format => 'float[3]',
7516             },
7517             156 => {
7518             Name => 'Channel8Label',
7519             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7',
7520             Format => 'int32u',
7521             SeparateTable => 'ChannelLabel',
7522             PrintConv => \%channelLabel,
7523             },
7524             160 => {
7525             Name => 'Channel8Flags',
7526             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7',
7527             Format => 'int32u',
7528             PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7529             },
7530             164 => {
7531             Name => 'Channel8Coordinates',
7532             Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7',
7533             Format => 'float[3]',
7534             },
7535             # (arbitrarily decode only first 8 channels)
7536             );
7537              
7538             # scheme type atom
7539             # ref http://xhelmboyx.tripod.com/formats/mp4-layout.txt
7540             %Image::ExifTool::QuickTime::SchemeType = (
7541             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
7542             GROUPS => { 2 => 'Audio' },
7543             # 0 - 4 bytes version
7544             4 => { Name => 'SchemeType', Format => 'undef[4]' },
7545             8 => { Name => 'SchemeVersion', Format => 'int16u' },
7546             10 => { Name => 'SchemeURL', Format => 'string[$size-10]' },
7547             );
7548              
7549             %Image::ExifTool::QuickTime::SchemeInfo = (
7550             PROCESS_PROC => \&ProcessMOV,
7551             GROUPS => { 2 => 'Audio' },
7552             user => {
7553             Name => 'UserID',
7554             Groups => { 2 => 'Author' },
7555             ValueConv => '"0x" . unpack("H*",$val)',
7556             },
7557             cert => { # ref http://www.onvif.org/specs/stream/ONVIF-ExportFileFormat-Spec-v100.pdf
7558             Name => 'Certificate',
7559             ValueConv => '"0x" . unpack("H*",$val)',
7560             },
7561             'key ' => {
7562             Name => 'KeyID',
7563             ValueConv => '"0x" . unpack("H*",$val)',
7564             },
7565             iviv => {
7566             Name => 'InitializationVector',
7567             ValueConv => 'unpack("H*",$val)',
7568             },
7569             righ => {
7570             Name => 'Rights',
7571             Groups => { 2 => 'Author' },
7572             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Rights' },
7573             },
7574             name => { Name => 'UserName', Groups => { 2 => 'Author' } },
7575             # chtb
7576             # priv - private data
7577             # sign
7578             # adkm - Adobe DRM key management system (ref http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf)
7579             # iKMS
7580             # iSFM
7581             # iSLT
7582             );
7583              
7584             %Image::ExifTool::QuickTime::Rights = (
7585             PROCESS_PROC => \&ProcessRights,
7586             GROUPS => { 2 => 'Audio' },
7587             veID => 'ItemVendorID', #PH ("VendorID" ref 19)
7588             plat => 'Platform', #18?
7589             aver => 'VersionRestrictions', #19 ("appversion?" ref 18)
7590             tran => 'TransactionID', #18
7591             song => 'ItemID', #19 ("appid" ref 18)
7592             tool => {
7593             Name => 'ItemTool', #PH (guess) ("itunes build?" ref 18)
7594             Format => 'string',
7595             },
7596             medi => 'MediaFlags', #PH (?)
7597             mode => 'ModeFlags', #PH (?) 0x04 is HD flag (https://compilr.com/heksesang/requiem-mac/UnDrm.java)
7598             );
7599              
7600             # MP4 hint sample description box (ref 5)
7601             # (ref https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-SW1)
7602             %Image::ExifTool::QuickTime::HintSampleDesc = (
7603             PROCESS_PROC => \&ProcessHybrid,
7604             VARS => { ID_LABEL => 'ID/Index' },
7605             NOTES => 'MP4 hint sample description.',
7606             4 => { Name => 'HintFormat', Format => 'undef[4]' },
7607             # 14 - int16u DataReferenceIndex
7608             16 => { Name => 'HintTrackVersion', Format => 'int16u' },
7609             # 18 - int16u LastCompatibleHintTrackVersion
7610             20 => { Name => 'MaxPacketSize', Format => 'int32u' },
7611             #
7612             # Observed offsets for child atoms of various HintFormat types:
7613             #
7614             # HintFormat Offset Child atoms
7615             # ----------- ------ ----------------
7616             # "rtp " 24 tims
7617             #
7618             tims => { Name => 'RTPTimeScale', Format => 'int32u' },
7619             tsro => { Name => 'TimestampRandomOffset', Format => 'int32u' },
7620             snro => { Name => 'SequenceNumberRandomOffset', Format => 'int32u' },
7621             );
7622              
7623             # MP4 metadata sample description box
7624             %Image::ExifTool::QuickTime::MetaSampleDesc = (
7625             PROCESS_PROC => \&ProcessHybrid,
7626             NOTES => 'MP4 metadata sample description.',
7627             4 => {
7628             Name => 'MetaFormat',
7629             Format => 'undef[4]',
7630             RawConv => '$$self{MetaFormat} = $val',
7631             },
7632             8 => { # starts at 8 for MetaFormat eq 'camm', and 17 for 'mett'
7633             Name => 'MetaType',
7634             Format => 'undef[$size-8]',
7635             # may start at various locations!
7636             RawConv => '$$self{MetaType} = ($val=~/(application[^\0]+)/ ? $1 : undef)',
7637             },
7638             #
7639             # Observed offsets for child atoms of various MetaFormat types:
7640             #
7641             # MetaFormat Offset Child atoms
7642             # ----------- ------ ----------------
7643             # mebx 24 keys,btrt,lidp,lidl
7644             # fdsc - -
7645             # gpmd - -
7646             # rtmd - -
7647             # CTMD - -
7648             #
7649             'keys' => { #PH (iPhone7+ hevc)
7650             Name => 'Keys',
7651             SubDirectory => {
7652             TagTable => 'Image::ExifTool::QuickTime::Keys',
7653             ProcessProc => \&ProcessMetaKeys,
7654             },
7655             },
7656             btrt => {
7657             Name => 'BitrateInfo',
7658             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Bitrate' },
7659             },
7660             );
7661              
7662             # MP4 generic sample description box
7663             %Image::ExifTool::QuickTime::OtherSampleDesc = (
7664             PROCESS_PROC => \&ProcessHybrid,
7665             4 => {
7666             Name => 'OtherFormat',
7667             Format => 'undef[4]',
7668             RawConv => '$$self{MetaFormat} = $val', # (yes, use MetaFormat for this too)
7669             },
7670             24 => {
7671             Condition => '$$self{MetaFormat} eq "tmcd"',
7672             Name => 'PlaybackFrameRate', # (may differ from recorded FrameRate eg. ../pics/FujiFilmX-H1.mov)
7673             Format => 'rational64u',
7674             },
7675             #
7676             # Observed offsets for child atoms of various OtherFormat types:
7677             #
7678             # OtherFormat Offset Child atoms
7679             # ----------- ------ ----------------
7680             # avc1 86 avcC
7681             # mp4a 36 esds
7682             # mp4s 16 esds
7683             # tmcd 34 name
7684             # data - -
7685             #
7686             ftab => { Name => 'FontTable', Format => 'undef', ValueConv => 'substr($val, 5)' },
7687             name => { Name => 'OtherName', Format => 'undef', ValueConv => 'substr($val, 4)' },
7688             # mrlh = GM header?
7689             # mrlv = GM data
7690             # mrld = GM data (448-byte records):
7691             # 0 - int32u count
7692             # 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=%
7693             # 8 - int32u ? (0,1,3,4,5)
7694             # 12 - string[64] units
7695             # 76 - int32u ? (1,3,7,15)
7696             # 80 - int32u 0
7697             # 84 - undef[4] ?
7698             # 88 - int16u[6] ?
7699             # 100 - undef[32] ?
7700             # 132 - string[64] measurement name
7701             # 196 - string[64] measurement name
7702             );
7703              
7704             # MP4 data information box (ref 5)
7705             %Image::ExifTool::QuickTime::DataInfo = (
7706             PROCESS_PROC => \&ProcessMOV,
7707             WRITE_PROC => \&WriteQuickTime, # (necessary to parse dref even though we don't change it)
7708             NOTES => 'MP4 data information box.',
7709             dref => {
7710             Name => 'DataRef',
7711             SubDirectory => {
7712             TagTable => 'Image::ExifTool::QuickTime::DataRef',
7713             Start => 8,
7714             },
7715             },
7716             );
7717              
7718             # Generic media header
7719             %Image::ExifTool::QuickTime::GenMediaHeader = (
7720             PROCESS_PROC => \&ProcessMOV,
7721             gmin => {
7722             Name => 'GenMediaInfo',
7723             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::GenMediaInfo' },
7724             },
7725             text => {
7726             Name => 'Text',
7727             Flags => ['Binary','Unknown'],
7728             },
7729             tmcd => {
7730             Name => 'TimeCode',
7731             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TimeCode' },
7732             },
7733             );
7734              
7735             # TimeCode header
7736             %Image::ExifTool::QuickTime::TimeCode = (
7737             PROCESS_PROC => \&ProcessMOV,
7738             tcmi => {
7739             Name => 'TCMediaInfo',
7740             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TCMediaInfo' },
7741             },
7742             );
7743              
7744             # TimeCode media info (ref 12)
7745             %Image::ExifTool::QuickTime::TCMediaInfo = (
7746             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
7747             GROUPS => { 2 => 'Video' },
7748             4 => {
7749             Name => 'TextFont',
7750             Format => 'int16u',
7751             PrintConv => { 0 => 'System' },
7752             },
7753             6 => {
7754             Name => 'TextFace',
7755             Format => 'int16u',
7756             PrintConv => {
7757             0 => 'Plain',
7758             BITMASK => {
7759             0 => 'Bold',
7760             1 => 'Italic',
7761             2 => 'Underline',
7762             3 => 'Outline',
7763             4 => 'Shadow',
7764             5 => 'Condense',
7765             6 => 'Extend',
7766             },
7767             },
7768             },
7769             8 => {
7770             Name => 'TextSize',
7771             Format => 'int16u',
7772             },
7773             # 10 - reserved
7774             12 => {
7775             Name => 'TextColor',
7776             Format => 'int16u[3]',
7777             },
7778             18 => {
7779             Name => 'BackgroundColor',
7780             Format => 'int16u[3]',
7781             },
7782             24 => {
7783             Name => 'FontName',
7784             Format => 'pstring',
7785             ValueConv => '$self->Decode($val, $self->Options("CharsetQuickTime"))',
7786             },
7787             );
7788              
7789             # Generic media info (ref http://sourceforge.jp/cvs/view/ntvrec/ntvrec/libqtime/gmin.h?view=co)
7790             %Image::ExifTool::QuickTime::GenMediaInfo = (
7791             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
7792             GROUPS => { 2 => 'Video' },
7793             0 => 'GenMediaVersion',
7794             1 => { Name => 'GenFlags', Format => 'int8u[3]' },
7795             4 => { Name => 'GenGraphicsMode',
7796             Format => 'int16u',
7797             PrintHex => 1,
7798             SeparateTable => 'GraphicsMode',
7799             PrintConv => \%graphicsMode,
7800             },
7801             6 => { Name => 'GenOpColor', Format => 'int16u[3]' },
7802             12 => { Name => 'GenBalance', Format => 'fixed16s' },
7803             );
7804              
7805             # MP4 data reference box (ref 5)
7806             %Image::ExifTool::QuickTime::DataRef = (
7807             PROCESS_PROC => \&ProcessMOV,
7808             WRITE_PROC => \&WriteQuickTime, # (necessary to parse dref even though we don't change it)
7809             NOTES => 'MP4 data reference box.',
7810             'url ' => {
7811             Name => 'URL',
7812             Format => 'undef', # (necessary to prevent decoding as string!)
7813             RawConv => q{
7814             # ignore if self-contained (flags bit 0 set)
7815             return undef if unpack("N",$val) & 0x01;
7816             $_ = substr($val,4); s/\0.*//s; $_;
7817             },
7818             },
7819             "url\0" => { # (written by GoPro)
7820             Name => 'URL',
7821             Format => 'undef', # (necessary to prevent decoding as string!)
7822             RawConv => q{
7823             # ignore if self-contained (flags bit 0 set)
7824             return undef if unpack("N",$val) & 0x01;
7825             $_ = substr($val,4); s/\0.*//s; $_;
7826             },
7827             },
7828             'urn ' => {
7829             Name => 'URN',
7830             Format => 'undef', # (necessary to prevent decoding as string!)
7831             RawConv => q{
7832             return undef if unpack("N",$val) & 0x01;
7833             $_ = substr($val,4); s/\0+/; /; s/\0.*//s; $_;
7834             },
7835             },
7836             );
7837              
7838             # MP4 handler box (ref 5)
7839             %Image::ExifTool::QuickTime::Handler = (
7840             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
7841             GROUPS => { 2 => 'Video' },
7842             4 => { #PH
7843             Name => 'HandlerClass',
7844             Format => 'undef[4]',
7845             RawConv => '$val eq "\0\0\0\0" ? undef : $val',
7846             PrintConv => {
7847             mhlr => 'Media Handler',
7848             dhlr => 'Data Handler',
7849             },
7850             },
7851             8 => {
7852             Name => 'HandlerType',
7853             Format => 'undef[4]',
7854             RawConv => q{
7855             $$self{HandlerType} = $val unless $val eq 'alis' or $val eq 'url ';
7856             $$self{HasHandler}{$val} = 1; # remember all our handlers
7857             return $val;
7858             },
7859             PrintConvColumns => 2,
7860             PrintConv => {
7861             alis => 'Alias Data', #PH
7862             crsm => 'Clock Reference', #3
7863             hint => 'Hint Track',
7864             ipsm => 'IPMP', #3
7865             m7sm => 'MPEG-7 Stream', #3
7866             meta => 'NRT Metadata', #PH
7867             mdir => 'Metadata', #3
7868             mdta => 'Metadata Tags', #PH
7869             mjsm => 'MPEG-J', #3
7870             ocsm => 'Object Content', #3
7871             odsm => 'Object Descriptor', #3
7872             priv => 'Private', #PH
7873             sdsm => 'Scene Description', #3
7874             soun => 'Audio Track',
7875             text => 'Text', #PH (but what type? subtitle?)
7876             tmcd => 'Time Code', #PH
7877             'url '=> 'URL', #3
7878             vide => 'Video Track',
7879             subp => 'Subpicture', #http://www.google.nl/patents/US7778526
7880             nrtm => 'Non-Real Time Metadata', #PH (Sony ILCE-7S) [how is this different from "meta"?]
7881             pict => 'Picture', # (HEIC images)
7882             camm => 'Camera Metadata', # (Insta360 MP4)
7883             psmd => 'Panasonic Static Metadata', #PH (Leica C-Lux CAM-DC25)
7884             data => 'Data', #PH (GPS and G-sensor data from DataKam)
7885             sbtl => 'Subtitle', #PH (TomTom Bandit Action Cam)
7886             },
7887             },
7888             12 => { #PH
7889             Name => 'HandlerVendorID',
7890             Format => 'undef[4]',
7891             RawConv => '$val eq "\0\0\0\0" ? undef : $val',
7892             PrintConv => \%vendorID,
7893             SeparateTable => 'VendorID',
7894             },
7895             24 => {
7896             Name => 'HandlerDescription',
7897             Format => 'string',
7898             # (sometimes this is a Pascal string, and sometimes it is a C string)
7899             RawConv => q{
7900             $val=substr($val,1,ord($1)) if $val=~/^([\0-\x1f])/ and ord($1)
7901             length $val ? $val : undef;
7902             },
7903             },
7904             );
7905              
7906             # Flip uuid data (ref PH)
7907             %Image::ExifTool::QuickTime::Flip = (
7908             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
7909             FORMAT => 'int32u',
7910             FIRST_ENTRY => 0,
7911             NOTES => 'Found in MP4 files from Flip Video cameras.',
7912             GROUPS => { 1 => 'MakerNotes', 2 => 'Image' },
7913             1 => 'PreviewImageWidth',
7914             2 => 'PreviewImageHeight',
7915             13 => 'PreviewImageLength',
7916             14 => { # (confirmed for FlipVideoMinoHD)
7917             Name => 'SerialNumber',
7918             Groups => { 2 => 'Camera' },
7919             Format => 'string[16]',
7920             },
7921             28 => {
7922             Name => 'PreviewImage',
7923             Groups => { 2 => 'Preview' },
7924             Format => 'undef[$val{13}]',
7925             RawConv => '$self->ValidateImage(\$val, $tag)',
7926             },
7927             );
7928              
7929             # atoms in Pittasoft "free" atom
7930             %Image::ExifTool::QuickTime::Pittasoft = (
7931             PROCESS_PROC => \&ProcessMOV,
7932             NOTES => 'Tags found in Pittasoft Blackvue dashcam "free" data.',
7933             cprt => 'Copyright',
7934             thum => {
7935             Name => 'PreviewImage',
7936             Groups => { 2 => 'Preview' },
7937             Binary => 1,
7938             RawConv => q{
7939             return undef unless length $val > 4;
7940             my $len = unpack('N', $val);
7941             return undef unless length $val >= 4 + $len;
7942             return substr($val, 4, $len);
7943             },
7944             },
7945             ptnm => {
7946             Name => 'OriginalFileName',
7947             ValueConv => 'substr($val, 4, -1)',
7948             },
7949             ptrh => {
7950             SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' },
7951             # contains these atoms:
7952             # ptvi - 27 bytes: '..avc1...'
7953             # ptso - 16 bytes: '..mp4a...'
7954             },
7955             'gps ' => {
7956             Name => 'GPSLog',
7957             Binary => 1, # (ASCII NMEA track log with leading timestamps)
7958             Notes => 'parsed to extract GPS separately when ExtractEmbedded is used',
7959             RawConv => q{
7960             $val =~ s/\0+$//; # remove trailing nulls
7961             if (length $val and $$self{OPTIONS}{ExtractEmbedded}) {
7962             my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
7963             Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl);
7964             }
7965             return $val;
7966             },
7967             },
7968             '3gf ' => {
7969             Name => 'AccelData',
7970             SubDirectory => {
7971             TagTable => 'Image::ExifTool::QuickTime::Stream',
7972             ProcessProc => \&Process_3gf,
7973             },
7974             },
7975             sttm => {
7976             Name => 'StartTime',
7977             Format => 'int64u',
7978             Groups => { 2 => 'Time' },
7979             RawConv => '$$self{StartTime} = $val',
7980             # (ms since Jan 1, 1970, in local time zone - PH)
7981             ValueConv => q{
7982             my $secs = int($val / 1000);
7983             return ConvertUnixTime($secs) . sprintf(".%03d",$val - $secs * 1000);
7984             },
7985             PrintConv => '$self->ConvertDateTime($val)',
7986             },
7987             );
7988              
7989             # QuickTime composite tags
7990             %Image::ExifTool::QuickTime::Composite = (
7991             GROUPS => { 2 => 'Video' },
7992             Rotation => {
7993             Notes => q{
7994             writing this tag updates QuickTime MatrixStructure for all tracks with a
7995             non-zero image size
7996             },
7997             Require => {
7998             0 => 'QuickTime:MatrixStructure',
7999             1 => 'QuickTime:HandlerType',
8000             },
8001             Writable => 1,
8002             Protected => 1,
8003             WriteAlso => {
8004             MatrixStructure => 'Image::ExifTool::QuickTime::GetRotationMatrix($val)',
8005             },
8006             ValueConv => 'Image::ExifTool::QuickTime::CalcRotation($self)',
8007             ValueConvInv => '$val',
8008             },
8009             AvgBitrate => {
8010             Priority => 0, # let QuickTime::AvgBitrate take priority
8011             Require => {
8012             0 => 'QuickTime::MediaDataSize',
8013             1 => 'QuickTime::Duration',
8014             },
8015             RawConv => q{
8016             return undef unless $val[1];
8017             $val[1] /= $$self{TimeScale} if $$self{TimeScale};
8018             my $key = 'MediaDataSize';
8019             my $size = $val[0];
8020             for (;;) {
8021             $key = $self->NextTagKey($key) or last;
8022             $size += $self->GetValue($key, 'ValueConv');
8023             }
8024             return int($size * 8 / $val[1] + 0.5);
8025             },
8026             PrintConv => 'ConvertBitrate($val)',
8027             },
8028             GPSLatitude => {
8029             Require => 'QuickTime:GPSCoordinates',
8030             Groups => { 2 => 'Location' },
8031             ValueConv => 'my @c = split " ", $val; $c[0]',
8032             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
8033             },
8034             GPSLongitude => {
8035             Require => 'QuickTime:GPSCoordinates',
8036             Groups => { 2 => 'Location' },
8037             ValueConv => 'my @c = split " ", $val; $c[1]',
8038             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
8039             },
8040             # split altitude into GPSAltitude/GPSAltitudeRef like EXIF and XMP
8041             GPSAltitude => {
8042             Require => 'QuickTime:GPSCoordinates',
8043             Groups => { 2 => 'Location' },
8044             Priority => 0, # (because it may not exist)
8045             ValueConv => 'my @c = split " ", $val; defined $c[2] ? abs($c[2]) : undef',
8046             PrintConv => '"$val m"',
8047             },
8048             GPSAltitudeRef => {
8049             Require => 'QuickTime:GPSCoordinates',
8050             Groups => { 2 => 'Location' },
8051             Priority => 0, # (because altitude information may not exist)
8052             ValueConv => 'my @c = split " ", $val; defined $c[2] ? ($c[2] < 0 ? 1 : 0) : undef',
8053             PrintConv => {
8054             0 => 'Above Sea Level',
8055             1 => 'Below Sea Level',
8056             },
8057             },
8058             GPSLatitude2 => {
8059             Name => 'GPSLatitude',
8060             Require => 'QuickTime:LocationInformation',
8061             Groups => { 2 => 'Location' },
8062             ValueConv => '$val =~ /Lat=([-+.\d]+)/; $1',
8063             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
8064             },
8065             GPSLongitude2 => {
8066             Name => 'GPSLongitude',
8067             Require => 'QuickTime:LocationInformation',
8068             Groups => { 2 => 'Location' },
8069             ValueConv => '$val =~ /Lon=([-+.\d]+)/; $1',
8070             PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
8071             },
8072             GPSAltitude2 => {
8073             Name => 'GPSAltitude',
8074             Require => 'QuickTime:LocationInformation',
8075             Groups => { 2 => 'Location' },
8076             ValueConv => '$val =~ /Alt=([-+.\d]+)/; abs($1)',
8077             PrintConv => '"$val m"',
8078             },
8079             GPSAltitudeRef2 => {
8080             Name => 'GPSAltitudeRef',
8081             Require => 'QuickTime:LocationInformation',
8082             Groups => { 2 => 'Location' },
8083             ValueConv => '$val =~ /Alt=([-+.\d]+)/; $1 < 0 ? 1 : 0',
8084             PrintConv => {
8085             0 => 'Above Sea Level',
8086             1 => 'Below Sea Level',
8087             },
8088             },
8089             CDDBDiscPlayTime => {
8090             Require => 'CDDB1Info',
8091             Groups => { 2 => 'Audio' },
8092             ValueConv => '$val =~ /^..([a-z0-9]{4})/i ? hex($1) : undef',
8093             PrintConv => 'ConvertDuration($val)',
8094             },
8095             CDDBDiscTracks => {
8096             Require => 'CDDB1Info',
8097             Groups => { 2 => 'Audio' },
8098             ValueConv => '$val =~ /^.{6}([a-z0-9]{2})/i ? hex($1) : undef',
8099             },
8100             );
8101              
8102             # add our composite tags
8103             Image::ExifTool::AddCompositeTags('Image::ExifTool::QuickTime');
8104              
8105              
8106             #------------------------------------------------------------------------------
8107             # AutoLoad our routines when necessary
8108             #
8109             sub AUTOLOAD
8110             {
8111             # (Note: no need to autoload routines in QuickTimeStream that use Stream table)
8112 22 50   22   145 if ($AUTOLOAD eq 'Image::ExifTool::QuickTime::Process_mebx') {
8113 0         0 require 'Image/ExifTool/QuickTimeStream.pl';
8114 30     30   439 no strict 'refs';
  30         87  
  30         413287  
8115 0         0 return &$AUTOLOAD(@_);
8116             } else {
8117 22         187 return Image::ExifTool::DoAutoLoad($AUTOLOAD, @_);
8118             }
8119             }
8120              
8121             #------------------------------------------------------------------------------
8122             # Get rotation matrix
8123             # Inputs: 0) angle in degrees
8124             # Returns: 9-element rotation matrix as a string (with 0 x/y offsets)
8125             sub GetRotationMatrix($)
8126             {
8127 1     1 0 7 my $ang = 3.14159265358979323846264 * shift() / 180;
8128 1         30 my $cos = cos $ang;
8129 1         5 my $sin = sin $ang;
8130             # round to zero
8131 1 50       6 $cos = 0 if abs($cos) < 1e-12;
8132 1 50       6 $sin = 0 if abs($sin) < 1e-12;
8133 1         3 my $msn = -$sin;
8134 1         14 return "$cos $sin 0 $msn $cos 0 0 0 1";
8135             }
8136              
8137             #------------------------------------------------------------------------------
8138             # Get rotation angle from a matrix
8139             # Inputs: 0) rotation matrix as a string
8140             # Return: positive rotation angle in degrees rounded to 3 decimal points,
8141             # or undef on error
8142             sub GetRotationAngle($)
8143             {
8144 5     5 0 15 my $rotMatrix = shift;
8145 5         51 my @a = split ' ', $rotMatrix;
8146 5 50 66     32 return undef if $a[0]==0 and $a[1]==0;
8147             # calculate the rotation angle (assume uniform rotation)
8148 5         42 my $angle = atan2($a[1], $a[0]) * 180 / 3.14159;
8149 5 100       20 $angle += 360 if $angle < 0;
8150 5         65 return int($angle * 1000 + 0.5) / 1000;
8151             }
8152              
8153             #------------------------------------------------------------------------------
8154             # Calculate rotation of video track
8155             # Inputs: 0) ExifTool object ref
8156             # Returns: rotation angle or undef
8157             sub CalcRotation($)
8158             {
8159 5     5 0 22 my $et = shift;
8160 5         16 my $value = $$et{VALUE};
8161 5         16 my ($i, $track);
8162             # get the video track family 1 group (eg. "Track1");
8163 5         15 for ($i=0; ; ++$i) {
8164 11 100       47 my $idx = $i ? " ($i)" : '';
8165 11         28 my $tag = "HandlerType$idx";
8166 11 100       41 last unless $$value{$tag};
8167 10 100       38 next unless $$value{$tag} eq 'vide';
8168 4         26 $track = $et->GetGroup($tag, 1);
8169 4         10 last;
8170             }
8171 5 100       25 return undef unless $track;
8172             # get the video track matrix
8173 4         13 for ($i=0; ; ++$i) {
8174 12 100       65 my $idx = $i ? " ($i)" : '';
8175 12         29 my $tag = "MatrixStructure$idx";
8176 12 50       49 last unless $$value{$tag};
8177 12 100       38 next unless $et->GetGroup($tag, 1) eq $track;
8178 4         29 return GetRotationAngle($$value{$tag});
8179             }
8180 0         0 return undef;
8181             }
8182              
8183             #------------------------------------------------------------------------------
8184             # Get MatrixStructure for a given rotation angle
8185             # Inputs: 0) rotation angle (deg), 1) ExifTool ref
8186             # Returns: matrix structure as a string, or undef if it can't be rotated
8187             # - requires ImageSizeLookahead to determine the video image size, and doesn't
8188             # rotate matrix unless image size is valid
8189             sub GetMatrixStructure($$)
8190             {
8191 2     2 0 6 my ($val, $et) = @_;
8192 2         14 my @a = split ' ', $val;
8193             # pass straight through if it already has an offset
8194 2 50 33     13 return $val unless $a[6] == 0 and $a[7] == 0;
8195 2         36 my @s = split ' ', $$et{ImageSizeLookahead};
8196 2         11 my ($w, $h) = @s[12,13];
8197 2 100 66     14 return undef unless $w and $h; # don't rotate 0-sized track
8198 1         7 $_ = Image::ExifTool::QuickTime::FixWrongFormat($_) foreach $w,$h;
8199             # apply necessary offsets for the standard rotations
8200 1         6 my $angle = GetRotationAngle($val);
8201 1 50       6 return undef unless defined $angle;
8202 1 50       9 if ($angle == 90) {
    50          
    50          
8203 0         0 @a[6,7] = ($h, 0);
8204             } elsif ($angle == 180) {
8205 0         0 @a[6,7] = ($w, $h);
8206             } elsif ($angle == 270) {
8207 1         5 @a[6,7] = (0, $w);
8208             }
8209 1         8 return "@a";
8210             }
8211              
8212             #------------------------------------------------------------------------------
8213             # Determine the average sample rate from a time-to-sample table
8214             # Inputs: 0) ExifTool object ref, 1) time-to-sample table data ref
8215             # Returns: average sample rate (in Hz)
8216             sub CalcSampleRate($$)
8217             {
8218 21     21 0 87 my ($et, $valPt) = @_;
8219 21         107 my @dat = unpack('N*', $$valPt);
8220 21         64 my ($num, $dur) = (0, 0);
8221 21         39 my $i;
8222 21         98 for ($i=2; $i<@dat-1; $i+=2) {
8223 21         56 $num += $dat[$i]; # total number of samples
8224 21         89 $dur += $dat[$i] * $dat[$i+1]; # total sample duration
8225             }
8226 21 50 33     187 return undef unless $num and $dur and $$et{MediaTS};
      33        
8227 21         233 return $num * $$et{MediaTS} / $dur;
8228             }
8229              
8230             #------------------------------------------------------------------------------
8231             # Fix incorrect format for ImageWidth/Height as written by Pentax
8232             sub FixWrongFormat($)
8233             {
8234 78     78 0 149 my $val = shift;
8235 78 100       219 return undef unless $val;
8236 44 50       259 return $val & 0xfff00000 ? unpack('n',pack('N',$val)) : $val;
8237             }
8238              
8239             #------------------------------------------------------------------------------
8240             # Convert ISO 6709 string to standard lag/lon format
8241             # Inputs: 0) ISO 6709 string (lat, lon, and optional alt)
8242             # Returns: position in decimal degrees with altitude if available
8243             # Notes: Wikipedia indicates altitude may be in feet -- how is this specified?
8244             sub ConvertISO6709($)
8245             {
8246 0     0 0 0 my $val = shift;
8247 0 0       0 if ($val =~ /^([-+]\d{1,2}(?:\.\d*)?)([-+]\d{1,3}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) {
    0          
    0          
8248             # +DD.DDD+DDD.DDD+AA.AAA
8249 0         0 $val = ($1 + 0) . ' ' . ($2 + 0);
8250 0 0       0 $val .= ' ' . ($3 + 0) if $3;
8251             } elsif ($val =~ /^([-+])(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) {
8252             # +DDMM.MMM+DDDMM.MMM+AA.AAA
8253 0         0 my $lat = $2 + $3 / 60;
8254 0 0       0 $lat = -$lat if $1 eq '-';
8255 0         0 my $lon = $5 + $6 / 60;
8256 0 0       0 $lon = -$lon if $4 eq '-';
8257 0         0 $val = "$lat $lon";
8258 0 0       0 $val .= ' ' . ($7 + 0) if $7;
8259             } elsif ($val =~ /^([-+])(\d{2})(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2})(\d{2}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) {
8260             # +DDMMSS.SSS+DDDMMSS.SSS+AA.AAA
8261 0         0 my $lat = $2 + $3 / 60 + $4 / 3600;
8262 0 0       0 $lat = -$lat if $1 eq '-';
8263 0         0 my $lon = $6 + $7 / 60 + $8 / 3600;
8264 0 0       0 $lon = -$lon if $5 eq '-';
8265 0         0 $val = "$lat $lon";
8266 0 0       0 $val .= ' ' . ($9 + 0) if $9;
8267             }
8268 0         0 return $val;
8269             }
8270              
8271             #------------------------------------------------------------------------------
8272             # Convert Nero chapter list (ref ffmpeg libavformat/movenc.c)
8273             # Inputs: 0) binary chpl data
8274             # Returns: chapter list
8275             sub ConvertChapterList($)
8276             {
8277 0     0 0 0 my $val = shift;
8278 0         0 my $size = length $val;
8279 0 0       0 return '' if $size < 9;
8280 0         0 my $num = Get8u(\$val, 8);
8281 0         0 my ($i, @chapters);
8282 0         0 my $pos = 9;
8283 0         0 for ($i=0; $i<$num; ++$i) {
8284 0 0       0 last if $pos + 9 > $size;
8285 0         0 my $dur = Get64u(\$val, $pos) / 10000000;
8286 0         0 my $len = Get8u(\$val, $pos + 8);
8287 0 0       0 last if $pos + 9 + $len > $size;
8288 0         0 my $title = substr($val, $pos + 9, $len);
8289 0         0 $pos += 9 + $len;
8290 0         0 push @chapters, "$dur $title";
8291             }
8292 0         0 return \@chapters; # return as a list
8293             }
8294              
8295             #------------------------------------------------------------------------------
8296             # Print conversion for a Nero chapter list item
8297             # Inputs: 0) ValueConv chapter string
8298             # Returns: formatted chapter string
8299             sub PrintChapter($)
8300             {
8301 0     0 0 0 my $val = shift;
8302 0 0       0 $val =~ /^(\S+) (.*)/ or return $val;
8303 0         0 my ($dur, $title) = ($1, $2);
8304 0         0 my $h = int($dur / 3600);
8305 0         0 $dur -= $h * 3600;
8306 0         0 my $m = int($dur / 60);
8307 0         0 my $s = $dur - $m * 60;
8308 0         0 my $ss = sprintf('%06.3f', $s);
8309 0 0       0 if ($ss >= 60) {
8310 0         0 $ss = '00.000';
8311 0 0       0 ++$m >= 60 and $m -= 60, ++$h;
8312             }
8313 0         0 return sprintf("[%d:%.2d:%s] %s",$h,$m,$ss,$title);
8314             }
8315              
8316             #------------------------------------------------------------------------------
8317             # Format GPSCoordinates for printing
8318             # Inputs: 0) string with numerical lat, lon and optional alt, separated by spaces
8319             # 1) ExifTool object reference
8320             # Returns: PrintConv value
8321             sub PrintGPSCoordinates($)
8322             {
8323 0     0 0 0 my ($val, $et) = @_;
8324 0         0 my @v = split ' ', $val;
8325 0         0 my $prt = Image::ExifTool::GPS::ToDMS($et, $v[0], 1, "N") . ', ' .
8326             Image::ExifTool::GPS::ToDMS($et, $v[1], 1, "E");
8327 0 0       0 if (defined $v[2]) {
8328 0 0       0 $prt .= ', ' . ($v[2] < 0 ? -$v[2] . ' m Below' : $v[2] . ' m Above') . ' Sea Level';
8329             }
8330 0         0 return $prt;
8331             }
8332              
8333             #------------------------------------------------------------------------------
8334             # Unpack packed ISO 639/T language code
8335             # Inputs: 0) packed language code (or undef/0), 1) true to not treat 'und' and 'eng' as default
8336             # Returns: language code, or undef/0 for default language, or 'err' for format error
8337             sub UnpackLang($;$)
8338             {
8339 10     10 0 21 my ($lang, $noDef) = @_;
8340 10 50       24 if ($lang) {
8341             # language code is packed in 5-bit characters
8342 10         21 $lang = pack 'C*', map { (($lang>>$_)&0x1f)+0x60 } 10, 5, 0;
  30         90  
8343             # validate language code
8344 10 50       66 if ($lang =~ /^[a-z]+$/) {
8345             # treat 'eng' or 'und' as the default language
8346 10 50 66     53 undef $lang if ($lang eq 'und' or $lang eq 'eng') and not $noDef;
      66        
8347             } else {
8348 0         0 $lang = 'err'; # invalid language code
8349             }
8350             }
8351 10         35 return $lang;
8352             }
8353              
8354             #------------------------------------------------------------------------------
8355             # Get language code string given QuickTime language and country codes
8356             # Inputs: 0) numerical language code, 1) numerical country code, 2) no defaults
8357             # Returns: language code string (ie. "fra-FR") or undef for default language
8358             sub GetLangCode($;$$)
8359             {
8360 6     6 0 17 my ($lang, $ctry, $noDef) = @_;
8361             # ignore country ('ctry') and language lists ('lang') for now
8362 6 50 66     31 undef $ctry if $ctry and $ctry <= 255;
8363 6 50 33     24 undef $lang if $lang and $lang <= 255;
8364 6         18 $lang = UnpackLang($lang, $noDef);
8365             # add country code if specified
8366 6 100       18 if ($ctry) {
8367 1         5 $ctry = unpack('a2',pack('n',$ctry)); # unpack as ISO 3166-1
8368             # treat 'ZZ' like a default country (see ref 12)
8369 1 50       5 undef $ctry if $ctry eq 'ZZ';
8370 1 50 33     10 if ($ctry and $ctry =~ /^[A-Z]{2}$/) {
8371 1 50       4 $lang or $lang = 'und';
8372 1         3 $lang .= "-$ctry";
8373             }
8374             }
8375 6         17 return $lang;
8376             }
8377              
8378             #------------------------------------------------------------------------------
8379             # Get langInfo hash and save details about alt-lang tags
8380             # Inputs: 0) ExifTool ref, 1) tagInfo hash ref, 2) locale code
8381             # Returns: new tagInfo hash ref, or undef if invalid
8382             sub GetLangInfoQT($$$)
8383             {
8384 1     1 0 4 my ($et, $tagInfo, $langCode) = @_;
8385 1         5 my $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $langCode);
8386 1 50       5 if ($langInfo) {
8387 1 50       5 $$et{QTLang} or $$et{QTLang} = [ ];
8388 1         3 push @{$$et{QTLang}}, $$langInfo{Name};
  1         5  
8389             }
8390 1         3 return $langInfo;
8391             }
8392              
8393             #------------------------------------------------------------------------------
8394             # Get variable-length integer from data (used by ParseItemLocation)
8395             # Inputs: 0) data ref, 1) start position, 2) integer size in bytes (0, 4 or 8),
8396             # 3) default value
8397             # Returns: integer value, and updates current position
8398             sub GetVarInt($$$;$)
8399             {
8400 78     78 0 159 my ($dataPt, $pos, $n, $default) = @_;
8401 78         120 my $len = length $$dataPt;
8402 78         115 $_[1] = $pos + $n; # update current position
8403 78 50       152 return undef if $pos + $n > $len;
8404 78 50       161 if ($n == 0) {
    50          
    0          
8405 0   0     0 return $default || 0;
8406             } elsif ($n == 4) {
8407 78         168 return Get32u($dataPt, $pos);
8408             } elsif ($n == 8) {
8409 0         0 return Get64u($dataPt, $pos);
8410             }
8411 0         0 return undef;
8412             }
8413              
8414             #------------------------------------------------------------------------------
8415             # Get null-terminated string from binary data (used by ParseItemInfoEntry)
8416             # Inputs: 0) data ref, 1) start position
8417             # Returns: string, and updates current position
8418             sub GetString($$)
8419             {
8420 30     30 0 55 my ($dataPt, $pos) = @_;
8421 30         59 my $len = length $$dataPt;
8422 30         48 my $str = '';
8423 30         70 while ($pos < $len) {
8424 240         330 my $ch = substr($$dataPt, $pos, 1);
8425 240         304 ++$pos;
8426 240 100       416 last if ord($ch) == 0;
8427 215         385 $str .= $ch;
8428             }
8429 30         55 $_[1] = $pos; # update current position
8430 30         92 return $str;
8431             }
8432              
8433             #------------------------------------------------------------------------------
8434             # Get a printable version of the tag ID
8435             # Inputs: 0) tag ID, 1) Flag: 0x01 - print as 4- or 8-digit hex value if necessary
8436             # 0x02 - put leading backslash before escaped character
8437             # Returns: Printable tag ID
8438             sub PrintableTagID($;$)
8439             {
8440 22     22 0 47 my $tag = $_[0];
8441 22         75 my $n = ($tag =~ s/([\x00-\x1f\x7f-\xff])/'x'.unpack('H*',$1)/eg);
  0         0  
8442 22 0 33     65 if ($n and $_[1]) {
8443 0 0 0     0 if ($n > 2 and $_[1] & 0x01) {
    0          
8444 0         0 $tag = '0x' . unpack('H8', $_[0]);
8445 0         0 $tag =~ s/^0x0000/0x/;
8446             } elsif ($_[1] & 0x02) {
8447 0         0 ($tag = $_[0]) =~ s/([\x00-\x1f\x7f-\xff])/'\\x'.unpack('H*',$1)/eg;
  0         0  
8448             }
8449             }
8450 22         58 return $tag;
8451             }
8452              
8453             #==============================================================================
8454             # The following ParseXxx routines parse various boxes to extract this
8455             # information about embedded items in a $$et{ItemInfo} hash, keyed by item ID:
8456             #
8457             # iloc:
8458             # ConstructionMethod - offset type: 0=file, 1=idat, 2=item
8459             # DataReferenceIndex - 0 for "this file", otherwise index in dref box
8460             # BaseOffset - base for file offsets
8461             # Extents - list of details for data in file:
8462             # 0) index (extent_index)
8463             # 1) offset (extent_offset)
8464             # 2) length (extent_length)
8465             # 3) nlen (length_size)
8466             # 4) lenPt (pointer to length word)
8467             # infe:
8468             # ProtectionIndex - index if item is protected (0 for unprotected)
8469             # Name - item name
8470             # ContentType - mime type of item
8471             # ContentEncoding - item encoding
8472             # URI - URI of a 'uri '-type item
8473             # ipma:
8474             # Association - list of associated properties in the ipco container
8475             # Essential - list of "essential" flags for the associated properties
8476             # cdsc:
8477             # RefersTo - hash lookup of flags based on referred item ID
8478             # other:
8479             # DocNum - exiftool document number for this item
8480             #
8481             #------------------------------------------------------------------------------
8482             # Parse item location (iloc) box (ref ISO 14496-12:2015 pg.79)
8483             # Inputs: 0) iloc data, 1) ExifTool ref
8484             # Returns: undef, and fills in ExifTool ItemInfo hash
8485             # Notes: see also Handle_iloc() in WriteQuickTime.pl
8486             sub ParseItemLocation($$)
8487             {
8488 6     6 0 24 my ($val, $et) = @_;
8489 6         27 my ($i, $j, $num, $pos, $id);
8490 6         0 my ($extent_index, $extent_offset, $extent_length);
8491              
8492 6 100       31 my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose');
8493 6   50     57 my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { });
8494 6         19 my $len = length $val;
8495 6 50       22 return undef if $len < 8;
8496 6         24 my $ver = Get8u(\$val, 0);
8497 6         23 my $siz = Get16u(\$val, 4);
8498 6         22 my $noff = ($siz >> 12);
8499 6         26 my $nlen = ($siz >> 8) & 0x0f;
8500 6         20 my $nbas = ($siz >> 4) & 0x0f;
8501 6         13 my $nind = $siz & 0x0f;
8502 6 50       23 if ($ver < 2) {
8503 6         16 $num = Get16u(\$val, 6);
8504 6         16 $pos = 8;
8505             } else {
8506 0 0       0 return undef if $len < 10;
8507 0         0 $num = Get32u(\$val, 6);
8508 0         0 $pos = 10;
8509             }
8510 6         30 for ($i=0; $i<$num; ++$i) {
8511 20 50       42 if ($ver < 2) {
8512 20 50       54 return undef if $pos + 2 > $len;
8513 20         46 $id = Get16u(\$val, $pos);
8514 20         38 $pos += 2;
8515             } else {
8516 0 0       0 return undef if $pos + 4 > $len;
8517 0         0 $id = Get32u(\$val, $pos);
8518 0         0 $pos += 4;
8519             }
8520 20 50 33     124 if ($ver == 1 or $ver == 2) {
8521 0 0       0 return undef if $pos + 2 > $len;
8522 0         0 $$items{$id}{ConstructionMethod} = Get16u(\$val, $pos) & 0x0f;
8523 0         0 $pos += 2;
8524             }
8525 20 50       53 return undef if $pos + 2 > $len;
8526 20         51 $$items{$id}{DataReferenceIndex} = Get16u(\$val, $pos);
8527 20         43 $pos += 2;
8528 20         47 $$items{$id}{BaseOffset} = GetVarInt(\$val, $pos, $nbas);
8529 20 50       66 return undef if $pos + 2 > $len;
8530 20         48 my $ext_num = Get16u(\$val, $pos);
8531 20         35 $pos += 2;
8532 20         29 my @extents;
8533 20         51 for ($j=0; $j<$ext_num; ++$j) {
8534 20 50 33     81 if ($ver == 1 or $ver == 2) {
8535 0         0 $extent_index = GetVarInt(\$val, $pos, $nind, 1);
8536             }
8537 20         46 $extent_offset = GetVarInt(\$val, $pos, $noff);
8538 20         50 $extent_length = GetVarInt(\$val, $pos, $nlen);
8539 20 50       49 return undef unless defined $extent_length;
8540             $et->VPrint(1, "$$et{INDENT} Item $id: const_meth=",
8541             defined $$items{$id}{ConstructionMethod} ? $$items{$id}{ConstructionMethod} : '',
8542             sprintf(" base=0x%x offset=0x%x len=0x%x\n", $$items{$id}{BaseOffset},
8543 20 0       43 $extent_offset, $extent_length)) if $verbose;
    50          
8544 20         77 push @extents, [ $extent_index, $extent_offset, $extent_length, $nlen, $pos-$nlen ];
8545             }
8546             # save item location information keyed on 1-based item ID:
8547 20         67 $$items{$id}{Extents} = \@extents;
8548             }
8549 6         23 return undef;
8550             }
8551              
8552             #------------------------------------------------------------------------------
8553             # Parse content describes entry (cdsc) box
8554             # Inputs: 0) cdsc data, 1) ExifTool ref
8555             # Returns: undef, and fills in ExifTool ItemInfo hash
8556             sub ParseContentDescribes($$)
8557             {
8558 8     8 0 29 my ($val, $et) = @_;
8559 8         16 my ($id, $count, @to);
8560 8 50       26 if ($$et{ItemRefVersion}) {
8561 0 0       0 return undef if length $val < 10;
8562 0         0 ($id, $count, @to) = unpack('NnN*', $val);
8563             } else {
8564 8 50       24 return undef if length $val < 6;
8565 8         32 ($id, $count, @to) = unpack('nnn*', $val);
8566             }
8567 8 50       38 if ($count > @to) {
    50          
8568 0         0 my $str = 'Missing values in ContentDescribes box';
8569 0 0       0 $$et{IsWriting} ? $et->Error($str) : $et->Warn($str);
8570             } elsif ($count < @to) {
8571 0         0 $et->Warn('Ignored extra values in ContentDescribes box', 1);
8572 0         0 @to = $count;
8573             }
8574             # add all referenced item ID's to a "RefersTo" lookup
8575 8         49 $$et{ItemInfo}{$id}{RefersTo}{$_} = 1 foreach @to;
8576 8         25 return undef;
8577             }
8578              
8579             #------------------------------------------------------------------------------
8580             # Parse item information entry (infe) box (ref ISO 14496-12:2015 pg.82)
8581             # Inputs: 0) infe data, 1) ExifTool ref
8582             # Returns: undef, and fills in ExifTool ItemInfo hash
8583             sub ParseItemInfoEntry($$)
8584             {
8585 20     20 0 61 my ($val, $et) = @_;
8586 20         34 my $id;
8587              
8588 20 100       72 my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose');
8589 20   50     82 my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { });
8590 20         37 my $len = length $val;
8591 20 50       54 return undef if $len < 4;
8592 20         66 my $ver = Get8u(\$val, 0);
8593 20         39 my $pos = 4;
8594 20 50       55 return undef if $pos + 4 > $len;
8595 20 50 33     81 if ($ver == 0 or $ver == 1) {
8596 0         0 $id = Get16u(\$val, $pos);
8597 0         0 $$items{$id}{ProtectionIndex} = Get16u(\$val, $pos + 2);
8598 0         0 $pos += 4;
8599 0         0 $$items{$id}{Name} = GetString(\$val, $pos);
8600 0         0 $$items{$id}{ContentType} = GetString(\$val, $pos);
8601 0         0 $$items{$id}{ContentEncoding} = GetString(\$val, $pos);
8602             } else {
8603 20 50       52 if ($ver == 2) {
    0          
8604 20         57 $id = Get16u(\$val, $pos);
8605 20         43 $pos += 2;
8606             } elsif ($ver == 3) {
8607 0         0 $id = Get32u(\$val, $pos);
8608 0         0 $pos += 4;
8609             }
8610 20 50       59 return undef if $pos + 6 > $len;
8611 20         51 $$items{$id}{ProtectionIndex} = Get16u(\$val, $pos);
8612 20         46 my $type = substr($val, $pos + 2, 4);
8613 20         52 $$items{$id}{Type} = $type;
8614 20         35 $pos += 6;
8615 20         55 $$items{$id}{Name} = GetString(\$val, $pos);
8616 20 100       83 if ($type eq 'mime') {
    50          
8617 5         19 $$items{$id}{ContentType} = GetString(\$val, $pos);
8618 5         22 $$items{$id}{ContentEncoding} = GetString(\$val, $pos);
8619             } elsif ($type eq 'uri ') {
8620 0         0 $$items{$id}{URI} = GetString(\$val, $pos);
8621             }
8622             }
8623             $et->VPrint(1, "$$et{INDENT} Item $id: Type=", $$items{$id}{Type} || '',
8624             ' Name=', $$items{$id}{Name} || '',
8625 20 50 0     47 ' ContentType=', $$items{$id}{ContentType} || '',
      0        
      0        
8626             "\n") if $verbose > 1;
8627 20         49 return undef;
8628             }
8629              
8630             #------------------------------------------------------------------------------
8631             # Parse item property association (ipma) box (ref https://github.com/gpac/gpac/blob/master/src/isomedia/iff.c)
8632             # Inputs: 0) ipma data, 1) ExifTool ref
8633             # Returns: undef, and fills in ExifTool ItemInfo hash
8634             sub ParseItemPropAssoc($$)
8635             {
8636 6     6 0 34 my ($val, $et) = @_;
8637 6         19 my ($i, $j, $id);
8638              
8639 6 100       34 my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose');
8640 6   50     29 my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { });
8641 6         20 my $len = length $val;
8642 6 50       26 return undef if $len < 8;
8643 6         24 my $ver = Get8u(\$val, 0);
8644 6         21 my $flg = Get32u(\$val, 0);
8645 6         25 my $num = Get32u(\$val, 4);
8646 6         18 my $pos = 8;
8647 6         27 for ($i=0; $i<$num; ++$i) {
8648 12 50       29 if ($ver == 0) {
8649 12 50       45 return undef if $pos + 3 > $len;
8650 12         31 $id = Get16u(\$val, $pos);
8651 12         27 $pos += 2;
8652             } else {
8653 0 0       0 return undef if $pos + 5 > $len;
8654 0         0 $id = Get32u(\$val, $pos);
8655 0         0 $pos += 4;
8656             }
8657 12         32 my $n = Get8u(\$val, $pos++);
8658 12         30 my (@association, @essential);
8659 12 50       36 if ($flg & 0x01) {
8660 0 0       0 return undef if $pos + $n * 2 > $len;
8661 0         0 for ($j=0; $j<$n; ++$j) {
8662 0         0 my $tmp = Get16u(\$val, $pos + $j * 2);
8663 0         0 push @association, $tmp & 0x7fff;
8664 0 0       0 push @essential, ($tmp & 0x8000) ? 1 : 0;
8665             }
8666 0         0 $pos += $n * 2;
8667             } else {
8668 12 50       34 return undef if $pos + $n > $len;
8669 12         40 for ($j=0; $j<$n; ++$j) {
8670 24         57 my $tmp = Get8u(\$val, $pos + $j);
8671 24         54 push @association, $tmp & 0x7f;
8672 24 100       70 push @essential, ($tmp & 0x80) ? 1 : 0;
8673             }
8674 12         33 $pos += $n;
8675             }
8676 12         35 $$items{$id}{Association} = \@association;
8677 12         41 $$items{$id}{Essential} = \@essential;
8678 12 50       48 $et->VPrint(1, "$$et{INDENT} Item $id properties: @association\n") if $verbose > 1;
8679             }
8680 6         21 return undef;
8681             }
8682              
8683             #------------------------------------------------------------------------------
8684             # Process item information now
8685             # Inputs: 0) ExifTool ref
8686             sub HandleItemInfo($)
8687             {
8688 45     45 0 108 my $et = shift;
8689 45         103 my $raf = $$et{RAF};
8690 45         118 my $items = $$et{ItemInfo};
8691 45         183 my $verbose = $et->Options('Verbose');
8692 45         157 my $buff;
8693              
8694             # extract information from EXIF/XMP metadata items
8695 45 100 66     216 if ($items and $raf) {
8696 3         7 push @{$$et{PATH}}, 'ItemInformation';
  3         10  
8697 3         13 my $curPos = $raf->Tell();
8698 3         16 my $primary = $$et{PrimaryItem};
8699 3         4 my $id;
8700 3         27 $et->VerboseDir('Processing items from ItemInformation', scalar(keys %$items));
8701 3         19 foreach $id (sort { $a <=> $b } keys %$items) {
  13         32  
8702 11         32 my $item = $$items{$id};
8703 11   50     49 my $type = $$item{ContentType} || $$item{Type} || next;
8704 11 50       31 if ($verbose) {
8705             # add up total length of this item for the verbose output
8706 0         0 my $len = 0;
8707 0 0 0     0 if ($$item{Extents} and @{$$item{Extents}}) {
  0         0  
8708 0         0 $len += $$_[2] foreach @{$$item{Extents}};
  0         0  
8709             }
8710 0         0 $et->VPrint(0, "$$et{INDENT}Item $id) '${type}' ($len bytes)\n");
8711             }
8712             # get ExifTool name for this item
8713 11   100     63 my $name = { Exif => 'EXIF', 'application/rdf+xml' => 'XMP', jpeg => 'PreviewImage' }->{$type} || '';
8714 11         32 my ($warn, $extent);
8715 11 50       25 $warn = "Can't currently decode encoded $type metadata" if $$item{ContentEncoding};
8716 11 50       27 $warn = "Can't currently decode protected $type metadata" if $$item{ProtectionIndex};
8717 11 50       24 $warn = "Can't currently extract $type with construction method $$item{ConstructionMethod}" if $$item{ConstructionMethod};
8718 11 50 33     30 $et->WarnOnce($warn) if $warn and $name;
8719 11 50       25 $warn = 'Not this file' if $$item{DataReferenceIndex}; # (can only extract from "this file")
8720 11 50 33     31 unless (($$item{Extents} and @{$$item{Extents}}) or $warn) {
  11   33     37  
8721 0         0 $warn = "No Extents for $type item";
8722 0 0       0 $et->WarnOnce($warn) if $name;
8723             }
8724 11 50       26 if ($warn) {
8725 0 0       0 $et->VPrint(0, "$$et{INDENT} [not extracted] ($warn)\n") if $verbose > 2;
8726 0         0 next;
8727             }
8728 11   100     35 my $base = $$item{BaseOffset} || 0;
8729 11 50       25 if ($verbose > 2) {
8730             # do verbose hex dump
8731 0         0 my $len = 0;
8732 0         0 undef $buff;
8733 0         0 my $val = '';
8734 0 0       0 my $maxLen = $verbose > 3 ? 2048 : 96;
8735 0         0 foreach $extent (@{$$item{Extents}}) {
  0         0  
8736 0         0 my $n = $$extent[2];
8737 0         0 my $more = $maxLen - $len;
8738 0 0 0     0 if ($more > 0 and $n) {
8739 0 0       0 $more = $n if $more > $n;
8740 0 0       0 $val .= $buff if defined $buff;
8741 0 0       0 $raf->Seek($$extent[1] + $base, 0) or last;
8742 0 0       0 $raf->Read($buff, $more) or last;
8743             }
8744 0         0 $len += $n;
8745             }
8746 0 0       0 if (defined $buff) {
8747 0 0       0 $buff = $val . $buff if length $val;
8748 0         0 $et->VerboseDump(\$buff, DataPos => $$item{Extents}[0][1] + $base);
8749 0         0 my $snip = $len - length $buff;
8750 0 0       0 $et->VPrint(0, "$$et{INDENT} [snip $snip bytes]\n") if $snip;
8751             }
8752             }
8753 11 100       31 next unless $name;
8754             # assemble the data for this item
8755 5         9 undef $buff;
8756 5         12 my $val = '';
8757 5         8 foreach $extent (@{$$item{Extents}}) {
  5         15  
8758 5 50       10 $val .= $buff if defined $buff;
8759 5 50       20 $raf->Seek($$extent[1] + $base, 0) or last;
8760 5 100       29 $raf->Read($buff, $$extent[2]) or last;
8761             }
8762 5 50       33 next unless defined $buff;
8763 5 50       22 $buff = $val . $buff if length $val;
8764 5 100       12 next unless length $buff; # ignore empty directories
8765 4         10 my ($start, $subTable, $proc);
8766 4         13 my $pos = $$item{Extents}[0][1] + $base;
8767 4 100 66     27 if ($name eq 'EXIF' and length $buff >= 4) {
    50          
8768 2 50       21 if ($buff =~ /^(MM\0\x2a|II\x2a\0)/) {
    50          
8769 0         0 $et->Warn('Missing Exif header');
8770 0         0 $start = 0;
8771             } elsif ($buff =~ /^Exif\0\0/) {
8772             # (haven't seen this yet, but it is just a matter of time
8773             # until someone screws it up like this)
8774 0         0 $et->Warn('Missing Exif header size');
8775 0         0 $start = 6;
8776             } else {
8777 2         8 my $n = unpack('N', $buff);
8778 2         6 $start = 4 + $n; # skip "Exif\0\0" header if it exists
8779 2 50       10 if ($start > length($buff)) {
8780 0         0 $et->Warn('Invalid EXIF header');
8781 0         0 next;
8782             }
8783 2 50       10 if ($$et{HTML_DUMP}) {
8784 0         0 $et->HDump($pos, 4, 'Exif header length', "Value: $n");
8785 0 0       0 $et->HDump($pos+4, $start-4, 'Exif header') if $n;
8786             }
8787             }
8788 2         9 $subTable = GetTagTable('Image::ExifTool::Exif::Main');
8789 2         7 $proc = \&Image::ExifTool::ProcessTIFF;
8790             } elsif ($name eq 'PreviewImage') {
8791             # take a quick stab at determining the size of the image
8792             # (based on JPEG previews found in Fuji X-H2S HIF images)
8793 0         0 my $type = 'PreviewImage';
8794 0 0       0 if ($buff =~ /^.{556}\xff\xc0\0\x11.(.{4})/s) {
8795 0         0 my ($h, $w) = unpack('n2', $1);
8796             # (not sure if $h is ever the long dimension, but test it just in case)
8797 0 0 0     0 if ($w == 160 or $h == 160) {
    0 0        
8798 0         0 $type = 'ThumbnailImage';
8799             } elsif ($w == 1920 or $h == 1920) {
8800 0         0 $type = 'OtherImage'; # (large preview)
8801             } # (PreviewImage is 640x480)
8802             }
8803 0         0 $et->FoundTag($type => $buff);
8804 0         0 next;
8805             } else {
8806 2         5 $start = 0;
8807 2         8 $subTable = GetTagTable('Image::ExifTool::XMP::Main');
8808             }
8809 4         29 my %dirInfo = (
8810             DataPt => \$buff,
8811             DataLen => length $buff,
8812             DirStart => $start,
8813             DirLen => length($buff) - $start,
8814             DataPos => $pos,
8815             Base => $pos + $start, # (needed for HtmlDump and IsOffset tags in binary data)
8816             );
8817             # handle processing of metadata for sub-documents
8818 4 50 33     36 if (defined $primary and $$item{RefersTo} and not $$item{RefersTo}{$primary}) {
      33        
8819             # set document number if this doesn't refer to the primary document
8820 0         0 $$et{DOC_NUM} = ++$$et{DOC_COUNT};
8821             # associate this document number with the lowest item index
8822 0         0 my ($lowest) = sort { $a <=> $b } keys %{$$item{RefersTo}};
  0         0  
  0         0  
8823 0         0 $$items{$lowest}{DocNum} = $$et{DOC_NUM};
8824             }
8825 4         18 $et->ProcessDirectory(\%dirInfo, $subTable, $proc);
8826 4         18 delete $$et{DOC_NUM};
8827             }
8828 3         20 $raf->Seek($curPos, 0); # seek back to original position
8829 3         7 pop @{$$et{PATH}};
  3         16  
8830             }
8831             # process the item properties now that we should know their associations and document numbers
8832 45 100       167 if ($$et{ItemPropertyContainer}) {
8833 3         7 my ($dirInfo, $subTable, $proc) = @{$$et{ItemPropertyContainer}};
  3         11  
8834 3         9 $$et{IsItemProperty} = 1; # set item property flag
8835 3         17 $et->ProcessDirectory($dirInfo, $subTable, $proc);
8836 3         11 delete $$et{ItemPropertyContainer};
8837 3         12 delete $$et{IsItemProperty};
8838 3         13 delete $$et{DOC_NUM};
8839             }
8840 45         139 delete $$et{ItemInfo};
8841             }
8842              
8843             #------------------------------------------------------------------------------
8844             # Warn if ExtractEmbedded option isn't used
8845             # Inputs: 0) ExifTool ref
8846             sub EEWarn($)
8847             {
8848 0     0 0 0 my $et = shift;
8849 0         0 $et->WarnOnce('The ExtractEmbedded option may find more tags in the media data',3);
8850             }
8851              
8852             #------------------------------------------------------------------------------
8853             # Get quicktime format from flags word
8854             # Inputs: 0) quicktime atom flags, 1) data length
8855             # Returns: ExifTool format string
8856             sub QuickTimeFormat($$)
8857             {
8858 12     12 0 42 my ($flags, $len) = @_;
8859 12         26 my $format;
8860 12 50 33     104 if ($flags == 0x15 or $flags == 0x16) {
    50          
    50          
    50          
8861 0         0 $format = { 1=>'int8', 2=>'int16', 4=>'int32', 8=>'int64' }->{$len};
8862 0 0       0 $format .= $flags == 0x15 ? 's' : 'u' if $format;
    0          
8863             } elsif ($flags == 0x17) {
8864 0         0 $format = 'float';
8865             } elsif ($flags == 0x18) {
8866 0         0 $format = 'double';
8867             } elsif ($flags == 0x00) {
8868 0         0 $format = { 1=>'int8u', 2=>'int16u' }->{$len};
8869             }
8870 12         30 return $format;
8871             }
8872              
8873             #------------------------------------------------------------------------------
8874             # Process MPEG-4 MTDT atom (ref 11)
8875             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
8876             # Returns: 1 on success
8877             sub ProcessMetaData($$$)
8878             {
8879 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
8880 0         0 my $dataPt = $$dirInfo{DataPt};
8881 0         0 my $dirLen = length $$dataPt;
8882 0         0 my $verbose = $et->Options('Verbose');
8883 0 0       0 return 0 unless $dirLen >= 2;
8884 0         0 my $count = Get16u($dataPt, 0);
8885 0 0       0 $verbose and $et->VerboseDir('MetaData', $count);
8886 0         0 my $i;
8887 0         0 my $pos = 2;
8888 0         0 for ($i=0; $i<$count; ++$i) {
8889 0 0       0 last if $pos + 10 > $dirLen;
8890 0         0 my $size = Get16u($dataPt, $pos);
8891 0 0 0     0 last if $size < 10 or $size + $pos > $dirLen;
8892 0         0 my $tag = Get32u($dataPt, $pos + 2);
8893 0         0 my $lang = Get16u($dataPt, $pos + 6);
8894 0         0 my $enc = Get16u($dataPt, $pos + 8);
8895 0         0 my $val = substr($$dataPt, $pos + 10, $size);
8896 0         0 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
8897 0 0       0 if ($tagInfo) {
8898             # convert language code to ASCII (ignore read-only bit)
8899 0         0 $lang = UnpackLang($lang);
8900             # handle alternate languages
8901 0 0       0 if ($lang) {
8902 0         0 my $langInfo = GetLangInfoQT($et, $tagInfo, $lang);
8903 0 0       0 $tagInfo = $langInfo if $langInfo;
8904             }
8905 0 0       0 $verbose and $et->VerboseInfo($tag, $tagInfo,
8906             Value => $val,
8907             DataPt => $dataPt,
8908             Start => $pos + 10,
8909             Size => $size - 10,
8910             );
8911             # convert from UTF-16 BE if necessary
8912 0 0       0 $val = $et->Decode($val, 'UCS2') if $enc == 1;
8913 0 0 0     0 if ($enc == 0 and $$tagInfo{Unknown}) {
8914             # binary data
8915 0         0 $et->FoundTag($tagInfo, \$val);
8916             } else {
8917 0         0 $et->FoundTag($tagInfo, $val);
8918             }
8919             }
8920 0         0 $pos += $size;
8921             }
8922 0         0 return 1;
8923             }
8924              
8925             #------------------------------------------------------------------------------
8926             # Process sample description table
8927             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
8928             # Returns: 1 on success
8929             # (ref https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25691)
8930             sub ProcessSampleDesc($$$)
8931             {
8932 38     38 0 132 my ($et, $dirInfo, $tagTablePtr) = @_;
8933 38         106 my $dataPt = $$dirInfo{DataPt};
8934 38   50     158 my $pos = $$dirInfo{DirStart} || 0;
8935 38   33     114 my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $pos);
8936 38 50       138 return 0 if $pos + 8 > $dirLen;
8937              
8938 38         141 my $num = Get32u($dataPt, 4); # get number of sample entries in table
8939 38         121 $pos += 8;
8940 38         85 my ($i, $err);
8941 38         131 for ($i=0; $i<$num; ++$i) { # loop through sample entries
8942 38 50       128 $pos + 8 > $dirLen and $err = 1, last;
8943 38         99 my $size = Get32u($dataPt, $pos);
8944 38 50       122 $pos + $size > $dirLen and $err = 1, last;
8945 38         108 $$dirInfo{DirStart} = $pos;
8946 38         82 $$dirInfo{DirLen} = $size;
8947 38         154 ProcessHybrid($et, $dirInfo, $tagTablePtr);
8948 38         124 $pos += $size;
8949             }
8950 38 0 33     136 if ($err and $$et{HandlerType}) {
8951 0   0     0 my $grp = $$et{SET_GROUP1} || $$dirInfo{Parent} || 'unknown';
8952 0         0 $et->Warn("Truncated $$et{HandlerType} sample table for $grp");
8953             }
8954 38         109 return 1;
8955             }
8956              
8957             #------------------------------------------------------------------------------
8958             # Process hybrid binary data + QuickTime container (ref PH)
8959             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
8960             # Returns: 1 on success
8961             sub ProcessHybrid($$$)
8962             {
8963 38     38 0 95 my ($et, $dirInfo, $tagTablePtr) = @_;
8964             # brute-force search for child atoms after first 8 bytes of binary data
8965 38         88 my $dataPt = $$dirInfo{DataPt};
8966 38   50     112 my $dirStart = $$dirInfo{DirStart} || 0;
8967 38   33     127 my $dirLen = $$dirInfo{DirLen} || length($$dataPt) - $dirStart;
8968 38         76 my $end = $dirStart + $dirLen;
8969 38         76 my $pos = $dirStart + 8; # skip length/version
8970 38         73 my $try = $pos;
8971 38         74 my $childPos;
8972              
8973 38         119 while ($pos <= $end - 8) {
8974 2204         3392 my $tag = substr($$dataPt, $try+4, 4);
8975             # look only for well-behaved tag ID's
8976 2204 100       5828 $tag =~ /[^\w ]/ and $try = ++$pos, next;
8977 94         229 my $size = Get32u($dataPt, $try);
8978 94 100       254 if ($size + $try == $end) {
8979             # the atom ends exactly at the end of the parent -- this must be it
8980 16         48 $childPos = $pos;
8981 16         39 $$dirInfo{DirLen} = $pos; # the binary data ends at the first child atom
8982 16         39 last;
8983             }
8984 78 100 100     273 if ($size < 8 or $size + $try > $end - 8) {
8985 58         124 $try = ++$pos; # fail. try next position
8986             } else {
8987 20         49 $try += $size; # could be another atom following this
8988             }
8989             }
8990             # process binary data
8991 38         125 $$dirInfo{MixedTags} = 1; # ignore non-integer tag ID's
8992 38         184 $et->ProcessBinaryData($dirInfo, $tagTablePtr);
8993             # process child atoms if found
8994 38 100       167 if ($childPos) {
8995 16         47 $$dirInfo{DirStart} = $childPos;
8996 16         47 $$dirInfo{DirLen} = $end - $childPos;
8997 16         58 ProcessMOV($et, $dirInfo, $tagTablePtr);
8998             }
8999 38         113 return 1;
9000             }
9001              
9002             #------------------------------------------------------------------------------
9003             # Process iTunes 'righ' atom (ref PH)
9004             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
9005             # Returns: 1 on success
9006             sub ProcessRights($$$)
9007             {
9008 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
9009 0         0 my $dataPt = $$dirInfo{DataPt};
9010 0         0 my $dataPos = $$dirInfo{Base};
9011 0         0 my $dirLen = length $$dataPt;
9012 0   0     0 my $unknown = $$et{OPTIONS}{Unknown} || $$et{OPTIONS}{Verbose};
9013 0         0 my $pos;
9014 0         0 $et->VerboseDir('righ', $dirLen / 8);
9015 0         0 for ($pos = 0; $pos + 8 <= $dirLen; $pos += 8) {
9016 0         0 my $tag = substr($$dataPt, $pos, 4);
9017 0 0       0 last if $tag eq "\0\0\0\0";
9018 0         0 my $val = substr($$dataPt, $pos + 4, 4);
9019 0         0 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
9020 0 0       0 unless ($tagInfo) {
9021 0 0       0 next unless $unknown;
9022 0         0 my $name = PrintableTagID($tag);
9023 0         0 $tagInfo = {
9024             Name => "Unknown_$name",
9025             Description => "Unknown $name",
9026             Unknown => 1,
9027             },
9028             AddTagToTable($tagTablePtr, $tag, $tagInfo);
9029             }
9030 0 0       0 $val = '0x' . unpack('H*', $val) unless $$tagInfo{Format};
9031 0         0 $et->HandleTag($tagTablePtr, $tag, $val,
9032             DataPt => $dataPt,
9033             DataPos => $dataPos,
9034             Start => $pos + 4,
9035             Size => 4,
9036             );
9037             }
9038 0         0 return 1;
9039             }
9040              
9041             #------------------------------------------------------------------------------
9042             # Process iTunes Encoding Params (ref PH)
9043             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
9044             # Returns: 1 on success
9045             sub ProcessEncodingParams($$$)
9046             {
9047 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
9048 0         0 my $dataPt = $$dirInfo{DataPt};
9049 0         0 my $dirLen = length $$dataPt;
9050 0         0 my $pos;
9051 0         0 $et->VerboseDir('Encoding Params', $dirLen / 8);
9052 0         0 for ($pos = 0; $pos + 8 <= $dirLen; $pos += 8) {
9053 0         0 my ($tag, $val) = unpack("x${pos}a4N", $$dataPt);
9054 0         0 $et->HandleTag($tagTablePtr, $tag, $val);
9055             }
9056 0         0 return 1;
9057             }
9058              
9059             #------------------------------------------------------------------------------
9060             # Read Meta Keys and add tags to ItemList table ('mdta' handler) (ref PH)
9061             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
9062             # Returns: 1 on success
9063             sub ProcessKeys($$$)
9064             {
9065 9     9 0 27 local $_;
9066 9         31 my ($et, $dirInfo, $tagTablePtr) = @_;
9067 9         30 my $dataPt = $$dirInfo{DataPt};
9068 9         27 my $dirLen = length $$dataPt;
9069 9         15 my $out;
9070 9 50       38 if ($et->Options('Verbose')) {
9071 0         0 $et->VerboseDir('Keys');
9072 0         0 $out = $et->Options('TextOut');
9073             }
9074 9         70 my $pos = 8;
9075 9         25 my $index = 1;
9076 9         20 ++$$et{KeysCount}; # increment key count for this directory
9077 9         29 my $itemList = GetTagTable('Image::ExifTool::QuickTime::ItemList');
9078 9         45 my $userData = GetTagTable('Image::ExifTool::QuickTime::UserData');
9079 9         45 while ($pos < $dirLen - 4) {
9080 22         87 my $len = unpack("x${pos}N", $$dataPt);
9081 22 50 33     120 last if $len < 8 or $pos + $len > $dirLen;
9082 22         44 delete $$tagTablePtr{$index};
9083 22         63 my $ns = substr($$dataPt, $pos + 4, 4);
9084 22         60 my $tag = substr($$dataPt, $pos + 8, $len - 8);
9085 22         56 $tag =~ s/\0.*//s; # truncate at null
9086 22         36 my $full = $tag;
9087 22 50       134 $tag =~ s/^com\.(apple\.quicktime\.)?// if $ns eq 'mdta'; # remove apple quicktime domain
9088 22 50       65 $tag = "Tag_$ns" unless $tag;
9089 22         53 my $short = $tag;
9090 22         30 my $tagInfo;
9091 22         40 for (;;) {
9092 22 50       81 $tagInfo = $et->GetTagInfo($tagTablePtr, $tag) and last;
9093             # also try ItemList and UserData tables
9094 0 0       0 $tagInfo = $et->GetTagInfo($itemList, $tag) and last;
9095 0 0       0 $tagInfo = $et->GetTagInfo($userData, $tag) and last;
9096             # (I have some samples where the tag is a reversed ItemList or UserData tag ID)
9097 0 0       0 if ($tag =~ /^\w{3}\xa9$/) {
9098 0         0 $tag = pack('N', unpack('V', $tag));
9099 0 0       0 $tagInfo = $et->GetTagInfo($itemList, $tag) and last;
9100 0         0 $tagInfo = $et->GetTagInfo($userData, $tag);
9101 0         0 last;
9102             }
9103 0 0       0 if ($tag eq $full) {
9104 0         0 $tag = $short;
9105 0         0 last;
9106             }
9107 0         0 $tag = $full;
9108             }
9109 22         55 my ($newInfo, $msg);
9110 22 50 0     53 if ($tagInfo) {
    0          
9111             # copy tag information into new Keys tag
9112             $newInfo = {
9113             Name => $$tagInfo{Name},
9114             Format => $$tagInfo{Format},
9115             ValueConv => $$tagInfo{ValueConv},
9116             ValueConvInv => $$tagInfo{ValueConvInv},
9117             PrintConv => $$tagInfo{PrintConv},
9118             PrintConvInv => $$tagInfo{PrintConvInv},
9119             Writable => defined $$tagInfo{Writable} ? $$tagInfo{Writable} : 1,
9120             SubDirectory => $$tagInfo{SubDirectory},
9121 22 50       227 };
9122 22         52 my $groups = $$tagInfo{Groups};
9123 22 100       122 $$newInfo{Groups} = $groups ? { %$groups } : { };
9124 22   66     235 $$newInfo{Groups}{$_} or $$newInfo{Groups}{$_} = $$tagTablePtr{GROUPS}{$_} foreach 0..2;
9125 22         53 $$newInfo{Groups}{1} = 'Keys';
9126             } elsif ($tag =~ /^[-\w. ]+$/ or $tag =~ /\w{4}/) {
9127             # create info for tags with reasonable id's
9128 0         0 my $name = ucfirst $tag;
9129 0         0 $name =~ tr/-0-9a-zA-Z_. //dc;
9130 0         0 $name =~ s/[. ]+(.?)/\U$1/g;
9131 0         0 $name =~ s/_([a-z])/_\U$1/g;
9132 0         0 $name =~ s/([a-z])_([A-Z])/$1$2/g;
9133 0 0       0 $name = "Tag_$name" if length $name < 2;
9134 0         0 $newInfo = { Name => $name, Groups => { 1 => 'Keys' } };
9135 0         0 $msg = ' (Unknown)';
9136             }
9137             # substitute this tag in the ItemList table with the given index
9138 22         66 my $id = $$et{KeysCount} . '.' . $index;
9139 22 100       96 if (ref $$itemList{$id} eq 'HASH') {
9140             # delete other languages too if they exist
9141 18         40 my $oldInfo = $$itemList{$id};
9142 18 50       59 if ($$oldInfo{OtherLang}) {
9143 0         0 delete $$itemList{$_} foreach @{$$oldInfo{OtherLang}};
  0         0  
9144             }
9145 18         169 delete $$itemList{$id};
9146             }
9147 22 50       67 if ($newInfo) {
9148 22         58 $$newInfo{KeysID} = $tag; # save original ID for use in family 7 group name
9149 22         93 AddTagToTable($itemList, $id, $newInfo);
9150 22 50       59 $msg or $msg = '';
9151 22 50       51 $out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $tag$msg\n";
9152             }
9153 22         46 $pos += $len;
9154 22         76 ++$index;
9155             }
9156 9         37 return 1;
9157             }
9158              
9159             #------------------------------------------------------------------------------
9160             # Process keys in MetaSampleDesc directory
9161             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
9162             # Returns: 1 on success
9163             sub ProcessMetaKeys($$$)
9164             {
9165 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
9166             # save this information to decode timed metadata samples when ExtractEmbedded is used
9167 0 0       0 SaveMetaKeys($et, $dirInfo, $tagTablePtr) if $$et{OPTIONS}{ExtractEmbedded};
9168 0         0 return 1;
9169             }
9170              
9171             #------------------------------------------------------------------------------
9172             # Process a QuickTime atom
9173             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) optional tag table ref
9174             # Returns: 1 on success
9175             sub ProcessMOV($$;$)
9176             {
9177 383     383 0 695 local $_;
9178 383         847 my ($et, $dirInfo, $tagTablePtr) = @_;
9179 383         738 my $raf = $$dirInfo{RAF};
9180 383         764 my $dataPt = $$dirInfo{DataPt};
9181 383         1232 my $verbose = $et->Options('Verbose');
9182 383         863 my $validate = $$et{OPTIONS}{Validate};
9183 383   100     1086 my $dataPos = $$dirInfo{Base} || 0;
9184 383   100     1096 my $dirID = $$dirInfo{DirID} || '';
9185 383         956 my $charsetQuickTime = $et->Options('CharsetQuickTime');
9186 383         1204 my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index);
9187 383         0 my ($dirEnd, $unkOpt, %saveOptions, $atomCount);
9188              
9189 383         803 my $topLevel = not $$et{InQuickTime};
9190 383         749 $$et{InQuickTime} = 1;
9191 383 100       1074 $$et{HandlerType} = $$et{MetaFormat} = '' unless defined $$et{HandlerType};
9192              
9193 383 100       964 unless (defined $$et{KeysCount}) {
9194 20         52 $$et{KeysCount} = 0; # initialize ItemList key directory count
9195 20         47 $doDefaultLang = 1; # flag to generate default language tags
9196             }
9197             # more convenient to package data as a RandomAccess file
9198 383 100       874 unless ($raf) {
9199 363         1195 $raf = new File::RandomAccess($dataPt);
9200 363 50 100     1755 $dirEnd = $dataPos + $$dirInfo{DirLen} + ($$dirInfo{DirStart} || 0) if $$dirInfo{DirLen};
9201             }
9202             # skip leading bytes if necessary
9203 383 100       898 if ($$dirInfo{DirStart}) {
9204 94 50       372 $raf->Seek($$dirInfo{DirStart}, 1) or return 0;
9205 94         243 $dataPos += $$dirInfo{DirStart};
9206             }
9207             # read size/tag name atom header
9208 383 50       979 $raf->Read($buff,8) == 8 or return 0;
9209 383         742 $dataPos += 8;
9210 383 100       798 if ($tagTablePtr) {
9211 363         1131 $isUserData = ($tagTablePtr eq \%Image::ExifTool::QuickTime::UserData);
9212             } else {
9213 20         81 $tagTablePtr = GetTagTable('Image::ExifTool::QuickTime::Main');
9214             }
9215 383         1623 ($size, $tag) = unpack('Na4', $buff);
9216 383 100       1194 if ($dataPt) {
9217 363 50       812 $verbose and $et->VerboseDir($$dirInfo{DirName});
9218             } else {
9219             # check on file type if called with a RAF
9220 20 50       89 $$tagTablePtr{$tag} or return 0;
9221 20 100 66     127 if ($tag eq 'ftyp' and $size >= 12) {
9222             # read ftyp atom to see what type of file this is
9223 11         34 my $fileType;
9224 11 50       66 if ($raf->Read($buff, $size-8) == $size-8) {
9225 11         75 $raf->Seek(-($size-8), 1);
9226 11         69 my $type = substr($buff, 0, 4);
9227 11         53 $$et{save_ftyp} = $type;
9228             # see if we know the extension for this file type
9229 11 50 33     182 if ($ftypLookup{$type} and $ftypLookup{$type} =~ /\(\.(\w+)/) {
    0          
    0          
    0          
9230 11         47 $fileType = $1;
9231             # check compatible brands
9232             } elsif ($buff =~ /^.{8}(.{4})+(mp41|mp42|avc1)/s) {
9233 0         0 $fileType = 'MP4';
9234             } elsif ($buff =~ /^.{8}(.{4})+(f4v )/s) {
9235 0         0 $fileType = 'F4V';
9236             } elsif ($buff =~ /^.{8}(.{4})+(qt )/s) {
9237 0         0 $fileType = 'MOV';
9238             }
9239             }
9240 11 50       54 $fileType or $fileType = 'MP4'; # default to MP4
9241 11   50     133 $et->SetFileType($fileType, $mimeLookup{$fileType} || 'video/mp4');
9242             # temporarily set ExtractEmbedded option for CRX files
9243 11 100       87 $saveOptions{ExtractEmbedded} = $et->Options(ExtractEmbedded => 1) if $fileType eq 'CRX';
9244             } else {
9245 9         45 $et->SetFileType(); # MOV
9246             }
9247 20         93 SetByteOrder('MM');
9248 20         102 $$et{PRIORITY_DIR} = 'XMP'; # have XMP take priority
9249             }
9250 383   50     1572 my $fast = $$et{OPTIONS}{FastScan} || 0;
9251 383 50       823 $$raf{NoBuffer} = 1 if $fast; # disable buffering in FastScan mode
9252              
9253 383         753 my $ee = $$et{OPTIONS}{ExtractEmbedded};
9254 383 100       824 if ($ee) {
9255 134         312 $unkOpt = $$et{OPTIONS}{Unknown};
9256 134         3036 require 'Image/ExifTool/QuickTimeStream.pl';
9257             }
9258 383 100       1078 if ($$tagTablePtr{VARS}) {
9259 22         85 $index = $$tagTablePtr{VARS}{START_INDEX};
9260 22         63 $atomCount = $$tagTablePtr{VARS}{ATOM_COUNT};
9261             }
9262 383         584 for (;;) {
9263 1253         2110 my ($eeTag, $ignore);
9264 1253 50 33     3121 last if defined $atomCount and --$atomCount < 0;
9265 1253 100       2669 if ($size < 8) {
9266 4 50       23 if ($size == 0) {
9267 0 0       0 if ($dataPt) {
9268             # a zero size isn't legal for contained atoms, but Canon uses it to
9269             # terminate the CNTH atom (eg. CanonEOS100D.mov), so tolerate it here
9270 0         0 my $pos = $raf->Tell() - 4;
9271 0         0 $raf->Seek(0,2);
9272 0         0 my $str = $$dirInfo{DirName} . ' with ' . ($raf->Tell() - $pos) . ' bytes';
9273 0         0 $et->VPrint(0,"$$et{INDENT}\[Terminator found in $str remaining]");
9274             } else {
9275 0         0 my $t = PrintableTagID($tag,2);
9276 0         0 $et->VPrint(0,"$$et{INDENT}Tag '${t}' extends to end of file");
9277 0 0       0 if ($$tagTablePtr{"$tag-size"}) {
9278 0         0 my $pos = $raf->Tell();
9279 0 0       0 unless ($fast) {
9280 0         0 $raf->Seek(0, 2);
9281 0         0 $et->HandleTag($tagTablePtr, "$tag-size", $raf->Tell() - $pos);
9282             }
9283 0 0       0 $et->HandleTag($tagTablePtr, "$tag-offset", $pos) if $$tagTablePtr{"$tag-offset"};
9284             }
9285             }
9286 0         0 last;
9287             }
9288 4 50       18 $size == 1 or $et->Warn('Invalid atom size'), last;
9289             # read extended atom size
9290 4 50       20 $raf->Read($buff, 8) == 8 or $et->Warn('Truncated atom header'), last;
9291 4         18 $dataPos += 8;
9292 4         19 my ($hi, $lo) = unpack('NN', $buff);
9293 4 50 33     38 if ($hi or $lo > 0x7fffffff) {
9294 0 0       0 if ($hi > 0x7fffffff) {
    0          
9295 0         0 $et->Warn('Invalid atom size');
9296 0         0 last;
9297             } elsif (not $et->Options('LargeFileSupport')) {
9298 0         0 $et->Warn('End of processing at large atom (LargeFileSupport not enabled)');
9299 0         0 last;
9300             }
9301             }
9302 4         17 $size = $hi * 4294967296 + $lo - 16;
9303 4 50       16 $size < 0 and $et->Warn('Invalid extended size'), last;
9304             } else {
9305 1249         2108 $size -= 8;
9306             }
9307 1253 50       2424 if ($validate) {
9308 0 0       0 $$et{ValidatePath} or $$et{ValidatePath} = { };
9309 0         0 my $path = join('-', @{$$et{PATH}}, $tag);
  0         0  
9310 0 0       0 $path =~ s/-Track-/-$$et{SET_GROUP1}-/ if $$et{SET_GROUP1};
9311 0 0 0     0 if ($$et{ValidatePath}{$path} and not $dupTagOK{$tag} and not $dupDirOK{$dirID}) {
      0        
9312 0         0 my $i = Get32u(\$tag,0);
9313 0 0       0 my $str = $i < 255 ? "index $i" : "tag '" . PrintableTagID($tag,2) . "'";
9314 0         0 $et->WarnOnce("Duplicate $str at " . join('-', @{$$et{PATH}}));
  0         0  
9315 0 0       0 $$et{ValidatePath} = { } if $path eq 'MOV-moov'; # avoid warnings for all contained dups
9316             }
9317 0         0 $$et{ValidatePath}{$path} = 1;
9318             }
9319 1253 50 66     2752 if ($isUserData and $$et{SET_GROUP1}) {
9320 0         0 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
9321             # add track name to UserData tags inside tracks
9322 0         0 $tag = $$et{SET_GROUP1} . $tag;
9323 0 0 0     0 if (not $$tagTablePtr{$tag} and $tagInfo) {
9324 0         0 my %newInfo = %$tagInfo;
9325 0         0 foreach ('Name', 'Description') {
9326 0 0       0 next unless $$tagInfo{$_};
9327 0         0 $newInfo{$_} = $$et{SET_GROUP1} . $$tagInfo{$_};
9328 0         0 $newInfo{$_} =~ s/^(Track\d+)Track/$1/; # remove duplicate "Track" in name
9329             }
9330 0         0 AddTagToTable($tagTablePtr, $tag, \%newInfo);
9331             }
9332             }
9333             # set flag to store additional information for ExtractEmbedded option
9334 1253         2718 my $handlerType = $$et{HandlerType};
9335 1253 100 100     6527 if ($eeBox{$handlerType} and $eeBox{$handlerType}{$tag}) {
    50 66        
      33        
      0        
9336 104 100 33     322 if ($ee) {
    50          
9337             # (there is another 'gps ' box with a track log that doesn't contain offsets)
9338 68 50 33     200 if ($tag ne 'gps ' or $eeBox{$handlerType}{$tag} eq $dirID) {
9339 68         115 $eeTag = 1;
9340 68         154 $$et{OPTIONS}{Unknown} = 1; # temporarily enable "Unknown" option
9341             }
9342             } elsif ($handlerType ne 'vide' and not $$et{OPTIONS}{Validate}) {
9343 0         0 EEWarn($et);
9344             }
9345             } elsif ($ee and $ee > 1 and $eeBox2{$handlerType} and $eeBox2{$handlerType}{$tag}) {
9346 0         0 $eeTag = 1;
9347 0         0 $$et{OPTIONS}{Unknown} = 1;
9348             }
9349 1253         3960 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
9350              
9351 1253 100       2748 $$et{OPTIONS}{Unknown} = $unkOpt if $eeTag; # restore Unknown option
9352              
9353             # allow numerical tag ID's
9354 1253 100       2939 unless ($tagInfo) {
9355 160         683 my $id = $$et{KeysCount} . '.' . unpack('N', $tag);
9356 160 100       552 if ($$tagTablePtr{$id}) {
9357 22         76 $tagInfo = $et->GetTagInfo($tagTablePtr, $id);
9358 22         68 $tag = $id;
9359             }
9360             }
9361             # generate tagInfo if Unknown option set
9362 1253 50 66     3273 if (not defined $tagInfo and ($$et{OPTIONS}{Unknown} or
      66        
9363             $verbose or $tag =~ /^\xa9/))
9364             {
9365 13         51 my $name = PrintableTagID($tag,1);
9366 13 50       46 if ($name =~ /^xa9(.*)/) {
9367 0         0 $tagInfo = {
9368             Name => "UserData_$1",
9369             Description => "User Data $1",
9370             };
9371             } else {
9372 13         108 $tagInfo = {
9373             Name => "Unknown_$name",
9374             Description => "Unknown $name",
9375             %unknownInfo,
9376             };
9377             }
9378 13         59 AddTagToTable($tagTablePtr, $tag, $tagInfo);
9379             }
9380             # save required tag sizes
9381 1253 100       3814 if ($$tagTablePtr{"$tag-size"}) {
9382 23         128 $et->HandleTag($tagTablePtr, "$tag-size", $size);
9383 23 50       226 $et->HandleTag($tagTablePtr, "$tag-offset", $raf->Tell()) if $$tagTablePtr{"$tag-offset"};
9384             }
9385             # stop processing at mdat/idat if -fast2 is used
9386 1253 0 0     2615 last if $fast > 1 and ($tag eq 'mdat' or $tag eq 'idat');
      33        
9387             # load values only if associated with a tag (or verbose) and not too big
9388 1253 50       2657 if ($size > 0x2000000) { # start to get worried above 32 MB
9389             # check for RIFF trailer (written by Auto-Vox dashcam)
9390 0 0       0 if ($buff =~ /^(gpsa|gps0|gsen|gsea)...\0/s) { # (yet seen only gpsa as first record)
9391 0         0 $et->VPrint(0, "Found RIFF trailer");
9392 0 0       0 if ($et->Options('ExtractEmbedded')) {
9393 0 0       0 $raf->Seek(-8, 1) or last; # seek back to start of trailer
9394 0         0 my $tbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
9395 0         0 ProcessRIFFTrailer($et, { RAF => $raf }, $tbl);
9396             } else {
9397 0         0 EEWarn($et);
9398             }
9399 0         0 last;
9400             }
9401 0         0 $ignore = 1;
9402 0 0 0     0 if ($tagInfo and not $$tagInfo{Unknown} and not $eeTag) {
      0        
9403 0         0 my $t = PrintableTagID($tag,2);
9404 0 0       0 if ($size > 0x8000000) {
9405 0         0 $et->Warn("Skipping '${t}' atom > 128 MB", 1);
9406             } else {
9407 0 0       0 $et->Warn("Skipping '${t}' atom > 32 MB", 2) or $ignore = 0;
9408             }
9409             }
9410             }
9411 1253 100 66     4045 if (defined $tagInfo and not $ignore) {
9412             # set document number for this item property if necessary
9413 1165 100       2571 if ($$et{IsItemProperty}) {
9414 12         27 my $items = $$et{ItemInfo};
9415 12         25 my ($id, $prop, $docNum, $lowest);
9416 12   50     34 my $primary = $$et{PrimaryItem} || 0;
9417 12         41 ItemID: foreach $id (keys %$items) {
9418 34 100       78 next unless $$items{$id}{Association};
9419 18         29 my $item = $$items{$id};
9420 18         32 foreach $prop (@{$$item{Association}}) {
  18         38  
9421 33 100       71 next unless $prop == $index;
9422 12 100 0     95 if ($id == $primary or (not $dontInherit{$tag} and
    100 33        
    50 66        
      33        
9423             (not $$item{RefersTo} or $$item{RefersTo}{$primary})))
9424             {
9425             # this is associated with the primary item or an item describing
9426             # the primary item, so consider this part of the main document
9427 6         10 undef $docNum;
9428 6         9 undef $lowest;
9429 6         15 last ItemID;
9430             } elsif ($$item{DocNum}) {
9431             # this property is already associated with an item that has
9432             # an ExifTool document number, so use the lowest associated DocNum
9433 3 50 33     19 $docNum = $$item{DocNum} if not defined $docNum or $docNum > $$item{DocNum};
9434             } elsif (not defined $lowest or $lowest > $id) {
9435             # keep track of the lowest associated item ID
9436 3         21 $lowest = $id;
9437             }
9438             }
9439             }
9440 12 100 100     46 if (not defined $docNum and defined $lowest) {
9441             # this is the first time we've seen metadata from this item,
9442             # so use a new document number
9443 3         7 $docNum = ++$$et{DOC_COUNT};
9444 3         11 $$items{$lowest}{DocNum} = $docNum;
9445             }
9446 12         33 $$et{DOC_NUM} = $docNum;
9447             }
9448 1165         1710 my $val;
9449 1165         3118 my $missing = $size - $raf->Read($val, $size);
9450 1165 50       2714 if ($missing) {
9451 0         0 my $t = PrintableTagID($tag,2);
9452 0         0 $et->Warn("Truncated '${t}' data (missing $missing bytes)");
9453 0         0 last;
9454             }
9455             # use value to get tag info if necessary
9456 1165 100       2528 $tagInfo or $tagInfo = $et->GetTagInfo($tagTablePtr, $tag, \$val);
9457 1165   66     3562 my $hasData = ($$dirInfo{HasData} and $val =~ /\0...data\0/s);
9458 1165 50 33     2873 if ($verbose and not $hasData) {
9459 0         0 my $tval;
9460 0 0 0     0 if ($tagInfo and $$tagInfo{Format}) {
9461 0         0 $tval = ReadValue(\$val, 0, $$tagInfo{Format}, $$tagInfo{Count}, length($val));
9462             }
9463             $et->VerboseInfo($tag, $tagInfo,
9464             Value => $tval,
9465             DataPt => \$val,
9466             DataPos => $dataPos,
9467             Size => $size,
9468             Format => $tagInfo ? $$tagInfo{Format} : undef,
9469 0 0       0 Index => $index,
9470             );
9471             # print iref item ID numbers
9472 0 0       0 if ($dirID eq 'iref') {
9473 0         0 my ($id, $count, @to, $i);
9474 0 0       0 if ($$et{ItemRefVersion}) {
9475 0 0       0 ($id, $count, @to) = unpack('NnN*', $val) if length $val >= 10;
9476             } else {
9477 0 0       0 ($id, $count, @to) = unpack('nnn*', $val) if length $val >= 6;
9478             }
9479 0 0       0 defined $id or $id = '', $count = 0;
9480 0 0       0 $id .= " (wrong count: $count)" if $count != @to;
9481             # convert sequential numbers to a range
9482 0         0 for ($i=1; $i<@to; ) {
9483 0 0 0     0 $to[$i-1] =~ /(\d+)$/ and $to[$i] == $1 + 1 or ++$i, next;
9484 0         0 $to[$i-1] =~ s/(-.*)?$/-$to[$i]/;
9485 0         0 splice @to, $i, 1;
9486             }
9487 0         0 $et->VPrint(1, "$$et{INDENT} Item $id refers to: ",join(',',@to),"\n");
9488             }
9489             }
9490             # extract metadata from stream if ExtractEmbedded option is enabled
9491 1165 100       2370 if ($eeTag) {
9492 68         269 ParseTag($et, $tag, \$val);
9493             # forget this tag if we generated it only for ExtractEmbedded
9494 68 100 66     397 undef $tagInfo if $tagInfo and $$tagInfo{Unknown} and not $unkOpt;
      100        
9495             }
9496              
9497             # handle iTunesInfo mean/name/data triplets
9498 1165 100 100     4152 if ($tagInfo and $$tagInfo{Triplet}) {
9499 9 100 66     153 if ($tag eq 'data' and $triplet{mean} and $triplet{name}) {
      33        
9500 3         8 $tag = $triplet{name};
9501             # add 'mean' to name unless it is 'com.apple.iTunes'
9502 3 50       21 $tag = $triplet{mean} . '/' . $tag unless $triplet{mean} eq 'com.apple.iTunes';
9503 3         16 $tagInfo = $et->GetTagInfo($tagTablePtr, $tag, \$val);
9504 3 50       14 unless ($tagInfo) {
9505 0         0 my $name = $triplet{name};
9506 0         0 my $desc = $name;
9507 0         0 $name =~ tr/-_a-zA-Z0-9//dc;
9508 0         0 $desc =~ tr/_/ /;
9509 0         0 $tagInfo = {
9510             Name => $name,
9511             Description => $desc,
9512             };
9513 0         0 $et->VPrint(0, $$et{INDENT}, "[adding QuickTime:$name]\n");
9514 0         0 AddTagToTable($tagTablePtr, $tag, $tagInfo);
9515             }
9516             # ignore 8-byte header
9517 3 50       15 $val = substr($val, 8) if length($val) >= 8;
9518 3 50 33     26 unless ($$tagInfo{Format} or $$tagInfo{SubDirectory}) {
9519             # extract as binary if it contains any non-ASCII or control characters
9520 3 50       24 if ($val =~ /[^\x20-\x7e]/) {
9521 0         0 my $buff = $val;
9522 0         0 $val = \$buff;
9523             }
9524             }
9525 3         9 $$tagInfo{List} = 1; # (allow any of these tags to have multiple data elements)
9526 3 50       11 $et->VerboseInfo($tag, $tagInfo, Value => $val) if $verbose;
9527             } else {
9528 6 50       29 $triplet{$tag} = substr($val,4) if length($val) > 4;
9529 6         15 undef $tagInfo; # don't store this tag
9530             }
9531             }
9532 1165 100       2578 if ($tagInfo) {
9533 1131         2216 my $subdir = $$tagInfo{SubDirectory};
9534 1131 100 66     3459 if ($subdir) {
    100          
    100          
9535 674   100     2167 my $start = $$subdir{Start} || 0;
9536 674         1401 my ($base, $dPos) = ($dataPos, 0);
9537 674 50       1573 if ($$subdir{Base}) {
9538 0         0 $dPos -= eval $$subdir{Base};
9539 0         0 $base -= $dPos;
9540             }
9541             my %dirInfo = (
9542             DataPt => \$val,
9543             DataLen => $size,
9544             DirStart => $start,
9545             DirLen => $size - $start,
9546             DirName => $$subdir{DirName} || $$tagInfo{Name},
9547             DirID => $tag,
9548             HasData => $$subdir{HasData},
9549             Multi => $$subdir{Multi},
9550             IgnoreProp => $$subdir{IgnoreProp}, # (XML hack)
9551 674   66     6026 DataPos => $dPos,
9552             Base => $base, # (needed for IsOffset tags in binary data)
9553             );
9554 674 50       1749 $dirInfo{BlockInfo} = $tagInfo if $$tagInfo{BlockExtract};
9555 674 100 66     1769 if ($$subdir{ByteOrder} and $$subdir{ByteOrder} =~ /^Little/) {
9556 6         24 SetByteOrder('II');
9557             }
9558 674         1287 my $oldGroup1 = $$et{SET_GROUP1};
9559 674 100 33     3629 if ($$tagInfo{SubDirectory} and $$tagInfo{SubDirectory}{TagTable} and
      66        
9560             $$tagInfo{SubDirectory}{TagTable} eq 'Image::ExifTool::QuickTime::Track')
9561             {
9562 38 100       153 $track or $track = 0;
9563 38         187 $$et{SET_GROUP1} = 'Track' . (++$track);
9564             }
9565 674         2090 my $subTable = GetTagTable($$subdir{TagTable});
9566 674         1313 my $proc = $$subdir{ProcessProc};
9567             # make ProcessMOV() the default processing procedure for subdirectories
9568 674 100 100     2876 $proc = \&ProcessMOV unless $proc or $$subTable{PROCESS_PROC};
9569 674 50       1440 if ($size > $start) {
9570             # delay processing of ipco box until after all other boxes
9571 674 100 66     1938 if ($tag eq 'ipco' and not $$et{IsItemProperty}) {
9572 3         26 $$et{ItemPropertyContainer} = [ \%dirInfo, $subTable, $proc ];
9573 3         18 $et->VPrint(0,"$$et{INDENT}\[Process ipco box later]");
9574             } else {
9575 671         2285 $et->ProcessDirectory(\%dirInfo, $subTable, $proc);
9576             }
9577             }
9578 674 100       2468 if ($tag eq 'stbl') {
    100          
9579             # process sample data when exiting SampleTable box if extracting embedded
9580 38 100       202 ProcessSamples($et) if $ee;
9581             } elsif ($tag eq 'minf') {
9582 38         124 $$et{HandlerType} = ''; # reset handler type at end of media info box
9583             }
9584 674         1372 $$et{SET_GROUP1} = $oldGroup1;
9585 674         1612 SetByteOrder('MM');
9586             } elsif ($hasData) {
9587             # handle atoms containing 'data' tags
9588             # (currently ignore contained atoms: 'itif', 'name', etc.)
9589 157         308 my $pos = 0;
9590 157         248 for (;;) {
9591 318 100       747 last if $pos + 16 > $size;
9592 161         761 my ($len, $type, $flags, $ctry, $lang) = unpack("x${pos}Na4Nnn", $val);
9593 161 50 33     643 last if $pos + $len > $size or not $len;
9594 161         292 my ($value, $langInfo, $oldDir);
9595 161         313 my $format = $$tagInfo{Format};
9596 161 50 33     581 if ($type eq 'data' and $len >= 16) {
9597 161         251 $pos += 16;
9598 161         261 $len -= 16;
9599 161         334 $value = substr($val, $pos, $len);
9600             # format flags (ref 12):
9601             # 0x0=binary, 0x1=UTF-8, 0x2=UTF-16, 0x3=ShiftJIS,
9602             # 0x4=UTF-8 0x5=UTF-16, 0xd=JPEG, 0xe=PNG,
9603             # 0x15=signed int, 0x16=unsigned int, 0x17=float,
9604             # 0x18=double, 0x1b=BMP, 0x1c='meta' atom
9605 161 100       382 if ($stringEncoding{$flags}) {
9606             # handle all string formats
9607 116         408 $value = $et->Decode($value, $stringEncoding{$flags});
9608             # (shouldn't be null terminated, but some software writes it anyway)
9609 116 50       409 $value =~ s/\0$// unless $$tagInfo{Binary};
9610             } else {
9611 45 100       245 if (not $format) {
    100          
9612 12         49 $format = QuickTimeFormat($flags, $len);
9613             } elsif ($format =~ /^int\d+([us])$/) {
9614             # adjust integer to available length (but not int64)
9615 15         100 my $fmt = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len};
9616 15 50       90 $format = $fmt . $1 if defined $fmt;
9617             }
9618 45 100       112 if ($format) {
    50          
9619 33         168 $value = ReadValue(\$value, 0, $format, $$tagInfo{Count}, $len);
9620             } elsif (not $$tagInfo{ValueConv}) {
9621             # make binary data a scalar reference unless a ValueConv exists
9622 12         27 my $buf = $value;
9623 12         55 $value = \$buf;
9624             }
9625             }
9626             }
9627 161 100 66     579 if ($ctry or $lang) {
9628 1         4 my $langCode = GetLangCode($lang, $ctry);
9629 1 50       5 if ($langCode) {
9630             # get tagInfo for other language
9631 1         6 $langInfo = GetLangInfoQT($et, $tagInfo, $langCode);
9632             # save other language tag ID's so we can delete later if necessary
9633 1 50       5 if ($langInfo) {
9634 1 50       6 $$tagInfo{OtherLang} or $$tagInfo{OtherLang} = [ ];
9635 1         2 push @{$$tagInfo{OtherLang}}, $$langInfo{TagID};
  1         6  
9636             }
9637             }
9638             }
9639 161 100       338 $langInfo or $langInfo = $tagInfo;
9640 161 0       314 $et->VerboseInfo($tag, $langInfo,
    50          
9641             Value => ref $value ? $$value : $value,
9642             DataPt => \$val,
9643             DataPos => $dataPos,
9644             Start => $pos,
9645             Size => $len,
9646             Format => $format,
9647             Index => $index,
9648             Extra => sprintf(", Type='${type}', Flags=0x%x, Lang=0x%.4x",$flags,$lang),
9649             ) if $verbose;
9650             # use "Keys" in path instead of ItemList if this was defined by a Keys tag
9651 161   100     902 my $isKey = $$tagInfo{Groups} && $$tagInfo{Groups}{1} && $$tagInfo{Groups}{1} eq 'Keys';
9652 161 100       340 if ($isKey) {
9653 22         46 $oldDir = $$et{PATH}[-1];
9654 22         52 $$et{PATH}[-1] = 'Keys';
9655             }
9656 161 50       609 $et->FoundTag($langInfo, $value) if defined $value;
9657 161 100       407 $$et{PATH}[-1] = $oldDir if $isKey;
9658 161         306 $pos += $len;
9659             }
9660             } elsif ($tag =~ /^\xa9/ or $$tagInfo{IText}) {
9661             # parse international text to extract all languages
9662 49         104 my $pos = 0;
9663 49 50       113 if ($$tagInfo{Format}) {
9664 0         0 $et->FoundTag($tagInfo, ReadValue(\$val, 0, $$tagInfo{Format}, undef, length($val)));
9665 0         0 $pos = $size;
9666             }
9667 49         76 for (;;) {
9668 98         160 my ($len, $lang);
9669 98 100 66     306 if ($$tagInfo{IText} and $$tagInfo{IText} >= 6) {
9670 4 100       14 last if $pos + $$tagInfo{IText} > $size;
9671 2         5 $pos += $$tagInfo{IText} - 2;
9672 2         7 $lang = unpack("x${pos}n", $val);
9673 2         4 $pos += 2;
9674 2         4 $len = $size - $pos;
9675             } else {
9676 94 100       251 last if $pos + 4 > $size;
9677 47         176 ($len, $lang) = unpack("x${pos}nn", $val);
9678 47         98 $pos += 4;
9679             # according to the QuickTime spec (ref 12), $len should include
9680             # 4 bytes for length and type words, but nobody (including
9681             # Apple, Pentax and Kodak) seems to add these in, so try
9682             # to allow for either
9683 47 50       110 if ($pos + $len > $size) {
9684 0         0 $len -= 4;
9685 0 0 0     0 last if $pos + $len > $size or $len < 0;
9686             }
9687             }
9688             # ignore any empty entries (or null padding) after the first
9689 49 50 33     122 next if not $len and $pos;
9690 49         110 my $str = substr($val, $pos, $len);
9691 49         77 my ($langInfo, $enc);
9692 49 50 33     220 if (($lang < 0x400 or $lang == 0x7fff) and $str !~ /^\xfe\xff/) {
      33        
9693             # this is a Macintosh language code
9694             # a language code of 0 is Macintosh english, so treat as default
9695 49 50       109 if ($lang) {
9696 0 0       0 if ($lang == 0x7fff) {
9697             # technically, ISO 639-2 doesn't have a 2-character
9698             # equivalent for 'und', but use 'un' anyway
9699 0         0 $lang = 'un';
9700             } else {
9701             # use Font.pm to look up language string
9702 0         0 require Image::ExifTool::Font;
9703 0         0 $lang = $Image::ExifTool::Font::ttLang{Macintosh}{$lang};
9704             }
9705             } else {
9706             # for the default language code of 0x0000, use UTF-8 instead
9707             # of the CharsetQuickTime setting if obviously UTF8
9708 49 50       206 $enc = 'UTF8' if Image::ExifTool::IsUTF8(\$str) > 0;
9709             }
9710             # the spec says only "Macintosh text encoding", but
9711             # allow this to be configured by the user
9712 49 50       131 $enc = $charsetQuickTime unless $enc;
9713             } else {
9714             # convert language code to ASCII (ignore read-only bit)
9715 0         0 $lang = UnpackLang($lang);
9716             # may be either UTF-8 or UTF-16BE
9717 0 0       0 $enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8';
9718             }
9719 49 100       130 unless ($$tagInfo{NoDecode}) {
9720 48         142 $str = $et->Decode($str, $enc);
9721 48         122 $str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags)
9722             }
9723 49 100 100     143 if ($$tagInfo{IText} and $$tagInfo{IText} > 6) {
9724 1         5 my $n = $$tagInfo{IText} - 6;
9725             # add back extra bytes (eg. 'rtng' box)
9726 1         4 $str = substr($val, $pos-$n-2, $n) . $str;
9727             }
9728 49 50       117 $langInfo = GetLangInfoQT($et, $tagInfo, $lang) if $lang;
9729 49   33     294 $et->FoundTag($langInfo || $tagInfo, $str);
9730 49         119 $pos += $len;
9731             }
9732             } else {
9733 251         601 my $format = $$tagInfo{Format};
9734 251 100       547 if ($format) {
9735 68         346 $val = ReadValue(\$val, 0, $format, $$tagInfo{Count}, length($val));
9736             }
9737 251         432 my $oldBase;
9738 251 50       674 if ($$tagInfo{SetBase}) {
9739 0         0 $oldBase = $$et{BASE};
9740 0         0 $$et{BASE} = $dataPos;
9741             }
9742 251         808 my $key = $et->FoundTag($tagInfo, $val);
9743 251 50       674 $$et{BASE} = $oldBase if defined $oldBase;
9744             # decode if necessary (NOTE: must be done after RawConv)
9745 251 50 66     1835 if (defined $key and (not $format or $format =~ /^string/) and
      100        
      100        
      66        
      100        
      66        
      66        
9746             not $$tagInfo{Unknown} and not $$tagInfo{ValueConv} and
9747             not $$tagInfo{Binary} and defined $$et{VALUE}{$key} and not ref $val)
9748             {
9749 20         72 my $vp = \$$et{VALUE}{$key};
9750 20 50 66     195 if (not ref $$vp and length($$vp) <= 65536 and $$vp =~ /[\x80-\xff]/) {
      66        
9751             # the encoding of this is not specified, so use CharsetQuickTime
9752             # unless the string is valid UTF-8
9753 0 0       0 my $enc = Image::ExifTool::IsUTF8($vp) > 0 ? 'UTF8' : $charsetQuickTime;
9754 0         0 $$vp = $et->Decode($$vp, $enc);
9755             }
9756             }
9757             }
9758             }
9759             } else {
9760 88 50       250 $et->VerboseInfo($tag, $tagInfo,
9761             Size => $size,
9762             Extra => sprintf(' at offset 0x%.4x', $raf->Tell()),
9763             ) if $verbose;
9764 88 50 33     402 if ($size and (not $raf->Seek($size-1, 1) or $raf->Read($buff, 1) != 1)) {
      66        
9765 0         0 my $t = PrintableTagID($tag,2);
9766 0         0 $et->Warn("Truncated '${t}' data");
9767 0         0 last;
9768             }
9769             }
9770 1253         2273 $dataPos += $size + 8; # point to start of next atom data
9771 1253 100 100     4351 last if $dirEnd and $dataPos >= $dirEnd; # (note: ignores last value if 0 bytes)
9772 890 100       2746 $raf->Read($buff, 8) == 8 or last;
9773 870         3219 ($size, $tag) = unpack('Na4', $buff);
9774 870 100       2543 ++$index if defined $index;
9775             }
9776             # tweak file type based on track content ("iso*" and "dash" ftyp only)
9777 383 0 66     1142 if ($topLevel and $$et{VALUE}{FileType} and $$et{VALUE}{FileType} eq 'MP4' and
      33        
      33        
      0        
      0        
      0        
      0        
9778             $$et{save_ftyp} and $$et{HasHandler} and $$et{save_ftyp} =~ /^(iso|dash)/ and
9779             $$et{HasHandler}{soun} and not $$et{HasHandler}{vide})
9780             {
9781 0         0 $et->OverrideFileType('M4A', 'audio/mp4');
9782             }
9783             # fill in missing defaults for alternate language tags
9784             # (the first language is taken as the default)
9785 383 100 100     848 if ($doDefaultLang and $$et{QTLang}) {
9786 1         4 QTLang: foreach $tag (@{$$et{QTLang}}) {
  1         5  
9787 1 50       6 next unless defined $$et{VALUE}{$tag};
9788 1 50       6 my $langInfo = $$et{TAG_INFO}{$tag} or next;
9789 1 50       4 my $tagInfo = $$langInfo{SrcTagInfo} or next;
9790 1         2 my $infoHash = $$et{TAG_INFO};
9791 1         6 my $name = $$tagInfo{Name};
9792             # loop through all instances of this tag name and generate the default-language
9793             # version only if we don't already have a QuickTime tag with this name
9794 1         2 my ($i, $key);
9795 1         5 for ($i=0, $key=$name; $$infoHash{$key}; ++$i, $key="$name ($i)") {
9796 1 50       7 next QTLang if $et->GetGroup($key, 0) eq 'QuickTime';
9797             }
9798 0         0 $et->FoundTag($tagInfo, $$et{VALUE}{$tag});
9799             }
9800 1         4 delete $$et{QTLang};
9801             }
9802             # process item information now that we are done processing its 'meta' container
9803 383 100 100     1487 HandleItemInfo($et) if $topLevel or $dirID eq 'meta';
9804              
9805 383 100 100     1001 ScanMediaData($et) if $ee and $topLevel; # brute force scan for metadata embedded in media data
9806              
9807             # restore any changed options
9808 383         957 $et->Options($_ => $saveOptions{$_}) foreach keys %saveOptions;
9809 383         1916 return 1;
9810             }
9811              
9812             #------------------------------------------------------------------------------
9813             # Process a QuickTime Image File
9814             # Inputs: 0) ExifTool object reference, 1) directory information reference
9815             # Returns: 1 on success
9816             sub ProcessQTIF($$)
9817             {
9818 0     0 0   my ($et, $dirInfo) = @_;
9819 0           my $table = GetTagTable('Image::ExifTool::QuickTime::ImageFile');
9820 0           return ProcessMOV($et, $dirInfo, $table);
9821             }
9822              
9823             1; # end
9824              
9825             __END__